微信支付(小程序+H5+扫码+APP)

今年年初做了小程序支付,最近又做了微信的h5支付和扫码支付,为了以后对接更得心应手,所以在这里做一个总结。(我是后端研发,所以这个总结主要针对后端)

就我自己理解,微信支付就4步:

1、申请微信商户号(收钱)+公众号|服务号+以及对应的秘钥
2、拿到上面的数据调用微信统一下单的接口(微信所有类型的支付,统一下单的地址都是一样的)
3、返回数据和地址给前端,前端调起微信支付
4、支付回调

然后细说一下上面的四个步骤:
一、第一步就不说了,因为申请账号的事情不需要我们做,如果以后需要自己申请了,我在百度吧!!
二、第二步是调用统一下单的接口,主要是看微信的开发者文档,把必填项为是的参数放进去请求接口就行,这里附上微信各个类型的开发者文档链接:
小程序:我是小程序开发者文档的链接
H5:我是H5开发者文档的链接
扫码:我是扫码开发者文档的链接
APP:我是APP开发者文档的链接
1、这里说一下各种类型需要注意的地方:
(1)、
微信支付(小程序+H5+扫码+APP)_第1张图片
(2)、微信小程序支付openId是必传的,h5支付scene_info是必传的,要注意。
(3)、金额都要转成分
在这里插入图片描述2、调用统一下单:
(1)、组装参数放进map
微信支付(小程序+H5+扫码+APP)_第2张图片
(2)、生成签名
微信支付(小程序+H5+扫码+APP)_第3张图片
微信支付(小程序+H5+扫码+APP)_第4张图片
3、调起微信支付:
(1)、这步后台需要做的是把需要的参数返给前端,,前端来调起微信支付。这里需要注意的是各种支付类型调起支付所需要的参数是不一样的。
H5需要mweb_url,
扫码需要code_url,
小程序需要appId、timeStamp、nonceStr、package、signType,
APP需要appid、partnerid、prepayid、package、noncestr、timestamp、sign。

4、支付回调:
(1)、验签
微信支付(小程序+H5+扫码+APP)_第5张图片
说实话,对于上面的签名验证,我都没有做,大概因为我们的业务量还不是很顶,没人搞我们!!!-_-||(官网都标红了,所以感觉这一步还是有必要的)
如果要验签,大家看微信的文档是没有的,推荐看微信给的demo,
官网的sdk:https://pay.weixin.qq.com/wiki/doc/api/jsapi_sl.php?chapter=11_1
到这个url去下载,里面有工具类,比如回调的时候验证签名:

WXPayUtil.java文件的isSignatureValid就是:

/**
     * 判断签名是否正确
     *
     * @param xmlStr XML格式数据
     * @param key API密钥
     * @return 签名是否正确
     * @throws Exception
     */
    public static boolean isSignatureValid(String xmlStr, String key) throws Exception {
     
        Map<String, String> data = xmlToMap(xmlStr);
        if (!data.containsKey(WXPayConstants.FIELD_SIGN) ) {
     
            return false;
        }
        String sign = data.get(WXPayConstants.FIELD_SIGN);
        return generateSignature(data, key).equals(sign);
    }

    /**
     * 判断签名是否正确,必须包含sign字段,否则返回false。使用MD5签名。
     *
     * @param data Map类型数据
     * @param key API密钥
     * @return 签名是否正确
     * @throws Exception
     */
    public static boolean isSignatureValid(Map<String, String> data, String key) throws Exception {
     
        return isSignatureValid(data, key, SignType.MD5);
    }

    /**
     * 判断签名是否正确,必须包含sign字段,否则返回false。
     *
     * @param data Map类型数据
     * @param key API密钥
     * @param signType 签名方式
     * @return 签名是否正确
     * @throws Exception
     */
    public static boolean isSignatureValid(Map<String, String> data, String key, SignType signType) throws Exception {
     
        if (!data.containsKey(WXPayConstants.FIELD_SIGN) ) {
     
            return false;
        }
        String sign = data.get(WXPayConstants.FIELD_SIGN);
        return generateSignature(data, key, signType).equals(sign);
    }

(2)、处理逻辑
微信支付(小程序+H5+扫码+APP)_第6张图片
微信支付(小程序+H5+扫码+APP)_第7张图片
下面是用到的工具类,小伙伴们可以参考一下:

