Micro-channel pay call interface (transfer)

Micro-channel pay call interface

 Disclaimer: This article is a blogger original article, shall not be reproduced without the bloggers allowed. https://blog.csdn.net/zoroduyu/article/details/79911278

In last week's blog, I talked about calling Alipay payment interface, this week we continue to talk about how to call micro-payment interface letter. 
Before talking about is still to be given an official letter of micro interface description . The official description of the scene is as follows:

Write pictures described here

In fact, the pc-payment scenarios are similar, the user clicks the button to generate a two-dimensional code, the payment after the success of micro-channel scan code. To call micro-channel interface, first you need to introduce jar package micro-channel pay, as follows:

        <dependency>
            <groupId>com.github.wxpay</groupId> <artifactId>wxpay-sdk</artifactId> <version>0.0.3</version> </dependency>

 

 

I call micro-channel official brought an example of changed a bit, became the following tools:

package com.example.ffmpeg;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry; import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.DocumentHelper; import org.dom4j.Element; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.github.wxpay.sdk.WXPay; public class WXService { private static Logger logger = LoggerFactory.getLogger(WXService.class); private WXPay wxpay; private WXPayConfigImpl config; private static WXService INSTANCE; private WXService() throws Exception { config = WXPayConfigImpl.getInstance(); wxpay = new WXPay(config); } public static WXService getInstance() throws Exception { if (INSTANCE == null) { synchronized (WXPayConfigImpl.class) { if (INSTANCE == null) { INSTANCE = new WXService(); } } } return INSTANCE; } /** * 微信下單接口 * * @param out_trade_no * @param body * @param money * @param applyNo * @return */ public String doUnifiedOrder(String out_trade_no, String body, Double money, String applyNo) { String amt = String.valueOf(money * 100); HashMap<String, String> data = new HashMap<String, String>(); data.put("body", body); data.put("out_trade_no", out_trade_no); data.put("device_info", "web"); data.put("fee_type", "CNY"); data.put("total_fee", amt.substring(0, amt.lastIndexOf("."))); data.put("spbill_create_ip", config.getSpbillCreateIp()); data.put("notify_url", config.getNotifUrl()); data.put("trade_type", config.getTradeType()); data.put("product_id", applyNo); System.out.println(String.valueOf(money * 100)); // data.put("time_expire", "20170112104120"); try { Map<String, String> r = wxpay.unifiedOrder(data); logger.info("返回的参数是" + r); return r.get("code_url"); } catch (Exception e) { e.printStackTrace(); logger.info(e.getMessage()); return null; } } /** * 退款 已测试 */ public void doRefund(String out_trade_no, String total_fee) { logger.info("退款时的订单号为:" + out_trade_no + "退款时的金额为:" + total_fee); String amt = String.valueOf(Double.parseDouble(total_fee) * 100); logger.info("修正后的金额为:" + amt); logger.info("最终的金额为:" + amt.substring(0, amt.lastIndexOf("."))); HashMap<String, String> data = new HashMap<String, String>(); data.put("out_trade_no", out_trade_no); data.put("out_refund_no", out_trade_no); data.put("total_fee", amt.substring(0, amt.lastIndexOf("."))); data.put("refund_fee", amt.substring(0, amt.lastIndexOf("."))); data.put("refund_fee_type", "CNY"); data.put("op_user_id", config.getMchID()); try { Map<String, String> r = wxpay.refund(data); logger.info("退款操作返回的参数为" + r); } catch (Exception e) { e.printStackTrace(); } } /** * 微信验签接口 * * @param out_trade_no * @param body * @param money * @param applyNo * @return * @throws DocumentException */ public boolean checkSign(String strXML) throws DocumentException { SortedMap<String, String> smap = new TreeMap<String, String>(); Document doc = DocumentHelper.parseText(strXML); Element root = doc.getRootElement(); for (Iterator iterator = root.elementIterator(); iterator.hasNext();) { Element e = (Element) iterator.next(); smap.put(e.getName(), e.getText()); } return isWechatSign(smap,config.getKey()); } private boolean isWechatSign(SortedMap<String, String> smap,String apiKey) { StringBuffer sb = new StringBuffer(); Set<Entry<String, String>> es = smap.entrySet(); Iterator<Entry<String, String>> it = es.iterator(); while (it.hasNext()) { Entry<String, String> entry = it.next(); String k = (String) entry.getKey(); String v = (String) entry.getValue(); if (!"sign".equals(k) && null != v && !"".equals(v) && !"key".equals(k)) { sb.append(k + "=" + v + "&"); } } sb.append("key=" + apiKey); /** 验证的签名 */ String sign = MD5Util.MD5Encode(sb.toString(), "utf-8").toUpperCase(); /** 微信端返回的合法签名 */ String validSign = ((String) smap.get("sign")).toUpperCase(); return validSign.equals(sign); } } 

 

I single micro-channel, refund, inspection to check the operation of the Packaging WXService tool inside the class. This class requires two member variables and wxpay config, are examples of object WXPay and WXPayConfigImpl. WXPay micro message is a quote from kits. WXPayConfigImpl it is to write a class, as follows:

package com.example.ffmpeg;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream; import com.github.wxpay.sdk.WXPayConfig; public class WXPayConfigImpl implements WXPayConfig{ private byte[] certData; private static WXPayConfigImpl INSTANCE; private WXPayConfigImpl() throws Exception{ String certPath = "F:\\weixin\\apiclient_cert.p12"; File file = new File(certPath); InputStream certStream = new FileInputStream(file); this.certData = new byte[(int) file.length()]; certStream.read(this.certData); certStream.close(); } public static WXPayConfigImpl getInstance() throws Exception{ if (INSTANCE == null) { synchronized (WXPayConfigImpl.class) { if (INSTANCE == null) { INSTANCE = new WXPayConfigImpl(); } } } return INSTANCE; } public String getAppID() { return "你的appid"; } public String getMchID() { return "你的商户id"; } public String getKey() { return "你设置的key值"; } public String getNotifUrl() { return "微信通知回调的url接口"; } public String getTradeType() { return "NATIVE"; } public InputStream getCertStream() { ByteArrayInputStream certBis; certBis = new ByteArrayInputStream(this.certData); return certBis; } public int getHttpConnectTimeoutMs() { return 2000; } public int getHttpReadTimeoutMs() { return 10000; } // IWXPayDomain getWXPayDomain() { // return WXPayDomainSimpleImpl.instance(); // } public String getPrimaryDomain() { return "api.mch.weixin.qq.com"; } public String getAlternateDomain() { return "api2.mch.weixin.qq.com"; } public int getReportWorkerNum() { return 1; } public int getReportBatchSize() { return 2; } public String getSpbillCreateIp() { // TODO Auto-generated method stub return "192.168.1.1"; } }

 

It can be seen that this class implements the interface WXPayConfig provided micro-channel, which encapsulates some methods, mainly return parameters needed to interface micro-channel. It is worth noting that this certificate file needs to read a file named apiclient_cert.p12 of. The certificate file that you can log on merchant platform micro letter . Here to download the certificate you need. WXPayConfigImpl inside the constructor to read the file, so the constructor throw an exception. Since the constructor throws an exception, so there is no internal static class object instead of using the double-locking manner to achieve a single embodiment.

回到WXService这个类中,代码往下走,在WXService的构造器中对config和wxpay进行了实例化。接下来同样是用双检锁的方式实现的单例。往下走,微信的下单接口,分别传入out_trade_no(外部订单号),body(商品描述), money(付款金额), applyNo(对应微信的product_id:商品id,由商户自定义)四个参数。进入方法后第一句话String amt = String.valueOf(money * 100);是把传入的钱数乘以100,并转换成字符串。这里之所以乘以100是因为微信那边会把我们传过去的钱数除以100得到应付金额,且不能传小数,所以下面的那一句amt.substring(0, amt.lastIndexOf(“.”))就是为了把金额中的小数点去掉。往下走,new出了一个hashmap,将参数传入hashmap中,然后调用wxpay.unifiedOrder(data);下单接口下单。得到返回的map集合,从map中获得的code_url这个参数就是微信返回给我们生成二维码的字符串。这样,下单的整个流程就跑通了,现在写个测试类来测试一下。

package com.example.ffmpeg;

public class Test {

    public static void main(String[] args) throws Exception { WXService wx = WXService.getInstance(); String QRcode = wx.doUnifiedOrder("test001", "测试下单接口", 0.01, "a123456"); System.out.println("得到的二维码是:"+QRcode); } }

 

运行结果如下图:

Write pictures described here

如何检验该二维码是否是正确的喃?很简单,打开百度,搜索二维码生成器,如下图所示:

Write pictures described here

点击进入第二个百度应用里面的进入应用,出现如下图所示:

Write pictures described here

选择通用文本,在中间的文本框中粘贴刚才拿到的二维码字符串,点击生成按钮,右边就会生成一个二维码了。如下:

Write pictures described here

当然,这只是我们后台人员测试时使用的方法,实际生产环境中前端可以用一些javascript的插件去生成二维码。

下单接口完了之后,紧接着就是退款的方法,该方法比较简单且和下单方法大同小异,同学们自己看看注释应该可以理解了。再往后走是微信验签的方法。在讲这个方法之前,先来看看微信的回调方法:

/**
     * 微信回调的接口
     * 
     * @param uuid
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/wxReturnPay")
    public void wxReturnPay(HttpServletResponse response, HttpServletRequest request)
            throws Exception {

        logger.info("****************************************wxReturnPay微信的回调函数被调用******************************"); String inputLine; String notityXml = ""; request.setCharacterEncoding("UTF-8"); response.setCharacterEncoding("UTF-8"); response.setContentType("text/html;charset=UTF-8"); response.setHeader("Access-Control-Allow-Origin", "*"); // 微信给返回的东西 try { while ((inputLine = request.getReader().readLine()) != null) { notityXml += inputLine; } request.getReader().close(); } catch (Exception e) { e.printStackTrace(); logger.info("xml获取失败"); response.getWriter().write(setXml("fail", "xml获取失败")); return; } if (StringUtils.isEmpty(notityXml)) { logger.info("xml为空"); response.getWriter().write(setXml("fail", "xml为空")); return; } WXService wxService = WXService.getInstance(); if(!wxService.checkSign(notityXml)) { response.getWriter().write(setXml("fail", "验签失败")); } logger.info("xml的值为:" + notityXml); XMLSerializer xmlSerializer = new XMLSerializer(); JSON json = xmlSerializer.read(notityXml); logger.info(json.toString()); JSONObject jsonObject=JSONObject.fromObject(json.toString()); UnifiedOrderRespose returnPay = (UnifiedOrderRespose) JSONObject.toBean(jsonObject, UnifiedOrderRespose.class); logger.info(("转换后的实体bean为:"+returnPay.toString())); logger.info(("订单号:"+returnPay.getOut_trade_no()+"价格:"+returnPay.getTotal_fee())); if (returnPay.getReturn_code().equals("SUCCESS") && returnPay.getOut_trade_no() != null && !returnPay.getOut_trade_no().isEmpty()) { double fee = Double.parseDouble(returnPay.getTotal_fee()); returnPay.setTotal_fee(String.valueOf(fee/100)); logger.info("微信的支付状态为SUCCESS"); tbPaymentRecordsService.wxPaySuccess(returnPay); } }

 

After successful payment, micro-channel will be the callback method (callback url is past when we pass under a single call to the interface). Entry method, the first instance of the object will get HttpServletRequest stream, he will read out, there is a result notityXml micro-channel read out, xml format string is a string, there are a variety of callback parameter information, example returns the result as follows:

<xml>
  <appid><![CDATA[wx2421b1c4370ec43b]]></appid> <attach><![CDATA[支付测试]]></attach> <bank_type><![CDATA[CFT]]></bank_type> <fee_type><![CDATA[CNY]]></fee_type> <is_subscribe><![CDATA[Y]]></is_subscribe> <mch_id><![CDATA[10000100]]></mch_id> <nonce_str><![CDATA[5d2b6c2a8db53831f7eda20af46e531c]]></nonce_str> <openid><![CDATA[oUpF8uMEb4qRXf22hE3X68TekukE]]></openid> <out_trade_no><![CDATA[1409811653]]></out_trade_no> <result_code><![CDATA[SUCCESS]]></result_code> <return_code><![CDATA[SUCCESS]]></return_code> <sign><![CDATA[B552ED6B279343CB493C5DD0D78AB241]]></sign> <sub_mch_id><![CDATA[10000100]]></sub_mch_id> <time_end><![CDATA[20140903131540]]></time_end> <total_fee>1</total_fee> <coupon_fee><![CDATA[10]]></coupon_fee> <coupon_count><![CDATA[1]]></coupon_count> <coupon_type><![CDATA[CASH]]></coupon_type> <coupon_id><![CDATA[10000]]></coupon_id> <coupon_fee><![CDATA[100]]></coupon_fee> <trade_type><![CDATA[JSAPI]]></trade_type> <transaction_id><![CDATA[1004400740201409030005092168]]></transaction_id> </xml> 

Returns the argument is that behind like this naturally involves parsing xml parameters. The method of sign into the experience:

/**
     * 微信验签接口
     * 
     * @param out_trade_no
     * @param body
     * @param money
     * @param applyNo * @return * @throws DocumentException */ public boolean checkSign(String strXML) throws DocumentException { SortedMap<String, String> smap = new TreeMap<String, String>(); Document doc = DocumentHelper.parseText(strXML); Element root = doc.getRootElement(); for (Iterator iterator = root.elementIterator(); iterator.hasNext();) { Element e = (Element) iterator.next(); smap.put(e.getName(), e.getText()); } return isWechatSign(smap,config.getKey()); } private boolean isWechatSign(SortedMap<String, String> smap,String apiKey) { StringBuffer sb = new StringBuffer(); Set<Entry<String, String>> es = smap.entrySet(); Iterator<Entry<String, String>> it = es.iterator(); while (it.hasNext()) { Entry<String, String> entry = it.next(); String k = (String) entry.getKey(); String v = (String) entry.getValue(); if (!"sign".equals(k) && null != v && !"".equals(v) && !"key".equals(k)) { sb.append(k + "=" + v + "&"); } } sb.append("key=" + apiKey); /** 验证的签名 */ String sign = MD5Util.MD5Encode(sb.toString(), "utf-8").toUpperCase(); /** 微信端返回的合法签名 */ String validSign = ((String) smap.get("sign")).toUpperCase(); return validSign.equals(sign); }

 

Dom4j DocumentHelper first with the resulting string parsing Document object, then the object obtained with the elements, traversal, the values ​​stored in the key and value SortedMap, and then passed together with the micro isWechatSign method SortedMap letter key, speaking of the method used in SortedMap iterates over, the key and value stitched key1 = value1 & key2 = such forms value2, splicing and note the following points:

◆ ASCII code parameter name in ascending order (lexicographical); 
◆ If the parameter is not involved in signature null; 
◆ parameter names are case-sensitive; 
when it returns or verification ◆ micro channel proactive notification signature, sign the signature does not participate in the transmitted parameters the generated signature value and the sign for check. 
◆ micro-channel interfaces may increase the field, it is necessary to support increased extension field during signature verification

After completion string concatenation, encrypted using MD5, then the resulting string is all converted to uppercase. The converted character string passed our micro-letter sign parameters for comparison, if the same, then the sign test is successful, if not the same, then the check fails inspection.

After verification method signature belongs to the category of business logic, business logic are not the same for everyone, and I will not repeat them here. So this is called micro-channel basic operation I had finished, to see how to call Alipay students can see my Alipay call interface of this article. Then this blog on here, bye.

Guess you like

Origin www.cnblogs.com/LiZhongZhongY/p/10992552.html