springboot 整合 微信小程序


针对各种窒息的微信操蛋接口

微信基本配置

微信支付API DEMO

下载链接 : https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1

微信EncryptedData解密

  1. EncryptedData Model

    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
    package com.obox.obox.model.WxLogin;

    public class EncryptedData {

    private String avatarUrl ;
    private String openId ;
    private String nickName ;
    private String gender ;
    private String city ;
    private String province ;
    private String country ;
    private String unionId ;
    private Watermark watermark ;

    public String getAvatarUrl() {
    return avatarUrl;
    }

    public void setAvatarUrl(String avatarUrl) {
    this.avatarUrl = avatarUrl;
    }

    public String getOpenId() {
    return openId;
    }

    public void setOpenId(String openId) {
    this.openId = openId;
    }

    public String getNickName() {
    return nickName;
    }

    public void setNickName(String nickName) {
    this.nickName = nickName;
    }

    public String getGender() {
    return gender;
    }

    public void setGender(String gender) {
    this.gender = gender;
    }

    public String getCity() {
    return city;
    }

    public void setCity(String city) {
    this.city = city;
    }

    public String getProvince() {
    return province;
    }

    public void setProvince(String province) {
    this.province = province;
    }

    public String getCountry() {
    return country;
    }

    public void setCountry(String country) {
    this.country = country;
    }

    public String getUnionId() {
    return unionId;
    }

    public void setUnionId(String unionId) {
    this.unionId = unionId;
    }

    public Watermark getWatermark() {
    return watermark;
    }

    public void setWatermark(Watermark watermark) {
    this.watermark = watermark;
    }
    }
  2. Encrycode Model

    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
    package com.obox.obox.model.WxLogin;

    public class Encrycode {

    private String session_key ;
    private String encrypted_data ;
    private String iv ;

    public String getSession_key() {
    return session_key;
    }

    public void setSession_key(String session_key) {
    this.session_key = session_key;
    }

    public String getEncrypted_data() {
    return encrypted_data;
    }

    public void setEncrypted_data(String encrypted_data) {
    this.encrypted_data = encrypted_data;
    }

    public String getIv() {
    return iv;
    }

    public void setIv(String iv) {
    this.iv = iv;
    }
    }
  3. EncryptedData解密

    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

    package com.obox.obox.Utils;
    import com.alibaba.fastjson.JSONObject;

    import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;

    import org.bouncycastle.jce.provider.BouncyCastleProvider;



    import javax.crypto.Cipher;

    import javax.crypto.spec.IvParameterSpec;

    import javax.crypto.spec.SecretKeySpec;

    import java.security.AlgorithmParameters;

    import java.security.Security;

    import java.util.Arrays;

    public class WxUtils {

    public static JSONObject getUserInfo(String encryptedData, String sessionKey, String iv){

    // 被加密的数据

    byte[] dataByte = Base64.decode(encryptedData);

    // 加密秘钥

    byte[] keyByte = Base64.decode(sessionKey);

    // 偏移量

    byte[] ivByte = Base64.decode(iv);



    try {

    // 如果密钥不足16位,那么就补足. 这个if 中的内容很重要

    int base = 16;

    if (keyByte.length % base != 0) {

    int groups = keyByte.length / base + (keyByte.length % base != 0 ? 1 : 0);

    byte[] temp = new byte[groups * base];

    Arrays.fill(temp, (byte) 0);

    System.arraycopy(keyByte, 0, temp, 0, keyByte.length);

    keyByte = temp;

    }

    // 初始化

    Security.addProvider(new BouncyCastleProvider());

    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding","BC");

    SecretKeySpec spec = new SecretKeySpec(keyByte, "AES");

    AlgorithmParameters parameters = AlgorithmParameters.getInstance("AES");

    parameters.init(new IvParameterSpec(ivByte));

    cipher.init(Cipher.DECRYPT_MODE, spec, parameters);// 初始化

    byte[] resultByte = cipher.doFinal(dataByte);

    if (null != resultByte && resultByte.length > 0) {

    String result = new String(resultByte, "UTF-8");

    return JSONObject.parseObject(result);

    }

    } catch (Exception e) {

    e.printStackTrace();

    }

    return null;

    }


    }

微信登陆

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
120
121
122
123
124
125
126
127
128
package com.obox.obox.controller.WeChat.WxApp;

import com.alibaba.fastjson.JSONObject;


