02-微信支付

image-20200829215904899

官网地址:https://pay.weixin.qq.com/static/applyment_guide/applyment_index.shtml

API文档:https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pages/api.shtml

1. 封装 XML 操作

Dom4J、Sax、pull、jackson

Dom4J解析XML工具类

2. 封装二维码操作

QrCodeUtil-二维码生成与解析

3. 微信支付 Demo

基于 微信开发文档 V2 版

准备工具:xml生成和解析、网络请求、微信支付的API、二维码、WebSocket(Socket、Nio、Netty)

网络请求,服务端请求第三方接口:
解决方案:
1.HttpURLConnection
2.HttpClient
3.OKhttp

3.1 HttpUtil

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;

import java.io.IOException;

public class HttpUtil {
//post请求
public static String postXml(String url, String xml) {
//1、实例化请求对象
HttpPost post = new HttpPost(url);
//HttpGet;
//HttpPut;
//HttpDelete;
try {
//2、实例化请求实体
HttpEntity entity = new StringEntity(xml, "UTF-8");
post.setEntity(entity);
//3、实例化客户端对象
HttpClient client = HttpClientBuilder.create().build();
//4、执行请求 获取响应结果
HttpResponse response = client.execute(post);
//5、验证http状态码
if (response.getStatusLine().getStatusCode() == 200) {
//6、返回响应结果
return EntityUtils.toString(response.getEntity());
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}

3.2 MD5Util

MD5加密和微信的签名算法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.MessageDigest;

public class MD5Util {
/**
* 字节数组转16进制字符串
*
* @param b
* @return
*/
private static String byteArrayToHexString(byte b[]) {
StringBuffer resultSb = new StringBuffer();
for (int i = 0; i < b.length; i++) {
resultSb.append(byteToHexString(b[i]));
}
return resultSb.toString();
}

/**
* 字节转16进制字符串
*
* @param b
* @return
*/
private static String byteToHexString(byte b) {
int n = b;
if (n < 0) {
n += 256;
}
int d1 = n / 16;
int d2 = n % 16;
return hexDigits[d1] + hexDigits[d2];
}

/**
* MD5 加密
*
* @param origin
* @param charsetname
* @return
*/
public static String MD5Encode(String origin, String charsetname) {
String resultString = null;
try {
resultString = new String(origin);
MessageDigest md = MessageDigest.getInstance("MD5");
if (charsetname == null || "".equals(charsetname)) {
resultString = byteArrayToHexString(md.digest(resultString
.getBytes()));
} else {
resultString = byteArrayToHexString(md.digest(resultString
.getBytes(charsetname)));
}
} catch (Exception exception) {
}
return resultString;
}

private static final String hexDigits[] = {"0", "1", "2", "3", "4", "5",
"6", "7", "8", "9", "a", "b", "c", "d", "e", "f"
};

public static String UrlEncode(String src) throws
UnsupportedEncodingException {
return URLEncoder.encode(src, "UTF-8").replace("+", "%20");
}
}

3.3 封装工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
import org.springframework.util.StringUtils;

import java.util.*;

public class WxPayUtil {
/**
* 微信相关配置
*/
public static String APP_ID = "(appid)";
public static String MCH_ID = "(mchid)";
public static String API_KEY = "(api key)";
public static String NOTIFY_URL = "(notify url)"; // eg: http://localhost:8080/
/**
* 常用API接口
*/
public static String WXPAY_UNIFIE = "https://api.mch.weixin.qq.com/pay/unifiedorder";
public static String WXPAY_QUERY = "https://api.mch.weixin.qq.com/pay/orderquery";
public static String WXPAY_CLOSE = "https://api.mch.weixin.qq.com/pay/closeorder";
public static String WXPAY_BILL = "https://api.mch.weixin.qq.com/pay/downloadbill";

private static TreeMap<String, String> initParam() {
TreeMap<String, String> map = new TreeMap<>();
map.put("appid", APP_ID);
map.put("mch_id", MCH_ID);
map.put("nonce_str", UUID.randomUUID().toString().replaceAll("-", ""));
return map;
}

private static String createSign(SortedMap<String, String> packageParams) {
StringBuffer sb = new StringBuffer();
Set<Map.Entry<String, String>> es = packageParams.entrySet();
for (Map.Entry<String, String> entry : es) {
String k = entry.getKey();
String v = entry.getValue();
if (null != v && !"".equals(v) && !"sign".equals(k) &&
!"key".equals(k)) {
sb.append(k + "=" + v + "&");
}
}
sb.append("key=" + API_KEY);
return MD5Util.MD5Encode(sb.toString(), "UTF-8").toUpperCase();
}

/**
* 生成预支付连接
*/
public static String wxpayCreate(PayDto dto) {
TreeMap<String, String> map = initParam();
map.put("body", dto.getOrderdes());
map.put("out_trade_no", dto.getOid());
map.put("total_fee", dto.getPrice() + "");
//map.put("total_fee",1);
map.put("spbill_create_ip", "117.159.15.221");
map.put("notify_url", NOTIFY_URL);
map.put("trade_type", "NATIVE");
map.put("sign", createSign(map));
String requestXml = XmlUtil.createXML(map);
System.err.println("------->" + requestXml);
String responseXml = HttpUtil.postXml(WXPAY_UNIFIE, requestXml);
System.err.println("------->" + responseXml);
if (!StringUtils.isEmpty(responseXml)) {
Map<String, String> res = XmlUtil.parseXml(responseXml);
if (res != null) {
return res.get("code_url");
}
}
return null;
}

/**
* 查询支付状态
*/
public static String wxpayQuery(String oid) {
TreeMap<String, String> map = initParam();
map.put("out_trade_no", oid);
map.put("sign", createSign(map));
String requestXml = XmlUtil.createXML(map);
String responseXml = HttpUtil.postXml(WXPAY_QUERY, requestXml);
if (!StringUtils.isEmpty(responseXml)) {
Map<String, String> res = XmlUtil.parseXml(responseXml);
//SUCCESS—支付成功
//REFUND—转入退款
//NOTPAY—未支付
//CLOSED—已关闭
//REVOKED—已撤销(付款码支付)
//USERPAYING--用户支付中(付款码支付)
//PAYERROR--支付失败(其他原因,如银行返回失败)
if (res != null) {
return res.get("trade_state");
}
}
return null;
}

/**
* 关闭支付
*/
public static String wxpayClose(String oid) {
TreeMap<String, String> map = initParam();
map.put("out_trade_no", oid);
map.put("sign", createSign(map));
String requestXml = XmlUtil.createXML(map);
String responseXml = HttpUtil.postXml(WXPAY_CLOSE, requestXml);
if (!StringUtils.isEmpty(responseXml)) {
Map<String, String> res = XmlUtil.parseXml(responseXml);
//SUCCESS—支付成功
//REFUND—转入退款
//NOTPAY—未支付
//CLOSED—已关闭
//REVOKED—已撤销(付款码支付)
//USERPAYING--用户支付中(付款码支付)
//PAYERROR--支付失败(其他原因,如银行返回失败)
if (res != null) {
return res.get("result_code");
}
}
return null;
}
}

3.4 封装接口实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// 接口
public interface WxPayService {
R<String> createPay(PayDto dto);
R<String> queryPay(String oid);
R<String> closePay(String oid);
}

// 实现类
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.Base64;

@Service
public class WxPayServiceImpl implements WxPayService {

@Override
public R<String> createPay(PayDto dto) {
String qrcode = WxPayUtil.wxpay_create(dto);
if (!StringUtils.isEmpty(qrcode)) {
//生成二维码
return R.ok("http://localhost:8085/api/qrcode/payqrcode/" + Base64.getUrlEncoder().encodeToString(qrcode.getBytes()));
}
return R.error();
}

@Override
public R<String> queryPay(String oid) {
return R.ok(WxPayUtil.wxpay_query(oid));
}

@Override
public R<String> closePay(String oid) {
return R.ok(WxPayUtil.wxpay_close(oid));
}
}

02-微信支付
https://janycode.github.io/2020/03/02/14_微服务/10_支付服务/02-微信支付/
作者
Jerry(姜源)
发布于
2020年3月2日
许可协议