Implementing wechat payment in Java

Keywords: Java xml

I. business requirements

To implement app wechat payment, the backend needs to generate advance payment documents and respond to the payment results.

II. Business process

View official documents

  https://pay.weixin.qq.com/wik...

III. implementation method

3.1 create the wechat tool class ConstantUtil
[Java] plain text view copy code
?

public class ConstantUtil {

/**
 * Wechat development platform application ID
 */
public static final String APP_ID="wx2421b1c4370ec43b";
/**
 * Apply corresponding voucher
 */
public static final String APP_SECRET="1add1a30ac87aa2db72f57a2375d8fec";
/**
 * Apply the corresponding key
 */
public static final String APP_KEY="1add1a30ac87aa2db72f57a2375d8fec";
/**
 * Wechat payment merchant No
 */
public static final String MCH_ID="10000100";
/**
 * Commodity Description
 */
public static final String BODY="Recharge";
/**
 * Key corresponding to merchant number
 */
public static final String PARTNER_key="*******"; 

/**
 * Merchant id
 */
public static final String PARTNER_ID="*******"; 
/**
 * Constant fixed value
 */
public static final String GRANT_TYPE="client_credential";
/**
 * Get the interface url of the pre payment id
 */
public static String GATEURL = "https://api.mch.weixin.qq.com/pay/unifiedorder";
/**
 * Wechat server callback notification url
 */
public static String NOTIFY_URL="http://url "; / / accessible url
/**
 * Wechat server query order url
 */
public static String ORDER_QUERY="https://api.mch.weixin.qq.com/pay/orderquery";

}

3.2 generate advance payment order
[Java] plain text view copy code
?

Map<String, Object> getOrder(@RequestParam(value = "totalFee") String totalFee, @RequestParam(value = "deviceInfo") String deviceInfo,

                             @RequestParam(value = "attach") String attach,
                             HttpServletRequest request, HttpServletResponse response)
        throws Exception {
    Map<String, Object> map = new HashMap<String, Object>();
    // Get the request class to generate the advance payment order
    PrepayIdRequestHandler prepayReqHandler = new PrepayIdRequestHandler(request, response);

// String totalFee = request.getParameter("total_fee");

    int total_fee = (int) (Float.valueOf(totalFee) * 100);
    System.out.println("total:" + total_fee);
    System.out.println("total_fee:" + total_fee);
    prepayReqHandler.setParameter("appid", ConstantUtil.APP_ID);
    prepayReqHandler.setParameter("body", ConstantUtil.BODY);
    prepayReqHandler.setParameter("mch_id", ConstantUtil.MCH_ID);
    prepayReqHandler.setParameter("device_info", deviceInfo); //Card number
    prepayReqHandler.setParameter("attach", attach);//Package value
    String nonce_str = WXUtil.getNonceStr();
    prepayReqHandler.setParameter("nonce_str", nonce_str);
    prepayReqHandler.setParameter("notify_url", ConstantUtil.NOTIFY_URL);
    out_trade_no = String.valueOf(UUID.next());
    prepayReqHandler.setParameter("out_trade_no", out_trade_no);
    prepayReqHandler.setParameter("spbill_create_ip", request.getRemoteAddr());
    String timestamp = WXUtil.getTimeStamp();
    prepayReqHandler.setParameter("time_start", timestamp);
    System.out.println(String.valueOf(total_fee));
    prepayReqHandler.setParameter("total_fee", String.valueOf(total_fee));
    prepayReqHandler.setParameter("trade_type", "APP");
    /**
     * Pay attention to the generation method of signature. For details, please refer to the official documents (all the parameters should participate in the generation of signature, and the parameter names should be sorted according to the dictionary order, followed by APP_KEY, and converted to uppercase)
     */
    prepayReqHandler.setParameter("sign", prepayReqHandler.createMD5Sign());
    prepayReqHandler.setGateUrl(ConstantUtil.GATEURL);
    String prepayid = prepayReqHandler.sendPrepay();
    // If the prepayid is obtained successfully, relevant information will be returned to the client
    if (prepayid != null && !prepayid.equals("")) {
        String signs = "appid=" + ConstantUtil.APP_ID + "&noncestr=" + nonce_str + "&package=Sign=WXPay&partnerid="
                + ConstantUtil.PARTNER_ID + "&prepayid=" + prepayid + "×tamp=" + timestamp + "&key="
                + ConstantUtil.APP_KEY;
        map.put("code", 0);
        map.put("info", "success");
        map.put("prepayid", prepayid);
        /**
         * The signature method is similar to the above
         */
        map.put("sign", MD5Util.MD5Encode(signs, "utf8").toUpperCase());
        map.put("appid", ConstantUtil.APP_ID);
        map.put("device_info", deviceInfo);
        map.put("attach", attach);
        map.put("timestamp", timestamp);  //Equal to time "start" when prepayId is requested
        map.put("noncestr", nonce_str);   //The value is the same as when prepayId is requested
        map.put("package", "Sign=WXPay");  //Fixed constant
        map.put("partnerid", ConstantUtil.PARTNER_ID);
    } else {
        map.put("code", 1);
        map.put("info", "Obtain prepayid fail");
    }
    return map;
}