import com.obox.obox.Utils.IdUtil;
import com.obox.obox.Utils.JwtUtils;
import com.obox.obox.Utils.WxUtils;
import com.obox.obox.mapper.InsertMapper.UserInsert;
import com.obox.obox.mapper.WxToolMapper;
import com.obox.obox.mapper.selectMapper.UserSelect;
import com.obox.obox.model.WxLogin.AccessToken;
import com.obox.obox.model.WxLogin.Encrycode;
import com.obox.obox.model.WxLogin.EncryptedData;
import com.obox.obox.model.token.NoToken;
import com.obox.obox.model.wechat.UO;
import com.obox.obox.model.wechat.UserInfo;
import com.sun.org.apache.xml.internal.security.exceptions.Base64DecodingException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import javax.jws.soap.SOAPBinding;
import java.util.HashMap;
import java.util.Map;

@RestController
@RequestMapping("login")
public class LoginController {


@Autowired
private RestTemplate restTemplate ;

@Autowired
private WxToolMapper wxToolMapper ;

@Autowired
private UserInsert userInsert ;

@Autowired
private UserSelect userSelect ;

@NoToken
@GetMapping("getlogin")
public Object Login(@RequestParam(value = "data",required = true) String data){

//WxLoginParams wxLoginParams = JSONObject.parseObject(data,WxLoginParams.class) ;
//WxLoginParams params = new WxLoginParams() ;
//params.setJs_code(data);
Map<String,String> p = new HashMap<>() ;
p.put("appid","wxfd4904504d50f9c2") ;
p.put("secret","1dcfdc0d47acda452a66a834f730340a") ;
p.put("js_code",data) ;
p.put("grant_type","authorization_code") ;
String url = "https://api.weixin.qq.com/sns/jscode2session?appid=wxfd4904504d50f9c2&secret=1dcfdc0d47acda452a66a834f730340a&js_code="+data+"&grant_type=authorization_code" ;

String json = restTemplate.getForObject(url,String.class) ;

return json ;


}


@NoToken
@PostMapping("/token")
public Object Token(@RequestBody String data) throws Base64DecodingException {

// 返回信息
Map<String,Object> d = new HashMap<>() ;
Encrycode encrycode = JSONObject.parseObject(data,Encrycode.class) ;
String s = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=wxfd4904504d50f9c2&secret=1dcfdc0d47acda452a66a834f730340a";
// 获取token
String token = restTemplate.getForObject(s,String.class) ;
d.put("token",JSONObject.parseObject(token, AccessToken.class)) ;
//data.put("code", WxUtils.decryptData(encrypte_data,session_key,iv));
// 解密encrypted
d.put("code",WxUtils.getUserInfo(encrycode.getEncrypted_data(),encrycode.getSession_key(),encrycode.getIv()));
// 取openid
EncryptedData encryptedData = JSONObject.parseObject(JSONObject.toJSONString(WxUtils.getUserInfo(encrycode.getEncrypted_data(),encrycode.getSession_key(),encrycode.getIv())),EncryptedData.class) ;
// 根据openid查找uid
UO uo = new UO() ;
uo.setOpenid(encryptedData.getOpenId());

if (wxToolMapper.SelectUOByOpenid(uo.getOpenid()) == null){ // 表中无用户信息,插入用户信息

// uo表中插入
uo.setUid(IdUtil.Uid());
wxToolMapper.InsertUO(uo) ;
// 插入用户初始化信息
UserInfo userInfo = new UserInfo() ;
userInfo.setUid(uo.getUid());
userInfo.setUsex(encryptedData.getGender());
userInfo.setUicon(encryptedData.getAvatarUrl());
userInfo.setUname(encryptedData.getNickName());
userInfo.setOpenid(encryptedData.getOpenId());
userInsert.InserUserInfo(userInfo) ;
d.put("user",userInfo) ;

}else { // 如果表中已经含有用户信息,则直接查找

UO u = wxToolMapper.SelectUOByOpenid(uo.getOpenid()) ;
String uid = u.getUid() ;
UserInfo userInfo = userSelect.SelectUserInfoByUid(uid) ;
d.put("user",userInfo) ;

}

// 生成用户token

String jwtuid = uo.getUid() ;
Map<String,Object> jwt = new HashMap<>() ;
jwt.put("wxdata",encryptedData) ;
jwt.put("uid",jwtuid) ;

String payload = JSONObject.toJSONString(jwt) ;
d.put("token", JwtUtils.geneJsonWebToken(payload));



return d ;

}



}

微信支付统一下单接口

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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
package com.obox.obox.controller.WeChat.WxPay;


