zoukankan      html  css  js  c++  java
  • 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";
  • 相关阅读:
    JDBC 复习4 批量执行SQL
    JDBC 复习3 存取Oracle大数据 clob blob
    Oracle复习
    Linux命令(1)grep
    JDBC 复习2 存取mysql 大数据
    JDBC 复习1 DBUtil
    php 环境搭建问题
    Windows 批处理 bat 开启 WiFi 菜单选项 设置ID PWD
    Bat 批处理启动和停止Oracle 服务
    docker 学习1 WSL docker ,Windows docker
  • 原文地址:https://www.cnblogs.com/zgghb/p/6857141.html
Copyright © 2011-2022 走看看