3.3 asynchronous notification of customer results

[Java] plain text view copy code
?

PrintWriter writer = response.getWriter();

    InputStream inStream = request.getInputStream();
    ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
    byte[] buffer = new byte[1024];
    int len = 0;
    while ((len = inStream.read(buffer)) != -1) {
        outSteam.write(buffer, 0, len);
    }
    outSteam.close();
    inStream.close();
    String result = new String(outSteam.toByteArray(), "utf-8");
    System.out.println("Wechat payment notice result:" + result);
    Map<String, String> map = null;
    try {
        /**
         * Analyze the information returned by wechat notification
         */
        map = XMLUtil.doXMLParse(result);
    } catch (JDOMException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

In the official documents, it is specially reminded that the merchant system must conduct signature verification for the content of payment result notification, and verify whether the returned order amount is consistent with the order amount on the merchant side, so as to prevent data leakage leading to "false notification" and capital loss.
The content of payment result notice shall be signed and verified.

[Java] plain text view copy code

//sign verification after successful payment
String appid=map.get("appid");
String transaction_id=map.get("transaction_id");
String nonce_str =map.get("nonce_str");
String bank_type =map.get("bank_type");
String openid=map.get("openid");
String sign =map.get("sign");
String fee_type =map.get("fee_type");
String mch_id =map.get("mch_id");
String cash_fee =map.get("cash_fee");
String device_info =map.get("device_info");
String out_trade_no =map.get("out_trade_no");
String total_fee =map.get("total_fee");
String trade_type =map.get("trade_type");
String result_code =map.get("result_code");
String attach =map.get("attach");
String time_end =map.get("time_end");
String is_subscribe =map.get("is_subscribe");
String return_code=map.get("return_code");

PrepayIdRequestHandler prepayReqHandler = new PrepayIdRequestHandler(request, response);
prepayReqHandler.setParameter("appid",appid);
prepayReqHandler.setParameter("attach",attach);
prepayReqHandler.setParameter("bank_type",bank_type);
prepayReqHandler.setParameter("cash_fee",cash_fee);
prepayReqHandler.setParameter("device_info",device_info);
prepayReqHandler.setParameter("fee_type",fee_type);
prepayReqHandler.setParameter("is_subscribe",is_subscribe);
prepayReqHandler.setParameter("mch_id",mch_id);
prepayReqHandler.setParameter("nonce_str",nonce_str);
prepayReqHandler.setParameter("openid",openid);
prepayReqHandler.setParameter("out_trade_no",out_trade_no);
prepayReqHandler.setParameter("result_code",result_code);
prepayReqHandler.setParameter("return_code",return_code);
prepayReqHandler.setParameter("time_end",time_end);
prepayReqHandler.setParameter("total_fee",total_fee);
prepayReqHandler.setParameter("trade_type",trade_type);
prepayReqHandler.setParameter("transaction_id",transaction_id);

String endSigns =prepayReqHandler.createMD5Sign(); / / content signature verification of payment result notification

Merchant amount query

[Java] plain text view copy code
?

PrepayIdRequestHandler orderQueryHandler = new PrepayIdRequestHandler(request, response);

    orderQueryHandler.setParameter("appid",appid);
    orderQueryHandler.setParameter("mch_id",mch_id);
    orderQueryHandler.setParameter("out_trade_no",out_trade_no);
    orderQueryHandler.setParameter("nonce_str",nonce_str);
    orderQueryHandler.setParameter("sign",orderQueryHandler.createMD5Sign());
    orderQueryHandler.setGateUrl(ConstantUtil.ORDER_QUERY);
    String resXml = "";
    WeixinOrderBean orderBean =orderQueryHandler.selectOrder();

Answer wechat

[AppleScript] plain text view copy code

If (sign. Equals (endsigns) & & integer. ParseInt (total fee) = = orderbean. Gettotal fee()) {/ / the order is signed and the returned amount is the same as the merchant amount

        // If the payment is successful, inform the wechat server to receive the notification
        if (map.get("return_code").equals("SUCCESS")) {
            System.out.println("Recharge succeeded!");
            //PayRecord payRecord=payRecordService.get(Long.valueOf(map.get("out_trade_no")));
            System.out.println("Order number:" + Long.valueOf(map.get("out_trade_no")));
            String iccids = map.get("device_info");
            String monthNum = map.get("attach");

/ / process according to your own business

            int count =trafficCardListService.selectExistTrafficCardByOutTradeNo(map.get("out_trade_no")); //Query whether the merchant order number exists
            if(count==0){//Insert if it doesn't exist
                List<MsisdnOrderBean> msisdnOrderList = trafficCardListService.selectTrafficCardRechargeResult(iccids, monthNum);
                if (msisdnOrderList.size() > 0) {
                    for (MsisdnOrderBean msisdnOrderBean : msisdnOrderList) {
                        msisdnOrderBean.setOutTradeNo(map.get("out_trade_no"));
                        msisdnOrderBean.setDate(map.get("time_end"));
                        msisdnOrderBean.setIccids(map.get("device_info"));
                        // msisdnOrderBean.setTotalFee(Integer.parseInt(map.get("total_fee")));
                        msisdnOrderBean.setTotalFee(BigDecimal.valueOf(Integer.parseInt(map.get("total_fee"))).divide(new BigDecimal(100)).doubleValue());
                        msisdnOrderBean.setTransactionId(map.get("transaction_id"));
                        msisdnOrderBean.setTrafficNo(DateUtils.getNowDataTime() + ApiUtils.getFourRandom()); //MM DD YY HHM S + four digit random number
                        trafficCardListService.insertTrafficCardList(msisdnOrderBean);
                    }
                }
            }
            resXml = XMLUtil.setXML("SUCCESS", "OK");
        } else {
            resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
                    + "<return_msg><![CDATA[Notification signature verification failed]]></return_msg>" + "</xml> ";
            logger.info("Notification signature verification failed");
        }
    }else{
        resXml =XMLUtil.setXML("FAIL", "Inconsistent signature");
    }

    writer.write(resXml);
    writer.flush();
    writer.close();

PrepayIdRequestHandler utility class applied

[Java] plain text view copy code

public class PrepayIdRequestHandler extends RequestHandler {

public PrepayIdRequestHandler(HttpServletRequest request,
                              HttpServletResponse response) {
    super(request, response);
}

public String createMD5Sign() {
    StringBuffer sb = new StringBuffer();
    Set es = super.getAllParameters().entrySet();
    Iterator it = es.iterator();
    while (it.hasNext()) {
        Map.Entry entry = (Map.Entry) it.next();
        String k = (String) entry.getKey();
        String v = (String) entry.getValue();
        sb.append(k + "=" + v + "&");
    }

    String params=sb.append("key="+ConstantUtil.APP_KEY).substring(0);
    String sign = MD5Util.MD5Encode(params, "utf8");
    return sign.toUpperCase();
}

// Submit advance payment
public String sendPrepay() throws Exception {
    String prepayid = "";

Posted by Goon on Tue, 05 Nov 2019 06:29:25 -0800