java对接支付宝实现app支付、退款

将前段时间做的支付工作,做个工作总结吧,顺便分享给大家一下。

 前期准备工作,注册支付宝商家平台,注册地址:https://b.alipay.com/page/portal/home

注册完之后能得到支付宝的appId、支付宝公钥,和应用私钥。如果要做支付宝转账还需要支付宝证书模式的appId、证书模式支付宝公钥和证书模式应用私钥。

pom依赖:

<dependency>
    <groupId>com.alipay.sdk</groupId>
    <artifactId>alipay-sdk-java</artifactId>
    <version>4.38.0.ALL</version>
</dependency>
<dependency>
    <groupId>com.aliyun</groupId>
    <artifactId>aliyun-java-sdk-core</artifactId>
    <version>4.0.3</version>
</dependency>

支付宝PayClient实例化bean注入(非加签模式非证书模式注入),一般用于app支付

@Configuration
@Component
@ConfigurationProperties(prefix = "gpets-cloud.alipay")
@Data
@Slf4j
public class AliPayClientConfig {
    /**
     * APPID
     */
    private String appId;

    /**
     * 商户私钥
     */
    private String privateKey;

    /**
     * 支付宝公钥
     */
    private String publicKey;


    /**
     * 回调地址
     */
    private String notifyUrl;

    @Bean
    public AlipayClient alipayClient() throws AlipayApiException {

        AlipayConfig alipayConfig=new AlipayConfig();
        alipayConfig.setServerUrl(AliPayUtil.SERVICE_URL);
        //设置appId
        alipayConfig.setAppId(appId);
        //设置商户私钥
        alipayConfig.setPrivateKey(privateKey);
        //设置支付宝公钥
        //设置请求格式,固定值json.
        alipayConfig.setFormat(AlipayConstants.FORMAT_JSON);
        //设置字符集
        alipayConfig.setCharset(AlipayConstants.CHARSET_UTF8);
        //设置签名类型
        alipayConfig.setSignType(AlipayConstants.SIGN_TYPE_RSA2);
        //构造client
        AlipayClient alipayClient=new DefaultAlipayClient(alipayConfig);
        return alipayClient;
    }

控制层: app支付流程一般是app端请求后台生成支付签名返回,app端获取到支付签名再去付款,所以我们后台只需要负责生成支付签名就好,等app端支付完之后,我们再根据配置的支付回调地址,我们做支付完成对应的业务处理

public class PayController {
    private final PayService alipayService;



    /**
     *  支付接口
     *
     */
    @PostMapping("/v1/order/pay")
    public Result appPay(@RequestBody @Validated AlipayReq param) {
        try {
            return alipayService.createAppPay(param);
        } catch (Exception e) {
            log.error("支付接口请求失败:{}",e);
            return Result.error(e.getMessage());
        }
    }


 


}

业务层:该业务层中增加了一部分业务操作,可用来参考支付和退款功能实现

@Service
@Slf4j
@RequiredArgsConstructor
public class PayServiceImpl implements PayService {
    private final OrderDataClient orderDataClient;
    private final AliPayClientConfig aliPayClientConfig;
    private final AlipayClient alipayClient;
    private final PayBackRecordService payBackRecordService;
    private final PayApplyRecordService payApplyRecordService;
    private final PayRefundRecordService payRefundRecordService;
    private final RedissonClient redissonClient;
    private final WxPayV3Bean wxPayV3Bean;
    private final UserInfoClient userInfoClient;
    private final RSAAutoCertificateConfig config;
    private final PayCommonService payCommonService;


    private void checkPay(String orderNo) {
        //校验该笔订单是否支付成功过
        PayBackRecord build = PayBackRecord.builder().orderNo(orderNo).deleted(Boolean.FALSE).build();
        long count = payBackRecordService.count(new QueryWrapper<>(build));
        if (count > long0) {
            throw new BizException("该订单已支付,请勿重复支付");
        }
    }