import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ser.Serializers;
import com.obox.obox.Utils.IdUtil;
import com.obox.obox.Utils.JwtUtils;
import com.obox.obox.mapper.BOMapper;
import com.obox.obox.mapper.BusinessMapper;
import com.obox.obox.mapper.InsertMapper.BaseOrderListInsert;
import com.obox.obox.mapper.QRMapper;
import com.obox.obox.mapper.selectMapper.BaseOrderListSelect;
import com.obox.obox.model.WxLogin.EncryptedData;
import com.obox.obox.model.WxPay.BO;
import com.obox.obox.model.WxPay.WxOrderGoodsInfo;
import com.obox.obox.model.WxPay.WxOrderList;
import com.obox.obox.model.token.NoToken;
import com.obox.obox.model.wechat.BaseOrderList;
import com.obox.obox.model.wechat.CheckSales;
import com.obox.obox.service.QR.QRService;
import com.obox.obox.service.wxpay.WxPaySDK.WXPayConstants;
import com.obox.obox.service.wxpay.WxPaySDK.WXPayUtil;
import com.sun.istack.internal.FinalArrayList;
import io.jsonwebtoken.Claims;
import io.netty.handler.codec.json.JsonObjectDecoder;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import javax.servlet.http.HttpServletRequest;
import java.nio.charset.StandardCharsets;
import java.sql.Struct;
import java.text.SimpleDateFormat;
import java.util.*;


