ssm 微信扫码支付

导入JAR包

     
     
1
2
3
4
5
     
     
// https://mvnrepository.com/artifact/com.google.zxing/javase
compile group: 'com.google.zxing', name: 'javase', version: '3.1.0'
// https://mvnrepository.com/artifact/com.github.wxpay/wxpay-sdk
compile group: 'com.github.wxpay', name: 'wxpay-sdk', version: '0.0.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
     
     
package com.shop.constant;
/**
* @author 阳十三
* @email wdful165177@gmail.com
* @blog http://www.item1024.com
* @date 2017/9/12
* 支付常量
*/
public class PayConstant {
//支付方式
/***
* 微信支付
*/
public final static int WEPAY=1;// 微信支付
/***
* 支付宝支付
*/
public final static int ALPAY=2;
/**
* 银联支付
*/
public final static int unionpay=3;
//微信商户相关资料
public final static String APP_ID = " ";
public final static String APP_SECRET = " ";
public final static String MCH_ID = " ";
public final static String API_KEY = " ";
//微信接口资料
public final static String NOTIFY_URL = " "; //支付结果异步回调地址
public final static String TRADE_TYPE = "NATIVE";//选择NAVITE那么上传的ip就可以是发机支付的本机ip
public final static String API_URL = " ";
public final static String CREATE_IP="127.0.0.1"; //本季ip
public final static String UFDODER_URL="https://api.mch.weixin.qq.com/pay/unifiedorder"; //微信下单接口
public final static String QUERY_URL="https://api.mch.weixin.qq.com/pay/orderquery"; //微信查询接口
public final static String REFUND_URL="https://api.mch.weixin.qq.com/secapi/pay/refund"; //申请退款的接口
}

支付配置文件

     
     
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
     
     
package com.shop.constant;
import com.github.wxpay.sdk.WXPayConfig;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import static com.shop.constant.PayConstant.API_KEY;
import static com.shop.constant.PayConstant.APP_ID;
import static com.shop.constant.PayConstant.MCH_ID;
/**
* @author 阳十三
* @email wdful165177@gmail.com
* @blog http://www.item1024.com
* @date 2017/9/13
*/
public class WxPayConfig implements WXPayConfig {
private byte[] certData;
//初始化退款、撤销时的商户证书
public WxPayConfig() throws Exception {
String certPath = "/Users/mac/IdeaProjects/GShop/src/main/resources/pay/cert/apiclient_cert.p12";
File file = new File(certPath);
InputStream certStream = new FileInputStream(file);
this.certData = new byte[(int) file.length()];
certStream.read(this.certData);
certStream.close();
}
public String getAppID() {
return APP_ID;
}
/** 微信支付商户号 */
public String getMchID() {
return MCH_ID;
}
public String getKey() {
return API_KEY;
}
public int getHttpConnectTimeoutMs() {
return 8000;
}
public int getHttpReadTimeoutMs() {
return 10000;
}
@Override
public InputStream getCertStream() {
ByteArrayInputStream certBis;
certBis = new ByteArrayInputStream(this.certData);
return certBis;
}
}

编写service

     
     
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
     
     
package com.shop.service;
import com.shop.annotation.DataSource;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;
/**
* @author 阳十三
* @email wdful165177@gmail.com
* @blog http://www.item1024.com
* @date 2017/9/12
*/
@Transactional(rollbackFor=Exception.class,isolation = Isolation.REPEATABLE_READ)
public interface WxPayService {
/**
* 下单接口
* @param out_trade_no 商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|*@ ,且在同一个商户号下唯一。
* @param total_fee 订单总金额,单位为分,只能为整数
* @param userId 用户id
* @param productId 商品id
* @return 二维码短链接
*/
@DataSource("write")
String wxPayByQrcode(String out_trade_no,String total_fee,String productId,int userId) throws Exception;
/**
*
* @param out_trade_no 商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|*@ ,且在同一个商户号下唯一。
* @param total_fee 订单总金额,单位为分,只能为整数
* @param out_refund_no 商户系统内部的退款单号,商户系统内部唯一,只能是数字、大小写字母_-|*@ ,同一退款单号多次请求只退一笔。
* @param refund_fee 退款总金额,订单总金额,单位为分,只能为整数
* @return String
*/
@DataSource("write")
String wxPayRefund(String out_trade_no,String total_fee,String out_refund_no,String refund_fee) throws Exception;
/**
* 支付回调接口
* @param request
* @param response
*/
@DataSource("write")
void wxPayNotify(HttpServletRequest request, HttpServletResponse response) throws Exception;
/**
* 订单查询接口
*/
Map<String,String> wxPayQuery(String out_trade_no) throws Exception;
}

