springboot整合微信支付笔记

2022-09-01 08:18:44

先来看一下微信支付的流程,可见在整个支付流程中后台需要处理的事情有:
1、调用统一下单api
2、生成JSAPI页面调用的支付参数,并请求支付
3、异步通知商户支付结果
4、返回微信异步通知的处理结果
在这里插入图片描述
下面来实际编程实现以上的过程,这里面我们使用了第三方Sdk,best-pay-sdk
https://github.com/Pay-Group/best-pay-sdk
maven引入依赖

<dependency><groupId>cn.springboot</groupId><artifactId>best-pay-sdk</artifactId><version>1.3.0</version></dependency>

支付最核心的就是要出现微信支付的界面,那么就需要在商户页面调起支付,那么如何调起支付界面呢,根据开发文档,调起支付需要执行下面的JS,JS中需要传入相应的信息
https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7&index=6
在这里插入图片描述
那么思路比较明确,只需要在controller层执行支付的逻辑,调用统一下单的api,并返回JSAPI页面调用的支付参数动态注入到这段JS支付模板就可以了,那么每次调用controller层的接口时,就会调起支付。

@Controller
@RequestMapping("/pay")
public class PayController{

    @Autowired
    private OrderService orderService;
    @Autowired
    private PayService payService;
    @GetMapping("/create")
    public ModelAndView create(@RequestParam("orderId")String orderId,
                               @RequestParam("returnUrl")String returnUrl,
                               Map<String,Object> map){
        //查询订单
        OrderDTO orderDTO=orderService.findOne(orderId);
        if(orderDTO==null){
            throw new OrderException(ResultEnum.ORDER_NOT_EXIST);}
        //配置创建支付所需的必要信息
        PayResponse payResponse=payService.create(orderDTO);
        //把信息放入支付模板中
        map.put("payResponse",payResponse);
        //returnUrl为支付成功之后需要跳转到的页面
        returnUrl="http://sell.com/#/order/"+orderId;
        map.put("returnUrl",returnUrl);return new ModelAndView("pay/create",map);}}

接下来需要将后台传过来的支付参数动态注入到支付模板中,这里使用了freemarker

<script>function onBridgeReady(){
        WeixinJSBridge.invoke('getBrandWCPayRequest',{"appId":"${payResponse.appId}",     //公众号名称,由商户传入"timeStamp":"${payResponse.timeStamp}",         //时间戳,自1970年以来的秒数"nonceStr":"${payResponse.nonceStr}", //随机串"package":"${payResponse.packAge}","signType":"MD5",         //微信签名方式:"paySign":"${payResponse.paySign}" //微信签名},
            function(res){
               /* if(res.err_msg=="get_brand_wcpay_request:ok"){
                    // 使用以上方式判断前端返回,微信团队郑重提示:
                    //res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。}
                */
               location.href="${returnUrl}";});}if(typeof WeixinJSBridge=="undefined"){
        if( document.addEventListener){
            document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);}elseif(document.attachEvent){
            document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
            document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);}}else{
        onBridgeReady();}</script>

service层中的逻辑,bestPayService.pay(payRequest)调用了统一支付的API,并返回了JSAPI页面调用的支付参数

@Service
@Slf4j
public class PayServiceImpl implements  PayService{
    @Autowired
    private OrderService orderService;
    private static final String ORDER_NAME="微信订单";

    @Autowired
    private BestPayServiceImpl bestPayService;
    @Override
    public PayResponse create(OrderDTO orderDTO){
        PayRequest payRequest=new PayRequest();
        payRequest.setOpenid(orderDTO.getBuyerOpenid());
        payRequest.setOrderAmount(orderDTO.getOrderAmount().doubleValue());
        payRequest.setOrderId(orderDTO.getOrderId());
        payRequest.setOrderName(ORDER_NAME);
        payRequest.setPayTypeEnum(BestPayTypeEnum.WXPAY_MP);
        log.info("【微信支付】payRequest={}", JsonUtil.toJson(payRequest));
        PayResponse payResponse=bestPayService.pay(payRequest);
        log.info("【微信支付】payResponse={}",JsonUtil.toJson(payResponse));return payResponse;}}

配置JAVAconfig,设置商户信息

@Configuration
public class WechatPayConfig{
    @Autowired
    private  WechatAccountConfig wechatAccountConfig;