/**
*
* 微信小程序支付
*/
@RestController
@RequestMapping("/wxpay")
public class WxPayController {

@Autowired
private RestTemplate restTemplate ;

@Autowired
private BaseOrderListInsert baseOrderListInsert ;

@Autowired
private BaseOrderListSelect baseOrderListSelect ;

@Autowired
private BusinessMapper businessMapper ;

@Autowired
private QRMapper qrMapper ;

@Autowired
private BOMapper boMapper ;

/**
* 订单下单
* @param data
* @param request
* @return
* @throws Exception
*/



@PostMapping("/sendwxpay")
public Object RequestWxPayAPI(@RequestBody String data, HttpServletRequest request) throws Exception {


/**
* Token获取
*/
String token = request.getHeader("Authorization");
if (StringUtils.isBlank(token)) {
token = request.getParameter("Authorization");
}

String jwtJson = JwtUtils.decipheringToken(token) ;
Map<String ,Object> jwtdata = JSONObject.parseObject(jwtJson,Map.class) ;
EncryptedData encryptedData = JSONObject.parseObject(JSONObject.toJSONString(jwtdata.get("wxdata")),EncryptedData.class) ;
String openid = encryptedData.getOpenId() ;



/**
* 初始化请求数据
*/
WxOrderList wxOrderList = JSONObject.parseObject(data,WxOrderList.class) ;

/**
* 初始化订单ID
*/
final String olid = IdUtil.Olid() ;

/**
* 请求微信api接口
*/
//String body = JSONObject.toJSONString(baseOrderList) ;
String url = "https://api.mch.weixin.qq.com/pay/unifiedorder" ;

/**
* 请求参数初始化
*/
Map<String,String> WxPayParams = new HashMap<>() ;
WxPayParams.put("appid" , "wxfd4904504d50f9c2") ;
WxPayParams.put("mch_id","1545831661") ;
WxPayParams.put("nonce_str", WXPayUtil.generateNonceStr());
WxPayParams.put("body","OBOX小程序订单支付") ;
WxPayParams.put("out_trade_no",olid) ;
WxPayParams.put("total_fee",String.valueOf(wxOrderList.getSum()));
WxPayParams.put("spbill_create_ip","118.31.120.92") ;
WxPayParams.put("notify_url","http://118.31.120.92/msg") ;
WxPayParams.put("trade_type","JSAPI") ;
WxPayParams.put("openid",openid) ;
WxPayParams.put("sign",WXPayUtil.generateSignature(WxPayParams,"x5pgk5c1TT8h96R489trD52dokUDPYW7"));
String XML = WXPayUtil.mapToXml(WxPayParams) ;

String r = new String(XML.getBytes(),"UTF-8");
// 请求数据编码配置
restTemplate.getMessageConverters().set(1,new StringHttpMessageConverter(StandardCharsets.UTF_8)) ;
String res = restTemplate.postForObject(url,r,String.class) ;

/**
* 将获得的内容转化为map类型
*/
Map<String,String> reponse = WXPayUtil.xmlToMap(res) ;
reponse.put("timeStamp",String.valueOf(new Date().getTime()/1000)) ;
reponse.put("signType","MD5") ;

Map<String,String> result = new HashMap<>() ;
result.put("appId",WxPayParams.get("appid")) ;
result.put("nonceStr",reponse.get("nonce_str")) ;
result.put("package","prepay_id="+reponse.get("prepay_id")) ;
result.put("signType","MD5") ;
result.put("timeStamp",String.valueOf(new Date().getTime()/1000)) ;

String paysign = WXPayUtil.generateSignature(result,"x5pgk5c1TT8h96R489trD52dokUDPYW7") ;

String inner = "" ;
for (String key : result.keySet()){
inner += key + "=" + result.get(key)+"&" ;
}

inner = inner.substring(0,inner.length()-1) ;
inner = "MD5(" + inner + ")" + "=" + paysign ;

result.put("paySign",paysign) ;
result.remove("appId") ;
result.remove("key") ;




/**
* 插入订单信息
*/
List<BaseOrderList> baseOrderLists = new ArrayList<>() ;

/**
* 循环遍历
*/
for (WxOrderGoodsInfo wxOrderGoodsInfo : wxOrderList.getGoods()) {

/**
* 初始化订单信息
*/
BaseOrderList baseOrderList = new BaseOrderList();
baseOrderList.setOlid(olid);
baseOrderList.setOltype("notpaid");
baseOrderList.setUid(qrMapper.SelectUidByOpendi(openid));
baseOrderList.setOlgid(wxOrderGoodsInfo.getGid());
baseOrderList.setOlgnum(wxOrderGoodsInfo.getGnum());
baseOrderList.setOlprice(wxOrderGoodsInfo.getGsum());
baseOrderList.setOlremark(wxOrderGoodsInfo.getRemarks());
baseOrderList.setOluphone(wxOrderList.getUphone());
Calendar calendar = Calendar.getInstance();
Date date = calendar.getTime();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String s = sdf.format(date);
baseOrderList.setOldate(s);
// 插入
baseOrderLists.add(baseOrderList);

/**
* 插入订单
*/
baseOrderListInsert.InsertBaseOrderList(baseOrderList);

}

Map<String,Object> resdata = new HashMap<>() ;
resdata.put("reponse",result) ;
resdata.put("olid",olid) ;

return resdata ;

}

/**
* 确认订单
* @param data 扫码后获得的qrid
* @return
*/
@PostMapping("checkwxpay")
public Object CheckPay(@RequestBody String data){

/**
* 初始化订单信息
*/
List<BaseOrderList> baseOrderLists = baseOrderListSelect.SelectBaseOrderList(data);

/**
* 更新订单信息
*/
baseOrderListInsert.UpdateBaseOrderList(data) ;

/**
* 二维码
*/
List<CheckSales> checkSales = new ArrayList<>() ;

/**
* 循环遍历
*/
for (BaseOrderList b : baseOrderLists) {

/**
* 初始化订单信息
*/
BaseOrderList baseOrderList = b ;

/**
* 插入BO信息
*/
BO bo = new BO();
bo.setOlid(baseOrderList.getOlid());
bo.setGid(baseOrderList.getOlgid());
bo.setGnum(baseOrderList.getOlgnum());
bo.setGprice(baseOrderList.getOlprice());
bo.setGtime(baseOrderList.getOldate());
bo.setBid(businessMapper.SelectBidByGid(baseOrderList.getOlgid()));
bo.setUid(baseOrderList.getUid());
// 插入
boMapper.InsertBO(bo) ;

/**
* 二维码生成
*/
for (int i = 0 ;i <bo.getGnum() ; i++){
CheckSales cs = new CheckSales() ;
cs.setGid(bo.getGid());
cs.setOlid(bo.getOlid());
cs.setQrid(IdUtil.Qrid());
cs.setStatus("0");
cs.setUid(baseOrderList.getUid());
cs.setQrhref(QRService.GenerateQR(cs.getQrid()));
checkSales.add(cs) ;
//插入
qrMapper.InsertQR(cs) ;
}


}
return checkSales ;
}


}

订单二维码生成器

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
package com.obox.obox.service.QR;


import com.alibaba.fastjson.JSON;

/**
*
* 二维码生成服务
*/
public class QRService {

private static String URL = "http://qr.liantu.com/api.php?text=" ;


/**
* 二维码图片链接
* @param id
* @return
*/
public static String GenerateQR(String id){

String OR_Code_Url = URL + id ;

return OR_Code_Url ;

}

}