微信小程序> 玩转小程序支付之付款(统一下单)

玩转小程序支付之付款(统一下单)

浏览量:1271 时间: 来源:南极一颗星

小程序的业务流程如下

小程序

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

步骤1:用户在商户APP中选择商品,提交订单,选择微信支付。

步骤2:商户后台收到用户支付单,调用微信支付统一下单接口。参见【统一下单API】。

步骤3:统一下单接口返回正常的prepay_id,再按签名规范重新生成签名后,将数据传输给APP。参与签名的字段名为appid,partnerid,prepayid,noncestr,timestamp,package。注意:package的值格式为Sign=WXPay

步骤4:商户APP调起微信支付。api参见本章节【app端开发步骤说明】

步骤5:商户后台接收支付通知。api参见【支付结果通知API】

步骤6:商户后台查询支付结果。,api参见【查询订单API】

API链接:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=8_3

 

支付的流程为:先调用统一下单API---->接着在小程序wx.requestPayment发起支付---->支付完之后会调用支付结果通知

小程序端代码

小程序

小程序
/**  * 支付  */var pay = function (event, that) {  if (that.data.detail.fee.indexOf("免费")>-1){    goApply(event, that)  }else{    wx.request({      url: app.globalData.server + 'requestPay/',      method: "POST",      data: {        activityId: event.currentTarget.dataset.activityid,        userId: app.globalData.userInfo.id,        sessionThirdKey: wx.getStorageSync('sessionThirdKey'),        money: that.data.detail.fee,        describe: that.data.detail.name,        detail: '报名活动费用'      },      header: {        "Content-Type": "application/x-www-form-urlencoded"      },      success: function (res) {        console.info(res);        //发起微信支付        wx.requestPayment({          'timeStamp': res.data.timeStamp,          'nonceStr': res.data.nonceStr,          'package': res.data.package_,          'signType': 'MD5',          'paySign': res.data.paySign,          success: function (res) {            console.info(res)            //报名            goApply(event, that)          },          fail: function (res) {            console.info(res)          },          complete: function (res) {            console.info(res)          }        })      }    })  }  }
小程序

后台Java代码:(基于SpringBoot)

小程序
@RestControllerpublic class PayApi {    @Value("${wxapp.appid}")    private String appId;    @Value("${wxapp.secret}")    private String secret;    @Value("${wxapp.url.jscode2session}")    private String jscode2session;    @Value("${wx.mch.id}")    private String mchId;    @Value("${wx.unified.order.url}")    private String createOrderURL;    @Value("${wx.pay.api.key}")    private String key;    @Value("${wx.bill.create.ip}")    private String spBillCreateIp;    @Value("${wx.server.url}")    private String baseUrl;    @Autowired    private RedisClient redisClient;    @Resource(name = "wxappUserServiceImpl")    private IWxappUserService wxappUserService;    @Resource(name = "wxappActivityServiceImpl")    private IWxappActivityService wxappActivityService;    @Resource(name = "wxappActivityApplyServiceImpl")    private IWxappActivityApplyService wxappActivityApplyService;    @Resource(name = "wxappPayServiceImpl")    private IWxappPayService wxappPayService;    @RequestMapping(value = "/requestPay",method = RequestMethod.POST)    public WxappPayDto requestPay(String userId, String activityId, String sessionThirdKey, String money, String describe, String detail) throws Exception {        WxappPayDto dto = new WxappPayDto();        //获取保存的sessionThirdKey(里面保存了openId)        String sessionKey = redisClient.get(sessionThirdKey);        String openId = sessionKey.split("w#w#w")[0];        //订单号        String orderNo="wx"+userId+"_"+System.currentTimeMillis();        dto = prePay(userId,activityId,openId,orderNo,money,describe,detail);          return dto;    }        /**     * 统一下单     * @param userId     * @param activityId     * @param openId     * @param orderNo     * @param money     * @param describe     * @param detail     * @return     */    private WxappPayDto prePay(String userId,String activityId,String openId,String orderNo,String money,String describe,String detail){        money = String.valueOf(Long.valueOf(money.substring(0, money.length()-1))*100);        String currTime = PayUtils.getCurrTime();        //8位日期        String strTime = currTime.substring(8, currTime.length());        //四位随机数        String strRandom = PayUtils.buildRandom(4) + "";        //10位序列号,可以自行调整。        String nonceStr = strTime + strRandom;        //这里notify_url是 支付完成后微信发给该链接信息,可以判断会员是否支付成功,改变订单状态等。        String notifyUrl = baseUrl+"/notify";        //附加数据,以一定格式保存userId和activityId。原样返回。        String attach = userId+"#wx#"+activityId;        SortedMap<String, String> packageParams = new TreeMap<String, String>();        packageParams.put("appid", appId);        packageParams.put("attach", attach);//附加数据        packageParams.put("body", describe);//商品描述        packageParams.put("detail", detail);        packageParams.put("mch_id", mchId);//商户号        packageParams.put("nonce_str", nonceStr);//随机数        packageParams.put("notify_url", notifyUrl);        packageParams.put("openid", openId);        packageParams.put("out_trade_no", orderNo);//商户订单号        packageParams.put("spbill_create_ip", spBillCreateIp);//订单生成的机器 IP        packageParams.put("total_fee", money);//总金额        packageParams.put("trade_type", "JSAPI");                  String sign = PayUtils.createSign(packageParams,key);        String xml="<xml>"+                "<appid>"+appId+"</appid>"+                "<attach>"+attach+"</attach>"+                "<body><![CDATA["+describe+"]]></body>"+                "<detail><![CDATA["+detail+"]]></detail>"+                "<mch_id>"+mchId+"</mch_id>"+                "<nonce_str>"+nonceStr+"</nonce_str>"+                "<sign>"+sign+"</sign>"+                "<notify_url>"+notifyUrl+"</notify_url>"+                "<openid>"+openId+"</openid>"+                "<out_trade_no>"+orderNo+"</out_trade_no>"+                "<spbill_create_ip>"+spBillCreateIp+"</spbill_create_ip>"+                "<total_fee>"+money+"</total_fee>"+                "<trade_type>JSAPI</trade_type>"+                "</xml>";        String prepay_id="";        try {            prepay_id = PayUtils.getPayNo(createOrderURL, xml);            if(prepay_id.equals("")){                //错误提示                System.out.println("统一支付接口获取预支付订单出错");            }        } catch (Exception e1) {            e1.printStackTrace();        }        SortedMap<String, String> finalpackage = new TreeMap<String, String>();        String timestamp = PayUtils.getTimeStamp();        String packages = "prepay_id="+prepay_id;        finalpackage.put("appId", appId);        finalpackage.put("nonceStr", nonceStr);         finalpackage.put("package", packages);          finalpackage.put("signType", "MD5");        finalpackage.put("timeStamp", timestamp);          String finalsign = PayUtils.createSign(finalpackage,key);                WxappPayDto dto = new WxappPayDto();        dto.setNonceStr(nonceStr);        dto.setPackage_(packages);        dto.setPaySign(finalsign);        dto.setSignType("MD5");        dto.setTimeStamp(timestamp);        return dto;    }        /**     * 支付完成通知     * @param request     * @param response     * @return     * @throws Exception     */    @RequestMapping(value = "/notify",method = RequestMethod.POST)    public String notify(HttpServletRequest request, HttpServletResponse response) throws Exception {        BufferedReader br = new BufferedReader(new InputStreamReader((ServletInputStream)request.getInputStream()));        String line = null;        StringBuilder sb = new StringBuilder();        while((line = br.readLine())!=null){            sb.append(line);        }        //解析并给微信发回收到通知确认        Map map =  PayUtils.doXMLParse(sb.toString());        String returnCode = map.get("return_code").toString();        if(returnCode.equals("SUCCESS")){            String resultCode = map.get("result_code").toString();            if(resultCode.equals("SUCCESS")){                SortedMap<String, String> packageParams = new TreeMap<String, String>();                packageParams.put("appid", map.get("appid").toString());                packageParams.put("attach", map.get("attach").toString());                packageParams.put("bank_type", map.get("bank_type").toString());                packageParams.put("cash_fee", map.get("cash_fee").toString());                packageParams.put("fee_type", map.get("fee_type").toString());                packageParams.put("is_subscribe", map.get("is_subscribe").toString());                packageParams.put("mch_id", map.get("mch_id").toString());                packageParams.put("nonce_str", map.get("nonce_str").toString());                packageParams.put("openid", map.get("openid").toString());                packageParams.put("out_trade_no", map.get("out_trade_no").toString());                packageParams.put("result_code", map.get("result_code").toString());                packageParams.put("return_code", map.get("return_code").toString());                 packageParams.put("time_end", map.get("time_end").toString());                packageParams.put("total_fee", map.get("total_fee").toString());                packageParams.put("trade_type", map.get("trade_type").toString());                packageParams.put("transaction_id", map.get("transaction_id").toString());                String sign = PayUtils.createSign(packageParams,key);                String originSign = map.get("sign").toString();                if(sign.equals(originSign)){                    //签名一致,保存支付流水                    String xml="<xml>"                              +"<return_code>SUCCESS</return_code>"                              +"<return_msg>OK</return_msg>"                              +"</xml>";                    ShopPayLog payLog = new ShopPayLog();                    payLog.setCreatedAt(new Date());                    payLog.setSource(Source.WeiXin);                    DecimalFormat df = new DecimalFormat("######0.00");                     payLog.setTotalFee(String.valueOf(df.format((Double.valueOf(map.get("total_fee").toString())/100))));                    payLog.setTradeNo(map.get("out_trade_no").toString());                    payLog.setTransactionId(map.get("transaction_id").toString());                    String attach = map.get("attach").toString();//userId+"#wx#"+activityId                    payLog.setUserId(attach.split("#wx#")[0]);                    payLog = wxappPayService.save(payLog);                    WxappUser user = wxappUserService.find(Long.valueOf(attach.split("#wx#")[0]));                    WxappActivity activity = wxappActivityService.find(Long.valueOf(attach.split("#wx#")[1]));                    WxappActivityApply activityApply = wxappActivityApplyService.findActivityApplyByUserAndActivity(user, activity);                    //在活动申请表中关联上支付流水的id                    activityApply.setPayLogId(String.valueOf(payLog.getId()));                    wxappActivityApplyService.save(activityApply);                    return xml;                }else{                    String xml="<xml>"                                +"<return_code>FAIL</return_code>"                                +"<return_msg>签名不一致</return_msg>"                                +"</xml>";                      return xml;                }            }else{                String xml="<xml>"                          +"<return_code>FAIL</return_code>"                          +"<return_msg>支付通知失败</return_msg>"                          +"</xml>";                        return xml;            }        } else {            String xml="<xml>"                    +"<return_code>FAIL</return_code>"                    +"<return_msg>支付通知失败</return_msg>"                    +"</xml>";                  return xml;        }    }
小程序

PayUtils.java

小程序
import java.io.BufferedReader;import java.io.ByteArrayInputStream;import java.io.File;import java.io.FileInputStream;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.UnsupportedEncodingException;import java.net.URLEncoder;import java.security.KeyStore;import java.security.MessageDigest;import java.text.SimpleDateFormat;import java.util.Date;import java.util.HashMap;import java.util.Iterator;import java.util.List;import java.util.Map;import java.util.Random;import java.util.Set;import java.util.SortedMap;import java.util.TreeMap;import javax.net.ssl.SSLContext;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.apache.http.HttpEntity;import org.apache.http.HttpResponse;import org.apache.http.client.methods.CloseableHttpResponse;import org.apache.http.client.methods.HttpPost;import org.apache.http.conn.ssl.SSLConnectionSocketFactory;import org.apache.http.entity.StringEntity;import org.apache.http.impl.client.CloseableHttpClient;import org.apache.http.impl.client.DefaultHttpClient;import org.apache.http.impl.client.HttpClients;import org.apache.http.ssl.SSLContexts;import org.apache.http.util.EntityUtils;import org.jdom.Document;import org.jdom.Element;import org.jdom.input.SAXBuilder;import com.pro.profwxappapi.api.PayApi;@SuppressWarnings("deprecation")public class PayUtils {    private static Object Server;    @SuppressWarnings("deprecation")    public static DefaultHttpClient httpclient;    private static SortedMap parameters;        static {        httpclient = new DefaultHttpClient();        httpclient = (DefaultHttpClient) HttpClientConnectionManager.getSSLInstance(httpclient);        parameters = new TreeMap();    }    /**     * 把对象转换成字符串     *      * @param obj     * @return String 转换成字符串,若对象为null,则返回空字符串.     */    public static String toString(Object obj) {        if (obj == null)            return "";        return obj.toString();    }    /**     * 把对象转换为int数值.     *      * @param obj     *            包含数字的对象.     * @return int 转换后的数值,对不能转换的对象返回0。     */    public static int toInt(Object obj) {        int a = 0;        try {            if (obj != null) {                a = Integer.parseInt(obj.toString());            }        } catch (Exception e) {            e.printStackTrace();        }        return a;    }    /**     * 获取从1970年开始到现在的秒数     *      * 
            
            

版权声明

即速应用倡导尊重与保护知识产权。如发现本站文章存在版权问题,烦请提供版权疑问、身份证明、版权证明、联系方式等发邮件至197452366@qq.com ,我们将及时处理。本站文章仅作分享交流用途,作者观点不等同于即速应用观点。用户与作者的任何交易与本站无关,请知悉。

产品经理

手机 : 13312967497

擅长 : 小程序流量变现

扫码领取礼包

热门模板

  • 头条
  • 搜狐
  • 微博
  • 百家
  • 一点资讯
  • 知乎