    @Override
    public Result createAppPay(AlipayReq param) {
        log.info("支付请求参数入参:{}", JSONUtil.toJsonStr(param));
        //同一时刻用户对同一个订单只能支付一次
        String lockKey = RedisKeyContant.LOCK_APP_PAY_ORDER + param.getOrderNo();
        RLock rLock = redissonClient.getLock(lockKey);
        boolean lockResult = rLock.tryLock();
        try {
            if (lockResult) {
                checkPay(param.getOrderNo());
                PayOrderInfo order = this.getOrderInfo(param.getOrderNo());
                if(order.getPrice().compareTo(BigDecimal.ZERO)<=0){
                    throw new BusinessException("支付金额必须大于0");
                }
                if (Objects.equals(PayWayEnum.PAY_ALIPAY.getCode(), param.getPayWay())) {
                    //支付宝支付
                    Result result = this.doAlipayApp(order.getOrderNo(), PayOrderTypeEnum.getByType(order.getPayOrderType()).getMsg(), order.getPrice());
                    //记录支付申请表
                    this.toSavePayApplyRecord(order, result, PayWayEnum.PAY_ALIPAY.getPayWay());
                    log.info("订单编号:{},支付宝响应结果:{}", param.getOrderNo(), JSONUtil.toJsonStr(result));
                    return result;
                }
                if (Objects.equals(PayWayEnum.PAY_WECHAT_APPLET.getCode(), param.getPayWay())) {
                    //微信小程序支付
                    Result<UserInfoVO> userResult = userInfoClient.getUserById(AuthUserUtil.getCurrentUserId());
                    if (!userResult.isSuccess() || Objects.isNull(userResult.getObject())) {
                        throw new BizException("查询用户信息接口异常");
                    }
                    UserInfoVO userInfoVo = userResult.getObject();
                    Result<PrepayWithRequestPaymentResponse> wxPayRespVOResult = this.doWechatAppletPay(order.getOrderNo(), PayOrderTypeEnum.getByType(order.getPayOrderType()).getMsg(), order.getPrice(), userInfoVo.getMiniOpenId());
                    //记录支付申请表
                    this.toSavePayApplyRecord(order, wxPayRespVOResult,PayWayEnum.PAY_WECHAT_APPLET.getPayWay());
                    return wxPayRespVOResult;
                }
                if (Objects.equals(PayWayEnum.PAY_WECHAT.getCode(), param.getPayWay())) {
                    //微信支付
                    Result<WxPayRespVO> payResult = this.doWechatAppPay(order.getOrderNo(), PayOrderTypeEnum.getByType(order.getPayOrderType()).getMsg(), order.getPrice());
                    //记录支付申请表
                    this.toSavePayApplyRecord(order, payResult, PayWayEnum.PAY_WECHAT.getPayWay());
                    return payResult;
                }
            }
            return Result.fail("支付中,请勿重复点击");
        } catch (Exception e) {
            log.error("支付请求失败:{}",e);
            return Result.fail(e.getMessage());
        } finally {
            if (lockResult) {
                rLock.unlock();
            }
        }
    }

