淘东电商项目(62) -聚合支付(基于模板方法设计模式管理支付回调-支付宝)

引言

本文代码已提交至Github(版本号:65e4ac8468af8af00546db391e158c8e611d9ab9),有兴趣的同学可以下载来看看:https://github.com/ylw-github/taodong-shop

阅读本文前,有兴趣的同学可以参考我之前写的聚合支付的文章:

目前「淘东电商项目」的聚合支付模块,已经完成了银联支付以及支付宝的集成,而且实现了基于"模板设计模式"的方式来管理银联支付结果回调接口。上一篇博客讲的只是“银联支付”的回调管理,本文主要讲的是“支付宝”支付结果回调接口管理。由于代码跟上一篇博客类似,所以直接上源码并测试。

本文目录结构:
l____引言
l____ 1. 支付宝支付结果核心源码
l____ 2. 测试

1. 支付宝支付结果核心源码

①模板实现源码:

/**
 * description: 阿里支付回调模版实现
 * create by: YangLinWei
 * create time: 2020/5/18 10:41 上午
 */
@Component
public class AliPayCallbackTemplate extends AbstractPayCallbackTemplate {

    @Autowired
    private PaymentTransactionMapper paymentTransactionMapper;

    @Override
    public Map<String, String> verifySignature(HttpServletRequest request, HttpServletResponse resp) throws UnsupportedEncodingException, AlipayApiException {
        Map<String, String> reqParam = new HashMap<>();
        //获取支付宝POST过来反馈信息
        Map<String, String> params = new HashMap<String, String>();
        Map<String, String[]> requestParams = request.getParameterMap();
        for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
            //乱码解决,这段代码在出现乱码时使用
            valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
            params.put(name, valueStr);
        }

        boolean signVerified = AlipaySignature.rsaCheckV1(params, AlipayConfig.alipay_public_key, AlipayConfig.charset, AlipayConfig.sign_type); //调用SDK验证签名

        //——请在这里编写您的程序(以下代码仅作参考)——

	/* 实际验证过程建议商户务必添加以下校验:
	1、需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号,
	2、判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额),
	3、校验通知中的seller_id(或者seller_email) 是否为out_trade_no这笔单据的对应的操作方(有的时候,一个商户可能有多个seller_id/seller_email)
	4、验证app_id是否为该商户本身。
	*/
        if (signVerified) {//验证成功
            //商户订单号
            String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"), "UTF-8");

            //支付宝交易号
            String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"), "UTF-8");

            //交易状态
            String trade_status = new String(request.getParameter("trade_status").getBytes("ISO-8859-1"), "UTF-8");

            reqParam.put("out_trade_no", out_trade_no);
            reqParam.put("trade_no", trade_no);
            reqParam.put("trade_status", trade_status);

            reqParam.put(PayConstant.RESULT_NAME, PayConstant.RESULT_PAYCODE_200);

        } else {//验证失败
            reqParam.put(PayConstant.RESULT_NAME, PayConstant.RESULT_PAYCODE_201);

            //调试用,写文本函数记录程序运行情况是否正常
            //String sWord = AlipaySignature.getSignCheckContentV1(params);
            //AlipayConfig.logResult(sWord);
        }
        return reqParam;
    }

    @Override
    public String syncService(HttpServletRequest request, HttpServletResponse resp) throws UnsupportedEncodingException, AlipayApiException {
        //获取支付宝GET过来反馈信息
        Map<String, String> params = new HashMap<String, String>();
        Map<String, String[]> requestParams = request.getParameterMap();
        for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
            //乱码解决,这段代码在出现乱码时使用
            valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
            params.put(name, valueStr);
        }

        boolean signVerified = AlipaySignature.rsaCheckV1(params, AlipayConfig.alipay_public_key, AlipayConfig.charset, AlipayConfig.sign_type); //调用SDK验证签名

        //——请在这里编写您的程序(以下代码仅作参考)——
        if (signVerified) {
            //商户订单号
            String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"), "UTF-8");

            //支付宝交易号
            String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"), "UTF-8");

            //付款金额
            String total_amount = new String(request.getParameter("total_amount").getBytes("ISO-8859-1"), "UTF-8");

            return "trade_no:" + trade_no + "<br/>out_trade_no:" + out_trade_no + "<br/>total_amount:" + total_amount;
        }
        return "验签失败";
    }

    @Override
    public String asyncService(Map<String, String> verifySignature) {

        String out_trade_no = verifySignature.get("out_trade_no");
        String trade_no = verifySignature.get("trade_no");
        String trade_status = verifySignature.get("trade_status");

        if (trade_status.equals("TRADE_FINISHED")) {
            //判断该笔订单是否在商户网站中已经做过处理
            //如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
            //如果有做过处理,不执行商户的业务程序

            //注意:
            //退款日期超过可退款期限后(如三个月可退款),支付宝系统发送该交易状态通知

            return failResult();
        } else if (trade_status.equals("TRADE_SUCCESS")) {
            //判断该笔订单是否在商户网站中已经做过处理
            //如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
            //如果有做过处理,不执行商户的业务程序

            //注意:
            //付款完成后,支付宝系统发送该交易状态通知
            // 根据日志 手动补偿 使用支付id调用第三方支付接口查询
            PaymentTransactionEntity paymentTransaction = paymentTransactionMapper.selectByPaymentId(out_trade_no);
            if (paymentTransaction.getPaymentStatus().equals(PayConstant.PAY_STATUS_SUCCESS)) {
                // 网络重试中,之前已经支付过
                return successResult();
            }
            // 2.将状态改为已经支付成功
            paymentTransactionMapper.updatePaymentStatus(PayConstant.PAY_STATUS_SUCCESS + "", out_trade_no);
            // 3.调用积分服务接口增加积分(处理幂等性问题)
            return successResult();
        }

        return failResult();

    }

    @Override
    public String failResult() {
        return PayConstant.ALI_RESULT_SUCCESS;
    }

    @Override
    public String successResult() {
        return PayConstant.ALI_RESULT_FAIL;
    }
}

