Java支付宝扫码支付[新]

简介: 版权声明:本文首发 http://asing1elife.com ,转载请注明出处。 https://blog.csdn.net/asing1elife/article/details/82619994 ...
版权声明:本文首发 http://asing1elife.com ,转载请注明出处。 https://blog.csdn.net/asing1elife/article/details/82619994

Java支付宝扫码支付[新]

支付宝老版本的 Web 端扫码支付产品为即时到账,更新到新版后现在的产品为电脑网站支付

更多精彩

官网

电脑网站支付快速接入

准备数据

  1. 电脑网站支付 应用需要在开发者页面端进行申请和签约
  2. 应用签约成功之后需要获取以下信息
    • app_id: 签约成功的应用唯一标识
    • app_private_key: 通过 RSA 密钥生成的应用私钥,由开发者自己通过签名软件生成[支付宝提供]
    • alipay_public_key: 通过应用私钥和公钥生成的支付宝公钥,由支付宝自动生成

下载 Java 版 SDK

  1. 前往 电脑网站支付 SDK 获取 下载 Java 的 SDK
  2. 该 SDK 目前不支持 Maven 方式引入,只能通过本地引入
  3. 正常开发模式只需要引入 alipay-sdk-java-3.0.0.jar 即可

获取支付宝客户端

  1. 支付宝客户端是调用所有接口的前置条件,所以应该放置在顶层父类做一次初始化
  2. SOPConstants.ALI_PAY_SEND_URL 是该支付方式的统一请求接口,值为 https://openapi.alipay.com/gateway.do
public class AliCoreServiceImpl extends OrderCoreServiceImpl {
    

    // 参数返回格式
    private static final String ALI_PAY_FORMAT = "json";

    // 编码集,支持 GBK/UTF-8
    protected static final String ALI_PAY_CHARSET = "utf-8";

    // 商户生成签名字符串所使用的签名算法类型,目前支持 RSA2/RSA ,推荐使用 RSA2
    protected static final String ALI_PAY_SIGN_TYPE = "RSA2";

    // 订单支付成功状态
    protected static final String TRADE_STATUS_SUCCESS = "TRADE_SUCCESS";

    // 订单支付结束状态
    protected static final String TRADE_STATUS_FINISHED = "TRADE_FINISHED";

    // 支付宝客户端
    protected static AlipayClient alipayClient;

    static {
        // 初始化支付宝客户端
        alipayClient = new DefaultAlipayClient(
                SOPConstants.ALI_PAY_SEND_URL,
                SOPConstants.ALI_PAY_APP_ID,
                SOPConstants.ALI_PAY_PRIVATE_KEY,
                ALI_PAY_FORMAT,
                ALI_PAY_CHARSET,
                SOPConstants.ALI_PAY_PUBLIC_KEY,
                ALI_PAY_SIGN_TYPE);
    }
}

发起支付宝付款页面请求

  1. 新版的扫码支付对请求参数响应参数都做了封装,只需要传入对应参数值即可
  2. SOPConstants.ALI_PAY_RETURN_URL 是支付宝付款成功需要的同步回执地址
  3. SOPConstants.ALI_PAY_NOTIFY_URL 是支付宝付款成功需要的异步回执地址
  4. 以上两个地址都需要能够外网访问
  5. 该请求方式是通过拼接请求使用 iframe 获取支付宝的付款二维码
    • 通过客户端发起请求时不使用一般的 pageExecute() 而使用 sdkExecute()
    • sdkExecute() 获取的是请求之后的参数值,所以还需要拼接请求地址
    • SOPConstants.ALI_PAY_SEND_URL 是支付请求地址
public class AliPayServiceImpl extends AliCoreServiceImpl {
    

    public String aliPay(Long orderId) {
        // 创建统一下单请求
        AlipayTradePagePayRequest payRequest = new AlipayTradePagePayRequest();
        payRequest.setReturnUrl(SOPConstants.ALI_PAY_RETURN_URL);
        payRequest.setNotifyUrl(SOPConstants.ALI_PAY_NOTIFY_URL);

        // 将订单详情传入业务请求参数中
        payRequest.setBizModel(generateOrderInfo(orderId));

        String body = null;
        try {
            body = alipayClient.sdkExecute(payRequest).getBody();
        } catch (AlipayApiException e) {
            logger.error("订单" + orderId + "获取支付宝付款界面失败!");
        }

        if (body == null) {
            logger.error("订单" + orderId + "未成功获取支付宝付款界面!");
        }

        return SOPConstants.ALI_PAY_SEND_URL + "?" + body;
    }