    @Bean WxPayConfig wxPayConfig(){
        WxPayConfig wxPayConfig=new WxPayConfig();
        wxPayConfig.setAppId(wechatAccountConfig.getMpAppId());
        wxPayConfig.setAppSecret(wechatAccountConfig.getMpAppSecret());
        wxPayConfig.setMchId(wechatAccountConfig.getMchId());
        wxPayConfig.setMchKey(wechatAccountConfig.getMchKey());
        wxPayConfig.setKeyPath(wechatAccountConfig.getKeyPath());
        wxPayConfig.setNotifyUrl(wechatAccountConfig.getNotifyUrl());return wxPayConfig;}
    @Bean
    public BestPayServiceImpl bestPayService(){

        BestPayServiceImpl bestPayService=new BestPayServiceImpl();
        bestPayService.setWxPayConfig(wxPayConfig());return  bestPayService;}}
@Data
@Component
@ConfigurationProperties(prefix="wechat")
public class WechatAccountConfig{
	//公众号ID
    private String mpAppId;
	//公众号密钥
    private String mpAppSecret;
	//商户号
    private String mchId;
    //商户密钥
    private String mchKey;
    //商户证书路径
    private String keyPath;
	//异步回调接口
    private String notifyUrl;}

然后在yml中配置相应的信息即可
在这里插入图片描述
此时打开微信端调用controller层的支付接口就可以实现支付了

支付完成之后还需要处理微信异步返回的结果,接收到异步返回的结果后可以处理业务逻辑,比如修改支付状态等,随后将处理结果返回微信,如果不处理请求,微信会一直返回异步通知。
在这里插入图片描述
controller层

    @PostMapping("/notify")
    public ModelAndView notify(@RequestBody String notifyData){
        payService.notify(notifyData);return new ModelAndView("pay/success");}

service层

    @Override
    public PayResponse notify( String notifyData){
        PayResponse payResponse=bestPayService.asyncNotify(notifyData);
        log.info("【微信异步通知】,payResonse={}",JsonUtil.toJson(payResponse));
        OrderDTO orderDTO=orderService.findOne(payResponse.getOrderId());
        orderService.paid(orderDTO);return payResponse;}

在这里插入图片描述
支付成功后返回的JS代码,至此支付的所有流程结束

<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>

支付测试:
调用统一支付API之后返回的内容,可见调用了统一支付API后返回了之后生成JSAPI页面调用的所需要的支付参数

2020-02-25 03:39:22.518  INFO 22880 ---[nio-8889-exec-6] okhttp3.OkHttpClient:<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg><appid><![CDATA[wxd898fcb01713c658]]></appid><mch_id><![CDATA[1483469312]]></mch_id><nonce_str><![CDATA[g1K2MKyNdNkMkn7t]]></nonce_str><sign><![CDATA[61D46CFE319025CE457FC8F90B6CBADC]]></sign><result_code><![CDATA[SUCCESS]]></result_code><prepay_id><![CDATA[wx250337332209497ce17477f81982372500]]></prepay_id><trade_type><![CDATA[JSAPI]]></trade_type></xml>
2020-02-25 03:39:22.518  INFO 22880 ---[nio-8889-exec-6] okhttp3.OkHttpClient:<-- END HTTP(456-byte body)
2020-02-25 03:39:22.531  INFO 22880 ---[nio-8889-exec-6] com.pers.food.service.PayServiceImpl: 
【微信支付】payResponse={"appId":"wxd898fcb01713c658","timeStamp":"1582573162","nonceStr":"75htValspgU82402","packAge":"prepay_id\u003dwx250337332209497ce17477f81982372500","signType":"MD5","paySign":"855A556EBA7799B011235554A00268DB"}

支付成功后,接收异步通知后返回的信息,可见返回了支付金额,订单号等信息

2020-02-25 03:40:24.144  INFO 22880 ---[nio-8889-exec-4] com.pers.food.service.PayServiceImpl: 
【微信异步通知】,payResonse={"orderAmount": 0.01,"orderId":"1582573104751271126","outTradeNo":"4200000512202002252531868211","payPlatformEnum":"WX"}
  • 作者:横石拦浪
  • 原文链接:https://blog.csdn.net/qq_20786911/article/details/104486995
    更新时间:2022-09-01 08:18:44