②请求接口:

/**
 * description: 阿里同步回调接口执行代码
 * create by: YangLinWei
 * create time: 2020/5/18 10:08 上午
 */
@RequestMapping("/aliPaySynCallback")
public String aliPaySynCallback(HttpServletRequest req, HttpServletResponse resp) throws UnsupportedEncodingException, AlipayApiException {
	AbstractPayCallbackTemplate abstractPayCallbackTemplate = TemplateFactory
			.getPayCallbackTemplate(ALIPAYCALLBACK_TEMPLATE);
	return abstractPayCallbackTemplate.syncService(req, resp);
}

/**
 * description: 阿里异步回调接口执行代码
 * create by: YangLinWei
 * create time: 2020/5/18 10:08 上午
 */
@RequestMapping("/aliPayAsynCallback")
public String aliPayAsynCallback(HttpServletRequest req, HttpServletResponse resp) throws UnsupportedEncodingException, AlipayApiException {
	AbstractPayCallbackTemplate abstractPayCallbackTemplate = TemplateFactory
			.getPayCallbackTemplate(ALIPAYCALLBACK_TEMPLATE);
	return abstractPayCallbackTemplate.asyncCallBack(req, resp);
}

2. 测试

首先启动项目(Eureka注册中心、单点服务中心、会员服务、支付服务、支付门户):
在这里插入图片描述

①配置银联支付的同步和异步回调地址,其SQL语句如下:

INSERT INTO `taodong-pay`.`payment_channel`(`ID`, `CHANNEL_NAME`, `CHANNEL_ID`, `MERCHANT_ID`, `SYNC_URL`, `ASYN_URL`, `PUBLIC_KEY`, `PRIVATE_KEY`, `CHANNEL_STATE`, `REVISION`, `CREATED_BY`, `CREATED_TIME`, `UPDATED_BY`, `UPDATED_TIME`, `CLASS_ADDRES`) VALUES (2, '支付宝', 'ali_pay', '777666655522521', 'http://localhost:8600/aliPaySynCallback', 'http://7z4nwp.natappfree.cc/aliPayAsynCallback', NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, 'com.ylw.service.pay.strategy.impl.AliPayStrategy');

②浏览器模拟提交订单:请求地址http://localhost:8600/cratePayToken?payAmount=99999&orderId=20200513141452&userId=27&productName=广东米酒
在这里插入图片描述
数据库订单状态为未支付:
在这里插入图片描述
③模拟使用银联支付,浏览器请求:http://localhost:8079/pay?payToken=pay_4366baebae434bc0af4e440fb8c89b64
在这里插入图片描述
④.点击支付宝支付,按照提示一步一步支付至完成(使用测试账号支付,账号:[email protected],密码和支付密码均为:111111):
在这里插入图片描述
支付成功:
在这里插入图片描述
可以看到订单状态为已支付:
在这里插入图片描述
可以看到同步回调也是成功的:
在这里插入图片描述

本文完!

猜你喜欢

转载自blog.csdn.net/qq_20042935/article/details/106188258