目录

  • 一、沙箱环境
  • 1. 配置密钥/证书
  • 系统默认密钥
  • 自定义密钥
  • 二、代码实现
  • 2.1 项目总体结构
  • 2.2 编码
  • 1. 添加相关依赖
  • 2. 配置文件:支付宝应用参数
  • 3. 配置文件类
  • 4. 初始化支付宝
  • 5. 调用 AliPayApi 中的接口
  • 扫码支付
  • 支付回调
  • 订单关闭
  • 支付退款
  • 订单查询
  • 退款查询
  • 2.3 测试
  • 三、总结


参考文档:


一、沙箱环境

记录一下犯的错误.
二级标题与官方文档的二级标题一致:方便于自己对比

1. 配置密钥/证书

系统默认密钥

使用 API 在线调试工具 调试 OpenAPI 必须使用 系统默认密钥。

不需要再配置 获取加签密钥/证书,系统的默认密钥在支付宝API 在线调试工具中可以看到,具体如下所示:

私钥:

支付宝沙箱接入springboot 支付宝沙箱使用_支付宝沙箱接入springboot


公钥:

支付宝沙箱接入springboot 支付宝沙箱使用_java_02

自定义密钥

官网文档:自定义密钥 里面写的很详细。

普通公钥与公钥证书二选一就行,普通公钥与公钥证书区别最主要区别是否涉及资金类支出接口接入。

需要注意的是:配置公钥证书组织与公司已经进行了更改

支付宝沙箱接入springboot 支付宝沙箱使用_支付宝_03


其他的与官方文档对应即可。

二、代码实现

2.1 项目总体结构

支付宝沙箱接入springboot 支付宝沙箱使用_初始化_04

2.2 编码

省略了一个工具类:OrderCodeUtils:主要用于订单号生成。

1. 添加相关依赖

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.7.19</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <!-- IJPay    -->
        <dependency>
            <groupId>com.github.javen205</groupId>
            <artifactId>IJPay-AliPay</artifactId>
            <version>2.8.0</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>

2. 配置文件:支付宝应用参数

server:
  port: 1314

alipay:
  # 应用编号
  appId: 
  # 应用私钥
  privateKey: 
  # 支付宝公钥 (如果是证书模式,公钥与私钥在CSR目录)
  publicKey: 
  # 通知地址或回调地址  !回调地址一定是外网可以访问到的域名!
  domain: 
  # 支付宝支付网关
  serviceUrl: 
  # 应用公钥证书 (证书模式必须)
#  appCertPath:
  # 支付宝公钥证书 (证书模式必须)
#  aliPayCertPath:
  # 支付宝根证书 (证书模式必须)
#  aliPayRootCertPath:

3. 配置文件类

@Component
@Data
@ConfigurationProperties(prefix = "alipay")
public class AlipayProperties {

    private String appId;
    private String privateKey;
    private String publicKey;
    private String doMain;
    private String serviceUrl;
}

4. 初始化支付宝

为什么要初始化支付宝?
支付宝初始化的原因:IJPay 中默认是使用当前线程中的 appId 对应的配置

方法一:使用@PostConstruct注解

@PostConstruct注解原理解析:@PostConstruct注解的方法会在程序启动的时候执行

在启动类上添加@PostConstruct注解的方法:

@SpringBootApplication
public class AlipayApplication {
    public static void main(String[] args){
        SpringApplication.run(AlipayApplication.class, args);
    }

    @PostConstruct
    public void aliPayInit() {
        AlipayProperties aliPayProperties = SpringUtil.getBean(AlipayProperties.class);
        AliPayApiConfig aliPayApiConfig = AliPayApiConfig.builder()
                .setAppId(aliPayProperties.getAppId())
                .setAliPayPublicKey(aliPayProperties.getPublicKey())
                .setPrivateKey(aliPayProperties.getPrivateKey())
                .setServiceUrl(aliPayProperties.getServiceUrl())
                .setCharset("UTF-8")
                .setSignType("RSA2")
                .build();
        AliPayApiConfigKit.putApiConfig(aliPayApiConfig);
    }
}