    private AlipayTradePagePayModel generateOrderInfo(Long orderId) {
        // 获取订单信息
        OrderDTO order = orderManageService.getOrder(orderId);

        AlipayTradePagePayModel model = new AlipayTradePagePayModel();
        model.setOutTradeNo(order.getCode());
        model.setProductCode("FAST_INSTANT_TRADE_PAY");
        model.setTotalAmount(String.valueOf(order.getPrice()));
        model.setSubject("实训在线-" + order.getName());
        model.setBody("实训在线-" + order.getName());
        // 二维码获取方式为模式4,最简洁模式,只有二维码
        model.setQrPayMode("4");
        model.setQrcodeWidth(240L);

        return model;
    }

}
  1. 控制层调用请求接口获取完整请求地址
@RequestMapping("/ali/{orderId}")
public String ali(Model model, @PathVariable String orderId) {
    model.addAttribute("order", orderManageService.getOrder(IdEncoder.decodeId(orderId)));
    model.addAttribute("orderType", OrderPay.aliPay.getCode());
    model.addAttribute("aliPayUrl", aliPayService.aliPay(IdEncoder.decodeId(orderId)));

    return "/order/pay/ali";
}
  1. 上述方法中拼接完整的二维码请求地址可以直接放置到 iframe 的 src 属性中
<iframe id="aliPayFrame" src="${aliPayUrl}" frameborder="0"></iframe>

接收同步回执

  1. 该地址需要与之前初始化客户端时提交给支付宝的同步回执地址保持一致
  2. 回执地址不能有任何多余参数
@RequestMapping("/ali/return")
public String aliReturn(HttpServletRequest request) {
    aliNotifyService.aliReturn(request);

    return null;
}
  1. 新版的同步回执中不会携带订单的状态信息,所以只能用做一般的信息接收,不能做为交易成功的依据
    • 同步回执需要验签,但验签的方法支付宝已提供,即 AlipaySignature.rsaCheckV2()
public void aliReturn(HttpServletRequest request) {
    // 订单号
    String orderCode = request.getParameter("out_trade_no");

    Boolean result = false;
    try {
        // 回执验签
        result = AlipaySignature.rsaCheckV2(parameterToMap(request, false), SOPConstants.ALI_PAY_PUBLIC_KEY, ALI_PAY_CHARSET, ALI_PAY_SIGN_TYPE);
    } catch (AlipayApiException e) {
        logger.error("支付宝订单" + orderCode + "同步回执验签失败!", e);
    }

    if (result) {
        logger.info("支付宝订单" + orderCode + "同步回执接收成功!");
    } else {
        logger.error("支付宝订单" + orderCode + "同步回执无效!");
    }
}
  1. 对同步回执中的响应参数验签之前,需要先将参数转化为 map 形式
private Map parameterToMap(HttpServletRequest request, Boolean isNotify) {
    // 获取回执内容
    Map requestParams = request.getParameterMap();

    // 过滤回执内容
    Map params = Maps.newHashMap();
    for (Object o : requestParams.keySet()) {
        String name = (String) o;
        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] + ",";
        }

        if (isNotify) {
            params.put(name, valueStr);
        } else {
            try {
                params.put(name, new String(valueStr.getBytes("ISO-8859-1"), "utf-8"));
            } catch (UnsupportedEncodingException e) {
                logger.error("支付宝订单同步回执转码失败!", e);
            }
        }
    }

    return params;
}

接收异步回执

  1. 该地址需要与之前初始化客户端时提交给支付宝的异步回执地址保持一致
  2. 回执地址不能携带任何参数
@RequestMapping(value = "/ali", method = RequestMethod.POST)
@ResponseBody
public String aliNotify(HttpServletRequest request) {
    return aliNotifyService.aliNotify(request);
}
  1. 异步回执作为支付成功的依据,支付宝成功通知到本地后,需要明确告知支付宝交易已成功
    • 交易成功后返回 success 即可
    • 当订单支付成功后订单可以展现两种状态,TRADE_SUCCESSTRADE_FINISHED