    /**
     * 微信支付
     *
     * @Param: [java.lang.String, java.lang.String, java.math.BigDecimal]
     * @return: cn.aimex.cloud.framework.core.domain.Result<cn.gpets.cloud.payment.server.domain.vo.WxPayRespVO>
     * @Author: FJT
     * @Date: 2023/11/9
     */
    private Result<WxPayRespVO> doWechatAppPay(String orderNo, String msg, BigDecimal price) {
        try {
            // 构建service
            AppService service = new AppService.Builder().config(config).build();
            com.wechat.pay.java.service.payments.app.model.PrepayRequest request = new com.wechat.pay.java.service.payments.app.model.PrepayRequest();
            com.wechat.pay.java.service.payments.app.model.Amount amount = new com.wechat.pay.java.service.payments.app.model.Amount();
            amount.setTotal(NumberUtil.mul(price, 100).intValue());
            request.setAmount(amount);
            request.setAppid(wxPayV3Bean.getAppId());
            request.setMchid(wxPayV3Bean.getMchId());
            request.setDescription(msg);
            request.setNotifyUrl(wxPayV3Bean.getNotifyUrl());
            request.setOutTradeNo(orderNo);
            // 调用下单方法,得到应答
            // 调用微信sdk接口,生成预支付交易单
            com.wechat.pay.java.service.payments.app.model.PrepayResponse response = service.prepay(request);
            WxPayRespVO vo = new WxPayRespVO();
            Signer signer = config.createSigner();
            long timestamp = Instant.now().getEpochSecond();
            vo.setTimeStamp(timestamp);
            String nonceStr = NonceUtil.createNonce(32);
            vo.setNonceStr(nonceStr);
            String message =
                    request.getAppid() + "\n" + timestamp + "\n" + nonceStr + "\n" + response.getPrepayId() + "\n";
            String sign = signer.sign(message).getSign();
            vo.setPaySign(sign);
            vo.setPrepayId(response.getPrepayId());
            vo.setAppId(wxPayV3Bean.getAppId());
            vo.setPartnerId(wxPayV3Bean.getMchId());
            log.info("微信支付请求返回:{}",JSONUtil.toJsonStr(vo));
            return Result.success(vo);
        } catch (ServiceException e) {
            log.error("微信支付请求异常:{}",e);
            return Result.fail(JSONUtil.toJsonStr(e.getResponseBody()));
        } catch (Exception e) {
            log.error("微信支付请求异常:{}",e);
            return Result.fail(JSONUtil.toJsonStr(e.getMessage()));
        }
    }

    /**
     * 微信小程序支付
     *
     * @param orderNo
     * @param msg
     * @param price
     * @Param: []
     * @return: void
     * @Author: FJT
     * @Date: 2023/11/8
     */
    private Result<PrepayWithRequestPaymentResponse> doWechatAppletPay(String orderNo, String msg, BigDecimal price, String openId) {
        try {
            // 构建service
            JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(config).build();
            // request.setXxx(val)设置所需参数,具体参数可见Request定义
            PrepayRequest request = new PrepayRequest();
            Amount amount = new Amount();
            amount.setTotal(NumberUtil.mul(price, 100).intValue());
            request.setAmount(amount);
            request.setAppid(wxPayV3Bean.getAppletAppId());
            request.setMchid(wxPayV3Bean.getMchId());
            request.setDescription(msg);
            request.setNotifyUrl(wxPayV3Bean.getNotifyUrl());
            request.setOutTradeNo(orderNo);
            Payer payer = new Payer();
            payer.setOpenid(openId);
            request.setPayer(payer);
            // 调用微信sdk接口,生成预支付交易单
            PrepayWithRequestPaymentResponse response = service.prepayWithRequestPayment(request);
//            Signer signer = config.createSigner();
//            long timestamp = Instant.now().getEpochSecond();
//            vo.setTimeStamp(timestamp);
//            String nonceStr = NonceUtil.createNonce(32);
//            vo.setNonceStr(nonceStr);
//            String message =
//                    request.getAppid() + "\n" + timestamp + "\n" + nonceStr + "\n" + response.getPrepayId() + "\n";
//            String sign = signer.sign(message).getSign();
//            vo.setPaySign(sign);
//            vo.setPrepayId(response.getPrepayId());
//            vo.setAppId(wxPayV3Bean.getAppletAppId());
//            vo.setPartnerId(wxPayV3Bean.getMchId());
            log.info("微信支付请求返回:{}",JSONUtil.toJsonStr(response));
            return Result.success(response);
        } catch (ServiceException e) {
            log.info("微信支付请求返回异常:{}",e);
            return Result.fail(JSONUtil.toJsonStr(e.getResponseBody()));
        } catch (Exception e) {
            log.info("微信支付请求返回异常:{}",e);
            return Result.fail(JSONUtil.toJsonStr(e.getMessage()));
        }
    }

    private void toSavePayApplyRecord(PayOrderInfo order, Result result, String payWay) {
        PayApplyRecord payApplyRecord = new PayApplyRecord();
        payApplyRecord.setApplyResult(JSONUtil.toJsonStr(result));
        payApplyRecord.setBusinessNo(order.getOrderNo());
        payApplyRecord.setPayChannel(order.getPayOrderType());
        payApplyRecord.setPayPrice(order.getPrice());
        payApplyRecord.setPayMode(payWay);
        payApplyRecord.setCreateDateTime(LocalDateTime.now());
        payApplyRecord.setCreateUser(AuthUserUtil.getCurrentUserId());
        payApplyRecordService.save(payApplyRecord);
    }

