基于 Spring Boot 支付宝沙箱支付(Java 版本)
作者:mmseoamin日期:2024-02-02

基于 Spring Boot 支付宝沙箱支付(Java 版本)

  • 步骤
    • 第一步:使用支付宝账户登录,打开控制台,进入沙箱环境
    • 第二步:配置内网穿透账号
    • 第三步:引入支付宝 SDK
    • 第四步: 配置 SpringBoot
    • 第五步: AliPayConfig.java 读取配置
    • 第六步: AliPayController

      步骤

      第一步:使用支付宝账户登录,打开控制台,进入沙箱环境

      打开沙箱地址:https://open.alipay.com/develop/sandbox/app

      基于 Spring Boot 支付宝沙箱支付(Java 版本),在这里插入图片描述,第1张

      基于 Spring Boot 支付宝沙箱支付(Java 版本),在这里插入图片描述,第2张需要获取:AppId、支付宝网关地址、应用私钥、支付宝公钥

      第二步:配置内网穿透账号

      1. 注册 https://natapp.cn/

      2. 购买免费隧道

        基于 Spring Boot 支付宝沙箱支付(Java 版本),在这里插入图片描述,第3张基于 Spring Boot 支付宝沙箱支付(Java 版本),在这里插入图片描述,第4张注意:需要记住这个 authtoken,配置文件用得到

      3. 配置隧道

        基于 Spring Boot 支付宝沙箱支付(Java 版本),在这里插入图片描述,第5张

      4. 文件 config 配置

      #将本文件放置于natapp同级目录 程序将读取 [default] 段
      #在命令行参数模式如 natapp -authtoken=xxx 等相同参数将会覆盖掉此配置
      #命令行参数 -config= 可以指定任意config.ini文件
      [default]
      authtoken= 将隧道的authtoken填进去               #对应一条隧道的authtoken
      clienttoken=                    #对应客户端的clienttoken,将会忽略authtoken,若无请留空,
      log=none                        #log 日志文件,可指定本地文件, none=不做记录,stdout=直接屏幕输出 ,默认为none
      loglevel=ERROR                  #日志等级 DEBUG, INFO, WARNING, ERROR 默认为 DEBUG
      http_proxy=                     #代理设置 如 http://10.123.10.10:3128 非代理上网用户请务必留空
      
      1. 配置文件需要与 natapp 放在同级目录下

        基于 Spring Boot 支付宝沙箱支付(Java 版本),在这里插入图片描述,第6张

      2. 启动 natapp

        基于 Spring Boot 支付宝沙箱支付(Java 版本),在这里插入图片描述,第7张

      为什么要使用 NATAPP?

      因为要把本地的服务暴露到公网,让支付宝可以调用我们的接口给我们传递数据

      第三步:引入支付宝 SDK

      
      com.alipay.sdk
      alipay-sdk-java
      4.35.79.ALL
      
      

      第四步: 配置 SpringBoot

      alipay:
        appId: xxx
        #  应用私钥
        appPrivateKey: xxx
        # 支付宝公钥
        alipayPublicKey:xxx
        #  每次重启会变化
        notifyUrl: http://ju2jpk.natappfree.cc/api/notify
        #natapp 代 理 的 url +/alipay/notify,这个是用于启动支付宝回调函数 notify 的接口
      

      应用私钥和支付宝公钥可以用默认的,也可以自己配置,若自己配置的话需要使用支付宝开放平台密钥工具

      基于 Spring Boot 支付宝沙箱支付(Java 版本),在这里插入图片描述,第8张

      第五步: AliPayConfig.java 读取配置

      package com.projects.config;
      import org.springframework.boot.context.properties.ConfigurationProperties;
      import org.springframework.stereotype.Component;
      @Component
      @ConfigurationProperties(prefix = "alipay") //读取配置文件中的alipay
      public class AliPayConfig {
          private String appId; //支付宝APPID
          private String appPrivateKey; //应用私钥
          private String alipayPublicKey; //支付宝公钥
          private String notifyUrl; //支付宝通知本地接口完整地址
          public String getAppId() {
              return appId;
          }
          public void setAppId(String appId) {
              this.appId = appId;
          }
          public String getAppPrivateKey() {
              return appPrivateKey;
          }
          public void setAppPrivateKey(String appPrivateKey) {
              this.appPrivateKey = appPrivateKey;
          }
          public String getAlipayPublicKey() {
              return alipayPublicKey;
          }
          public void setAlipayPublicKey(String alipayPublicKey) {
              this.alipayPublicKey = alipayPublicKey;
          }
          public String getNotifyUrl() {
              return notifyUrl;
          }
          public void setNotifyUrl(String notifyUrl) {
              this.notifyUrl = notifyUrl;
          }
      }
      

      第六步: AliPayController

      package com.example.controller;
      import cn.hutool.json.JSONObject;
      import com.alipay.api.AlipayApiException;
      import com.alipay.api.AlipayClient;
      import com.alipay.api.DefaultAlipayClient;
      import com.alipay.api.internal.util.AlipaySignature;
      import com.alipay.api.request.AlipayTradePagePayRequest;
      import com.example.common.AliPayConfig;
      import com.example.entity.Orders;
      import com.example.service.OrdersService;
      import org.springframework.web.bind.annotation.GetMapping;
      import org.springframework.web.bind.annotation.PostMapping;
      import org.springframework.web.bind.annotation.RequestMapping;
      import org.springframework.web.bind.annotation.RestController;
      import javax.annotation.Resource;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
      import java.util.HashMap;
      import java.util.Map;
      //  https://natapp.cn/
      // ekihat7647@sandbox.com
      @RestController
      @RequestMapping("/alipay")
      public class AliPayController {
          // 支付宝沙箱网关地址
          private static final String GATEWAY_URL = "https://openapi-sandbox.dl.alipaydev.com/gateway.do";
          private static final String FORMAT = "JSON";
          private static final String CHARSET = "UTF-8";
          //签名方式
          private static final String SIGN_TYPE = "RSA2";
          @Resource
          private AliPayConfig aliPayConfig;
          @Resource
          private OrdersService ordersService;
          @GetMapping("/pay")  //  /alipay/pay?orderNo=xxx
          public void pay(String orderNo, HttpServletResponse httpResponse) throws Exception {
              // 查询订单信息
              Orders orders = ordersService.selectByOrderNo(orderNo);
              if (orders == null) {
                  return;
              }
              // 1. 创建Client,通用SDK提供的Client,负责调用支付宝的API
              AlipayClient alipayClient = new DefaultAlipayClient(GATEWAY_URL, aliPayConfig.getAppId(),
                      aliPayConfig.getAppPrivateKey(), FORMAT, CHARSET, aliPayConfig.getAlipayPublicKey(), SIGN_TYPE);
              // 2. 创建 Request并设置Request参数
              AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();  // 发送请求的 Request类
              request.setNotifyUrl(aliPayConfig.getNotifyUrl());
              JSONObject bizContent = new JSONObject();
              bizContent.put("out_trade_no", orders.getOrderNo());  // 我们自己生成的订单编号
              bizContent.put("total_amount", orders.getTotal()); // 订单的总金额
              bizContent.put("subject", orders.getGoodsName());   // 支付的名称
              bizContent.put("product_code", "FAST_INSTANT_TRADE_PAY");  // 固定配置
              request.setBizContent(bizContent.toString());
              request.setReturnUrl("http://localhost:8080/orders"); // 支付完成后自动跳转到本地页面的路径
              // 执行请求,拿到响应的结果,返回给浏览器
              String form = "";
              try {
                  form = alipayClient.pageExecute(request).getBody(); // 调用SDK生成表单
              } catch (AlipayApiException e) {
                  e.printStackTrace();
              }
              httpResponse.setContentType("text/html;charset=" + CHARSET);
              httpResponse.getWriter().write(form);// 直接将完整的表单html输出到页面
              httpResponse.getWriter().flush();
              httpResponse.getWriter().close();
          }
          @PostMapping("/notify")  // 注意这里必须是POST接口
          public void payNotify(HttpServletRequest request) throws Exception {
              if (request.getParameter("trade_status").equals("TRADE_SUCCESS")) {
                  System.out.println("=========支付宝异步回调========");
                  Map params = new HashMap<>();
                  Map requestParams = request.getParameterMap();
                  for (String name : requestParams.keySet()) {
                      params.put(name, request.getParameter(name));
                  }
                  String sign = params.get("sign");
                  String content = AlipaySignature.getSignCheckContentV1(params);
                  boolean checkSignature = AlipaySignature.rsa256CheckContent(content, sign, aliPayConfig.getAlipayPublicKey(), "UTF-8"); // 验证签名
                  // 支付宝验签
                  if (checkSignature) {
                      // 验签通过
                      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"));
                      String tradeNo = params.get("out_trade_no");
                      String gmtPayment = params.get("gmt_payment");
                      String alipayTradeNo = params.get("trade_no");
                      // 更新订单状态为已支付,设置支付信息
                      Orders orders = ordersService.selectByOrderNo(tradeNo);
                      orders.setStatus("已支付");
                      orders.setPayTime(gmtPayment);
                      orders.setPayNo(alipayTradeNo);
                      ordersService.updateById(orders);
                  }
              }
          }
      }
      

      基于 Spring Boot 支付宝沙箱支付(Java 版本),在这里插入图片描述,第9张基于 Spring Boot 支付宝沙箱支付(Java 版本),在这里插入图片描述,第10张

      基于 Spring Boot 支付宝沙箱支付(Java 版本),在这里插入图片描述,第11张

      基于 Spring Boot 支付宝沙箱支付(Java 版本),在这里插入图片描述,第12张

      基于 Spring Boot 支付宝沙箱支付(Java 版本),在这里插入图片描述,第13张