【开发技巧】-- 一篇女朋友也能看懂的Spring整合第三方支付(微信支付-扫码支付实现篇)

1.1 为什么要在项目中使用微信支付?

众所周知,支付宝与财付通(微信支付)是如今第三方支付的两大领头企业,同是微信是一个拥有大量用户群体的一个软件,在项目中整合微信支付在一定程度上可以方便用户购物支付。

1.2 如何在Spring项目(SpringBoot)中整合微信支付?

1.2.1 前置准备
  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整合完毕,如果文章对你有帮助的话请给我点个赞哦,也可以关注博主我将持续更新一些组件使用教程❤️

发布了140 篇原创文章 · 获赞 75 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_43199016/article/details/105358260