    @Override
    public PayOrderInfo getOrderInfo(String orderNo) {
        Result<PayOrderInfo> orderResult = orderDataClient.getOrderInfoByOrderNo(orderNo);
        if (!orderResult.isSuccess()) {
            throw new BizException("查询订单信息异常");
        }
        PayOrderInfo order = orderResult.getObject();
        if (Objects.isNull(order)) {
            throw new BizException("订单信息不存在");
        }
        return order;
    }

    @Override
    public Result getOrderPayState(AlipayReq param) {
        if (Objects.equals(PayWayEnum.PAY_ALIPAY.getCode(), param.getPayWay())) {
            //查询支付宝支付状态
            AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
            AlipayTradeQueryModel model = new AlipayTradeQueryModel();
            model.setOutTradeNo(param.getOrderNo());
            request.setBizModel(model);
            try {
                AlipayTradeQueryResponse response = alipayClient.execute(request);
                log.info("订单号:{},支付订单状态结果:{}", JSONUtil.toJsonStr(param.getOrderNo()), JSONUtil.toJsonStr(response));
                if (response.getTradeStatus().equals(AliPayUtil.TRADE_SUCCESS)) {
                    return Result.success(JSONUtil.parseObj(response.getBody()));
                }
                return Result.fail("订单支付失败");
            } catch (AlipayApiException e) {
                log.error("获取支付订单支付状态失败:{}", e);
                return Result.fail(e.getErrMsg());
            }
        }

        if (Objects.equals(PayWayEnum.PAY_WECHAT.getCode(), param.getPayWay())
                || Objects.equals(PayWayEnum.PAY_WECHAT_APPLET.getCode(), param.getPayWay())) {
            AppService service = new AppService.Builder().config(config).build();
            QueryOrderByOutTradeNoRequest request = new QueryOrderByOutTradeNoRequest();
            request.setOutTradeNo(param.getOrderNo());
            request.setMchid(wxPayV3Bean.getMchId());
            Transaction transaction = null;
            try {
                transaction = service.queryOrderByOutTradeNo(request);
                log.info("微信订单支付状态响应结果:{}", JSONUtil.toJsonStr(transaction));
                if (transaction.getTradeState().equals(Transaction.TradeStateEnum.SUCCESS)) {
                    return Result.success(JSONUtil.parse(transaction));
                }
            } catch (ServiceException e) {
                log.error("获取支付订单支付状态异常:{}", e);
                return Result.fail(e.getErrorMessage());
            }

            return Result.fail("订单支付失败");
        }

        return Result.fail();
    }

