spring boot整合支付宝支付(沙箱环境)

spring boot整合支付宝支付(沙盒环境)

1.1、注册支付宝开放平台账号

https://openhome.alipay.com/platform/home.htm

1.2进入管理中心

spring boot整合支付宝支付(沙箱环境)

1.3进入研发服务

spring boot整合支付宝支付(沙箱环境)

1.4下载支付宝支付SDK

https://opendocs.alipay.com/open/54/106682(提供参考)

1.5在项目中新建一个配置类

AlipayConfig 配置类代码示例

package com.alipay.config;
public class AlipayConfig {
	//在这里填入沙箱应用中的信息
	// 商户appid
	public static String APPID = "";

	// 私钥 pkcs8格式的
	public static String RSA_PRIVATE_KEY = "";

	// 服务器异步通知页面路径 需http://或者https://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
	public static String notify_url = "http://商户网关地址/alipay.trade.wap.pay-JAVA-UTF-8/notify_url.jsp";

	// 页面跳转同步通知页面路径 需http://或者https://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问 商户可以自定义同步跳转地址
	public static String return_url = "http://商户网关地址/alipay.trade.wap.pay-JAVA-UTF-8/return_url.jsp";

	// 请求网关地址
	public static String URL = "https://openapi.alipay.com/gateway.do";

	// 编码
	public static String CHARSET = "UTF-8";

	// 返回格式
	public static String FORMAT = "json";

	// 支付宝公钥
	public static String ALIPAY_PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjrEVFMOSiNJXaRNKicQuQdsREraftDA9Tua3WNZwcpeXeh8Wrt+V9JilLqSa7N7sVqwpvv8zWChgXhX/A96hEg97Oxe6GKUmzaZRNh0cZZ88vpkn5tlgL4mH/dhSr3Ip00kvM4rHq9PwuT4k7z1DpZAf1eghK8Q5BgxL88d0X07m9X96Ijd0yMkXArzD7jg+noqfbztEKoH3kPMRJC2w4ByVdweWUT2PwrlATpZZtYLmtDvUKG/sOkNAIKEMg3Rut1oKWpjyYanzDgS7Cg3awr1KPTl9rHCazk15aNYowmYtVabKwbGVToCAGK+qQ1gT3ELhkGnf3+h53fukNqRH+wIDAQAB";

	// 日志记录目录定义在 logFile 中
	public static String log_path = "/log";

	// RSA2
	public static String SIGNTYPE = "RSA2";

}

notify_url和return_url必须要外网能访问

1.6提交页面

配置类填好之后修改订单提交页面

spring boot整合支付宝支付(沙箱环境)

参数列表:https://opendocs.alipay.com/apis/api_1/alipay.trade.wap.pay

1.7 支付宝支付控制器

