java微信小程序支付_统一下单与更新订单状态

1.登录微信支付商户平台

https://pay.weixin.qq.com/index.php/partner/public/home

2.点击开发文档


3.进入如下界面点击小程序支付

4.微信公众平台支付账户认证

认证流程如下:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_sl_api.php?chapter=3_1

认证完成后,微信开发支付参数说明如下:

appid为和服务商商户号绑定的服务商appid,一般情况为认证的服务号appid;

mch_id为服务商商户号,目前仅在认证服务号后台(mp.weixin.qq.com)开放申请服务商商户号,申请开通后即在微信支付系统创建绑定关系;

sub_mch_id为和服务商商户号有父子绑定关系的子商户号; 

sub_appid为服务商模式的场景appid,在小程序中拉起支付时该字段必传;

trade_type请填写JSAPI;

openid为appid对应的微信用户标识; 


sub_openid为sub_appid对应的微信用户标识,小程序服务商模式下单中的openid和sub_openid必须至少传其中一个,在小程序中拉起支付一般情况下只能获取到sub_openid,即使用wx.login接口获得的openid。

5.小程序业务流程

商户系统和微信支付系统主要交互:

1)小程序内调用登录接口,获取到用户的openid,api参见公共api【小程序登录API

2)商户server调用支付统一下单,api参见公共api【统一下单API

3)商户server调用再次签名,api参见公共api【再次签名

4)商户server接收支付通知,api参见公共api【支付结果通知API

5)商户server查询支付结果,api参见公共api【查询订单API

小程序支付的交互图如下:

6.java程序接口API实现:

1)  生成订单

packagecom.jingweiiot.smart_home.utils.weixin.WXPay;

importjava.util.Map;

importjava.util.SortedMap;

importjava.util.TreeMap;

importjavax.servlet.http.HttpServletRequest;

importcom.fasterxml.jackson.core.JsonProcessingException;

importcom.fasterxml.jackson.databind.ObjectMapper;

importcom.jingweiiot.smart_home.model.UserOrderInfo;

publicclass CreateUserOrderInfo {

/**

 * 生成订单

 * @paramuserOrderInfo

 * @paramrequest

 *@return

 *@throws JsonProcessingException

 */

public static Map<String, String>createPayInfo(UserOrderInfo userOrderInfo,HttpServletRequest request) throwsJsonProcessingException {

          

           SortedMap<String, String>params = new TreeMap<String, String>();

           //自定义不重复的长度不长于32

           String nonceStr =StringUtil.getRandomString(30);

           params.put("openid",userOrderInfo.getOpenId());

        //微信开放平台审核通过的应用APPID

       params.put("appid",WXPramsContent.appId);

        //微信支付分配的商户号

       params.put("mch_id",WXPramsContent.mchId);

        //随机字符串

//       params.put("nonce_str","1233212131221121212");

       params.put("nonce_str",nonceStr);

        //商品描述

       params.put("body",WXPramsContent.body);

        //商户订单号

        params.put("out_trade_no",userOrderInfo.getOrderNum());

        //总金额

        params.put("total_fee","1");

//      params.put("total_fee",userOrderInfo.getPayAmount().multiply(new BigDecimal(100)).toString());

        //终端IP

       params.put("spbill_create_ip",WXPramsContent.getIpAddr(request));

        //通知地址

        params.put("notify_url",WXPramsContent.notifyUrl);

        //交易类型

        params.put("trade_type",WXPramsContent.tradeType);

        //MD5签名

        String sign =WeChat.createSign(params);

        params.put("sign", sign);

         //统一下单支付接口

        String xmlStr =WeChat.httpsRequest(WXPramsContent.payUrl,"POST",WeChat.map2XmlString(params));

//        System.err.println("xml:" +WeChat.map2XmlString(params));

          //微信商户平台返回支付结果以及预支付id

        Map<String, String> response =WeChat.readXmlString2Map(xmlStr);

        //二次签名

        //拼接签名需要的参数 

        ObjectMapper mapper = newObjectMapper();

       System.err.println("response:" +mapper.writeValueAsString(response));

        SortedMap<String, String>signParams = new TreeMap<String, String>();

        signParams.put("appId",WXPramsContent.appId);//app_id

        signParams.put("nonceStr", nonceStr);//自定义不重复的长度不长于32位

        signParams.put("package","prepay_id="+response.get("prepay_id"));//预付订单id

       System.out.println("package:"+response.get("prepay_id"));

        signParams.put("signType","MD5");

       signParams.put("timeStamp",String.valueOf(System.currentTimeMillis()));//北京时间时间戳

        String signAgain =WeChat.createSign(signParams);

        signParams.put("paySign",signAgain);

           return signParams;

    }

}

