支付项目:5、通用型支付系统(1)

项目初始化

使用 Spring Initializer 进行项目初始化, 记得后面选上 lombok、spring web、mybatis、mysql driver
在这里插入图片描述
在 application.yml 中对数据库连接进行配置:

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost/mall?characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
    username: root
    password: 123456

对接微信Native支付

1、引入作者的maven支付包

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

2、编写接口

package com.imooc.pay.service;

import com.lly835.bestpay.model.PayResponse;

import java.math.BigDecimal;

public interface IPayService {
    /**
     * 创建/发起字符
     */
    PayResponse create(String orderId, BigDecimal amount);
}

3、编写实现类

package com.imooc.pay.service.impl;

import com.imooc.pay.service.IPayService;
import com.lly835.bestpay.config.WxPayConfig;
import com.lly835.bestpay.enums.BestPayTypeEnum;
import com.lly835.bestpay.model.PayRequest;
import com.lly835.bestpay.model.PayResponse;
import com.lly835.bestpay.service.impl.BestPayServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.xml.ws.Response;
import java.math.BigDecimal;

@Slf4j
@Service
public class PayService implements IPayService {

    /**
     *
     * @param orderId
     * @param amount
     */
    @Override
    public PayResponse create(String orderId, BigDecimal amount) {
        WxPayConfig wxPayConfig =  new WxPayConfig();
        wxPayConfig.setAppId("wxd898fcb01713c658");  //设置AppId
        wxPayConfig.setMchId("1483469312");  //设置商户Id
        wxPayConfig.setMchKey("7mdApPMfXddfWWbbP4DUaVYm2wjyh3v3"); //设置商户密钥
        wxPayConfig.setNotifyUrl("http://localhost");

        BestPayServiceImpl bestPayService = new BestPayServiceImpl();
        bestPayService.setWxPayConfig(wxPayConfig);

        PayRequest request = new PayRequest();
        request.setOrderName("9442081-支付测试");
        request.setOrderId(orderId);
        request.setOrderAmount(amount.doubleValue());
        request.setPayTypeEnum(BestPayTypeEnum.WXPAY_NATIVE);

        PayResponse response = bestPayService.pay(request);
        log.info("response={}", response);

        return response;
    }
}

4、编写测试代码

package com.imooc.pay.service.impl;

import com.imooc.pay.PayApplication;
import com.imooc.pay.PayApplicationTests;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;

import java.math.BigDecimal;

import static org.junit.Assert.*;

public class PayServiceTest extends PayApplicationTests {

    @Autowired
    private PayService payService;

    @Test
    public void create() {
        payService.create("chenxin123456", BigDecimal.valueOf(0.01));
    }
}

运行结果:
在这里插入图片描述
红线的部分生成二维码就可以完成支付!!

使用程序实现将支付链路转换为二维码

1、引入 spring-boot-starter-freemarker 依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>

2、编写controller类

package com.imooc.pay.controller;

import com.imooc.pay.service.impl.PayService;
import com.lly835.bestpay.model.PayResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

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

    @Autowired
    private PayService payService;

    @GetMapping("/create")
    public ModelAndView create(@RequestParam("orderId") String orderId,
                               @RequestParam("amount") BigDecimal amount) {
        PayResponse response = payService.create(orderId, amount);
        Map map = new HashMap<>();
        map.put("codeUrl", response.getCodeUrl());
        return new ModelAndView("create", map);
    }
}

3、在templates下编写create.ftl。两端 jquery 代码是从 https://www.bootcdn.cn/ 中拷贝的。qrcode可以将一段字符串变成一张二维码来进行显示。

<html>
    <head>
        <meta charset="utf-8">
        <title>支付</title>
    </head>

    <body>
        <div id="myQrcode"></div>
        <script src="https://cdn.bootcdn.net/ajax/libs/jquery/1.5.1/jquery.min.js"></script>
        <script src="https://cdn.bootcdn.net/ajax/libs/jquery.qrcode/1.0/jquery.qrcode.min.js"></script>
        <script>
            jQuery('#myQrcode').qrcode({
                text:"${codeUrl}"
            });
        </script>
    </body>

