SpringBoot整合支付宝沙箱支付

环境说明:SpringBoot3.0.2

支付宝沙箱地址:沙箱地址
获取配置信息
在这里插入图片描述
因支付需要回调地址,回调地址必须是公网,如果有公网的话,那直接在下面配置文件填写自己的公网,没有的话,就需要我们借助第三方工具来进行回调。具体操作请看这篇博客

引入依赖

<dependency>
  	<groupId>com.alipay.sdk</groupId>
   	<artifactId>alipay-sdk-java</artifactId>
   	<version>4.22.110.ALL</version>
</dependency>

配置文件

yz:
 alipay:
  gatewayUrl: https://openapi-sandbox.dl.alipaydev.com/gateway.do
  appId: 你的appid
  privateKey: 你的私钥
  format: json
  publicKey: 你的公钥
  charset: UTF-8
  signType: RSA2
  returnUrl: http://xxxxxx.natappfree.cc/api/pay/finish   # 回调成功后,调用的地址
  notifyUrl: http://xxxxxx.natappfree.cc/api/pay/notify   # 回调地址
  expireTime: 15m
 return:
  url: http://localhost:8000/account/center  # 这个就写你支付成功跳转的页面

配置类

@Data
@Configuration
@ConfigurationProperties(prefix = "yz.alipay")
public class AliPayProperties {

    private String gatewayUrl;

    private String appId;

    private String privateKey;

    private String format;

    private String publicKey;

    private String charset;

    private String signType;

    private String notifyUrl;

    private String returnUrl;

    private String expireTime;
}

@Data
@Configuration
@ConfigurationProperties(prefix = "yz.return")
public class ReturnProperties {

    private String url;
}

订单信息

@Data
public class PayOrderRequest {

    private static final long serialVersionUID = 3191241716373120793L;

    @Schema(description = "订单号")
    private Long id;

    @Schema(description = "用户id")
    private Long uid;

    @Schema(description = "主题")
    private String subject;

    @Schema(description = "充值金额")
    private Long amount;

    @Schema(description = "实际金额")
    private Float realAmount;

    @Schema(description = "优惠率")
    private Float discountRate;
}

支付的回调信息,封装成类,

@Data
public class AlipayNotifyDto {


    private String gmt_create;

    private String charset;

    private String gmt_payment;

    private String notify_time;

    private String subject;

    private String sign;

    private String buyer_id;

    private String invoice_amount;

    private String version;

    private String notify_id;

    private String fund_bill_list;

    private String notify_type;

    private String out_trade_no;

    private String total_amount;

    private String trade_status;

    private String trade_no;

    private String auth_app_id;

    private String receipt_amount;

    private String point_amount;

    private String buyer_pay_amount;

    private String app_id;

    private String sign_type;

    private String seller_id;
}

Facade接口

@Tag(name = "支付接口")
public interface PayFacade {

    @Operation(summary = "支付")
    @Parameters(value = {@Parameter(name = "uid", description = "用户id", in = ParameterIn.HEADER)})
    @PostMapping("/pay/")
    BaseResponse<String> reCharge(@RequestHeader Long uid, @RequestBody PayOrderRequest payOrderRequest);

    @Operation(summary = "支付宝异步通知,支付宝支付后,会回调该接口")
    @PostMapping("/pay/notify")
    String notify(AlipayNotifyDto alipayNotifyDto);

    @Operation(summary = "同步跳转,告诉你是否调用成功,不能拿来判断支付成功")
    @GetMapping("/pay/finish")
    void finish(HttpServletResponse response);
}

Controller类

@Slf4j
@RestController
@RequiredArgsConstructor
public class PayController implements PayFacade {

    private final PayService payService;

    @Override
    public BaseResponse<String> reCharge(Long uid, PayOrderRequest payOrderRequest) {
        if(payOrderRequest == null || uid == null){
            throw new RuntimeException("参数不能为空");
        }
        String res = payService.reCharge(uid, payOrderRequest);
        return ResultUtils.success("",res);
    }
    
	public String notify(AlipayNotifyDto alipayNotifyDto) {
        if(alipayNotifyDto == null){
            throw new RuntimeException("参数不能为空");
        }
        String res = payService.notifyUrl(alipayNotifyDto);
        return res;
    }

    public void finish(HttpServletResponse response) {
        try{
            response.sendRedirect(returnProperties.getUrl());
        } catch (Exception e){
            log.error("【同步跳转,告诉你是否调用成功,不能拿来判断支付成功】",e);

        }

    }
}

Service类

@Slf4j
@Service
@RequiredArgsConstructor
public class PayServiceImpl extends ServiceImpl<PayMapper, PayFlow> implements PayService {

    private final AliPayProperties aliPayProperties;

    private final PayMessageProducer payMessageProducer;

    private final UserMessageProducer userMessageProducer;

    private final PromotionMessageProducer promotionMessageProducer;

    private final OrderMessageProducer orderMessageProducer;

	// 携带订单信息获取支付url
    @Override
    public String reCharge(Long uid, PayOrderRequest payOrderRequest) {
        try{
            log.info("payOrderRequest支付信息:{}", payOrderRequest);
            //保存流水---交给mq处理
            payMessageProducer.sendMessage(JSON.toJSONString(payOrderRequest));
            // 交易
            String path = sendPayment(payOrderRequest);
            return path;
        }catch (Exception e){
            log.info("支付异常", e);
            throw new RuntimeException("系统出错");
        }
    }

