SSM框架整合支付宝沙箱(2021年6月)

SSM框架整合支付宝沙箱

如果你觉得这篇文章对你有用,不要白嫖,请点赞+评论+收藏+转发!

一、进入支付宝开放平台的管理中心的沙箱服务

网址:https://open.alipay.com/

在这里插入图片描述

在这里插入图片描述

二、设置RSA2(SHA256)密钥

在这里插入图片描述

1、下载支付宝开发助手

网址:https://opendocs.alipay.com/open/291/introduce
在这里插入图片描述

2、生成密钥

在这里插入图片描述

3、复制公钥到支付宝沙箱设置RSA2(SHA256)密钥

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

4、保存生成的支付宝公钥

在这里插入图片描述

三、在pom.xml中引入相关依赖

<dependency>
    <groupId>com.alipay.sdk</groupId>
    <artifactId>alipay-sdk-java</artifactId>
    <version>4.13.50.ALL</version>
</dependency>
<dependency>
    <groupId>com.alipay.sdk</groupId>
    <artifactId>alipay-easysdk</artifactId>
    <version>2.1.0</version>
</dependency>

四、在resources资源文件夹下,新建支付宝沙箱的配置文件:“apply.properties”

## 支付宝配置(不需要应用公钥,应用公钥只是为了生成支付宝公钥),以下配置均可在支付宝沙箱设置中找到
# 应用ID
alipay.appId = 
# 应用私钥
alipay.privateKey = 
# 支付宝公钥,注意不是生成的应用公钥
alipay.publicKey = 
#支付网关配置,这一项是写死的,正式环境是openapi.alipay.com  注意这边不要加https或http等协议名称
alipay.gateway = 
# 支付宝前台跳转地址(自己编写逻辑和页面)
alipay.returnUrl = 
# 支付宝后台通知地址(自己编写逻辑和页面)
alipay.notifyUrl = 
# 支付宝前台手机网页支付中途取消跳转地址(自己编写逻辑和页面)
alipay.errorUrl = 

五、编写支付宝沙箱配置初始化类:AlipayConfig

编写此类的目的是:将支付宝的配置加载到Spring容器中,完成支付宝SDK的初始化。

其中,配置类需要实现ApplicationListener接口,其泛型为ContextRefreshedEvent,作用为当所有的bean都初始化完成并被成功装载后会触发ContextRefreshedEvent事件,ContextRefreshedEvent中提供有一个onApplicationEvent方法,也就是初始化完后将会执行onApplicationEvent方法,将初始化的逻辑编写在此方法中即可。

import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.kernel.Config;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;

@PropertySource("classpath:/apply.properties")  //引入支付宝配置文件
@Component
public class AlipayConfig implements ApplicationListener<ContextRefreshedEvent> {
    // 应用id
    @Value("${alipay.appId}")
    private String appId;

    // 私钥
    @Value("${alipay.privateKey}")
    private String privateKey;

    // 公钥
    @Value("${alipay.publicKey}")
    private String publicKey;

    // 支付宝网关
    @Value("${alipay.gateway}")
    private String gateway;

    // 支付成功后的接口回调地址,不是回调的友好页面,不要弄混了
    @Value("${alipay.notifyUrl}")
    private String notifyUrl;

    private Config getOptions() {
        //这里省略了一些不必要的配置,可参考文档的说明

        Config config = new Config();
        config.protocol = "https";
        config.gatewayHost = this.gateway;
        config.signType = "RSA2";

        config.appId = this.appId;

        // 为避免私钥随源码泄露,推荐从文件中读取私钥字符串而不是写入源码中
        config.merchantPrivateKey = this.privateKey;

        // 注:如果采用非证书模式,则无需赋值上面的三个证书路径,改为赋值如下的支付宝公钥字符串即可
        config.alipayPublicKey = this.publicKey;

        // 可设置异步通知接收服务地址(可选)
        config.notifyUrl = notifyUrl;

        return config;
    }


    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        //初始化支付宝SDK
        Factory.setOptions(getOptions());
        System.out.println("**********支付宝SDK初始化完成**********");
    }
}

六、新建"AlipayService"类,编写支付宝服务层的逻辑代码

说明:这里只进行电脑支付和手机支付两种支付方式的模拟,其他方式请参考官方文档,自行测试!

package cn.bjwlxy.service;

import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.payment.facetoface.models.AlipayTradePayResponse;
import com.alipay.easysdk.payment.page.models.AlipayTradePagePayResponse;
import com.alipay.easysdk.payment.wap.models.AlipayTradeWapPayResponse;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Service;

@PropertySource("classpath:/apply.properties")
@Service
public class AlipayService {
    // 支付成功后要跳转的页面
    @Value("${alipay.returnUrl}")
    private String returnUrl;

    // 支付宝前台手机网页支付中途取消跳转地址
    @Value("${alipay.errorUrl}")
    private String errorUrl;