</html>

微信异步通知

  • notify_url 要在微信后台设置吗?
  • notify_url 一定要用域名吗?

1、在 NATAPP.cn 网站购买一个隧道,可以将127.0.0.1映射到公网,启动下载的natapp.exe可获得一个公网地址:
在这里插入图片描述

2、更改NotifyUrl的值:

wxPayConfig.setNotifyUrl("http://xiaoxin-mall.natapp1.cc/pay/notify");

3、在PayController.java中编写方法:

@PostMapping("/notify")
public void asyncNotify(@RequestBody String notifyData) {
    log.info("notifyData={}", notifyData);
}

4、支付一笔订单,可以发现,在控制台,可以收到多次重复的返回信息。

5、现在我们收到返回信息后在本地进行验证,并将验证成功地消息返回微信,这样微信就不会再给我们发信息了。

PayService.java:

/**
 * 异步通知处理
 * @param notifyData
 */
@Override
public String asyncNotify(String notifyData) {
    //1、签名校验
    PayResponse payResponse = bestPayService.asyncNotify(notifyData);
    log.info("payResponse = {}", payResponse);

    //2、金额校验(从数据库查订单)

    //3、修改订单支付状态

    //4、告诉微信我已经收到

    return "<xml>\n" +
            "   <return_code><![CDATA[SUCCESS]]></return_code>\n" +
            "   <return_msg><![CDATA[OK]]></return_msg>\n" +
            "</xml>";
}

PayController.java:

@PostMapping("/notify")
@ResponseBody
public String asyncNotify(@RequestBody String notifyData) {
    log.info("notifyData={}", notifyData);
    return payService.asyncNotify(notifyData);
}

支付宝支付

1、支付宝密钥说明

  • 一共涉及到4个密钥,分别是:商户应用公钥、商户应用私钥、支付宝公钥、支付宝私钥。
  • 用户在本地生成商户应用公钥和商户应用私钥,然后将商户应用公钥与支付宝公钥进行绑定,支付宝的私钥存储在支付宝的后台,这个用户看不到。
  • 发起支付:商户(商户应用私钥签名)—> 支付宝(商户应用公钥验签)
  • 异步通知:支付宝(支付宝私钥签名)----> 商户(支付宝公钥验签)
  • 注意:RSA签名不等于RAS加密。签名和加密的代码是不一样的。

2、编写代码,加入支付宝支付

接口IPayService:

public interface IPayService {
    /**
     * 创建/发起支付
     */
    PayResponse create(String orderId, BigDecimal amount, BestPayTypeEnum bestPayTypeEnum);

    /**
     * 异步通知处理
     */
    String asyncNotify(String notifyData);
}

BestPayConfig.java:

@Component
public class BestPayConfig {