	// 处理回调逻辑
    @Override
    public String notifyUrl(AlipayNotifyDto alipayNotifyDto) {
        log.info("setTradeStatus: {}", alipayNotifyDto.getTrade_status());
        log.info("回调了");
        String payStatus = "fail";
        boolean signVerified = false;
        Map<String, String> mp = JSON.parseObject(JSON.toJSONString(alipayNotifyDto), Map.class);
        try {
            signVerified = AlipaySignature.rsaCheckV1(mp, aliPayProperties.getPublicKey(), aliPayProperties.getCharset(), aliPayProperties.getSignType());
            log.info("【异步通知签名验证】" + signVerified);
        }catch (AlipayApiException e){
            System.out.println("【异步签名异常】" + e.getErrMsg());
            return payStatus;
        }
        if(signVerified && "TRADE_SUCCESS".equals(alipayNotifyDto.getTrade_status())){
            // 更新流水---这块应该也交给mq处理,不想写了,就这样吧
            updatePayFlowSuccess(alipayNotifyDto.getOut_trade_no());
            // 更新订单---交给mq处理
            orderMessageProducer.sendMessage(alipayNotifyDto.getOut_trade_no());
            // 消费优惠卷---交给mq处理
            promotionMessageProducer.sendMessage(alipayNotifyDto.getOut_trade_no());
            // 用户金币新增---交给mq处理
            userMessageProducer.sendMessage(alipayNotifyDto.getOut_trade_no());
            payStatus = "success";
        }
        log.info("【异步通知签名验证】" + payStatus);
        return payStatus;
    }

    @Override
    public void returnUrl(HttpServletRequest request) throws UnsupportedEncodingException {

    }

	// 更新支付流水
    private void updatePayFlowSuccess(String outTradeNo){
        QueryWrapper<PayFlow> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("out_trade_no", Long.parseLong(outTradeNo));
        PayFlow payFlow = PayFlow.builder().build();
        payFlow.setTradeStatus(PayConstant.TRADE_SUCCESS);
        payFlow.setPaySuccess(true);
        boolean update = this.update(payFlow, queryWrapper);
        if(!update){
            log.info("更新流水失败");
            throw new RuntimeException("更新流水失败");
        }
    }

	// 支付配置
    private AlipayConfig getAlipayConfig() {
        AlipayConfig alipayConfig = new AlipayConfig();
        alipayConfig.setServerUrl(aliPayProperties.getGatewayUrl());
        alipayConfig.setAlipayPublicKey(aliPayProperties.getPublicKey());
        alipayConfig.setPrivateKey(aliPayProperties.getPrivateKey());
        alipayConfig.setAppId(aliPayProperties.getAppId());
        alipayConfig.setFormat(aliPayProperties.getFormat());
        alipayConfig.setCharset(aliPayProperties.getCharset());
        alipayConfig.setSignType(aliPayProperties.getSignType());
        return alipayConfig;
    }

	// 返回支付url
    private String sendPayment(PayOrderRequest payOrderRequest){
        try {
            AlipayClient alipayClient = new DefaultAlipayClient(this.getAlipayConfig());
            AlipayTradePagePayRequest request = this.getAlipayTradePagePayRequest(payOrderRequest);
            request.setReturnUrl(aliPayProperties.getReturnUrl());
            request.setNotifyUrl(aliPayProperties.getNotifyUrl());
            // 调用SDK生成表单
            AlipayTradePagePayResponse alipayTradePagePayResponse = alipayClient.pageExecute(request, "GET");
            String body = alipayTradePagePayResponse.getBody();
            return body;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private AlipayTradePagePayRequest getAlipayTradePagePayRequest(PayOrderRequest payOrderRequest) {
        AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
        //异步接收地址,仅支持http/https,公网可访问
        request.setNotifyUrl("");
        //同步跳转地址,仅支持http/https
        request.setReturnUrl("");
        /******必传参数******/
        JSONObject bizContent = new JSONObject();
        //商户订单号,商家自定义,保持唯一性
        bizContent.put("out_trade_no", payOrderRequest.getId());
        //支付金额,最小值0.01元
        bizContent.put("total_amount", payOrderRequest.getRealAmount());
        //订单标题,不可使用特殊符号
        bizContent.put("subject", payOrderRequest.getSubject());
        //电脑网站支付场景固定传值FAST_INSTANT_TRADE_PAY
        bizContent.put("product_code", "FAST_INSTANT_TRADE_PAY");
        bizContent.put("timeout_express", aliPayProperties.getExpireTime());

        request.setBizContent(bizContent.toString());
        return request;
    }
}

相关推荐

  1. springboot3整合支付沙箱网页版

    2024-04-14 03:42:01       33 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-04-14 03:42:01       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-04-14 03:42:01       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-04-14 03:42:01       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-04-14 03:42:01       20 阅读

热门阅读

  1. pyqt写个星三角降压启动方式2

    2024-04-14 03:42:01       13 阅读
  2. postgis使用

    2024-04-14 03:42:01       16 阅读
  3. photoshop基础学习笔记

    2024-04-14 03:42:01       13 阅读
  4. 第六周学习笔记DAY.1

    2024-04-14 03:42:01       16 阅读
  5. 100个好用的安全工具推荐

    2024-04-14 03:42:01       10 阅读
  6. C++ 传值调用

    2024-04-14 03:42:01       15 阅读
  7. 有趣的小知识(五).sh文件是什么

    2024-04-14 03:42:01       15 阅读
  8. CMakeLists使用总结

    2024-04-14 03:42:01       16 阅读
  9. 设计模式示例

    2024-04-14 03:42:01       16 阅读
  10. 机器学习算法

    2024-04-14 03:42:01       13 阅读
  11. Android沙盒机制

    2024-04-14 03:42:01       15 阅读
  12. 在 Ubuntu 系统上安装 Python 3.10.0

    2024-04-14 03:42:01       11 阅读