编写实现类 impl

     
     
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
     
     
package com.shop.service.Impl;
import com.github.wxpay.sdk.WXPay;
import com.github.wxpay.sdk.WXPayUtil;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.common.BitMatrix;
import com.shop.constant.WxPayConfig;
import com.shop.mapper.*;
import com.shop.pojo.IntegralLog;
import com.shop.pojo.Orders;
import com.shop.pojo.SystemOption;
import com.shop.pojo.UserPayList;
import com.shop.service.UserPayListService;
import com.shop.service.WxPayService;
import com.shop.utils.WxPayUtils;
import com.shop.utils.XmlUtils;
import org.jdom2.JDOMException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.*;
import java.util.concurrent.TimeUnit;
import static com.shop.constant.PayConstant.*;
/**
* @author 阳十三
* @email wdful165177@gmail.com
* @blog http://www.item1024.com
* @date 2017/9/12
*/
@Service
public class WxPayServiceImpl implements WxPayService {
@Autowired
private RedisTemplate<String, String> redisTemplate;
@Resource
private UserPayListMapper userPayListMapper;
private WxPayConfig wxPayConfig;
private WXPay wxPay;
@Resource
private OrdersMapper ordersMapper;
@Resource
private UserInfoMapper userInfoMapper;
@Resource
private SystemOptionMapper systemOptionMapper;
@Resource
private IntegralLogMapper integralLogMapper;
/**
* @param out_trade_no 商户订单号
* @param total_fee 标价金额
* @param userId 用户id
* @param productId 商品id
* @return 微信支付所需的二维码生成的 短链接
*/
@Override
public String wxPayByQrcode(String out_trade_no, String total_fee, String productId, int userId) throws Exception {
System.out.println("Wxpay start");
//防止请求二维码的时候订单号会重复
if (redisTemplate.hasKey(out_trade_no)) {
System.out.println("Wxpay二维码存在 返回缓存的二维码");
return redisTemplate.opsForValue().get(out_trade_no);
}
UserPayList userPayList = new UserPayList();
userPayList.setOrderId((out_trade_no));
userPayList.setPayAmount(Double.valueOf(total_fee) / 100);
userPayList.setPayType(WEPAY);
userPayList.setPayCreatetime(new java.sql.Date(System.currentTimeMillis()));
userPayList.setUserId(userId);
userPayList.setpStatus(0);
String code_url = "订单重复了";
wxPayConfig = new WxPayConfig();
wxPay = new WXPay(wxPayConfig);
String currTime = WxPayUtils.getCurrTime();
String strTime = currTime.substring(8, currTime.length());
String strRandom = WxPayUtils.buildRandom(4) + "";
String nonce_str = strTime + strRandom;
//设置请求参数
Map<String, String> data = new HashMap<String, String>();
data.put("body", "奥农汇");
data.put("out_trade_no", out_trade_no);
data.put("nonce_str", nonce_str);
data.put("fee_type", "CNY");
data.put("total_fee", total_fee);
data.put("spbill_create_ip", CREATE_IP);
data.put("notify_url", NOTIFY_URL);
data.put("trade_type", TRADE_TYPE); // 此处指定为扫码支付
data.put("product_id", productId);
try {
//发起支付
Map<String, String> resp = wxPay.unifiedOrder(data);
System.out.println(resp);
if (resp.get("result_code").equals("SUCCESS")) {
//获取二维码URL
code_url = resp.get("code_url");
userPayListMapper.insertSelective(userPayList);
//存入redis 防止二次请求重复
redisTemplate.opsForValue().set(out_trade_no, code_url);
//设置半个小时二维码过期
redisTemplate.expire(out_trade_no, 15, TimeUnit.MINUTES);
}
} catch (Exception e) {
e.printStackTrace();
}
return code_url;
}
@Override
public String wxPayRefund(String out_trade_no, String total_fee, String out_refund_no, String refund_fee) throws Exception {
//设置请求参数
String flag = "FAIL";
HashMap<String, String> data = new HashMap<String, String>();
wxPayConfig = new WxPayConfig();
wxPay = new WXPay(wxPayConfig);
data.put("out_trade_no", out_trade_no);
data.put("out_refund_no", out_refund_no);
data.put("total_fee", total_fee);
data.put("refund_fee", refund_fee);
data.put("refund_fee_type", "CNY");
try {
//调用sdk发起退款
Map<String, String> result = wxPay.refund(data);
System.out.println(result);
if ("SUCCESS".equals(result.get("result_code"))) {
//TODO:更新订单
System.out.println("订单" + result.get("out_trade_no") + "微信退款成功");
try {
ordersMapper.updateStaByOrderIdAndSta(result.get("out_trade_no"), 8, 6);
flag = "SUCCESS";
} catch (Exception e) {
e.getStackTrace();
}
}
} catch (Exception e) {
e.printStackTrace();
}
return flag;
}
@Override
public void wxPayNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 读取回调内容
InputStream inputStream;
StringBuffer sb = new StringBuffer();
inputStream = request.getInputStream();
String s;
BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
while ((s = in.readLine()) != null) {
sb.append(s);
}
in.close();
inputStream.close();
// 支付结果通知的xml格式数据
String notifyData = sb.toString();
// 转换成map
Map<String, String> notifyMap = WXPayUtil.xmlToMap(notifyData);
//支付确认内容
String resXml = "";
wxPayConfig = new WxPayConfig();
wxPay = new WXPay(wxPayConfig);
//验证签名
if (wxPay.isPayResultNotifySignatureValid(notifyMap)) { // 签名正确
if (notifyMap.get("out_trade_no") != null) {
if ("SUCCESS".equals(notifyMap.get("result_code"))) { //交易成功
// TODO:更新订单
System.out.println("订单" + notifyMap.get("out_trade_no") + "微信支付成功");
try {
//更改订单状态
ordersMapper.updateStaByOrderIdAndSta(notifyMap.get("out_trade_no"), 1, 2);
//更改支付记录表状态
userPayListMapper.updateStaByOrderIdAndSta(notifyMap.get("out_trade_no"), 0, 1);
//增加用户积分
int userid = userPayListMapper.selectUserIdByOrderId(notifyMap.get("out_trade_no"));
//获取积分规则
SystemOption systemOption = systemOptionMapper.selectByPrimaryKey(1);
Double amount = Double.parseDouble(notifyMap.get("total_fee")) / 100 / systemOption.getIntegralMinusrule();
userInfoMapper.updateAmountByUserIdInc(amount, userid);
//积分日志
IntegralLog integralLog = new IntegralLog();
integralLog.setIntegralChangenum(amount);
integralLog.setIntegralChangereason("购买商品");
integralLog.setIntegralChangetime(new Date(System.currentTimeMillis()));
integralLog.setIntegralChangetype(1);
integralLog.setIntegralRestnum(0.00);
integralLogMapper.insertSelective(integralLog);
//设置成功确认内容
resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
} catch (Exception e) {
System.out.println("更改订单状态异常");
e.getStackTrace();
}
} else { //交易失败
try {
ordersMapper.updateStaByOrderIdAndSta(notifyMap.get("out_trade_no"), null, 7);
} catch (Exception e) {
e.getStackTrace();
}
resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg></return_msg>" + "</xml> ";
System.out.println("订单" + notifyMap.get("out_trade_no") + "微信支付失败");
}
}
// 注意特殊情况:订单已经退款,但收到了支付结果成功的通知,不应把商户侧订单状态从退款改成支付成功
} else { // 签名错误,如果数据里没有sign字段,也认为是签名错误
//设置失败确认内容
resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg></return_msg>" + "</xml> ";
System.out.println("订单" + notifyMap.get("out_trade_no") + "微信支付失败");
}
//发送通知
response.getWriter().println(resXml);
}
/**
*
* @param out_trade_no 订单号
* @return
* @throws Exception
*/
@Override
public Map<String, String> wxPayQuery(String out_trade_no) throws Exception {
HashMap<String, String> data = new HashMap<String, String>();
Map<String, String> result = new HashMap<>();
wxPayConfig = new WxPayConfig();
wxPay = new WXPay(wxPayConfig);
data.put("out_trade_no", out_trade_no);
try {
//调用sdk发起退款
result = wxPay.orderQuery(data);
}catch (Exception e){
e.getStackTrace();
}
return result;
}
}