    /**
     * 订单退款
     *
     * @Param: [cn.gpets.cloud.payment.clent.domain.req.RefundOrderReq]
     * @return: cn.aimex.cloud.framework.core.domain.Result
     * @Author: FJT
     * @Date: 2023/11/7
     */
    @Override
    public Result refundOrder(RefundOrderReq req) {
        log.info("订单退款入参:{}", JSONUtil.toJsonStr(req));
        String refundNo = req.getRefundNo();
        //查询是否成功退款过
        PayRefundRecord payRefundRecordBuild = PayRefundRecord.builder().refundNo(refundNo).deleted(Boolean.FALSE).build();
        PayRefundRecord payRefundRecord = payRefundRecordService.getOne(new QueryWrapper<>(payRefundRecordBuild));
        if (Objects.isNull(payRefundRecord)) {
            log.error("用户没有退款记录,无法退款,退款单号:{}",req.getRefundNo());
            throw new BizException("用户没有退款记录,无法退款");
        }
        if (payRefundRecord.getRefundSuccess()) {
            log.error("该商品已退款,请勿重复退款,退款单号:{}",req.getRefundNo());
            throw new BizException("该商品已退款,请勿重复退款");
        }
        PayOrderInfo orderInfo = this.getOrderInfo(payRefundRecord.getRefundBusinessNo());
        Result<OrderProductVo> result = orderDataClient.getOrderProductInfo(payRefundRecord.getOrderProductId(), orderInfo.getPayOrderType());
        if (!result.isSuccess()) {
            throw new BizException("查询商品行信息接口异常");
        }
        OrderProductVo productVo = result.getObject();
        //查询支付申请记录,查看该笔是否成功支付过
        PayBackRecord payBackRecord = payBackRecordService.getOne(new QueryWrapper<>(PayBackRecord.builder().orderNo(payRefundRecord.getRefundBusinessNo()).deleted(Boolean.FALSE).build()));
        if (Objects.isNull(payBackRecord)) {
            log.error("订单未支付过,无法退款,退款单号:{}",req.getRefundNo());
            throw new BizException("订单未支付过,无法退款");
        }
        //同一时刻对同一个商品只能退一次
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append(RedisKeyContant.LOCK_REFUND_ORDER).append(refundNo);
        String lockKey = stringBuffer.toString();
        RLock rLock = redissonClient.getLock(lockKey);
        boolean lockResult = rLock.tryLock();
        try {
            if (lockResult) {
                payRefundRecordBuild.setRefundNo(refundNo);
                BigDecimal price = productVo.getPrice();
                if (Objects.nonNull(req.getRefundPrice()) && price.compareTo(req.getRefundPrice()) >= 0) {
                    //如果传过来的退款金额不为空,并且小于原商品行的支付金额,则使用传递的退款金额
                    price = req.getRefundPrice();
                }
                if (Objects.equals(PayWayEnum.PAY_ALIPAY.getPayWay(), payBackRecord.getPayWay())) {
                    //原使用支付宝进行支付的,使用支付宝进行退款
                    AlipayTradeRefundResponse refundResult = this.doAlipayRefund(payRefundRecord.getRefundBusinessNo(), price, payRefundRecord.getRefundReason(),refundNo);
                    log.info("退款单号:{},支付宝退款响应结果:{}", refundNo, JSONUtil.toJsonStr(refundResult));
                    if (refundResult.isSuccess()&&refundResult.getFundChange().equals(AliPayUtil.CHANGE_STATE_YES)) {
                        //更新退款申请表的退款状态
                        payRefundRecord.setRefundSuccess(Boolean.TRUE);
                        payRefundRecord.setUpdateDateTime(LocalDateTime.now());
                        payRefundRecord.setTradeNo(refundResult.getTradeNo());
                        payRefundRecord.setRefundDetail(JSONUtil.toJsonStr(refundResult));
                        payRefundRecordService.updateById(payRefundRecord);
                        //更新订单退款状态
                        UpdateOrderRefundReq updateOrderRefundReq = new UpdateOrderRefundReq();
                        updateOrderRefundReq.setOrderNo(orderInfo.getOrderNo());
                        updateOrderRefundReq.setOrderProductId(payRefundRecord.getOrderProductId());
                        updateOrderRefundReq.setOrderProductState(payRefundRecord.getOrderProductState());
                        updateOrderRefundReq.setPayOrderType(orderInfo.getPayOrderType());
                        if(Objects.equals(PayOrderTypeEnum.PET_ALL_PAY.getType(),orderInfo.getPayOrderType())){
                            updateOrderRefundReq.setRefundOrderState(PetOrderStateEnum.STATE_7.getTagId());
                        }
                        StringBuffer stringBuffer1 = new StringBuffer();
                        updateOrderRefundReq.setRefundMsg(stringBuffer1.append(req.getRefundMsg()).append(":").append(OrderRemarkEnum.BUYER_HAD_REFUND.getMsg()).toString());
                        orderDataClient.updateOrderRefundState(updateOrderRefundReq);
                        //发送钱包通知消息
                        payCommonService.doSendRefundMag(MessageContentEnum.REFUND_TO_ACCOUNT,payRefundRecord.getRefundNo(),price,orderInfo.getUserId(),payRefundRecord.getRefundReason());
                        //给python端发送退款到账消息
                        payCommonService.doSendRefundResult(refundNo,Boolean.TRUE,null);
                        return Result.success();
                    }
                    return Result.fail(refundResult.getSubMsg());
                }
                if (Objects.equals(PayWayEnum.PAY_WECHAT.getPayWay(), payBackRecord.getPayWay())
                        || Objects.equals(PayWayEnum.PAY_WECHAT_APPLET.getPayWay(), payBackRecord.getPayWay())) {
                    //使用微信退款
                    Refund refund = this.doWechatRefund(price, refundNo, payBackRecord.getPayPrice(),payBackRecord.getOrderNo(),req.getRefundMsg());
                    log.info("退款单号:{},微信退款响应结果:{}", refundNo, JSONUtil.toJsonStr(refund));
                    if (refund.getStatus().equals(Status.SUCCESS)||refund.getStatus().equals(Status.PROCESSING)) {
                        //更新订单退款状态
                        UpdateOrderRefundReq updateOrderRefundReq = new UpdateOrderRefundReq();
                        updateOrderRefundReq.setOrderNo(orderInfo.getOrderNo());
                        updateOrderRefundReq.setOrderProductId(payRefundRecord.getOrderProductId());
                        updateOrderRefundReq.setOrderProductState(payRefundRecord.getOrderProductState());
                        updateOrderRefundReq.setPayOrderType(orderInfo.getPayOrderType());
                        if(Objects.equals(PayOrderTypeEnum.PET_ALL_PAY.getType(),orderInfo.getPayOrderType())){
                            updateOrderRefundReq.setRefundOrderState(PetOrderStateEnum.STATE_6.getTagId());
                        }
                        updateOrderRefundReq.setRefundMsg(OrderRemarkEnum.BUYER_APPLY_REFUND.getMsg());
                        orderDataClient.updateOrderRefundState(updateOrderRefundReq);
                        //发送钱包通知消息
                        payCommonService.doSendRefundMag(MessageContentEnum.RETURN_HAD_ACCEPTANCE,payRefundRecord.getRefundNo(),price,orderInfo.getUserId(),payRefundRecord.getRefundReason());
                        return Result.success();
                    }
                }
            } else {
                return Result.fail("请勿重复退款");
            }
        } catch (BizException e) {
            log.info("退款失败:{}", e.getMessage());
            return Result.fail(e.getMessage());
        } finally {
            if (lockResult) {
                rLock.unlock();
            }
        }
        return Result.fail();
    }