    @Bean
    public BestPayService bestPayService() {

        //微信支付配置
        WxPayConfig wxPayConfig =  new WxPayConfig();
        wxPayConfig.setAppId("wxd898fcb01713c658");  //设置AppId
        wxPayConfig.setMchId("1483469312");  //设置商户Id
        wxPayConfig.setMchKey("7mdApPMfXddfWWbbP4DUaVYm2wjyh3v3"); //设置商户密钥
        wxPayConfig.setNotifyUrl("http://xiaoxin-mall.natapp1.cc/pay/notify");

        //支付宝配置
        AliPayConfig aliPayConfig = new AliPayConfig();
        aliPayConfig.setAppId("2018062960540016");
        aliPayConfig.setPrivateKey("MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDUcbUUBaTJA4ngFx1xED2WHrkS4YCi3BRDPu/qU+MXj7VNy/ip+VKSK9aGPd2dRswkt/4DOoOxnnesJDcve+2W9y2gPoOdSVjGlEwTE6MqeB5f3l+RO9Kcb2zL4JwCRxlE0HHLeRdWtnmbelh1rg8zTFwGnoi1pbQajAT/FGDFqIpdI6FrEYbyeR/VNxFXIGK16Z7gfnWRnS4TP93O5ckcuaAcE8tqW16G7u41bKsnsv2149mucBM2hFSEVD/KcGYYke3pD7VpQdk0+WhxITSsa5I8DfSFRKokN7iJoKjYWjI4gN3fxFWLbymeIumoOWdJflwYI5oL+GdVIHfQ0ETLAgMBAAECggEBALaqurdnjuQkfcXIOlGAVGQjMKFycmgWcfnMQQAsdyRINe2Zx8tnDL+QoBm3UjmsqVWdOvVNt/TevCmwzh6vIYBgMsQJXKO+cG33D16L0Q1wUTW/gE7hsFtAV70J+TrgJXMNA/ufuBigN/oe/bbaHknOi4ZJhGUkALOe16D4xajNjHcYdvkfw5Zkv9nAt+GjFphe1lt35KIx6ahFzMcnzzHYy4ezDFdQWPkT7CqrL8Nh9KPm6Sjbzw2JP3RH91OU1q44gPj7yyLTs1oxt4gEqOgVnczJWXoH+eKRmxRoIvodnB4kf1W9LTzAc4Qs7OneDccvhrOoTD3MGhqW0poXZFkCgYEA6dxBCLnU5oeoctoltnh42DXCzEv/M/gkv9HMY/FFnuM6e0qU5EcFjQtTPRRW1S45ctZaHHhpGppHF7RG+okdALj4x2OC1NG9DL4HboVW3CJ4TzmEeZRkR+LWRWw7FA8eXefDBTC4ojAwqkmbvYP3dm6FjSfNBGYs43Wm6qKTcB0CgYEA6I5rPmAv6rB1BBXF8riNhuoDntbHFHOC9kCwuVJooDBBnxXNCqA9mTdnwE8hjgCgbO5lQkeeIRYiZwFYdCLPW78j6Np5CaX0/ZxcVSUQBFYc3d0e3po+rqpX6BGOj7qGhzDXvAs+HScu7ERy0Kbq6b/EbuLlR3oCKIGncGIaxAcCgYBJyWrjm+6mxgrKIjZf+mb2oQ/Tce8VsKe3tjRtHEVBOqTLHd8Yn6gKtpYO4Yn8PVd2+lb4QK247RCdVA5JIlX6UmJ8VtOC3qJtkM+7eWrMjjuzk4xO6Bkz7Uh6IwoI7DRCoMuRqau30MiqEguHoknEHl8ZCIPRbYOgSRDfW2h1qQKBgF9ODnFPphN+IVZ9PdRNAeMqgDVWO9wLwr38oPAx76LGY/44RwF1zgi+hgxv4YZ6h0RdJq5U/1773TltebyOj4BAAw1oi3YCxzYwID7co4XDbK0X85CykcGvGbuHhm8st/krcR4lVV1JM5esLYmI/nixGGWBIwl53OyQxffunJ19AoGBAOX9cBWFIWh5EHVXYvW90HRBQoo1AYtsdrxTedqrij6cWQms6ACeQZPd5O0V6/Lhz3Lw5NRnUl9MbzwOC7BBSBvhWwNzBOzFnaoOvBABa5nFZsdF5jSI3LJHbnxmMvxnKjCgogSGf+hfgR042b/WKDDBEA965MQJ59tCVhALD81z");
        aliPayConfig.setAliPayPublicKey("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtojdtkETo4OEsQLeyyPwtWK9ZqYJANq6jjXC74vk9n/r88yW577y7VdxcK9X/F/wvR7D8of7lndYdhg6xZro0eO2skPZTU+A549J7tfzahVbIBAS+x1WPFJwPtVrfBBvkwHL8PT+YnMcxKyBxOa6wo8fzJs1NgU1+qnDCpwUFyv59GUfdzBvTPL1fY3ZzvRHFHbapevVltbO/jNV0thb8dafmcJXl8lnjQy3XlH3eTH28tlVfqickacfRl/WSD8WN3dGgF7dTDKYfSR7YB7jsHe6VzoHM3UnD9/yQbi/Z3ZrL7yOxEjq4tfrKlZIW7ZCoUpOU4QdPIRhLeC6nWyGrQIDAQAB");
        aliPayConfig.setNotifyUrl("http://xiaoxin-mall.natapp1.cc/pay/notify");
        aliPayConfig.setReturnUrl("http://127.0.0.1");

        BestPayServiceImpl bestPayService = new BestPayServiceImpl();
        bestPayService.setWxPayConfig(wxPayConfig);
        bestPayService.setAliPayConfig(aliPayConfig);

        return bestPayService;
    }
}

