Spring Boot 整合支付宝支付(新版 Alipay Easy SDK 2.0)

接入准备

介入前的准备工作可以参考我的这篇博文(新版和老版的流程都是相同的):
jsp对接支付宝支付接口,实现网站在线支付

如果使用的是旧版的 SDK,请移步 Spring Boot 整合支付宝

在接入过程中,会遇到生成密钥的情况,生成密钥工具请见:
生成密钥工具请见: https://opendocs.alipay.com/open/291/105971

网页导航

由于网站改动较大,所以在此记录一下 SDK 的位置。
进入支付宝开放平台首页,点击 文档 => 网页&移动应用
在这里插入图片描述
然后点击 快速示例 DEMO
在这里插入图片描述
找到左侧的 服务端 SDK 新版 即可
在这里插入图片描述

搭建项目

以下涉及到的 API 内容全部来自支付宝官方文档:
https://opendocs.alipay.com/open/54/00y8k9
API 文档请见:
https://github.com/alipay/alipay-easysdk/blob/master/APIDoc.md

导入依赖

服务端 SDK 界面找到相应的依赖链接
在这里插入图片描述
然后复制依赖坐标到 pom.xml
在这里插入图片描述

在这里插入图片描述

  • pom.xml
<!-- 支付宝 SDK -->
<dependency>
    <groupId>com.alipay.sdk</groupId>
    <artifactId>alipay-easysdk</artifactId>
    <version>2.2.0</version>
</dependency>
<!-- thymeleaf -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

创建支付二维码

服务端 SDK 界面找到相应的 API Factory.Payment.Page().pay()
在这里插入图片描述
然后直接复制下面的代码到自己的项目中,然后修改相应的配置即可:
在这里插入图片描述
上面,我们已经复制的代码就是用来生成支付扫描界面的,所以,只需将接口的返回值直接返回给前端即可,这里我把复制的代码放在了一个配置类 AplipayConfig.java 中,因为代码中有如下的信息:

// 1. 设置参数(全局只需设置一次)
Factory.setOptions(getOptions());

由于全局只设置一次,所以可以考虑将配置在项目启动时就进行初始化:

  • AlipayConfig.java
@Component
public class AlipayConfig {

    // 1. 设置参数(全局只需设置一次)
    static {
        Factory.setOptions(getOptions());
    }

    private static Config getOptions() {
        Config config = new Config();

        config.protocol = "https";

        // 沙箱环境修改为 openapi.alipaydev.com
        config.gatewayHost = "openapi.alipaydev.com";

        config.signType = "RSA2";

        config.appId = "你的 APPID";

        // 为避免私钥随源码泄露,推荐从文件中读取私钥字符串而不是写入源码中
        config.merchantPrivateKey = FileUtils.readFileOfTxt("C:\\Users\\w\\Documents\\支付宝开放平台开发助手\\RSA密钥\\应用私钥2048.txt");

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

        //可设置异步通知接收服务地址(可选)(该地址需要外网能够访问)
        config.notifyUrl = "";

        return config;
    }
}

进入 沙箱环境 查看 APPID 和 支付宝公钥:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
上面用到的文件工具类如下:

  • FileUtils.java
/**
 * @author: Dai Junfeng
 * @create: 2021-04-05
 */
public class FileUtils {