/**
	 * 获取随机字符串 Nonce Str
	 *
	 * @return String 随机字符串
	 */
	public static String generateNonceStr() {
     
		return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32);
	}
	
	/**
	 * 除去数组中的空值和签名参数
	 * 
	 * @param sArray
	 *            签名参数组
	 * @return 去掉空值与签名参数后的新签名参数组
	 */
	public static Map<String, String> paraFilter(Map<String, String> sArray) {
     

		Map<String, String> result = new HashMap<String, String>();

		if (sArray == null || sArray.size() <= 0) {
     
			return result;
		}

		for (String key : sArray.keySet()) {
     
			String value = sArray.get(key);
			if (value == null || value.equals("") || key.equalsIgnoreCase("sign")) {
     
				continue;
			}
			result.put(key, value);
		}

		return result;
	}
	
	/**
	 * 将Map转换为XML格式的字符串
	 *
	 * @param data
	 *            Map类型数据
	 * @return XML格式的字符串
	 * @throws Exception
	 */
	public static String mapToXml(Map<String, String> data) throws Exception {
     
		DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
		DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
		org.w3c.dom.Document document = documentBuilder.newDocument();
		org.w3c.dom.Element root = document.createElement("xml");
		document.appendChild(root);
		for (String key : data.keySet()) {
     
			String value = data.get(key);
			if (value == null) {
     
				value = "";
			}
			value = value.trim();
			org.w3c.dom.Element filed = document.createElement(key);
			filed.appendChild(document.createTextNode(value));
			root.appendChild(filed);
		}
		TransformerFactory tf = TransformerFactory.newInstance();
		Transformer transformer = tf.newTransformer();
		DOMSource source = new DOMSource(document);
		transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
		transformer.setOutputProperty(OutputKeys.INDENT, "yes");
		StringWriter writer = new StringWriter();
		StreamResult result = new StreamResult(writer);
		transformer.transform(source, result);
		String output = writer.getBuffer().toString(); // .replaceAll("\n|\r",
														// "");
		try {
     
			writer.close();
		} catch (Exception ex) {
     
		}
		return output;
	}
	/**
     * xml数据转map
     * @param xml
     * @return
     * @throws DocumentException
     * @author Ban Wei
     */
    @SuppressWarnings("rawtypes")
	public static Map<String, Object> Dom2Map(String xml) throws DocumentException{
       
        Map<String, Object> map = new HashMap<String, Object>(); 
        Document doc= DocumentHelper.parseText(xml);
        if(doc == null)  
            return map;  
        Element root = doc.getRootElement();  
        for (Iterator iterator = root.elementIterator(); iterator.hasNext();) {
       
            Element e = (Element) iterator.next();  
            List list = e.elements();  
            if(list.size() > 0){
       
                map.put(e.getName(), Dom2Map(e));  
            }else  
                map.put(e.getName(), e.getText());  
        }  
        return map;  
    }
	/**
	 * 获取当前时间戳,单位秒
	 * 
	 * @return
	 */
	public static long getCurrentTimestamp() {
     
		return System.currentTimeMillis() / 1000;
	}
	
	/**
	 * 把数组所有元素字典排序,并按照“参数=参数值”的模式用“&”字符拼接成字符串
	 * 
	 * @param params
	 *            需要排序并参与字符拼接的参数组
	 * @return 拼接后字符串
	 */
	public static String createLinkString(Map<String, String> params) {
     

		List<String> keys = new ArrayList<String>(params.keySet());
		Collections.sort(keys);

		String prestr = "";

		for (int i = 0; i < keys.size(); i++) {
     
			String key = keys.get(i);
			String value = params.get(key);
			prestr = prestr + key + "=" + value + "&";
		}

		return prestr;
	}
	
	/**
	 * 生成 MD5
	 *
	 * @param data
	 *            待处理数据
	 * @return MD5结果
	 * @throws Exception
	 */
	public static String MD5(String data) throws Exception {
     
		java.security.MessageDigest md = MessageDigest.getInstance("MD5");
		byte[] array = md.digest(data.getBytes("UTF-8"));
		StringBuilder sb = new StringBuilder();
		for (byte item : array) {
     
			sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
		}
		return sb.toString().toUpperCase();
	}
	
	/**
	 *发送post请求
	 * @param reqUrl
	 * @param content
	 * @param charset
	 * @return
	 * @throws IOException
	 */
	public static String post(String reqUrl, String content, String charset) throws IOException {
     

		URL url = new URL(reqUrl);
		HttpURLConnection con = (HttpURLConnection) url.openConnection();
		con.setDoInput(true);
		con.setDoOutput(true);
		con.setAllowUserInteraction(false);
		con.setUseCaches(false);

		con.setRequestMethod("POST");
		con.setConnectTimeout(30000);// 连接超时 单位毫秒
		con.setDoOutput(true);// 是否输入参数
		con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=" + charset);
		// con.setRequestProperty("Content-Type","text/plain;charset=" +
		// charset);

		DataOutputStream dataOutput = new DataOutputStream(con.getOutputStream());

		byte[] bytes = content.toString().getBytes(charset);
		dataOutput.write(bytes);// 输入参数

		dataOutput.flush();
		dataOutput.close();

		BufferedReader bin = new BufferedReader(new InputStreamReader(con.getInputStream(), charset), SIZE);

		StringBuilder result = new StringBuilder();
		while (true) {
     
			String line = bin.readLine();
			if (line == null) {
     
				break;
			} else {
     
				result.append(line);
			}
		}
		bin.close();
		return result.toString();
	}

END!!!!!!
明天继续把支付宝支付也总结一下,奥利给!

你可能感兴趣的:(线上支付,java,vue.js)