2)  工具类

packagecom.jingweiiot.smart_home.utils.weixin.WXPay;

importorg.dom4j.Document;

importorg.dom4j.DocumentException;

importorg.dom4j.DocumentHelper;

importorg.dom4j.Element;

importcom.fasterxml.jackson.core.JsonProcessingException;

importcom.fasterxml.jackson.databind.ObjectMapper;

importjava.io.BufferedReader;

importjava.io.InputStream;

importjava.io.InputStreamReader;

importjava.io.OutputStream;

importjava.net.ConnectException;

importjava.net.HttpURLConnection;

importjava.net.URL;

importjava.security.MessageDigest;

importjava.util.HashMap;

importjava.util.Iterator;

importjava.util.List;

importjava.util.Map;

importjava.util.Set;

importjava.util.SortedMap;

importjava.util.TreeMap;

/**

 *dom4j解析xml

 * 利用HttpClient进行post请求的工具类

 */

publicclass WeChat {

    // 微信支付请求

    static String httpsRequest(StringrequestUrl, String requestMethod, String outputStr) {

        try {

            URL url = new URL(requestUrl);

            HttpURLConnection conn = (HttpURLConnection)url.openConnection();

            conn.setDoOutput(true);

            conn.setDoInput(true);

            conn.setUseCaches(false);

            // 设置请求方式(GET/POST)

           conn.setRequestMethod(requestMethod);

           conn.setRequestProperty("content-type","application/x-www-form-urlencoded");

            // 当outputStr不为null时向输出流写数据

            if (null != outputStr) {

                OutputStream outputStream =conn.getOutputStream();

                // 注意编码格式

               outputStream.write(outputStr.getBytes("UTF-8"));

                outputStream.close();

            }

            // 从输入流读取返回内容

            InputStream inputStream =conn.getInputStream();

            InputStreamReader inputStreamReader= new InputStreamReader(inputStream, "utf-8");

            BufferedReader bufferedReader = newBufferedReader(inputStreamReader);

            String str;

            StringBuffer buffer = newStringBuffer();

            while ((str = bufferedReader.readLine())!= null) {

                buffer.append(str);

            }

            // 释放资源

            bufferedReader.close();

            inputStreamReader.close();

            inputStream.close();

            conn.disconnect();

            return buffer.toString();

        } catch (ConnectException ce) {

        } catch (Exception e) {

        }

        return null;

    }

    /**

     * map转xml格式字符串

     */

    static Stringmap2XmlString(SortedMap<String, String> params) {

        String xmlResult;

        StringBuffer sb = new StringBuffer();

        sb.append("<xml>");

        for (String key : params.keySet()) {

            String value ="<![CDATA[" + params.get(key) + "]]>";

            sb.append("<" + key +">" + value + "</" + key + ">");

        }

        sb.append("</xml>");

        xmlResult = sb.toString();

        return xmlResult;

    }

    /**

     * 将xml字符串转换成map

     */

    static HashMap<String, String>readXmlString2Map(String xml) {

    HashMap<String,String> map = new HashMap<String, String>();

        Document doc;

        try {

            doc =DocumentHelper.parseText(xml); // 将字符串转为XML

            Element rootElt =doc.getRootElement(); // 获取根节点

            List<Element> list =rootElt.elements();// 获取根节点下所有节点

            for (Element element : list) { // 遍历节点

                map.put(element.getName(),element.getText()); // 节点的name为map的key,text为map的value

            }

        } catch (DocumentException e) {

            e.printStackTrace();

        } catch (Exception e) {

            e.printStackTrace();

        }

        return map;

    }

    public static  String createSign(SortedMap<String,String> params) {

        StringBuffer sb = new StringBuffer();

        Set es = params.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();

            //为空不参与签名、参数名区分大小写

            if (null != v &&!"".equals(v) && !"sign".equals(k)

                    &&!"key".equals(k)) {

                sb.append(k + "=" + v+ "&");

            }

        }

        //第二步拼接key,key设置路径:微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置

       sb.append("key="+WXPramsContent.key);

       

        String sign = MD5Util.MD5Encode(sb.toString(),"utf-8")

                .toUpperCase();//MD5加密

       

        return sign;

    }

    static class MD5Util {

        private static StringbyteArrayToHexString(byte[] b) {

            StringBuffer resultSb = newStringBuffer();

            for (int i = 0; i < b.length;i++)

               resultSb.append(byteToHexString(b[i]));

            return resultSb.toString();

        }

        private static StringbyteToHexString(byte b) {

            int n = b;

            if (n < 0)

                n += 256;

            int d1 = n / 16;

            int d2 = n % 16;

            return hexDigits[d1] +hexDigits[d2];

        }

        static String MD5Encode(String origin,String charsetname) {

            String resultString = null;

            try {

                resultString = newString(origin);

                MessageDigest md =MessageDigest.getInstance("MD5");

                if (charsetname == null ||"".equals(charsetname))

                    resultString =byteArrayToHexString(md.digest(resultString

                            .getBytes()));

                else

                    resultString =byteArrayToHexString(md.digest(resultString

                           .getBytes(charsetname)));

            } catch (Exception exception) {

            }

            return resultString;

        }

        private static final String[] hexDigits= new String[]{"0", "1", "2", "3","4", "5","6", "7", "8","9", "a", "b", "c", "d","e", "f"};

    }

   

    public static boolean isTenpaySign(StringcharacterEncoding, SortedMap<Object, Object> packageParams, StringAPI_KEY) { 

        StringBuffer sb = newStringBuffer(); 

        Set es = packageParams.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(); 

            if(!"sign".equals(k)&& null != v && !"".equals(v)) { 

                sb.append(k + "=" + v+ "&"); 

            } 

        } 

         

        sb.append("key=" +API_KEY); 

         

        //算出摘要 

        String mysign =MD5Util.MD5Encode(sb.toString(), characterEncoding).toLowerCase(); 

        String tenpaySign =((String)packageParams.get("sign")).toLowerCase(); 

         

        //System.out.println(tenpaySign +"    " + mysign); 

        return tenpaySign.equals(mysign); 

    } 

  

}

