uniapp+springboot之微信app支付

907 阅读3分钟

注意!注意!注意!

重要的事情说三遍

只需要修改以下几点:

1、前端修改圈起来的url地址

2308385-20210318003254715-45289440.png

2、util需要修改成自己的APP_ID KEY MCH_ID certPath

2308385-20210318003632495-288611007.png

3、impl层主要修改 NOTIFY_URL

2308385-20210318003935101-1491950819.png

pom引入

<dependency>
     <groupId>com.github.wxpay</groupId>
     <artifactId>wxpay-sdk</artifactId>
     <version>0.0.3</version>
 </dependency>

uniapp

wxPay() {
                var price =0.01;
                console.log(price)
                uni.request({
                    url: 'xxxxxx/order/wx',   //域名+接口
                    method: 'POST',
                    header: {
                        'content-type': 'application/x-www-form-urlencoded'
                    },
                    data: {
                        'price': price,
                    },

                    success: function(data) {
                        console.log(JSON.stringify(data.data))
                        uni.requestPayment({
                            provider: 'wxpay',
                            orderInfo: JSON.stringify(data.data), //微信、支付宝订单数据
                            success: function(res) {
                                console.log('success:' + JSON.stringify(res));
                            },
                            fail: function(err) {
                                uni.showToast({
                                    title:JSON.stringify(err),
                                    duration:100000000,
                                    icon:'none'
                                })
                                console.log('fail:' + JSON.stringify(err));
                            }
                        });
                    }
                });
            }

后端代码:

controller

 1 package com.tf.medicaworkers.wxpay;
 2 
 3 import io.swagger.annotations.ApiOperation;
 4 import org.springframework.beans.factory.annotation.Autowired;
 5 import org.springframework.web.bind.annotation.PostMapping;
 6 import org.springframework.web.bind.annotation.RequestMapping;
 7 import org.springframework.web.bind.annotation.RestController;
 8 
 9 import javax.servlet.http.HttpServletRequest;
10 import java.io.BufferedReader;
11 import java.io.IOException;
12 import java.io.InputStream;
13 import java.io.InputStreamReader;
14 import java.util.Map;
15 
16 @RestController
17 @RequestMapping("/order")
18 public class OrderController {
19 
20     @Autowired
21     private WxService wxService;
22 
23     @PostMapping("/wx")
24     public Map wxAdd(HttpServletRequest request, float price) throws Exception {
25      //把元转换成分
26         int prices= (int) (price*100);
27         return wxService.doUnifiedOrder(request,prices);
28     }
29 
30     @PostMapping("/notify")
31     @ApiOperation("微信回调")
32     public String wxPayNotify(HttpServletRequest request) {
33         String resXml = "";
34         try {
35             InputStream inputStream = request.getInputStream();
36             //将InputStream转换成xmlString
37             BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
38             StringBuilder sb = new StringBuilder();
39             String line = null;
40             try {
41                 while ((line = reader.readLine()) != null) {
42                     sb.append(line + "\n");
43                 }
44             } catch (IOException e) {
45                 System.out.println(e.getMessage());
46             } finally {
47                 try {
48                     inputStream.close();
49                 } catch (IOException e) {
50                     e.printStackTrace();
51                 }
52             }
53             resXml = sb.toString();
54             String result = wxService.payBack(resXml);
55             return result;
56         } catch (Exception e) {
57             System.out.println("微信手机支付失败:" + e.getMessage());
58             String result = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
59             return result;
60         }
61     }
62 }

util

 1 package com.tf.medicaworkers.wxpay;
 2 
 3 import com.github.wxpay.sdk.WXPayConfig;
 4 import org.springframework.util.ClassUtils;
 5 
 6 import java.io.ByteArrayInputStream;
 7 import java.io.File;
 8 import java.io.FileInputStream;
 9 import java.io.InputStream;
10 
11 public class WXConfigUtil implements WXPayConfig {
12     private byte[] certData;
13     public static final String APP_ID = "xxxxxxxx";     //appid
14     public static final String KEY = "xxxxxxxxxxxx";    //此处是支付密钥切记不是appScret
15     public static final String MCH_ID = "xxxxx";     //商户id
16 
17     public WXConfigUtil() throws Exception {
18         19         
20         String certPath = "D:/Java/tfMW/JAR/weixin/apiclient_cert.p12";//从微信商户平台下载的安全证书存放的路径
21 
22         File file = new File(certPath);
23         System.out.println(certPath);
24         InputStream certStream = new FileInputStream(file);
25         this.certData = new byte[(int) file.length()];
26         certStream.read(this.certData);
27         certStream.close();
28     }
29 
30     @Override
31     public String getAppID() {
32         return APP_ID;
33     }
34 
35     //parnerid,商户号
36     @Override
37     public String getMchID() {
38         return MCH_ID;
39     }
40 
41     @Override
42     public String getKey() {
43         return KEY;
44     }
45 
46     @Override
47     public InputStream getCertStream() {
48         ByteArrayInputStream certBis = new ByteArrayInputStream(this.certData);
49         return certBis;
50     }
51 
52     @Override
53     public int getHttpConnectTimeoutMs() {
54         return 8000;
55     }
56 
57     @Override
58     public int getHttpReadTimeoutMs() {
59         return 10000;
60     }
61 }

