注意!注意!注意!
重要的事情说三遍
只需要修改以下几点:
1、前端修改圈起来的url地址
2、util需要修改成自己的APP_ID KEY MCH_ID certPath
3、impl层主要修改 NOTIFY_URL
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("下单失败");
}
}