• Java +支付宝 +接入


    说下业务场景, 公司之前的支付宝业务是PHP对接的现在改成 Java ,在接入出现不同的问题。之前PHP用的是老的移动支付, 现在Java的新接口 , 需要签约。 跟运维沟通好几次, 说签约不了, 只能用老的移动支付方式;

    1.1 移动支付文档

    https://doc.open.alipay.com/doc2/detail?treeId=59&articleId=103563&docType=1

    1.2 基本配置

     按照支付宝的流程 。 生成 用户的私钥和公钥对 。 把 开发者的公约上传 到支付宝, 支付宝会生成一对, 支付宝私钥公钥对。 意思就是 两套私钥公钥 ; 怎么使用呢?

    用户加签 的时候是用用户的私钥, 解密的时候是用  支付宝的 公钥  。

    支付宝解密的时候用 用户的 公约, 加密的时候用支付宝 的私钥,  双向的; 这个逻辑必须要明白。

    说下我这里的难题:因为以前的开发者公钥和私钥都是  PHP的,  Java接入需要 使用 pks 8格式,  这里怎么解决了? 只用一步 , 把 PHP开发者的私钥 ---》转换成  Java的 的pks 8 私钥、 其他都不用管了。(因为涉及到了两种 语言的兼顾)。

    1.3 Java 服务端需要考虑哪写?

      第一个: 预购单签名 。 用户下单的时候 , 对  参数校验, 用开发者私钥, 生成签名字符串 给 APP。  APP 去完成支付、

      第二个: 支付回调、 支付完成了, 支付宝会异步通知商户系统,我们要定义一个接口去处理参数。

      第三个:可能加个查询接口 ,查询订单等。

      第四个:支付宝退款。

      第五个:支付宝退款回调。

    =============================================

    1.4 例子:

    1. 下预购单:

        public String getPayInfo(PayRequest request) {
    
            // 签约合作者身份ID
            String orderInfo = "partner=" + """ + AliPayConstants.PARTER_ID + """;
    
            // 签约卖家支付宝账号
            orderInfo += "&seller_id=" + """ + AliPayConstants.APP_ACCOUNT + """;
    
            // 商户网站唯一订单号
            orderInfo += "&out_trade_no=" + """ + request.getOutTradeNo() + """;
    
            // 商品名称
            orderInfo += "&subject=" + """ + request.getSubject() + """;
    
            // 商品详情
            orderInfo += "&body=" + """ + request.getBody() + """;
    
            // 商品金额
            orderInfo += "&total_fee=" + """
                    + new BigDecimal(request.getTotalFee()).divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP) + """;
    
            // 服务器异步通知页面路径
            orderInfo += "&notify_url=" + """ + "" + """;
    
            // 服务接口名称, 固定值
            orderInfo += "&service="mobile.securitypay.pay"";
    
            // 支付类型, 固定值
            orderInfo += "&payment_type="1"";
    
            // 参数编码, 固定值
            orderInfo += "&_input_charset="utf-8"";
    
            // 设置未付款交易的超时时间
            // 默认30分钟,一旦超时,该笔交易就会自动被关闭。
            // 取值范围:1m~15d。
            // m-分钟,h-小时,d-天,1c-当天(无论交易何时创建,都在0点关闭)。
            // 该参数数值不接受小数点,如1.5h,可转换为90m。
            orderInfo += "&it_b_pay="30m"";
    
            // extern_token为经过快登授权获取到的alipay_open_id,带上此参数用户将使用授权的账户进行支付
            // orderInfo += "&extern_token=" + """ + extern_token + """;
    
            // 支付宝处理完请求后,当前页面跳转到商户指定页面的路径,可空
            orderInfo += "&return_url="m.alipay.com"";
    
            // 调用银行卡支付,需配置此参数,参与签名, 固定值 (需要签约《无线银行卡快捷支付》才能使用)
            // orderInfo += "&paymethod="expressGateway"";
    
            /**
             * 特别注意,这里的签名逻辑需要放在服务端,切勿将私钥泄露在代码中!
             */
            // sign = AlipaySignature.rsaSign(result,
            // Constants.Ali_QM.ALI_APP_PRIVATE_KEY, Constants.Ali_QM.ALI_UNICODE);
            String sign = SignUtils.sign(orderInfo, AliPayConstants.PRIVATE_KEY);
            try {
                sign = URLEncoder.encode(sign, "UTF-8");
            } catch (UnsupportedEncodingException e) {
                LOGGER.error(e.getMessage());
            }
    
            final String payInfo = orderInfo + "&sign="" + sign + ""&" + "sign_type="RSA"";
    
            LOGGER.info("返回信息:" + payInfo);
            return payInfo;
        }

    2. 支付宝支付完成回调: 传过来一个 request, 获取里面的参数, 如果校验正确, 返回 个给 支付宝 一个字符串 success。  告诉 支付宝  我们已经成功接收到回调了

        public String aliCallback(HttpServletRequest request) {
            LOGGER.info("正在回调");
            PaymentDetail detail = new PaymentDetail();
            detail.setorderOutId(request.getParameter("out_trade_no"));
            detail.setTradeNo(request.getParameter("trade_no"));
            detail.setUserId(request.getParameter("buyer_logon_id"));
            // 设置为已回调
            detail.setCallbackStatus(CallbackType.callable.getStatusValue());
            boolean isPaySuccess = false;
            if ("TRADE_SUCCESS".equals(request.getParameter("trade_status"))) {
    
                Enumeration<?> pNames = request.getParameterNames();
                Map<String, String> param = new HashMap<String, String>();
                try {
                    while (pNames.hasMoreElements()) {
                        String pName = (String) pNames.nextElement();
                        param.put(pName, request.getParameter(pName));
                    }
    
                    boolean signVerified = AlipaySignature.rsaCheckV1(param, AliPayConstants.PUBLIC_KEY,
                            AliPayConstants.CHARSET); // 校验签名是否正确
                    if (signVerified) {
                        // 按照支付结果异步通知中的描述,对支付结果中的业务内容进行1234二次校验,校验成功后在response中返回success,校验失败返回failure
                        LOGGER.info("订单支付成功:" + JSON.toJSONString(param));
                        // 设置订单状态为支付成功
                        detail.setStatus(PayStatus.paySuccess.getStatusValue());
                        isPaySuccess = true;
                    }
    
                } catch (Exception e) {
                    LOGGER.error("回调异常");
                    throw new TradeException(MessageCode.PayBackError);
                }
    
            }
            
            Integer callBackStatus = isPaySuccess ? PaymentConstant.PayCallBackStatus.SUCCESS
                    : PaymentConstant.PayCallBackStatus.FAILURE;
            tradeService.dealWithPayCallBack(request.getParameter("out_trade_no"), request.getParameter("trade_no"),
                    callBackStatus, PaymentConstant.TradeAction.ALI_ACCOUNT);
            paymentDetailsMapper.updatePayment(detail);
            return "success";
  • 相关阅读:
    Unity 之 中文乱码
    fork调用的底层实现
    Linux错误代码含义
    VMware 获取该虚拟机的所有权失败
    Qt ------ QAction
    C++ ------ const迭代器 和 const_iterator的区别
    IAR ------- 在线调试技巧
    STM32 ------ HardFault_Hander 中断函数
    从一张表中复制数据到另一张表中
    分布式任务调度平台xxl-job
  • 原文地址:https://www.cnblogs.com/zgghb/p/6857141.html
Copyright © 2020-2023  润新知