//支付
@RequestMapping("/aliPay")
@ResponseBody
public String pay(Pay pay) throws AlipayApiException {
    AlipayConfig alipayConfig = new AlipayConfig();
    //1.封装Rsa签名方式
    AlipayClient alipayClient = new DefaultAlipayClient(
            alipayConfig.URL,
            alipayConfig.APPID,
            alipayConfig.RSA_PRIVATE_KEY,
            alipayConfig.FORMAT,
            alipayConfig.CHARSET,
            alipayConfig.ALIPAY_PUBLIC_KEY,
            alipayConfig.SIGNTYPE);
    //2.创建Request请求
    AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest();
    //3.封装传入参数
    AlipayTradeWapPayModel model = new AlipayTradeWapPayModel();
    model.setOutTradeNo(pay.getOut_trade_no());//商品Id
    model.setSubject(pay.getSubject());//商品名称
    model.setBody(pay.getBody());//商品描述
    model.setProductCode(pay.getProduct_code());//商品码
    model.setTimeoutExpress(pay.getTimeout_express());//支付超时时间
    model.setTotalAmount(pay.getTotal_amount());//商品金额
    request.setBizModel(model);
    //设置异步回调地址
    request.setNotifyUrl(AlipayConfig.notify_url);
    //设置同步回调地址
    request.setReturnUrl(AlipayConfig.return_url);
    String form = alipayClient.pageExecute(request).getBody();
    System.out.println(form);
    //返回请求体
    return form;

到这里就已经可以完成支付宝支付了,在支付完成后,支付宝会发给我们支付完成的通知,包括同步通知(return_url)和异步通知(notify_url),所以我们需要写控制器来接收通知。

1.7通知回调(异步和同步)

日志和线程:

private static Logger logger = LoggerFactory.getLogger(AlipayCallBackController.class);
private ExecutorService executorService = Executors.newFixedThreadPool(20);

1.7.1处理请求体信息

private static Map<String, String> convertRequestParamsToMap(HttpServletRequest request) {
    Map<String, String> retMap = new HashMap<>();
    Set<Map.Entry<String, String[]>> entrySet = request.getParameterMap().entrySet();
    for (Map.Entry<String, String[]> entry : entrySet) {
        String name = entry.getKey();
        String[] values = entry.getValue();
        int valLen = values.length;
        if (valLen == 1) {
            retMap.put(name, values[0]);
        } else if (valLen > 1) {
            StringBuilder stringBuilder = new StringBuilder();
            for (String value : values) {
                stringBuilder.append(",").append(value);
            }
            retMap.put(name, stringBuilder.toString().substring(1));
        } else {
            retMap.put(name, "");
        }
    }
    return retMap;
}

1.7.2JSON字符串的处理

private AlipayNotifyParam buildAliPayNotifyParam(Map<String, String> params) {
    //将json数据转为字符串
    String json = JSON.toJSONString(params);
    //将字符串转为object对象
    return JSON.parseObject(json, AlipayNotifyParam.class);
}

1.7.3检验订单信息是否一致

private void check(Map<String, String> params) throws AlipayApiException {
    String outTradeNo = params.get("out_trade_no");
    //1、商户需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号
    Order order = orderService.findIdByOrderNum(outTradeNo);
    if (order == null) {
        throw new AlipayApiException("out_trade_no错误");
    }

    //2、判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额)
    long total_amount = new BigDecimal(params.get("total_amount")).multiply(new BigDecimal(1)).longValue();
    if (total_amount != order.getOrder_total().longValue()) {
        throw new AlipayApiException("total_amount错误");
    }

    //3、校验通知中的seller_id(或者seller_email)是否为out_trade_no这笔单据的对应的操作方(有的时候,一个商户可能有多个seller_id/seller_email)
    // 第三步可根据实际情况省略

    // 4、验证app_id是否为该商户本身。
    if (!params.get("app_id").equals(AlipayConfig.APPID)) {
        throw new AlipayApiException("app_id不一致");
    }

}

1.7.4调用异步回调

@RequestMapping("/alipay_callback")
@ResponseBody
public String callback(HttpServletRequest request) {
    System.out.println("--------异步调用成功--------");
    Map<String, String> params = convertRequestParamsToMap(request);
    String paramsJson = JSON.toJSONString(params);
    logger.info("支付宝回调,{}", paramsJson);
    try {
        AlipayConfig alipayConfig = new AlipayConfig();
        //支付宝验签
        boolean signVerified = AlipaySignature.rsaCheckV1(params, AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.CHARSET, AlipayConfig.SIGNTYPE);
        if (signVerified) {
            logger.info("支付宝回调签名认证成功");
            //按照支付结果异步通知中描述,对支付结果中的业务内容进行1\2\3\4二次校验,校验成功后在response中返回success,校验失败返回failure
            this.check(params);
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    AlipayNotifyParam param = buildAliPayNotifyParam(params);
                    String trade_status = param.getTradeStatus();
                    //支付成功
                    if (trade_status.equals("TRADE_SUCCESS")) {
                        try {
                            //修改订单状态
                            String out_trade_no = params.get("out_trade_no");
                            orderService.updateOrderStatus(out_trade_no, "1");
                            System.out.println("------订单付款成功------");
                        } catch (Exception e) {
                            logger.error("支付宝回调业务处理报错,params:" + paramsJson, e);
                        }
                    } else {
                        logger.error("没有处理支付宝回调业务,支付宝交易状态:{},params:{}", trade_status, paramsJson);
                    }
                    //订单完成
                    if (trade_status.equals("TRADE_FINISHED")) {
                        try {
                            //修改订单状态
                            String out_trade_no = params.get("out_trade_no");
                            orderService.updateOrderStatus(out_trade_no, "1");
                            System.out.println("------订单已经付款,请勿重复付款------");
                        } catch (Exception e) {
                            logger.error("支付宝回调业务处理报错,params:" + paramsJson, e);
                        }
                    } else {
                        logger.error("没有处理支付宝回调业务,支付宝交易状态:{},params:{}", trade_status, paramsJson);
                    }

                }
            });
            // 如果签名验证正确,立即返回success,后续业务另起线程单独处理
            // 业务处理失败,可查看日志进行补偿,跟支付宝已经没多大关系。
            return "success";
        } else {
            logger.info("支付宝回调签名认证失败,signVerified=false, paramsJson:{}", paramsJson);
            return "failure";
        }
    } catch (AlipayApiException e) {
        logger.error("支付宝回调签名认证失败,paramsJson:{},errorMsg:{}", paramsJson, e.getMessage());
        return "failure";
    }
}

