1.1 为什么要在项目中使用微信支付?
众所周知,支付宝与财付通(微信支付)是如今第三方支付的两大领头企业,同是微信是一个拥有大量用户群体的一个软件,在项目中整合微信支付在一定程度上可以方便用户购物支付。
1.2 如何在Spring项目(SpringBoot)中整合微信支付?
1.2.1 前置准备
- 下载微信支付官方SDK,进行相关配置修改(比如自动装配,以适应SpringBoot开发环境)
我这里以及有一份修改好的SDK,只需要安装到Maven仓库即可,qingyun-wxpay-sdk点击链接下载
- IDEA安装Maven依赖示意图
1.2.2 开始在项目中整合微信支付
1.2.2.1 引入刚刚安装到仓库中的微信支付sdk依赖
<dependency>
<groupId>com.github.wxpay</groupId>
<artifactId>qingyun-wxpay-sdk</artifactId>
<version>1.0</version>
</dependency>
1.2.2.2 配置微信支付所需基础配置信息(这个是在sdk中已经定义好的参数了)
wechat.appId=xxxxx
wechat.mchId=xxx
wechat.key=xxx
wechat.notifyUrl=异步回调地址
1.2.2.3 创建一个微信支付实现类PayServiceImpl
,它包含了发起支付、支付状态查询、异步通知处理
package com.qingyun.wechatpay.service.impl;
import com.github.wxpay.sdk.WXPay;
import com.github.wxpay.sdk.WXPayUtil;
import com.qingyun.wechatpay.enums.PayStatusEnum;
import com.qingyun.wechatpay.enums.PayTypeEnum;
import com.qingyun.wechatpay.mapper.OrderMapper;
import com.qingyun.wechatpay.model.Order;
import com.qingyun.wechatpay.service.OrderService;
import com.qingyun.wechatpay.service.PayService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
/**
* Created with IntelliJ IDEA.
* User: 李敷斌.
* Date: 2020-04-03
* Time: 21:06
* Explain: 支付业务实现类
*/
@Service
@Slf4j
public class PayServiceImpl implements PayService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private OrderService orderService;
@Value(value = "${wechat.notifyUrl}")
private String wechatNotifyUrl;
@Autowired
private WXPay wxPay;
/**
* 发起支付
*
* @param order
* @param ipStr
* @return
*/
@Override
public Map<String, String> luanchPay(Order order,String ipStr) throws Exception {
Map<String, String> data = new HashMap<String, String>();
data.put("body", order.getRemark());
data.put("out_trade_no", order.getOrderNo());
data.put("device_info", "WEB");
data.put("fee_type", "CNY");
data.put("total_fee", order.getAmount()+"");
data.put("spbill_create_ip", ipStr);
data.put("notify_url", wechatNotifyUrl);
data.put("trade_type", "NATIVE"); // 此处指定为扫码支付
data.put("product_id", "1");
Map<String, String> resultMap = wxPay.unifiedOrder(data);
log.info(resultMap.toString());
return resultMap;
}
/**
* @param orderNo
* @return
*/
@Override
public String queryPayStatus(String orderNo) throws Exception {
Map<String, String> data = new HashMap<String, String>();
data.put("out_trade_no", orderNo);
Map<String, String> resp = wxPay.orderQuery(data);
if ("success".equalsIgnoreCase(resp.get("return_code"))){
if ("success".equalsIgnoreCase(resp.get("trade_state"))){
Order order=orderService.getOrderByOrderNo(orderNo);
//修改订单状态
if (order!=null&&order.getStatus().equals(PayStatusEnum.UNPAID)){
order.setPayType(PayTypeEnum.WECHAT_PAY.getCode());
order.setStatus(PayStatusEnum.PAID.getCode());
order.setTradeNo(resp.get("transaction_id"));
}
}
}
return resp.get("trade_state");
}
/**
* 微信支付异步通知处理
*
* @param request
* @return
*/
@Override
public String wechatNotify(HttpServletRequest request) {
try{
String notifyData = ""; // 支付结果通知的xml格式数据
//1.从request获取XML流,转化成为MAP数据
InputStream inputStream = request.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
StringBuffer sb = new StringBuffer();
String temp;
while ((temp = reader.readLine()) != null) {
sb.append(temp);
}
reader.close();
inputStream.close();
notifyData = sb.toString();
Map<String, String> notifyMap = WXPayUtil.xmlToMap(notifyData); // 转换成map
//对数据进行签名
if (wxPay.isResponseSignatureValid(notifyMap)) {
// 签名正确
// 进行处理。
// 注意特殊情况:订单已经退款,但收到了支付结果成功的通知,不应把商户侧订单状态从退款改成支付成功
String returnCode = notifyMap.get("return_code");
if (returnCode.equals("SUCCESS")) {
if(notifyMap.get("result_code").equals("SUCCESS")){
//微信支付订单号
String transactionId = notifyMap.get("transaction_id");
//商户订单号
String outTradeNo = notifyMap.get("out_trade_no");
Order order = orderService.getOrderByOrderNo(outTradeNo);
if (order!=null && order.getStatus()==0) {
order.setPayType(PayTypeEnum.WECHAT_PAY.getCode());
order.setStatus(PayStatusEnum.PAID.getCode());
order.setTradeNo(transactionId);
orderService.updateOrder(order);
}
System.out.println("微信支付成功");
} else {
System.out.println("微信支付失败,"+notifyMap.get("err_code")+"---"+notifyMap.get("err_code_des"));
}
} else {
System.out.println("微信支付失败,"+notifyMap.get("return_msg"));
}
return "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
} else {
// 签名错误,如果数据里没有sign字段,也认为是签名错误
System.out.println("微信支付异步通知,签名错误");
return "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[签名失败]]></return_msg></xml>";
}
} catch (Exception e){
e.printStackTrace();
}
return "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[FAILED]]></return_msg></xml>";
}
}
1.2.2.4 创建一个支付请求控制器,用于处理支付请求
package com.qingyun.wechatpay.controller;
import com.github.wxpay.sdk.WXPay;
import com.qingyun.wechatpay.enums.PayStatusEnum;
import com.qingyun.wechatpay.model.Order;
import com.qingyun.wechatpay.service.OrderService;
import com.qingyun.wechatpay.service.PayService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
/**
* Created with IntelliJ IDEA.
* User: 李敷斌.
* Date: 2020-04-03
* Time: 18:22
* Explain: 支付请求控制器
*/
@Controller
@RequestMapping(value = "/pay")
public class PayController {
@Autowired
private WXPay wxPay;
@Autowired
private PayService payService;
@Autowired
private OrderService orderService;
@RequestMapping(value = "/luanchwechat")
public String wechatPay(String orderNo, Model model, HttpServletRequest httpServletRequest) throws Exception {
Order order=orderService.getOrderByOrderNo(orderNo);
Map<String, String> resp = payService.luanchPay(order,this.getRemortIP(httpServletRequest));
model.addAttribute("code_url",resp.get("code_url"));
model.addAttribute("orderNo",order.getOrderNo());
return "wechatpay";
}
@RequestMapping(value = "/querywechat")
@ResponseBody
public String payStatusQuery(String orderNo){
Order order=orderService.getOrderByOrderNo(orderNo);
if (order.getStatus().equals(PayStatusEnum.PAID.getCode())){
return "success";
}else{
String reuslt= null;
try {
reuslt = payService.queryPayStatus(orderNo);
} catch (Exception e) {
e.printStackTrace();
}
return reuslt;
}
}
@RequestMapping(value = "/wechat/notify")
public String wechatNotify(HttpServletRequest request){
return payService.wechatNotify(request);
}
/**
* 获取用户IP
* @param request
* @return
*/
private String getRemortIP(HttpServletRequest request) {
if (request.getHeader("x-forwarded-for") == null) {
return request.getRemoteAddr();
}
return request.getHeader("x-forwarded-for");
}
}
1.2.2.5 创建一个页面,用于生成并展示微信扫码支付二维码(可以使用thymeleaf模板引擎),页面中所需要的静态资源可以在文末中给出的git仓库地址中找到
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>微信支付页</title>
</head>
<body>
<div id="qrcode" ></div>
</body>
<script type="text/javascript" src="/js/qrcode.min.js"></script>
<script type="text/javascript" src="/js/jquery-1.8.2.min.js"></script>
<script type="text/javascript">
//显示二维码
new QRCode(document.getElementById("qrcode"), "[[${code_url}]]");
//轮询订单是否支付成功
var t1 = window.setInterval('queryStatus()', 5000);
function queryStatus(){
$.ajax({
type: 'post',
url: '/pay/querywechat',
data: {orderNo:"[[${orderNo}]]"},
success: function(str){
console.log(str);
if('SUCCESS' == str){
location.href='/success';
}
},
error: function(){
alert('执行错误!');
}
});
}
</script>
</html>
源代码见我的gitee码云,wechatpay-demo点击蓝色字体链接即可访问
至此微信支付与spring整合完毕,如果文章对你有帮助的话请给我点个赞哦,也可以关注博主我将持续更新一些组件使用教程❤️
!