    /**
     * 微信或微信小程序退款
     *
     * @Param: [java.lang.String, java.math.BigDecimal, java.lang.String]
     * @return: void
     * @Author: FJT
     * @Date: 2023/11/9
     */
    private Refund doWechatRefund(BigDecimal price, String refundNo, BigDecimal payPrice, String orderNo, String refundMsg) {
        Refund refund = null;
        try {
            // 构建退款service
            RefundService service = new RefundService.Builder().config(config).build();
            // request.setXxx(val)设置所需参数,具体参数可见Request定义
            //构建退款请求
            CreateRequest request = new CreateRequest();
            //构建订单金额信息
            AmountReq amountReq = new AmountReq();
            //退款金额
            amountReq.setRefund(NumberUtil.mul(price, 100).longValue());
            //原订单金额
            amountReq.setTotal(NumberUtil.mul(payPrice, 100).longValue());
            //货币类型(默认人民币)
            amountReq.setCurrency("CNY");
            request.setAmount(amountReq);
            request.setOutTradeNo(orderNo);
            request.setReason(refundMsg);
            //商户退款单号
            request.setOutRefundNo(refundNo);
            //退款通知回调地址
            request.setNotifyUrl(wxPayV3Bean.getRefundNotifyUrl());
            // 调用退款方法,得到应答
            // 调用微信sdk接口
            refund = service.create(request);
            //接收退款返回参数
            return refund;
        } catch (ServiceException e) {
            log.error("退款异常:{}", e);
            throw new BizException(e.getErrorMessage());
        } catch (Exception e) {
            log.error("退款异常:{}", e);
            throw new BizException(e.getMessage());
        }
    }