PayService.java:

@Slf4j
@Service
public class PayService implements IPayService {

    @Autowired
    private BestPayService bestPayService;

    /**
     *
     * @param orderId
     * @param amount
     */
    @Override
    public PayResponse create(String orderId, BigDecimal amount, BestPayTypeEnum bestPayTypeEnum) {
        PayRequest request = new PayRequest();
        request.setOrderName("9442081-支付测试");
        request.setOrderId(orderId);
        request.setOrderAmount(amount.doubleValue());
        request.setPayTypeEnum(bestPayTypeEnum);

        PayResponse response = bestPayService.pay(request);
        log.info("response={}", response);

        return response;
    }

    /**
     * 异步通知处理
     * @param notifyData
     */
    @Override
    public String asyncNotify(String notifyData) {
        //1、签名校验
        PayResponse payResponse = bestPayService.asyncNotify(notifyData);
        log.info("payResponse = {}", payResponse);

        //2、金额校验(从数据库查订单)

        //3、修改订单支付状态

        //4、告诉微信我已经收到

        if(payResponse.getPayPlatformEnum() == BestPayPlatformEnum.WX) {
            return "<xml>\n" +
                    "   <return_code><![CDATA[SUCCESS]]></return_code>\n" +
                    "   <return_msg><![CDATA[OK]]></return_msg>\n" +
                    "</xml>";
        } else if(payResponse.getPayPlatformEnum() == BestPayPlatformEnum.ALIPAY)
        return "success";

        throw new RuntimeException("异步通知中错误的支付平台");
    }
}

PayController.java:

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

    @Autowired
    private PayService payService;

    @GetMapping("/create")
    public ModelAndView create(@RequestParam("orderId") String orderId,
                               @RequestParam("amount") BigDecimal amount,
                               @RequestParam("payType") BestPayTypeEnum bestPayTypeEnum) {
        PayResponse response = payService.create(orderId, amount, bestPayTypeEnum);

        //支付方式不同,渲染就不同,WXPAY_NATIVE使用codeUrl,ALIPAY_PC使用body
        Map<String, String> map = new HashMap<>();
        if(bestPayTypeEnum == BestPayTypeEnum.WXPAY_NATIVE) {
            map.put("codeUrl", response.getCodeUrl());
            return new ModelAndView("createForWxNative", map);
        } else if(bestPayTypeEnum == BestPayTypeEnum.ALIPAY_PC) {
            map.put("body", response.getBody());
            return new ModelAndView("createForAlipayPC", map);
        }
        throw new RuntimeException("暂不支持的支付类型");
    }

    @PostMapping("/notify")
    @ResponseBody
    public String asyncNotify(@RequestBody String notifyData) {
        log.info("notifyData={}", notifyData);
        return payService.asyncNotify(notifyData);
    }
}

createForAlipayPC.ftl:

<html>
<head>
    <meta charset="utf-8">
    <title>支付</title>
</head>

<body>
${body}
</body>

</html>
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值