public String aliNotify(HttpServletRequest request) {
    // 订单号
    String orderCode = request.getParameter("out_trade_no");
    // 订单状态
    String orderStatus = request.getParameter("trade_status");

    boolean result = false;
    try {
        result = AlipaySignature.rsaCheckV2(parameterToMap(request, true), SOPConstants.ALI_PAY_PUBLIC_KEY, ALI_PAY_CHARSET, ALI_PAY_SIGN_TYPE);
    } catch (AlipayApiException e) {
        logger.error("支付宝订单" + orderCode + "异步回执验签失败,订单状态为:" + orderStatus + "!", e);
    }

    // 验签成功
    if (result) {
        // 订单已支付
        if (orderStatus.equals(TRADE_STATUS_SUCCESS) || orderStatus.equals(TRADE_STATUS_FINISHED)) {
            // 更新订单状态
            updateOrderInfo(orderCode, OrderPay.aliPay.getCode());

            return "success";
        } else {
            logger.error("支付宝订单" + orderCode + "未支付,订单状态为:" + orderStatus + "!");
            return "fail";
        }
    } else {
        logger.error("支付宝订单" + orderCode + "异步回执接收失败,订单状态为:" + orderStatus + "!");
        return "fail";
    }
}
目录
相关文章
|
5月前
|
JSON Java 数据安全/隐私保护
一篇文章讲明白Java第三方支付接入案例(支付宝)
一篇文章讲明白Java第三方支付接入案例(支付宝)
278 0
|
5月前
|
XML Java 程序员
Java SpringMVC实现PC端网页微信扫码支付完整版
Java SpringMVC实现PC端网页微信扫码支付完整版
245 0
|
5月前
|
前端开发 小程序 Java
(JAVA)获取支付宝二维码 带参数
(JAVA)获取支付宝二维码 带参数
|
5月前
|
小程序 前端开发 Java
(JAVA)支付宝小程序登录相关(authToken获取用户唯一userId、encryptedData解密手机号)
(JAVA)支付宝小程序登录相关(authToken获取用户唯一userId、encryptedData解密手机号)
439 0
|
6月前
|
网络协议 Java 应用服务中间件
本地配置Java支付宝沙箱环境模拟支付并内网穿透远程调试
本地配置Java支付宝沙箱环境模拟支付并内网穿透远程调试
195 0
|
6月前
|
负载均衡 安全 NoSQL
三面阿里(支付宝)Java高开岗,疫情期间复习两月有幸拿到offer
每个程序员都有一个大厂的梦,而互联网大厂首当其冲自然是阿里巴巴最吃香,今天小编就来分享一个小伙进阿里巴巴(支付宝三面)的面经!
|
6月前
|
Java 应用服务中间件 开发工具
Java开发者必备:支付宝沙箱环境支付远程调试指南
Java开发者必备:支付宝沙箱环境支付远程调试指南
|
网络协议 Java 应用服务中间件
Java支付宝沙箱环境支付,官方Demo远程调试【内网穿透】
Java支付宝沙箱环境支付,官方Demo远程调试【内网穿透】
|
JavaScript Java 数据安全/隐私保护
java对接支付宝在线支付 沙箱环境测试
首先去https://open.alipay.com/platform/home.htm注册 点击进入我的开放平台
|
负载均衡 安全 NoSQL
三面阿里(支付宝)Java高开岗,疫情期间复习两月有幸拿到offer
每个程序员都有一个大厂的梦,而互联网大厂首当其冲自然是阿里巴巴最吃香,今天小编就来分享一个小伙进阿里巴巴(支付宝三面)的面经! “不想进大厂的程序员不是好程序员”哈哈哈!!! 今年由于疫情原因,互联网整个行业都比较严峻,我比较幸运,不久前意外收到支付宝的面试(三面)已经拿到了offer。 本来春节过后,是金三银四找工作旺季,大部分人年前年后也都准备好了这在两个月里谋得一份自己心仪的工作,奈何今年的2020有些特殊,肺炎肆虐,对我们的工作和生活都造成了极大的影响。那么,是不是这样,我们就不工作,不学习了呢?实际上,正是因为现在正值传染病毒传播期间,所以我们宅在家里好好学习是再好不过的。对于
下一篇
无影云桌面