方法二:使用方法拦截器

OrderController里面,添加初始化支付宝的方法

@RestController
@RequestMapping(value = "/aliPay")
@Slf4j
public class OrderController {

    @Autowired
    private AlipayProperties alipayProperties;
    
    public AliPayApiConfig getApiConfig() {
        AliPayApiConfig aliPayApiConfig = AliPayApiConfig.builder()
                .setAppId(alipayProperties.getAppId())
                .setAliPayPublicKey(alipayProperties.getPublicKey())
                .setPrivateKey(alipayProperties.getPrivateKey())
                .setServiceUrl(alipayProperties.getServiceUrl())
                .setCharset("UTF-8")
                .setSignType("RSA2")
                // 证书模式
                // .setAppCertPath(alipayProperties.getAppCertPath())
                // .setAliPayCertPath(alipayProperties.getAliPayCertPath())
                // .setAliPayRootCertPath(alipayProperties.getAliPayRootCertPath())
                // 普通公钥方式
                .build();
                // 证书模式
                // .buildByCert();
        return aliPayApiConfig;
    }
}

设置OrderController的拦截器AliPayInterceptor

public class AliPayInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler) throws AlipayApiException {
        if (HandlerMethod.class.equals(handler.getClass())) {
            HandlerMethod method = (HandlerMethod) handler;
            Object methodBean = method.getBean();
            AliPayApiConfigKit.setThreadLocalAliPayApiConfig(((OrderController) methodBean).getApiConfig());
            return true;
        }
        return false;
    }
}

AlipayConfig 继承WebMvcConfigurationSupport类,并配置拦截器

@Configuration
public class AlipayConfig extends WebMvcConfigurationSupport {

    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new AliPayInterceptor()).addPathPatterns("/aliPay/**");
        super.addInterceptors(registry);
    }
}

5. 调用 AliPayApi 中的接口

OrderController里面,编写URL请求方法。

此处,以调用 付款码支付 为例子。

扫码支付

这里会返回一个URL,到 二维码制作 中生成二维码,使用支付宝提供的 沙箱版支付宝钱包 ,登录买家账号,发起购买。

特别注意: 回调地址一定是外网可以访问到的域名,可以使用外网端口映射相关的工具来处理。(我买的是花生壳Http,6元),也可以找度娘。

