微信支付——统一下单

前段时间做了微信支付,遇到了很多问题,现在总结一下:

1.前端页面js:

  1       var totalprice = document.getElementById("total").innerHTML;  //支付总金额
  2     var appId = null;
  3     var nonceStr =null;
  4     var package1 = "prepay_id=";  //流水号
  5     var signType = "MD5";
  6     var timeStamp = null;
  7     var paySign =null; 
  8     
  9     function is_weixn(){
 10         var ua = navigator.userAgent.toLowerCase();
 11         if(ua.match(/MicroMessenger/i)=="micromessenger") {
 12             return true;
 13         } else {
 14             location.href = "javascript:history.go(-1);";
 15         }
 16     }
 17     is_weixn();
 18     
 19 //获取时间戳
 20      function getTimeStamp(){
 21                     var timestamp=new Date().getTime();
 22                     var timestampstring = timestamp.toString();//一定要转换字符串
 23                     oldTimeStamp = timestampstring;
 24                     return timestampstring;
 25                 };
 26       //随机字符串
 27                  function getNonceStr(){
 28                     var $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
 29                     var maxPos = $chars.length;
 30                     var noceStr = "";
 31                     for (var i = 0; i < 32; i++) {
 32                         noceStr += $chars.charAt(Math.floor(Math.random() * maxPos));
 33                     }
 34                     oldNonceStr = noceStr;
 35                     return noceStr;
 36                 };
 37                 
 38                 function md5(string){
 39                 return hex_md5(string).toUpperCase();
 40                 };
 41                 
 42                 function onBridgeReady(){
 43             //        alert("appId="+appId+"--timeStamp="+timeStamp+"--nonceStr="+nonceStr+"--package="+package1+"--signType="+signType+"--paySign="+paySign);
 44                        WeixinJSBridge.invoke(
 45                            'getBrandWCPayRequest', {
 46                                        "appId" : appId,     //公众号名称,由商户传入     
 47                                        "timeStamp": timeStamp,         //时间戳,自1970年以来的秒数     
 48                                        "nonceStr" : nonceStr, //随机串     
 49                                        "package" : package1,     
 50                                        "signType" : signType,         //微信签名方式:     
 51                                        "paySign" : paySign    //微信签名 
 52                            },
 53                            function(res){ 
 54                              //  alert(res.err_msg)
 55                                if(res.err_msg == "get_brand_wcpay_request:ok" ) {
 56                                 //  getjuan();//支付成功后,调用的后台的方法
 57                                    location.href = "gift.html";
 58                                }     // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回    ok,但并不保证它绝对可靠。 
 59                            }
 60                        ); 
 61                     };
 62                     
 63          //调用支付接口
 64         function getTotal() {
 65          //alert(code+total);
 66             $.ajax({
 67                 type : "post",
 68                 url : "../jf/shoplist/pay",
 69                 dataType : "json",
 70                 data : {
 71                     money : <%=totalprice%>,
 72                     user_id : <%=uid%>,
 73                     num : <%=num%>,
 74                     id : <%=id%>
 75                     },
 76                 success : function(data) {
 77                     if(data[0]=="eFAIL"){
 78                         alert("支付金额有误!");        
 79                     }else{
 80                             appId = data[1];
 81                          nonceStr =getNonceStr();
 82                          package1 = "prepay_id="+data[0];
 83                          signType = "MD5";
 84                          timeStamp = getTimeStamp().substring(0,10) ;
 85                          paySign = md5("appId="+appId+"&nonceStr="+nonceStr+"&package="+package1+"&signType=MD5"+"&timeStamp="+timeStamp+"&key=f4pjDRy09D0urJG4uySYwdd1J6Pr9hhD");
 86                          if (typeof WeixinJSBridge == "undefined"){
 87                                if( document.addEventListener ){
 88                                    document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
 89                                }else if (document.attachEvent){
 90                                    document.attachEvent('WeixinJSBridgeReady', onBridgeReady); 
 91                                    document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
 92                                }
 93                         }else{
 94                         // alert("onBridgeReady--------");
 95                            onBridgeReady();
 96                         }
 97                     }
 98                 },
 99                 error : function(data) {
100                     alert("支付失败");
101                 }
102             });
103 
104         }
105     

 

 


2.后台:

appid:公众号id
body:商品描述
mch_id:商户编号
nonce_str:随机字符串(自己生成的)
notify_url : 成功返回url    (自己配置的)
openid : 客户openid
out_trade_no: 商户内部订单号(自己生成的)
spbill_create_ip:客户ip(自己获取的:getRequest().getRemoteAddr())
total_fee:订单金额 (自己计算的)
trade_type:支付方式(JSAPI)
sign:按照文档的说明生成sign(自己生成的)
(1)随机数的生成:
  public static String getNonceStr() {
     Random random = new Random();
     return MD5util.MD5Encode(UUID.randomUUID().toString().replace("-",""), "").toUpperCase();
   }