1.7.5调用同步回调

@RequestMapping("/return_callback")
public String returnCallback(HttpServletRequest request, Model model) {
    System.out.println("--------同步调用成功--------");
    OrderInfoDTO orderInfoDTO = new OrderInfoDTO();
    Map<String, String> params = convertRequestParamsToMap(request);
    String paramsJson = JSON.toJSONString(params);
    try {
        AlipayConfig alipayConfig = new AlipayConfig();
        //支付宝验签
        boolean signVerified = AlipaySignature.rsaCheckV1(params, AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.CHARSET, AlipayConfig.SIGNTYPE);
        if (signVerified) {
            //按照支付结果异步通知中描述,对支付结果中的业务内容进行1\2\3\4二次校验,校验成功后在response中返回success,校验失败返回failure
            this.check(params);
            //获取支付金额
            Double totalAmount = Double.valueOf(params.get("total_amount"));
            //获取支付单号
            String outTradeNo = params.get("out_trade_no");
            //校验
            if (outTradeNo != null && totalAmount != null) {
                orderInfoDTO.setOrder_total(totalAmount);
                orderInfoDTO.setOrder_num(outTradeNo);
                model.addAttribute("order", orderInfoDTO);
                return "returnCallback";
            }
            model.addAttribute("error", "订单处理失败,请联系管理员处理!!!");
            return "returnCallback";
        } else {
            logger.info("支付宝回调签名认证失败,signVerified=false, paramsJson:{}", paramsJson);
            model.addAttribute("error", "订单验签失败,请联系管理员处理!!!");
            return "returnCallback";
        }
    } catch (AlipayApiException e) {
        logger.error("支付宝回调签名认证失败,paramsJson:{},errorMsg:{}", paramsJson, e.getMessage());
        model.addAttribute("error", "订单异常,请联系管理员处理!!!");
        return "returnCallback";
    }
}

调用完成后在沙盒平台里配置同步和异步地址

spring boot整合支付宝支付(沙箱环境)

到这里支付宝支付就成功了,这里仅限于沙盒环境!!!

注意!!!

同步回调和异步回调的地址需要在拦截器配置中放开,不然会被拦截!!

注意!!!

同步回调和异步回调的地址需要在拦截器配置中放开,不然会被拦截!!

spring boot整合支付宝支付(沙箱环境)
回调参考自:https://blog.csdn.net/thc1987/article/details/80269181

仅供自己参考,勿喷。有错欢迎指点。

上一篇:支付宝网页支付对接


下一篇:简单了解WebSocket协议与Http协议,聊天室实现(WebSocket方式)