/**
     * 扫码支付
     *
     * @return java.lang.String
     * @date 2022/2/9 11:34
     */
    @GetMapping(value = "/tradePreCreatePay")
    public String tradePreCreatePay() {

        String notifyUrl = alipayProperties.getDoMain() + "/aliPay/aliPayNotifyUrl";

        AlipayTradePrecreateModel model = new AlipayTradePrecreateModel();
        model.setSubject("Javen 支付宝扫码支付测试");
        model.setTotalAmount("10");
        model.setStoreId("123");
        model.setTimeoutExpress("5m");
        String orderNo = OrderCodeUtils.getRandom();
        model.setOutTradeNo(orderNo);
        try {
            AlipayTradePrecreateResponse response = AliPayApi.tradePrecreatePayToResponse(model, notifyUrl);
            String resultStr = response.getBody();
            JSONObject jsonObject = JSONObject.parseObject(resultStr);
            return jsonObject.getJSONObject("alipay_trade_precreate_response").getString("qr_code");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
支付回调
/**
     * 支付回调
     *
     * @param request 请求体
     * @return java.lang.String
     * @date 2022/2/9 11:34
     */
    @PostMapping(value = "/aliPayNotifyUrl")
    public String aliPayNotifyUrl(HttpServletRequest request) {
        try {
            // 获取支付宝POST过来反馈信息
            Map<String, String> params = AliPayApi.toMap(request);
            // 遍历打印出反馈信息
            // for (Map.Entry<String, String> entry : params.entrySet()) {
            //     System.out.println(entry.getKey() + " = " + entry.getValue());
            // }

            boolean verifyResult = AlipaySignature.rsaCheckV1(params, alipayProperties.getPublicKey(), "UTF-8", "RSA2");

            if (verifyResult) {
                // TODO 请在这里加上商户的业务逻辑程序代码 异步通知可能出现订单重复通知 需要做去重处理
                System.out.println("notify_url 验证成功succcess");
                return "success";
            } else {
                System.out.println("notify_url 验证失败");
                // TODO
                return "failure";
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
            return "failure";
        }
    }
订单关闭
/**
     * 关闭订单
     *
     * @param outTradeNo 商家内部订单号
     * @date 2022/2/9 11:53
     * @return java.lang.String
     */
    @GetMapping(value = "/tradeClose")
    public String tradeClose(@RequestParam("outTradeNo") String outTradeNo){
        try {
            AlipayTradeCloseModel closeModel = new AlipayTradeCloseModel();
            closeModel.setOutTradeNo(outTradeNo);
            return AliPayApi.tradeCloseToResponse(closeModel).getBody();
        } catch (AlipayApiException e){
            e.printStackTrace();
        }
        return null;
    }
支付退款
/**
     * 支付退款
     *
     * @param outTradeNo 商家内部订单号
     * @date 2022/2/9 15:38
     * @return java.lang.String
     */
    @GetMapping(value = "/tradeRefund")
    public String tradeRefund(@RequestParam("outTradeNo") String outTradeNo){
        try {
            AlipayTradeRefundModel refundModel = new AlipayTradeRefundModel();
            refundModel.setOutTradeNo(outTradeNo);
            refundModel.setRefundAmount("10");
            refundModel.setRefundReason("退款测试");
            return AliPayApi.tradeRefundToResponse(refundModel).getBody();
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        return null;
    }
订单查询
/**
     * 订单查询
     *
     * @param outTradeNo 商家内部订单号
     * @date 2022/2/9 15:37
     * @return java.lang.String
     */
    @GetMapping(value = "/tradeQuery")
    public String tradeQuery(@RequestParam("outTradeNo") String outTradeNo){
        AlipayTradeQueryModel queryModel = new AlipayTradeQueryModel();
        queryModel.setOutTradeNo(outTradeNo);
        try {
            AlipayTradeQueryResponse queryResponse = AliPayApi.tradeQueryToResponse(queryModel);
            return queryResponse.getBody();
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        return null;
    }
退款查询
/**
     * 退款查询
     *
     * @param outTradeNo 商户内部交易号
     * @date 2022/2/9 15:47
     * @return java.lang.String
     */
    @GetMapping(value = "/refundQuery")
    public String refundQuery(@RequestParam("outTradeNo") String outTradeNo){
        AlipayTradeFastpayRefundQueryModel refundQueryModel = new AlipayTradeFastpayRefundQueryModel();
        refundQueryModel.setOutTradeNo(outTradeNo);
        refundQueryModel.setOutRequestNo(outTradeNo);
        try {
            return AliPayApi.tradeRefundQueryToResponse(refundQueryModel).getBody();
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        return null;
    }

2.3 测试

### 扫码支付
GET http://localhost:1314/aliPay/tradePreCreatePay

### 关闭订单
GET http://localhost:1314/aliPay/tradeClose?outTradeNo=1491259312927019008

### 支付退款
GET http://localhost:1314/aliPay/tradeRefund?outTradeNo=1491238575935721472

### 订单查询
GET http://localhost:1314/aliPay/tradeQuery?outTradeNo=1491259312927019008

### 退款查询
GET http://localhost:1314/aliPay/refundQuery?outTradeNo=1491238575935721472

三、总结

  1. 相比较于微信支付,阿里的支付宝开发文档支付实在是太友好了。
  2. 支付流程的话,与微信支付差不多。