    /**
     * 支付宝退款
     *
     * @Param: [java.lang.String, java.math.BigDecimal, java.lang.String]
     * @return: void
     * @Author: FJT
     * @Date: 2023/11/7
     */
    private AlipayTradeRefundResponse doAlipayRefund(String refundBusinessNo, BigDecimal sumPrice, String refundReason, String refundNo) {

        AlipayTradeRefundResponse response = null;
        try {
            AlipayTradeRefundRequest alipayTradeCloseRequest = new AlipayTradeRefundRequest();
            //请求参数集合对象,除了公共参数之外,所有参数都可通过此对象传递
            AlipayTradeRefundModel alipayTradeRefundModel = new AlipayTradeRefundModel();
            //退款的订单号,传入生成支付订单时的订单号即可
            alipayTradeRefundModel.setOutTradeNo(refundBusinessNo);
            //退款金额
            alipayTradeRefundModel.setRefundAmount(sumPrice.toString());
            //退款的原因
            alipayTradeRefundModel.setRefundReason(refundReason);
            alipayTradeRefundModel.setOutRequestNo(refundNo);
            alipayTradeCloseRequest.setBizModel(alipayTradeRefundModel);

            //退款的执行流程与支付不太一样,支付时成功之后,需要通知回调接口,而退款则不需要,只需判断响应			参数 refundResponse.getFundChange().equals("Y") 判断是否发生了资金变化, equals("Y")表示资金发生了变化,退款成功
            response = alipayClient.execute(alipayTradeCloseRequest);
            return response;
        } catch (AlipayApiException e) {
            log.error("支付宝退款失败:{}", e);
            return response;
        }
    }

    /**
     * 支付宝app支付
     *
     * @Param: [java.lang.String, java.lang.String, java.math.BigDecimal]
     * @return: cn.aimex.cloud.framework.core.domain.Result
     * @Author: FJT
     * @Date: 2023/11/7
     */
    private Result doAlipayApp(String orderNumber, String msg, BigDecimal price) {
        //实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.app.pay
        AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();

        //SDK已经封装掉了公共参数,这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
        AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();

        model.setSubject(msg);
        model.setOutTradeNo(orderNumber);
        model.setTimeoutExpress(AliPayUtil.TIME_OUT_EXPRESS);
        model.setTotalAmount(price.toString());
        request.setBizModel(model);
        //异步通知地址
        request.setNotifyUrl(aliPayClientConfig.getNotifyUrl());
        try {
            //这里和普通的接口调用不同,使用的是sdkExecute
            AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
            if (!response.isSuccess()) {
                log.error("接口调用错误:{}", response.getBody());
                return Result.fail(response.getBody());
            }
            //就是orderString 可以直接给客户端请求,无需再做处理。
            log.info("支付请求返回:{}",response.getBody());
            return Result.success().setData(Collections.singletonList(response.getBody()));
        } catch (AlipayApiException e) {
            log.error("生成支付订单错误:", e);
            return Result.fail(e.getErrMsg());
        }
    }

}

支付宝支付回调控制层

public class AlipayCallBackController {
    private final PayCallBackServiceImpl alipayCallBackService;


    /**
     *  支付宝支付回调
     *
     */
    @PostMapping("/v1/callBack/result")
    public Result<Boolean> callBack(@RequestParam Map<String,String> params) {
        try {
            return alipayCallBackService.alipayCallBack(params);
        } catch (Exception e) {
            return Result.error(e.getMessage());
        }
    }

 支付回调业务处理