    public static String readFileOfTxt(String path){

        StringBuilder sb = new StringBuilder();

        try(BufferedReader bufferedReader = new BufferedReader(new FileReader(path))) {
            char[] buf = new char[1024];
            int len = -1;
            while ((len = bufferedReader.read(buf)) != -1) {
                sb.append(new String(buf, 0, len));
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return sb.toString();
    }
}
  • AlipayService.java
@Service
public class AlipayService {

    /**
     * 生成支付表单
     * @param subject
     * @param money
     * @return
     * @throws Exception
     */
    public String toPay(String subject, BigDecimal money) throws Exception {
    	// 最后一个参数是支付完成之后跳转到的界面, 一般为项目的首页
        AlipayTradePagePayResponse pay = Factory.Payment.Page().pay(subject, this.generateTradeNo(),
                String.valueOf(money), "http://localhost:8080");
        String payForm = null;
        if (ResponseChecker.success(pay)) {
            payForm = pay.getBody();
        }
        return payForm;
    }
    
    /**
     * 通过时间生成外部订单号 out_trade_no
     * @return
     */
    private String generateTradeNo() {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS");
        String tradeNo = LocalDateTime.now(ZoneOffset.of("+8")).format(formatter);
        return tradeNo;
    }
}
  • AlipayController.java
@Controller
@CrossOrigin
@RequestMapping("/pay")
public class AlipayController {

    @Autowired
    private AlipayService alipayService;

    @GetMapping("/topay")
    @ResponseBody
    public String toPay(String subject, BigDecimal money) throws Exception {
        String form = alipayService.toPay(subject, money);
        return form;
    }
}
  • index.html
<form action="/pay/topay">
    描述: <input name="subject" value=""/><br>
    金额: <input name="money" value=""/><br>
    <input type="submit" value="去结算"/>
</form>

启动项目,然后访问即可
在这里插入图片描述
点击结算后就会跳转到支付界面了
在这里插入图片描述
然后使用 沙箱环境的 APP 支付即可。支付宝文档中提供了 Android 的 沙箱环境 的支付 APP,下载即可使用:
在这里插入图片描述

支付结果异步通知

对于什么是异步通知,为什么要使用异步通知,可以参考官方文档 异步通知说明,我在 Spring Boot 整合支付宝 中也有说明。

在支付宝的新版 SDK 中只有下面简短的几行代码:
在这里插入图片描述
但是,如果想知道怎么使用的话,请参考 异步通知说明,我在 Spring Boot 整合支付宝 中也有写到。新版 SDK 直接调用 Factory.Payment.Common().verifyNotify(), 话不多说,在 AlipayController.java 中添加以下代码即可:

  • AlipayController.java
@PostMapping("/callback")
@ResponseBody
public String notifyCallback(HttpServletRequest request) throws Exception {
    System.out.println("进入异步");
    String success = "success";
    String failure = "failure";

    // https://opendocs.alipay.com/open/54/00y8k9 新老版本说明中有异步通知的新版说明
    // 获取支付宝异步回调信息, 将其转为 Map<String, String>
    Map<String, String> params = new HashMap<>();
    Map<String, String[]> requestParams = request.getParameterMap();
    for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) {
        String name = (String) iter.next();
        String[] values = (String[]) requestParams.get(name);
        String valueStr = "";
        for (int i = 0; i < values.length; i++) {
            valueStr = (i == values.length - 1) ? valueStr + values[i]
                    : valueStr + values[i] + ",";
        }
        // 乱码解决,这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
        // valueStr = new String(valueStr.getBytes("ISO-8859-1"), "gbk");
        params.put(name, valueStr);
    }

    // 新版 SDK 不用移除 sign_type
    // params.remove("sign_type");

    // 验签
    boolean signVerified = Factory.Payment.Common().verifyNotify(params);

    if(signVerified){ // 验签通过
        System.out.println("通过验签");
        return success;
    }else{ // 验签失败
        return failure;
    }
}

需要注意的是,还需要给支付宝提供一个 外网可访问的回调 url:
在这里插入图片描述
这里推荐一款免费的内网穿透工具 NATAPP。
同时,需要在支付宝配置中配置异步回调的 url:

  • AlipayConfig.java
// 设置异步通知接收服务地址
config.notifyUrl = "";

订单支付状态查询

请见 alipay.trade.query(统一收单线下交易查询)

该接口提供所有支付宝支付订单的查询,商户可以通过该接口主动查询订单状态,完成下一步的业务逻辑。 需要调用查询接口的情况: 当商户后台、网络、服务器等出现异常,商户系统最终未接收到支付通知; 调用支付接口后,返回系统错误或未知交易状态情况; 调用alipay.trade.pay,返回INPROCESS的状态; 调用alipay.trade.cancel之前,需确认支付状态。
在这里插入图片描述