    /**
     * 支付宝电脑网页支付
     * @param total  金额
     * @param orderId  订单编号
     * @return  
     */
    public String page(String total, String orderId) {
        try {

            AlipayTradePagePayResponse response = Factory.Payment
                    // 选择电脑网站
                    .Page()
                    // 调用支付方法(订单名称, 商家订单号, 金额, 成功页面)
                    .pay("支付测试", orderId, total, returnUrl);

            return response.body;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;

    }

    /**
     * 支付宝手机网页支付
     * @param total     金额
     * @param orderId  订单编号
     * @return
     */
    public String wap(String total, String orderId) {

        try {
            AlipayTradeWapPayResponse response = Factory.Payment
                    //选择手机网站
                    .Wap()
                    // 调用支付方法(订单名称, 商家订单号, 金额, 中途退出页面, 成功页面)
                    .pay("支付测试", orderId, total, errorUrl, returnUrl);

            return response.body;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }


}

六、新建"AlipayController"类,编写支付宝控制层的逻辑代码

package cn.bjwlxy.controller;

import cn.bjwlxy.service.AlipayService;
import com.alipay.easysdk.factory.Factory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

@RestController
@RequestMapping("/api/alipay")
public class AlipayController {
    @Autowired
    private AlipayService alipayService;


    /**
     * @description: 支付宝电脑网页支付
     * @param total: 金额
     * @return java.lang.String
     */
    //此处produces = {"text/html;charset=UTF-8"}设置返回数据的编码集,防止传递过程中出错
    @PostMapping(value = "/page",produces = {"text/html;charset=UTF-8"})
    public String page(String total,String orderId)  
        return alipayService.page(total,orderId);
    }

    /**
     * @description: 支付宝手机网页支付
     * @param orderId: 订单编号
     * @param total: 金额
     * @return java.lang.String
     */
	//此处produces = {"text/html;charset=UTF-8"}设置返回数据的编码集,防止传递过程中出错
    @PostMapping(value = "/wap",produces = {"text/html;charset=UTF-8"})
    public String wap(String total,String orderId) {
        return alipayService.wap(total, orderId);
    }

	
    /**
     * @description: 支付宝异步回调
     * @param request: 请求
     * @return java.lang.String
     */
    @PostMapping("/notify_url")
    public String notify_url(HttpServletRequest request) throws Exception {

        if (request.getParameter("trade_status").equals("TRADE_SUCCESS")) {
            System.out.println("=========支付宝异步回调========");

            Map<String, String> params = new HashMap<>();
            Map<String, String[]> requestParams = request.getParameterMap();
            for (String name : requestParams.keySet()) {
                params.put(name, request.getParameter(name));
            }

            // 支付宝验签
            if (Factory.Payment.Common().verifyNotify(params)) {
                // 验签通过
                System.out.println("交易名称: " + params.get("subject"));
                System.out.println("交易状态: " + params.get("trade_status"));
                System.out.println("支付宝交易凭证号: " + params.get("trade_no"));
                System.out.println("商户订单号: " + params.get("out_trade_no"));
                System.out.println("交易金额: " + params.get("total_amount"));
                System.out.println("买家在支付宝唯一id: " + params.get("buyer_id"));
                System.out.println("买家付款时间: " + params.get("gmt_payment"));
                System.out.println("买家付款金额: " + params.get("buyer_pay_amount"));
            }
        }

        return "success";
    }


}

七、编写生成订单号方法

新建OrderUtil,编写生成订单号方法:

package cn.bjwlxy.common;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;

public class OrderUtil {
    /**
     *  根据时间戳生成订单号
     * */
    public static String getOrderNo () {
        DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS");
        LocalDateTime localDateTime = Instant.ofEpochMilli(System.currentTimeMillis()).atZone(ZoneOffset.ofHours(8)).toLocalDateTime();
        return df.format(localDateTime);
    }

}

八、编写前端测试页面

到此处后端代码编写完毕,下面开始编写前端测试页面,前端测试页面需要三个:购买页面(buy.jsp)、支付成功页面(return_url.html)、支付失败页面(error_url.html),这里只是为了测试,不做任何效果。

1、购买页面(buy.jsp)

<%@ page import="cn.bjwlxy.common.OrderUtil" %>
<%@ taglib prefix="security" uri="http://www.springframework.org/security/tags" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>

<h1>商品购买页面</h1>
商品一共${param.total_price}<form action="/api/alipay/page" method="post">
    订单编号:<input type="text" value="<%=OrderUtil.getOrderNo()%>" name="orderId" readonly/>
    订单总金额:<input type="text" value="${param.total_price}" name="total" readonly/>
    <button type="submit">电脑确认支付</button>
</form>
<form action="/api/alipay/wap" method="post">
    订单编号:<input type="text" value="<%=OrderUtil.getOrderNo()%>" name="orderId" readonly/>
    订单总金额:<input type="text" value="${param.total_price}" name="total" readonly/>
    <button type="submit">手机确认支付</button>
</form>

<script>
</script>
</html>

如果请求成功,会返回整个响应的支付页面的HTML元素,如果使用异步请求,可以使用doucument.write()或response.write()写入页面!

2、支付成功页面(return_url.html)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h2>支付成功</h2>
</body>
</html>

3、支付失败页面(error_url.html)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h2>支付失败</h2>
</body>
</html>

九、支付宝沙箱购买测试

1、购买页面

在这里插入图片描述

2、电脑支付测试

在这里插入图片描述

这里有两种测试方法:

第一种是下载支付宝沙箱版APP,扫码支付

第二种是在支付宝开放平台获取虚拟的账号和密码,手动输入

在这里插入图片描述

在这里插入图片描述

其实,支付宝沙箱模拟的就是一个买家和商家之间的互相交易,因为是是在沙箱环境中模拟的,所以不会产生真实交易。

支付宝官方给提供了一个买家账号和商家账号,我们付款时,使用买家账号,当付款成功后,买家账号中的金额相应的进行扣除,商家账号中的金额相应的增加,这样就模拟了一个在真实环境中的交易情况。

我们现在使用的网关地址为https://openapi.alipaydev.com/gateway.do,这个是支付宝沙箱的一个网关,当使用这个网关配置时,支付时,自动跳转到沙箱环境中。如果全部测试通过后,只需要将配置中的网关换为https://openapi.alipay.com就可以了,非常方便!

3、手机支付测试

手机测试的过程大致相同,只不过将支付的设备换为了手机,此处不再截图示意。

  • 11
    点赞
  • 60
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 10
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jackson Xi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值