 /***
     * 支付宝支付回调
     * @Param: [java.util.Map<java.lang.String, java.lang.String>]
     * @return: cn.aimex.cloud.framework.core.domain.Result<java.lang.Boolean>
     * @Author: FJT
     * @Date: 2023/11/6
     */
    @Override
    public Result alipayCallBack(Map<String, String> params) {
        log.info("支付宝支付回调,入参:{}", JSONUtil.toJsonStr(params));
        try {
            //验签
            boolean signVerified = AlipaySignature.rsaCheckV1(params,
                    aliPayClientConfig.getPublicKey(),
                    AlipayConstants.CHARSET_UTF8,
                    AlipayConstants.SIGN_TYPE_RSA2); //调用SDK验证签名

            //验签成功
            if (signVerified) {
                log.info("验签成功");
                //1.商家需要验证该通知数据中的 out_trade_no 是否为商家系统中创建的订单号
                String orderNo = params.get("out_trade_no");
                Result<PayOrderInfo> orderResult = orderDataClient.getOrderInfoByOrderNo(orderNo);
                if (!orderResult.isSuccess()) {
                    throw new BizException("查询订单信息接口失败");
                }
                PayOrderInfo order = orderResult.getObject();
                if (Objects.isNull(order)) {
                    throw new BizException("订单不存在");
                }

                //2.判断 total_amount 是否确实为该订单的实际金额(即商家订单创建时的金额)
                String totalAmount = params.get("total_amount");
                if (!totalAmount.equals(order.getPrice().toString())) {
                    log.error("金额校验失败");
                    return Result.fail("金额校验失败");
                }

                //3.验证 app_id 是否为该商家本身
                String appId = params.get("app_id");
                if (!aliPayClientConfig.getAppId().equals(appId)) {
                    log.error("应用APPID校验失败");
                    return Result.fail("应用APPID校验失败");
                }
                //4.在支付宝的业务通知中,只有交易通知状态为 TRADE_SUCCESS 或 TRADE_FINISHED 时,支付宝才会认定为买家付款成功。,
                String tradeStatus = params.get("trade_status");
                String payApplyNo = params.get("trade_no");
                //保存回调记录
                this.toSavePayBackRecord(orderNo, payApplyNo, order.getPayOrderType(), PayWayEnum.PAY_ALIPAY.getPayWay(), order.getPrice(),JSONUtil.toJsonStr(params));
                if (!AliPayUtil.TRADE_SUCCESS.equals(tradeStatus)) {
                    log.error("支付未成功");
                    return Result.fail("支付未成功");
                }
                //更新支付状态
                UpdateOrderPayStateReq req = new UpdateOrderPayStateReq();
                req.setOrderNo(orderNo);
                req.setPayOrderType(order.getPayOrderType());
                req.setPayWay(PayWayEnum.PAY_ALIPAY.getPayWay());
                req.setPayApplyNo(payApplyNo);
                orderDataClient.updateOrderPayState(req);
                //发送钱包通知消息
                payCommonService.doSendPayMag(MessageContentEnum.PAY_SUCCESS,payApplyNo,order.getPrice(),order.getUserId());
                return Result.success();
            } else {
                log.error("验签失败");
                return Result.fail("验签失败");
            }
        } catch (AlipayApiException e) {
            log.error("验签异常:{}", e);
            return Result.fail(e.getErrMsg());
        }
    }

对象类信息

1.支付请求类

@Data
public class AlipayReq {

    /**订单编号:聚合支付传聚合支付单号,子单支付传子单号**/
    @NotNull(message = "订单编号不能为空")
    private String orderNo;

    /**支付方式1:支付宝支付,2:微信支付,3:微信小程序支付**/
    private Integer payWay;


}

2.退款请求类

@Data
public class RefundOrderReq {

    /**退款单号**/
    @NotNull(message = "退款单号不能为空")
    private String refundNo;

    /**加密字符串**/
    @NotNull(message = "加密字符串不能为空")
    private String sign;


    /**实际退还金额,如果该字段为空,则使用商品行金额,该金额不能大于商品行金额**/
    private BigDecimal refundPrice;

    /**退款原因**/
    private String refundMsg;


}

部分工具类

@Slf4j
public class AliPayUtil {

    public static String TIME_OUT_EXPRESS = "30m";
    public static String ALIPAY_PUBLIC_CER_PATH = "";

    public static String SERVICE_URL="https://openapi.alipay.com/gateway.do";

    public static String CHARSET = "utf-8";

    public static String CHANGE_STATE_YES = "Y";



    public static String SIGN_TYPE = "RSA2";
    public static String TRADE_SUCCESS = "TRADE_SUCCESS";
    public static String TRADE_FINISHED = "TRADE_FINISHED";
}

好了,今天分享就到这里,如果有什么问题的话,欢迎大家留言,探讨一下。后续将微信的支付退款实现过程也发布一下。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值