尚品汇-支付宝支付同步异步回调实现(四十七)

目录:

(1)订单支付码有效时间

(2)支付后回调—同步回调

(3)支付宝回调—异步回调

(1)订单支付码有效时间

(2)支付后回调—同步回调

 

 

static修饰,不能通过Vuale注解获取配置文件的值,可以通过下面的方法进行获取值 

 

实现类放开同步回调地址 

 

 

成功页面:

 修改配置类:

控制器AlipayController

/**
 * 支付宝回调
 * @return
 */
@RequestMapping("callback/return")
public String callBack() {
    // 同步回调给用户展示信息
    return "redirect:" + AlipayConfig.return_order_url;
}

在web-all 项目中添加对应的返回控制器

/**
 * 支付成功页
 * @return
 */
@GetMapping("pay/success.html")
public String success() {
    return "payment/success";
}

 

最终跳转到这个页面:

 

(3)支付宝回调—异步回调

 

 

 

 

 

 

... 

 

 

 

 

异步回调有两个重要的职责:

确认并记录用户已付款通知电商模块。新版本的支付接口已经取消了同步回调的支付结果传递。所以用户付款成功与否全看异步回调。

接收到回调要做的事情:

  1. 验证回调信息的真伪
  2. 验证用户付款的成功与否
  3. 把新的支付状态写入支付信息表{paymentInfo}中。
  4. 通知电商
  5. 给支付宝返回回执。

 

 

应用公网暴露 

支付宝异步回调,需要我们的应用在公网上,怎么办呢?可以使用一个软件把我们的应用跟公网绑定,相当于我们的应用就在公网了

 

 

 

authttoken是申请的

双击启动:就实现了我们的应用进行了公网地址的绑定

 

这样就接受到了异步回调的数据了:

 

配置类: 

 

 

 

 

控制器AlipayController

@Autowired
private PaymentService paymentService;
@PostMapping("/callback/notify")
@ResponseBody
public String callbackNotify(@RequestParam Map<String, String> paramsMap){
    System.out.println("你回来了.....");
    // Map<String, String> paramsMap = ... // 将异步通知中收到的所有参数都存放到map中


    //返回的异步结果进行验签
    boolean signVerified = false; //调用SDK验证签名
    try {
        //参数阿里公钥、字符编码、签名算法
        signVerified = AlipaySignature.rsaCheckV1(paramsMap, AlipayConfig.alipay_public_key, AlipayConfig.charset, AlipayConfig.sign_type);
    } catch (AlipayApiException e) {
        e.printStackTrace();
    }
    //  获取异步通知的参数中的订单号!
    String outTradeNo = paramsMap.get("out_trade_no");
    //  获取异步通知的参数中的订单总金额!
    String totalAmount = paramsMap.get("total_amount");
    //  获取异步通知的参数中的appId!
    String appId = paramsMap.get("app_id");
    //  获取异步通知的参数中的交易状态!
    String tradeStatus = paramsMap.get("trade_status");
    //  根据outTradeNo 查询数据!
    PaymentInfo paymentinfo = this.paymentService.getPaymentInfo(outTradeNo, PaymentType.ALIPAY.name());
    //  保证异步通知的幂等性!notify_id
    String notifyId = paramsMap.get("notify_id");

    //  true:
    if(signVerified){
        // TODO 验签成功后,按照支付结果异步通知中的描述,对支付结果中的业务内容进行二次校验,校验成功后在response中返回success并继续商户自身业务处理,校验失败返回failure
        if (paymentinfo==null || new BigDecimal("0.01").compareTo(new BigDecimal(totalAmount))!=0
            || AlipayConfig.app_id.equals(appId)){
            return "failure";
        }
        //  放入redis! setnx:当 key 不存在的时候生效!
        Boolean flag = this.redisTemplate.opsForValue().setIfAbsent(notifyId, notifyId, 1462, TimeUnit.MINUTES);
        //  说明已经处理过了!
        if (!flag){
            return "failure";
        }
        if ("TRADE_SUCCESS".equals(tradeStatus) || "TRADE_FINISHED".equals(tradeStatus)){
            //  修改交易记录状态!再订单状态!
            this.paymentService.paySuccess(outTradeNo,PaymentType.ALIPAY.name(),paramsMap);
            //  this.paymentService.paySuccess(paymentinfo.getId(),paramsMap);
            return "success";
        }
    }else{
        // TODO 验签失败则记录异常日志,并在response中返回failure.
        return "failure";
    }
    return "failure";
}

幂等性:多次操作跟一次操作是一样的

这里更上面返回的不一样,返回sucess,支付宝就不会再发送了,如果返回faild支付宝会间隔一段的时间持续发送,返回啥都一样功能都能够实现 

 

为了保证更新支付状态时出现异常,前面存不进去了,出现异常删掉前面Redis中的key 

 

 

接口PaymentService

/**
 * 获取paymentInfo 对象
 * @param outTradeNo
 * @param name
 * @return
 */
PaymentInfo getPaymentInfo(String outTradeNo, String name);

/**
 * 支付成功更新交易记录方法
 * @param outTradeNo
 * @param name
 * @param paramMap
 */
void paySuccess(String outTradeNo, String name, Map<String, String> paramMap);

/**
 * 根据outTradeNo 支付方式name 更新数据
 * @param outTradeNo
 * @param name
 * @param paymentInfo
 */
void updatePaymentInfo(String outTradeNo, String name, PaymentInfo paymentInfo);

实现类

@Override
public PaymentInfo getPaymentInfo(String outTradeNo, String name) {
    //  select * from payment_info where out_trade_no = ? and payment_type = ?
    QueryWrapper<PaymentInfo> paymentInfoQueryWrapper = new QueryWrapper<>();
    paymentInfoQueryWrapper.eq("out_trade_no",outTradeNo);
    paymentInfoQueryWrapper.eq("payment_type",name);
    return paymentInfoMapper.selectOne(paymentInfoQueryWrapper);
}

@Override
public void paySuccess(String outTradeNo, String paymentType, Map<String, String> paramsMap) {

    //  根据outTradeNo,paymentType 查询
    PaymentInfo paymentInfoQuery = this.getPaymentInfo(outTradeNo, paymentType);
    if (paymentInfoQuery==null){
        return;
    }
    
    try {
        //  改造一下更新的方法!
        PaymentInfo paymentInfo = new PaymentInfo();
       //回调时间
        paymentInfo.setCallbackTime(new Date());
        //支付状态
        paymentInfo.setPaymentStatus(PaymentStatus.PAID.name());
        /回调内容
        paymentInfo.setCallbackContent(paramsMap.toString());
        //交易编号
        paymentInfo.setTradeNo(paramsMap.get("trade_no"));
        //  查询条件也可以作为更新条件!
        this.updatePaymentInfo(outTradeNo, paymentType, paymentInfo);
    } catch (Exception e) {
        //  删除key
        this.redisTemplate.delete(paramsMap.get("notify_id"));
        e.printStackTrace();
    }

}

//  更新交易状态记录!
public void updatePaymentInfo(String outTradeNo, String name, PaymentInfo paymentInfo) {
    QueryWrapper<PaymentInfo> paymentInfoQueryWrapper = new QueryWrapper<>();
    paymentInfoQueryWrapper.eq("out_trade_no",outTradeNo);
    paymentInfoQueryWrapper.eq("payment_type",name);
    paymentInfoMapper.update(paymentInfo,paymentInfoQueryWrapper);
}

 支付成功后数据库的状态会更改

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

喵俺第一专栏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值