service层

package com.tf.medicaworkers.wxpay;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;

public interface WxService {
    String payBack(String resXml);

    Map doUnifiedOrder(HttpServletRequest request, int price) throws Exception;
}

impl层

package com.tf.medicaworkers.wxpay;
import com.github.wxpay.sdk.WXPay;
import com.github.wxpay.sdk.WXPayConstants;
import com.github.wxpay.sdk.WXPayUtil;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

@Service
public class WxServiceImpl implements WxService{
//    public static final String SPBILL_CREATE_IP = "";
    public static final String NOTIFY_URL = "http://127.0.0.1:8234/order/notify";//必须是外网地址,ip+接口
    public static final String TRADE_TYPE_APP = "APP";//类型 APP、JSPI......


    @Override
    public String payBack(String resXml) {
        WXConfigUtil config = null;
        try {
            config = new WXConfigUtil();
        } catch (Exception e) {
            e.printStackTrace();
        }
        WXPay wxpay = new WXPay(config);
        String xmlBack = "";
        Map<String, String> notifyMap = null;
        try {
            notifyMap = WXPayUtil.xmlToMap(resXml);         // 调用官方SDK转换成map类型数据
            if (wxpay.isPayResultNotifySignatureValid(notifyMap)) {//验证签名是否有效,有效则进一步处理

                String return_code = notifyMap.get("return_code");//状态
                String out_trade_no = notifyMap.get("out_trade_no");//商户订单号
                if (return_code.equals("SUCCESS")) {
                    if (out_trade_no != null) {
                        // 注意特殊情况:订单已经退款,但收到了支付结果成功的通知,不应把商户的订单状态从退款改成支付成功
                        // 注意特殊情况:微信服务端同样的通知可能会多次发送给商户系统,所以数据持久化之前需要检查是否已经处理过了,处理了直接返回成功标志
                        // 业务数据持久化
                        System.err.println("微信手机支付回调成功订单号:{}");
                        System.err.println(out_trade_no);
                        xmlBack = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
                    } else {
                        System.err.println("微信手机支付回调失败订单号:{}");
                        System.err.println(out_trade_no);
                        xmlBack = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
                    }
                }
                return xmlBack;
            } else {
                // 签名错误,如果数据里没有sign字段,也认为是签名错误
                // 失败的数据要不要存储?
                System.err.println("手机支付回调通知签名错误");
                xmlBack = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
                return xmlBack;
            }
        } catch (Exception e) {
            System.err.println("手机支付回调通知签名错误");
            System.err.println(e);
            xmlBack = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
        }
        return xmlBack;
    }

    @Override
    public Map doUnifiedOrder(HttpServletRequest request,int price) throws Exception {
        try {
            WXConfigUtil config = new WXConfigUtil();
            WXPay wxpay = new WXPay(config);
            Map<String, String> data = new HashMap<>();
            //生成商户订单号,不可重复
            data.put("appid", config.getAppID());
            data.put("mch_id", config.getMchID());
            data.put("nonce_str", WXPayUtil.generateNonceStr());
            String body = "订单支付";
            data.put("body", body);
            data.put("out_trade_no", System.currentTimeMillis()+ "");
            data.put("total_fee", String.valueOf(price));
            //自己的服务器IP地址
            data.put("spbill_create_ip", request.getRemoteAddr());
            //异步通知地址(请注意必须是外网)
            data.put("notify_url", NOTIFY_URL);
            //交易类型
            data.put("trade_type", TRADE_TYPE_APP);
            //附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据
            data.put("attach", "");
            data.put("sign", WXPayUtil.generateSignature(data, config.getKey(),
                    WXPayConstants.SignType.MD5));
            //使用官方API请求预付订单
            Map<String, String> response = wxpay.unifiedOrder(data);
            System.out.println(response);
            if ("SUCCESS".equals(response.get("return_code"))) {//主要返回以下5个参数
                Map<String, String> param = new HashMap<>();
                param.put("appid", config.getAppID());
                param.put("partnerid", response.get("mch_id"));
                param.put("prepayid", response.get("prepay_id"));
                param.put("package", "Sign=WXPay");
                param.put("noncestr", WXPayUtil.generateNonceStr());
                param.put("timestamp", System.currentTimeMillis() / 1000 + "");
                param.put("sign", WXPayUtil.generateSignature(param, config.getKey(),
                        WXPayConstants.SignType.MD5));
                System.out.println(param);
                return param;
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new Exception("下单失败");
        }
        throw new Exception("下单失败");
    }
}