  • AlipayService.java
/**
 * 查询交易状态
 * @param outTradeNo 生成的外部订单号 out_trade_no
 * @return
 * @throws Exception
 */
public Object queryTradeStatus(String outTradeNo) throws Exception {
    AlipayTradeQueryResponse query = Factory.Payment.Common().query(outTradeNo);
    Map<String, Object> map = JSONUtils.jsonToMap(query.getHttpBody());

    // 返回交易结果, 是否交易成功需要根据该对象中的 trade_status 来确定
    // trade_status 的枚举值如下, 请见 https://opendocs.alipay.com/apis/api_1/alipay.trade.query
    // WAIT_BUYER_PAY(交易创建,等待买家付款)
    // TRADE_CLOSED(未付款交易超时关闭,或支付完成后全额退款)
    // TRADE_SUCCESS(交易支付成功)
    // TRADE_FINISHED(交易结束,不可退款)
    // 当 trade_status 等于 TRADE_SUCCESS 或 TRADE_FINISHED 时, 表示支付成功
    return map.get("alipay_trade_query_response");
}

用到的 JSON 工具类

  • JSONUtils.java
public class JSONUtils {

    private static final ObjectMapper mapper = new ObjectMapper();

    public static Map<String, Object> jsonToMap(String jsonStr) throws JsonProcessingException {
        Map<String, Object> map = mapper.readValue(jsonStr, Map.class);
        return map;
    }
}
  • AlipayController.java
@GetMapping("/query")
@ResponseBody
public Object queryTradeStatus(String outTradeNo) throws Exception {
    Object result = alipayService.queryTradeStatus(outTradeNo);
    return result;
}

然后调用该接口, 传入我们生成的订单号:
在这里插入图片描述

完整项目代码请见:Gitee

  • 16
    点赞
  • 49
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
1. 引入依赖 在 pom.xml 文件中添加以下依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-elasticsearch</artifactId> </dependency> ``` 2. 配置数据源 在 application.properties 或 application.yml 文件中添加以下配置: ```yaml spring.data.elasticsearch.cluster-nodes=127.0.0.1:9300 spring.data.elasticsearch.cluster-name=my-elasticsearch-cluster ``` 3. 创建实体类 创建一个与 Elasticsearch 中的索引(index)对应的实体类,例如: ```java @Document(indexName = "book", type = "novel") public class Novel { @Id private String id; private String name; private String author; private String description; // getter 和 setter } ``` 其中,@Document 注解用于指定索引的名称和类型,@Id 注解用于指定文档的唯一标识。 4. 创建仓库类 创建一个继承自 ElasticsearchRepository 接口的仓库类,例如: ```java public interface NovelRepository extends ElasticsearchRepository<Novel, String> { List<Novel> findByName(String name); } ``` 其中,ElasticsearchRepository 是 Spring Data Elasticsearch 提供的默认仓库接口,提供了基本的 CRUD 操作,也可以自定义查询方法。 5. 编写查询方法 在仓库类中编写自定义查询方法,例如: ```java List<Novel> findByName(String name); ``` 6. 启动应用程序 启动应用程序后,即可使用 Spring Data Elasticsearch 提供的各种方法对 Elasticsearch 中的数据进行操作,例如: ```java @Autowired private NovelRepository novelRepository; public void saveNovel(Novel novel) { novelRepository.save(novel); } public List<Novel> findNovelByName(String name) { return novelRepository.findByName(name); } ``` 以上就是 Spring Boot 整合 Elasticsearch 的基本步骤。需要注意的是,Elasticsearch 的版本和 Spring Data Elasticsearch 的版本需要匹配,否则可能会出现不兼容的情况。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值