壹影博客.
我在下午4点钟开始想你
SpringBoot对接支付宝实现支付功能
  • 2023-7-25日
  • 0评论
  • 228围观

SpringBoot对接支付宝实现支付功能

准备工作:

① 去支付宝开放平台创建一个沙箱应用
官网:https://open.alipay.com/develop/sandbox/app

申请完毕之后获得如下内容:

开启公钥模式

总之要拿到如下内容:

1.APPID(自动生成)
2.应用私钥(自动生成)
3.支付宝公钥(自动生成)
4.支付宝网关地址(自动生成)
5.授权回调地址(自己准备地址)
6.应用网关地址(自己准备地址)

做好如上准备之后我们就可以着手开发了

开发环境

我这里开发的是JavaWeb项目,使用Maven管理,依赖SpringBoot

对接步骤

第一、在Maven的pom.xml加入支付宝依赖的SDK

<!-- 阿里支付SDK -->
<dependency>
    <groupId>com.alipay.sdk</groupId>
    <artifactId>alipay-sdk-java</artifactId>
    <version>4.38.23.ALL</version>
</dependency>

第二、新建一个config类配置如下信息(变量自行替换)

/**
 * @Author gityyge
 * @Description 支付功能配置类(支付宝)
 * @Date 2023/7/25 11:55
 * @Version 1.0
 */
public class AlipayConfig {

  public static final String APPID = "商户Appid";
  /**
   * (RSA加密方法)  私钥-加密用 pkcs8格式的
   */
  public static final String RSA_PRIVATE_KEY = "应用私钥";
  /**
   * (RSA加密方法) 支付宝公钥-解密用
   */
  public static final String ALIPAY_PUBLIC_KEY = "支付宝公钥";

  /**
   * 服务器异步通知页面路径POST请求 需http://或者https://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
   * 这个地址就是支付成功后回调的地址POST请求
   */
  public static final String notify_url = "请求地址";

    /**
     * 页面跳转同步通知页面路径 需http://或者https://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问 商户可以自定义同步跳转地址
     * 这个地址是支付成功后跳转的地址GET请求
     */
  public static String return_url = "页面跳转同步通知页面路径";

  public static String URL = "请求网关地址";

  /**
   * 编码
   */
  public static String CHARSET = "UTF-8";
  /**
   * 返回格式
   */
  public static String FORMAT = "json";

  /**
   * 日志记录目录
   */
  public static String log_path = "/log";
  /**
   * RSA2 签名 加密算法
   */
  public static String SIGNTYPE = "RSA2";
}

第三、在controller包下面新建一个controller类用于请求支付的功能

import cn.hutool.core.util.StrUtil;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeWapPayModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradeWapPayRequest;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.yyge.common.enums.AckCode;
import com.yyge.common.exception.ServiceException;
import com.yyge.config.AlipayConfig;
import com.yyge.entity.Orders;
import com.yyge.service.OrdersService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
/**
 * @Author gityyge
 * @Description 支付的业务逻辑控制器
 * @Date 2023/7/25 11:42
 * @Version 1.0
 */
@RestController
@RequestMapping(value = "/front/alipay")
public class AlipayController{

  //注入业务逻辑的Bean对象
  @Autowired
  private OrdersService ordersService;

  //向支付宝提交支付申请
  @GetMapping(value = "/{orderNumber}")
  public void submitAlipay(@PathVariable(value = "orderNumber") String orderNumber, HttpServletResponse response) throws UnsupportedEncodingException{
    //1.判断当前的orderNumber 订单号是否为空 如果为空则抛出异常
    if(StrUtil.isBlank(orderNumber)){
      throw new ServiceException(AckCode.SYSTEM_PARAM_FAIL);
    }

    //2、向支付宝发起支付申请 ( 必须是一个网页,不能是json字符串)
    // 商户订单号,商户网站订单系统中唯一订单号,必填
    String out_trade_no = orderNumber + "";
    // 订单名称,必填
    String merchandiserName = this.ordersService.searchByMerchandiserName(orderNumber);
    String subject = "向" + merchandiserName + "付款";
    // 付款金额(保留2位小数),必填
    String total_amount = dbOrder.getAmount().setScale(2, RoundingMode.HALF_UP).doubleValue() + "";
    // 商品描述,可空
    String body = merchandiserName;
    // 超时时间 可空
    String timeout_express = "2m";
    /**********************/
    // SDK 公共请求类,包含公共请求参数,以及封装了签名与验签,开发者无需关注签名与验签
    //调用RSA签名方式
    AlipayClient client = new DefaultAlipayClient(AlipayConfig.URL, AlipayConfig.APPID, AlipayConfig.RSA_PRIVATE_KEY, AlipayConfig.FORMAT, AlipayConfig.CHARSET, AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.SIGNTYPE);
    AlipayTradeWapPayRequest alipay_request = new AlipayTradeWapPayRequest();
    // 封装请求支付信息
    AlipayTradeWapPayModel model = new AlipayTradeWapPayModel();
    model.setOutTradeNo(out_trade_no);
    model.setSubject(subject);
    model.setTotalAmount(total_amount);
    model.setBody(body);
    model.setTimeoutExpress(timeout_express);
    alipay_request.setBizModel(model);
    // 设置异步通知地址
    alipay_request.setNotifyUrl(AlipayConfig.notify_url);
    // 设置同步地址
    alipay_request.setReturnUrl(AlipayConfig.return_url);
    // form表单生产
    String form = "";
    try{
      // 调用SDK生成表单
      form = client.pageExecute(alipay_request).getBody();
      log.info(form);
      response.setContentType("text/html;charset=" + AlipayConfig.CHARSET);
      //直接将完整的表单html输出到页面
      response.getWriter().write(form);
      response.getWriter().flush();
      response.getWriter().close();
    }catch (AlipayApiException | IOException e){
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }

  //支付宝通知支付情况
  @PostMapping(value = "/notify")
  public void alipay_notify(HttpServletRequest request, HttpServletResponse response) throws AlipayApiException, ParseException, IOException
  {
    PrintWriter out = response.getWriter();
    Map < String, String > params = new HashMap < > ();
    Map < String, String[] > requestParams = request.getParameterMap();
    for(String name: requestParams.keySet()){
      params.put(name, request.getParameter(name));
    }

    //商户订单号
    String out_trade_no = params.get("out_trade_no");
    //支付宝交易号
    String trade_no = params.get("trade_no");
    //实际支付金额
    String total_amount = params.get("total_amount");
    //交易时间 yyyy-MM-dd HH:mm:ss
    String gmt_payment = params.get("gmt_payment");
    //交易状态
    String trade_status = params.get("trade_status");
    SimpleDateFormat smf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    //计算得出通知验证结果
    boolean verify_result = AlipaySignature.rsaCheckV1(params, AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.CHARSET, "RSA2");
    if(verify_result){
      //支付成功
      if(trade_status.equals("TRADE_SUCCESS")){
        //更新订单状态
        //支付成功的业务逻辑
        //....
        out.println("success");
      }
    }else{
      out.println("fail");
    }
  }
}

展示效果:

发表评论