控制器编写

     
     
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
     
     
package com.shop.controller;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.shop.service.WxPayService;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
/**
* @author 阳十三
* @email wdful165177@gmail.com
* @blog http://www.item1024.com
* @date 2017/9/12
* 系统支付控制器
*/
@Controller
@RequestMapping(value = "/Pay")
public class PayController {
@Resource
private WxPayService wxPayService;
@RequestMapping("/wxPayByQrcode.py")
@ResponseBody
public void orderPay(HttpServletRequest request, HttpServletResponse response) throws Exception {
String code_url = wxPayService.wxPayByQrcode("20150806125377", "1", "18", 59);
System.out.println(code_url);
//根据url生成二维码
MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
// 设置二维码参数
Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
BitMatrix bitMatrix = multiFormatWriter.encode(code_url, BarcodeFormat.QR_CODE, 300, 300, hints);
//返回二维码
MatrixToImageWriter.writeToStream(bitMatrix, "jpg", response.getOutputStream());
}
@RequestMapping("wxPayNotify")
@ResponseBody
public void wxPayNotify(HttpServletRequest request,HttpServletResponse response) throws Exception {
wxPayService.wxPayNotify(request,response);
}
}

下单 退款测试

     
     
1
2
3
4
5
6
     
     
@Test
public void wxPayRund() throws Exception {
String str = wxPayService.wxPayRefund("20150806125377","1","","1");
System.out.println(str);
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阳十三

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值