• 微信支付对接


    最近涉及到微信支付这块的内容,分为两种情形的使用:网站直接调起进行支付操作、手机客户端发起支付

    1.手机客户端发起支付

    大致流程:客户端发起支付请求 -> 服务端接收请求,本地下单处理 -> 服务端对微信做预下单处理,组织下单参数吐回客户端 -> 客户端调起微信支付

    这里主要记录下微信预下单处理过程:

     1 private String weixinClientPay(PayRequestWeixin data) throws UnsupportedEncodingException, JSONException {
     2          Map<String, Object> map = new HashMap<String, Object>();
     3          String dealcode = data.getTopupDealcode();//获取本地下单的订单号
     4          Deal topupOrder  = sdkDealService.getTopupOrder(dealcode, Boolean.FALSE);//获取本地下单的订单信息
     5          BigDecimal amount = topupOrder.getAmount();//以分为单位
     6          String product =  StringUtils.isNotBlank(data.getItem_name())?data.getItem_name():(ConvertUtils.toCNYStr(amount)+ PaymentChannelConstants.CNY);
     7          //接收财付通通知的URL
     8          String notify_url = topupOrder.getNotifyUrl();
     9          String return_url = topupOrder.getReturnUrl();
    10  
    11          String out_trade_no = topupOrder.getDealId();
    12  
    13          Map<String, Object> paramsMap = data.getParmas();
    14          PackageRequestHandler packageReqHandler = (PackageRequestHandler)paramsMap.get(WeixinPayConstants.packageReqHandler);//获取package的请求类 
    15          PrepayIdRequestHandler prepayReqHandler = (PrepayIdRequestHandler)paramsMap.get(WeixinPayConstants.prepayReqHandler);//获取prepayid的请求类
    16          ClientRequestHandler clientHandler = (ClientRequestHandler)paramsMap.get(WeixinPayConstants.clientHandler);//返回客户端支付参数的请求类
    17          packageReqHandler.setKey(ConstantUtil.SDK_PARTNER_KEY); //商户号对应的密钥
    18  
    19          int retcode;
    20          String retmsg = "";
    21          String retVal = "";
    22          //获取token值 
    23          String token = AccessTokenRequestHandler.getAccessToken("");
    24          if (!"".equals(token)) {
    25              //设置package订单参数
    26              packageReqHandler.setParameter("bank_type", "WX");//银行渠道
    27              packageReqHandler.setParameter("body",product); //商品描述   
    28              packageReqHandler.setParameter("notify_url", notify_url); //接收财付通通知的URL  
    29              packageReqHandler.setParameter("partner", ConstantUtil.PARTNER); //商户号
    30              packageReqHandler.setParameter("out_trade_no", out_trade_no); //商家订单号   
    31              packageReqHandler.setParameter("total_fee", ConvertUtils.toMobiStr(amount)); //商品金额,以分为单位  
    32              packageReqHandler.setParameter("spbill_create_ip", data.getIp()); //订单生成的机器IP,指用户浏览器端IP  
    33              packageReqHandler.setParameter("fee_type", "1"); //币种,1人民币   66
    34              packageReqHandler.setParameter("input_charset", "UTF-8"); //字符编码
    35              packageReqHandler.setParameter("return_url", return_url);
    36              packageReqHandler.setParameter("attach", "sdk");
    37  
    38              //获取package包
    39              String packageValue = packageReqHandler.getRequestURL();
    40  
    41              String noncestr = WXUtil.getNonceStr();
    42              String timestamp = WXUtil.getTimeStamp();
    43              String traceid = "";
    44              ////设置获取prepayid支付参数
    45              prepayReqHandler.setParameter("appid", ConstantUtil.SDK_APP_ID);//微信开发平台应用id
    46              prepayReqHandler.setParameter("appkey", ConstantUtil.APP_KEY);//应用对应的凭证
    47  
    48              prepayReqHandler.setParameter("noncestr", noncestr);
    49              prepayReqHandler.setParameter("package", packageValue);
    50              prepayReqHandler.setParameter("timestamp", timestamp);
    51              prepayReqHandler.setParameter("traceid", traceid);
    52  
    53              //生成获取预支付签名
    54              String sign = prepayReqHandler.createSHA1Sign();
    55              //增加非参与签名的额外参数
    56              prepayReqHandler.setParameter("app_signature", sign);
    57              prepayReqHandler.setParameter("sign_method",ConstantUtil.SIGN_METHOD);//签名算法常量值:sha1
    58              String gateUrl = ConstantUtil.GATEURL + token;//获取预支付id的接口url:https://api.weixin.qq.com/pay/genprepay?access_token=
    59              prepayReqHandler.setGateUrl(gateUrl);
    60  
    61              //获取prepayId
    62              String prepayid = prepayReqHandler.sendPrepay();
    63              //吐回给客户端的参数
    64              if (null != prepayid && !"".equals(prepayid)) {
    65                  //输出参数列表
    66                  clientHandler.setParameter("appid", ConstantUtil.SDK_APP_ID);
    67                  clientHandler.setParameter("appkey", ConstantUtil.APP_KEY);
    68                  clientHandler.setParameter("partnerid", ConstantUtil.PARTNER);
    69                  
    70                  clientHandler.setParameter("noncestr", noncestr);
    71                  clientHandler.setParameter("package", "Sign=WXPay");
    72                  clientHandler.setParameter("prepayid", prepayid);
    73                  clientHandler.setParameter("timestamp", timestamp);
    74                  //生成签名
    75                  sign = clientHandler.createSHA1Sign();
    76                  clientHandler.setParameter("sign", sign);
    77  
    78                  retcode = 0;
    79                  retmsg = "OK";
    80                  
    81                  String appId = ConstantUtil.SDK_APP_ID;
    82                  String partner = ConstantUtil.PARTNER;//商户号
    83                  
    84                  retVal = "<?xml version="1.0" encoding="utf-8"?><root><retcode>"+retcode+"</retcode><retmsg>"+retmsg+"</retmsg>"+"<appid>"+ appId+"</appid><noncestr>"+noncestr+"</noncestr>" +
    85                          "<package>Sign=WXPay</package><partnerid>"+partner+"</partnerid><prepayid>"+prepayid+
    86                          "</prepayid><sign>"+sign+"</sign><timestamp>"+timestamp+"</timestamp>"+"</root>";
    87              } else {
    88                  retcode = -2;
    89                 retmsg = "错误:获取prepayId失败";
    90              }
    91          } else {
    92              retcode = -1;
    93              retmsg = "错误:获取不到Token";
    94          }
    95          log.info("weixin client pay, retmsg: " + retmsg + ", retVal:
    " + retVal);
    96      }
    ps:省略部分输出性代码

    其中获取accessToken:String token = AccessTokenRequestHandler.getAccessToken("");

     1 protected static String getAccessToken() {
     2         String requestUrl = ConstantUtil.TOKENURL + "?grant_type=" + ConstantUtil.GRANT_TYPE + "&appid="
     3               + ConstantUtil.SDK_APP_ID + "&secret=" + ConstantUtil.SDK_APP_SECRET;
     4         
     5         String resContent = "";
     6         TenpayHttpClient httpClient = new TenpayHttpClient();
     7         httpClient.setMethod("GET");
     8         httpClient.setReqContent(requestUrl);
     9         if (httpClient.call()) {
    10             resContent = httpClient.getResContent();
    11             if (resContent.indexOf(ConstantUtil.ACCESS_TOKEN) > 0) {
    12                 access_token = getJsonValue(resContent, ConstantUtil.ACCESS_TOKEN);
    13             } else {
    14                 log.info("获取access_token值返回错误!!!");
    15             }
    16         } else {
    17             log.info("后台调用通信失败");
    18             log.info(httpClient.getResponseCode());
    19             log.info(httpClient.getErrInfo());
    20             // 有可能因为网络原因,请求已经处理,但未收到应答。
    21         }
    22         return access_token;
    23     }

    预下单:String prepayid = prepayReqHandler.sendPrepay();

     1 // 提交预支付
     2     public String sendPrepay() throws JSONException {
     3         String prepayid = "";
     4         StringBuffer sb = new StringBuffer("{");
     5         Set es = super.getAllParameters().entrySet();
     6         Iterator it = es.iterator();
     7         while (it.hasNext()) {
     8             Map.Entry entry = (Map.Entry) it.next();
     9             String k = (String) entry.getKey();
    10             String v = (String) entry.getValue();
    11             if (null != v && !"".equals(v) && !"appkey".equals(k)) {
    12                 sb.append(""" + k + "":"" + v + "",");
    13             }
    14         }
    15         String params = sb.substring(0, sb.lastIndexOf(","));
    16         params += "}";
    17         String requestUrl = super.getGateUrl();
    18         TenpayHttpClient httpClient = new TenpayHttpClient();
    19         httpClient.setReqContent(requestUrl);
    20         String resContent = "";
    21         this.setDebugInfo(this.getDebugInfo() + "
    " + "post data:" + params);
    22         if (httpClient.callHttpPost(requestUrl, params)) {
    23             resContent = httpClient.getResContent();
    24             if (2 == resContent.indexOf("prepayid")) {
    25                 prepayid = getJsonValue(resContent, "prepayid");
    26             }
    27         }
    28         return prepayid;
    29     }

    大致过程,其中省略部分数据初始化以及微信支付等常量设置。

    2. 页面调起进行支付操作

    首先jsp:

      1 //引入weixinjs
      2 <script type="text/javascript" src="https://res.wx.qq.com/open/js/jweixin-1.0.0.js" ></script>
      3 //设置
      4 $(function(){
      5     wx.config({
      6         debug: false, 
      7         appId: '${wxConf["appId"]}', // 必填,公众号的唯一标识
      8         timestamp: '${wxConf["timestamp"]}', // 必填,生成签名的时间戳
      9         nonceStr:  '${wxConf["noncestr"]}', // 必填,生成签名的随机串
     10         signature: '${wxConf["signature"]}',// 必填,签名,见附录1
     11         jsApiList: ['onMenuShareTimeline','onMenuShareAppMessage','onMenuShareQQ','onMenuShareWeibo','onMenuShareQZone', 'chooseWXPay'] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
     12     });
     13     
     14     wx.ready(function() {
     15         // config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
     16         wx.onMenuShareTimeline({
     17             title: '${WEIXIN_SHARE_TITLE}',
     18             desc:'${WEIXIN_SHARE_DESC}',
     19             link: '${WEIXIN_SHARE_URL}',
     20             imgUrl: '${WEIXIN_SHARE_ICON}',
     21             trigger: function (res) {
     22             },
     23             success: function (res) {
     24             },
     25             cancel: function (res) {
     26             },
     27             fail: function (res) {
     28             }
     29         });
     30         wx.onMenuShareAppMessage({
     31                 title: '${WEIXIN_SHARE_TITLE}',
     32                 desc:'${WEIXIN_SHARE_DESC}',
     33                 link: '${WEIXIN_SHARE_URL}',
     34                 imgUrl: '${WEIXIN_SHARE_ICON}',
     35                 trigger: function (res) {
     36                 },
     37                 success: function (res) {
     38                 },
     39                 cancel: function (res) {
     40                 },
     41                 fail: function (res) {
     42                 }
     43         });
     44         //分享QQ
     45         wx.onMenuShareQQ({
     46              title: '${WEIXIN_SHARE_TITLE}',
     47              desc:'${WEIXIN_SHARE_DESC}',
     48              link: '${WEIXIN_SHARE_URL}',
     49              imgUrl: '${WEIXIN_SHARE_ICON}',
     50             success: function () { 
     51                // 用户确认分享后执行的回调函数
     52             },
     53             cancel: function () { 
     54                // 用户取消分享后执行的回调函数
     55             }
     56         });
     57         //分享微博
     58         wx.onMenuShareWeibo({
     59              title: '${WEIXIN_SHARE_TITLE}',
     60              desc:'${WEIXIN_SHARE_DESC}',
     61              link: '${WEIXIN_SHARE_URL}',
     62              imgUrl: '${WEIXIN_SHARE_ICON}',
     63             success: function () { 
     64                // 用户确认分享后执行的回调函数
     65             },
     66             cancel: function () { 
     67                 // 用户取消分享后执行的回调函数
     68             }
     69         });
     70         //分享QQ空间
     71         wx.onMenuShareQZone({
     72              title: '${WEIXIN_SHARE_TITLE}',
     73              desc:'${WEIXIN_SHARE_DESC}',
     74              link: '${WEIXIN_SHARE_URL}',
     75              imgUrl: '${WEIXIN_SHARE_ICON}',
     76             success: function () { 
     77                // 用户确认分享后执行的回调函数
     78             },
     79             cancel: function () { 
     80                 // 用户取消分享后执行的回调函数
     81             }
     82         });
     83         
     84     });
     85     wx.error(function(res) {
     86         // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
     87         //alert("微信JS执行失败." + res.errMsg);
     88     });
     89     wx.checkJsApi({
     90         jsApiList: [
     91             'onMenuShareTimeline','onMenuShareAppMessage','chooseWXPay'
     92         ]
     93     });
     94 });
     95 
     96 function pay(appId,mobile,amount,dealCode){
     97   //ajax提交数据到后台处理
     98   $.ajax({
     99                 url:"/xxxx/xxx.shtml?m=payWithWeixin&channel=weixinpay&subchannel=JSPAY&amount="+amount+"&topupPage=7&mobile="+mobile+"&openId="+openId+"&remark=MMACTIVE_"+dealCode
    100             }).done(function(data){
    101                 data = data.replace(/"/g, "");
    102                 //alert(data);
    103                 var arr = data.split("|");
    104                 wx.chooseWXPay({
    105                     timestamp: arr[1], // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
    106                     nonceStr: arr[2], // 支付签名随机串,不长于 32 位
    107                     package: arr[3], // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=***)
    108                     signType: 'MD5', // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'
    109                     paySign: arr[4], // 支付签名
    110                     success: function (res) {
    111                         if(typeof(doWeixinPayResultCallBack)){
    112                             //微信支付成功回调114                             //可处理自己的相关的页面代码操作115                         }
    116                         window.location.reload();
    117                     }
    118                 });
    119             });
    120 }

    数据提交到后台,数据的处理封装省略,直接上微信支付预下单处理:

     1 private String jsApiPay(PayRequest data) throws Exception {
     2         String dealcode = data.getTopupDealcode();
     3         String nonce_str = WXUtil.getNonceStr();
     4         String timeStamp = WXUtil.getTimeStamp();
     5         TopupOrder topupOrder  = dealService.getTopupOrder(dealcode, Boolean.FALSE);
     6         String product =  topupOrder.getAmount().doubleValue()+ PaymentChannelConstants.CNY;
     7         StringBuilder stringBuilder = new StringBuilder();
     8         stringBuilder.append("appid=").append(JSAPI_APP_ID);
     9         stringBuilder.append("&body=").append(product);
    10         stringBuilder.append("&mch_id=").append(JSAPI_MCH_ID);
    11         stringBuilder.append("&nonce_str=").append(nonce_str);
    12         stringBuilder.append("&notify_url=").append(topupOrder.getNotifyURL());
    13         stringBuilder.append("&openid=").append(data.getOpenId());
    14         stringBuilder.append("&out_trade_no=").append(topupOrder.getDealcode());
    15         stringBuilder.append("&spbill_create_ip=").append(data.getIp());
    16         stringBuilder.append("&total_fee=").append(topupOrder.getAmount().multiply(BigDecimal.valueOf(100)).setScale(0));//金额 以分为单位
    17         stringBuilder.append("&trade_type=JSAPI");
    18         String sign = Md5Encrypt.encrypt(stringBuilder.toString()+"&key="+JSAPI_KEY).toUpperCase();
    19         
    20         stringBuilder = new StringBuilder();
    21         stringBuilder.append("<xml>");
    22         stringBuilder.append("<appid>"+JSAPI_APP_ID+"</appid>");
    23         stringBuilder.append("<body><![CDATA["+ product +"]]></body>");
    24         stringBuilder.append("<mch_id>"+JSAPI_MCH_ID+"</mch_id>");
    25         stringBuilder.append("<nonce_str>"+nonce_str+"</nonce_str>");
    26         stringBuilder.append("<notify_url>"+topupOrder.getNotifyURL()+"</notify_url>");
    27         stringBuilder.append("<openid>"+data.getOpenId()+"</openid>");
    28         stringBuilder.append("<out_trade_no>"+ topupOrder.getDealcode()+"</out_trade_no>");
    29         stringBuilder.append("<spbill_create_ip>"+data.getIp()+"</spbill_create_ip>");
    30         stringBuilder.append("<total_fee>"+topupOrder.getAmount().multiply(BigDecimal.valueOf(100)).setScale(0).toString()+"</total_fee>");
    31         stringBuilder.append("<trade_type>JSAPI</trade_type>");
    32         stringBuilder.append("<sign><![CDATA["+sign+"]]></sign>");
    33         stringBuilder.append("</xml>");
    34         
    35         String prepayId = getResponseData(UNIFIED_ORDER_URL, new String(stringBuilder.toString().getBytes(), "ISO8859-1"));//解决中文问题
    36         //String prepayId = getResponseData(UNIFIED_ORDER_URL, new String(stringBuilder.toString()));
    37         prepayId =  (String)XMLUtil.doXMLParse(prepayId).get("prepay_id");
    38         prepayId = "prepay_id=" + prepayId;
    39         
    40         stringBuilder = new StringBuilder();
    41         stringBuilder.append("appId=").append(JSAPI_APP_ID)
    42         .append("&nonceStr=").append(nonce_str)
    43         .append("&package=").append(prepayId)
    44         .append("&signType=").append("MD5")
    45         .append("&timeStamp=").append(timeStamp)
    46         .append("&key=").append(JSAPI_KEY);
    47 
    48         String paySign = Md5Encrypt.encrypt(stringBuilder.toString()).toUpperCase();
    49         String payInfo = MessageFormat.format(""{0}"|"{1}"|"{2}"|"{3}"|"{4}"|"{5}"",JSAPI_APP_ID,timeStamp,nonce_str,prepayId,paySign,topupOrder.getDealcode());
    50         return payInfo;
    51     }
    52 其中:
    53 public static String getNonceStr() {
    54         Random random = new Random();
    55         return MD5Util.MD5Encode(String.valueOf(random.nextInt(10000)), "UTF-8");
    56     }
    57 
    58     public static String getTimeStamp() {
    59         return String.valueOf(System.currentTimeMillis() / 1000);
    60     }
  • 相关阅读:
    CF 120F Spider 树的直径 简单题
    POJ 1155 TELE 背包型树形DP 经典题
    CF 219D Choosing Capital for Treeland 树形DP 好题
    POJ 3162 Walking Race 树形DP+线段树
    HDU 2196 Computer 树形DP 经典题
    __str__()、__repr__()和__format__()
    item系列方法
    getattribute
    isinstance和issubclass
    继承方式完成包装
  • 原文地址:https://www.cnblogs.com/eric-fang/p/4962926.html
Copyright © 2020-2023  润新知