3)  订单支付完成回调更新订单状态

   

public void PayNotifyAction(HttpServletRequest request,HttpServletResponseresponse) throws Exception{ 

    System.err.println("已进入微信支付回调接口-----订单支付完成回调更新订单状态");

  //读取参数 

     InputStream inputStream ; 

     StringBuffer sb = new StringBuffer(); 

      inputStream= request.getInputStream(); 

     String s ; 

     BufferedReader in = new BufferedReader(newInputStreamReader(inputStream, "UTF-8")); 

      while((s = in.readLine()) != null){ 

          sb.append(s); 

     } 

      in.close(); 

      inputStream.close(); 

      //解析xml成map 

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

      map= XMLUtil.doXMLParse(sb.toString())

       System.err.println("map:" +map);

      //过滤空 设置TreeMap 

     SortedMap<Object,Object> packageParams = newTreeMap<Object,Object>();       

      Iteratorit = map.keySet().iterator(); 

      while(it.hasNext()) { 

         String parameter = (String) it.next(); 

         String parameterValue = map.get(parameter); 

           

         String v = ""; 

          if(null!= parameterValue) { 

             v = parameterValue.trim(); 

         } 

          packageParams.put(parameter,v); 

     } 

       

      // 账号信息 

  String key = WXPramsContent.key;// key 

   

      logger.info(packageParams); 

      //判断签名是否正确 

      if(WeChat.isTenpaySign("UTF-8",packageParams,key)) { 

         String mch_id = (String)packageParams.get("mch_id"); 

          String openid = (String)packageParams.get("openid"); 

          String is_subscribe = (String)packageParams.get("is_subscribe"); 

          String out_trade_no = (String)packageParams.get("out_trade_no"); 

          String total_fee = (String)packageParams.get("total_fee"); 

          logger.info("mch_id:"+mch_id); 

          logger.info("openid:"+openid); 

          logger.info("is_subscribe:"+is_subscribe); 

          logger.info("out_trade_no:"+out_trade_no); 

          logger.info("total_fee:"+total_fee); 

         String resXml = ""; 

          if("SUCCESS".equals((String)packageParams.get("result_code"))){ 

             //--------------您的业务逻辑处理部分---------------

                logger.info("支付成功"); 

                //通知微信.异步确认成功.必写.不然会一直通知后台.八次之后就认为交易失败了. 

             resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" 

                                          + "<return_msg><![CDATA[OK]]></return_msg>"+ "</xml> ";

             }

         } else

             logger.info("支付失败,错误信息:" + packageParams.get("err_code")); 

             resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" 

                      + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml>"; 

         } 

         BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream()); 

          out.write(resXml.getBytes()); 

          out.flush(); 

          out.close(); 

         System.err.println("resXml:" + resXml.getBytes());

         } else

             logger.info("通知签名验证失败"); 

         } 

   } 




猜你喜欢

转载自blog.csdn.net/weixin_40129263/article/details/80986077