(2)sign的生成方式:签名将通过API 密匙 先按照accsii升序排序,再通过md5加密,最后转换为大写字母
public static String createSign(SortedMap<String, Object> payParams,String key){
    StringBuffer sb = new StringBuffer();
    Set es = payParams.entrySet();//所有参与传参的参数按照accsii排序(升序)
    Iterator it = es.iterator();
    while(it.hasNext()) {
      Map.Entry entry = (Map.Entry)it.next();
      String k = (String)entry.getKey();
      Object v =  entry.getValue();
      if(null != v && !"".equals(v) 
          && !"sign".equals(k) && !"key".equals(k)) {
        sb.append(k + "=" + v + "&");
      }
    }
    sb.append("key=" + key);
    System.out.println("XML源串+key:"+sb.toString());
    String sign = MD5util.MD5Encode(sb.toString(), "").toUpperCase();
    System.out.println("md5后的字符串"+sign);
    return sign;
  }
(3)生成xml格式时的方法:
public static String buildUnifiedOrderReq(Map<String,Object> payParams){
        String payStr = "";
        payStr += "<xml>";//<![CDATA[你的appid]]>
        payStr +=    "<appid><![CDATA["+payParams.get("appid")+"]]></appid>";
        payStr +=    "<body><![CDATA["+payParams.get("body")+"]]></body>";
        payStr +=    "<mch_id><![CDATA["+payParams.get("mch_id")+"]]></mch_id>";
        payStr +=    "<nonce_str><![CDATA["+payParams.get("nonce_str")+"]]></nonce_str>";
        payStr +=    "<notify_url><![CDATA["+payParams.get("notify_url")+"]]></notify_url>";
        payStr +=    "<openid><![CDATA["+payParams.get("openid")+"]]></openid>";
        payStr +=    "<out_trade_no><![CDATA["+payParams.get("out_trade_no")+"]]></out_trade_no>";
        payStr +=    "<spbill_create_ip><![CDATA["+payParams.get("spbill_create_ip")+"]]></spbill_create_ip>";
        payStr +=    "<total_fee><![CDATA["+payParams.get("total_fee")+"]]></total_fee>";
        payStr +=    "<trade_type><![CDATA[JSAPI]]></trade_type>";
        payStr +=    "<sign><![CDATA["+payParams.get("sign")+"]]></sign>";
        payStr +="</xml>";
        System.out.println("最终提交的xml:"+payStr);
        return payStr;
    }
(4)成功返回url(支付流水---最重要)
//处理微信支付返回逻辑
public void payresponse() throws Exception{
System.out.println("支付通知url");
// 解析结果存储在HashMap
    Map<String, String> map = new HashMap<String, String>();
    InputStream inputStream = getRequest().getInputStream();
    StringBuilder stringBuilder = new StringBuilder();
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        boolean firstLine = true;
        String line = null; ;
        while((line = bufferedReader.readLine()) != null){
            if(!firstLine){
                stringBuilder.append(System.getProperty("line.separator"));
            }else{
                firstLine = false;
            }
            stringBuilder.append(line);
        }
       
        HashMap<String,String> zhifutongzhi = new HashMap<String, String>();
        zhifutongzhi = (HashMap<String, String>) payutil.parseXml(stringBuilder.toString());
        System.out.println("返回支付通知:【业务结果】"+zhifutongzhi.get("result_code"));
        System.out.println("返回支付通知:【内部订单】"+zhifutongzhi.get("out_trade_no"));
        System.out.println("返回支付通知:【流水】"+zhifutongzhi.get("transaction_id"));
  
       
    // 释放资源
    inputStream.close();
    inputStream = null;
   
    getResponse().setContentType("text/xml; charset=UTF-8"); 
    String resXml= null;
    if("SUCCESS".equals(zhifutongzhi.get("result_code"))){
   
    System.out.println("进入支付-------------------------------------------"+new Date());
    //支付成功
    double money=(Double.valueOf(zhifutongzhi.get("total_fee"))/100);
    //int money=(int) (Double.valueOf(zhifutongzhi.get("total_fee"))/100);
    String sql="select user_id,num,gift_id from cbb_orders where order_code =?";
    Record  re= Db.findFirst(sql,zhifutongzhi.get("out_trade_no"));
    int user_id = re.getInt("user_id");
    int num = re.getInt("num");
    int id = re.getInt("gift_id");  //商品id
    //修改订单状态
         String bigorder="update cbb_orders set total = ?,state=1,payflowcode=?,update_time=now()  where order_code=?";     
         int flag = Db.update(bigorder, money,zhifutongzhi.get("transaction_id"),zhifutongzhi.get("out_trade_no"));
        /* if(flag<=0){
    //try {
    // DbKit.getConfig().getConnection().rollback();
    String sql1="INSERT INTO order_pay_log VALUES (NULL,?,?,?,?,NOW(),0)";
    Db.update(sql1,re.getInt("user_id"),money,zhifutongzhi.get("transaction_id"),zhifutongzhi.get("out_trade_no"));
    //} catch (SQLException e) {
    // e.printStackTrace();
    // renderJson("修改order_state错误");
    // return ;
    //}
    }*/
          
         //生成支付流水
         String payflow = "insert into payflow (ordertype,paytype,payflowcode,paymoney,user_id,pay_time,create_time)values(1,2,?,?,?,now(),now())";
int payfplwfalg = Db.use("mysql").update(payflow, zhifutongzhi.get("transaction_id"), money, re.getInt("user_id"));
if (payfplwfalg == 0) {
try {
DbKit.getConfig().getConnection().rollback();
} catch (SQLException e) {
e.printStackTrace();
renderJson("生成支付流水失败");
return ;
}
}
    resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
    + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
   
    }else{
    resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
    + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
    }
    System.out.println("微信支付回调数据结束");
 
    BufferedOutputStream out = new BufferedOutputStream(getResponse().getOutputStream());
    out.write(resXml.getBytes());
    out.flush();
   
    out.close();
   System.out.println("支付处理结束!");
   renderJson(zhifutongzhi.get("result_code"));
}
(5)返回消息的方法:
public static Map<String, String> parseXml(String xml) throws Exception {
Map<String, String> map = new HashMap<String, String>();
Document document = DocumentHelper.parseText(xml);
Element root = document.getRootElement();
List<Element> elementList = root.elements();
for (Element e : elementList)
map.put(e.getName(), e.getText());
return map;
}
(6)传值调用支付的方法,并返回消息:
public static HashMap<String, String> tyjk(String body,int money,String openid,String out_trade_no,String spbill_create_ip){
System.out.println("统一接口money:"+money);
System.out.println("key:"+Config.KEY1);
SortedMap<String,Object> payParams = new TreeMap<String,Object>();
String payStr = "";
payParams.put("appid", Config.APPID1);//公众号id
payParams.put("body", body);//商品描述
payParams.put("mch_id", Config.MCH_ID2);//商户编号
payParams.put("nonce_str", payutil.getNonceStr());//随机字符串
payParams.put("notify_url", Config.NOTIFY_URl3);//成功返回url
payParams.put("openid", openid);//客户openid
payParams.put("out_trade_no", out_trade_no);//商户内部订单号
payParams.put("spbill_create_ip", spbill_create_ip);//客户ip
payParams.put("total_fee", money);//订单金额
payParams.put("trade_type", "JSAPI");//支付方式
String sign = payutil.createSign(payParams, Config.KEY1);//按照文档的说明生成sign
payParams.put("sign", sign);
 
payStr=payutil.buildUnifiedOrderReq(payParams);//生成请求xml字符串
 
HttpUtil hutil = new HttpUtil();//调用统一接口
HashMap<String,String> tongjifh = new HashMap<String, String>();
String rs = hutil.sendHttpsPOST("https://api.mch.weixin.qq.com/pay/unifiedorder", payStr);//发送http请求
 
try {
tongjifh = (HashMap<String, String>) payutil.parseXml(rs);
return tongjifh;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
return tongjifh;
}
(7)在controller中传参数
public void pay() {
 // 4个参数依次 :订单描述, 金额[单位为 元],用户openid,内部订单号,客户ip地址
   // 返回结果:如果统一接口成功 则返回 预支付id 否则返回"FAIL"
   HashMap<String, String> tongjifh = new HashMap<String, String>();
   System.out.println("code+++++++++++++++++++++++++++++++" + code);
   tongjifh = Tongyijiekou.tyjk("QianJiJuan", (int) (money * 100),
     openid, code, getRequest().getRemoteAddr());
   System.out.println("fanhui=" + tongjifh);
   if ("FAIL".equalsIgnoreCase(tongjifh.get("return_code"))) {
    obj[0] = "FAIL";
   } else {
    System.out.println("prepay_id----APPID1"
      + tongjifh.get("prepay_id"));
    obj[0] = tongjifh.get("prepay_id");
    obj[1] = Config.APPID1;
   }
renderJson(obj);
}
(8)商户平台的参数配置:
最后说一下,我遇到的坑吧:
(1)fanhui={return_msg=受理机构必须传入sub_mch_id,return_code_FAIL}
        商户id写错了,微信公众号支付,只需要普通的商户id就可以了,但是我传入的是服务商的商户id;
(2)fanhui={return_msg=xml格式错误,return_code_FAIL}
      此时应仔细核对xml中传入的参数,商户id写错;
(3)fanhui={return_msg=xml格式错误,return_code_FAIL}
      xml里面的body是中文,此时报错,改成英文或字母就好;
posted @ 2017-11-15 15:38  咿呀咿呀咿  阅读(837)  评论(0编辑  收藏  举报