支付宝支付+退款(公钥证书方式+普通公钥方式)app+java

  支付宝的签名方式有两种(普通公钥方式、公钥证书方式),一般最常用的就是普通公钥方式,也相对比较简单,但是公钥证书方式是现在支付宝支付官方文档上面推荐的签名方式.
申请步骤可以参照官方文档:
参考链接:https://docs.open.alipay.com/291/105971/

 

pom依赖,不要乱用,网上有很多不同的依赖,我都试过,不好用,这个依赖是我试过,好用的

 <dependency>
              <groupId>com.alipay.sdk</groupId>
              <artifactId>alipay-sdk-java</artifactId>
              <version>4.16.50.ALL</version>
        </dependency>

yml的相关配置

公钥证书模式

实现类里(支付宝也是先请求预下单,返回一个body的数据,安卓拿着body去拉起支付宝支付,最后支付成功,会调用自己写的回调接口)


    /**
     * 把预下单封装成一个对象,共同调用这个
     * @param totalAmount 金额,以元为单位
     * @param orderNo 商户自定义编号
     * @return
     */
    public R<String> aliPrePay( BigDecimal totalAmount,String  orderNo,String  notifyUrl){
        CertAlipayRequest certAlipayRequest = new CertAlipayRequest();
        certAlipayRequest.setServerUrl(getwayUrl);//设置网关地址
        certAlipayRequest.setAppId(appId);//设置应用Id
        certAlipayRequest.setPrivateKey(merchantPrivateKey); //设置应用私钥
        certAlipayRequest.setFormat("json"); //设置请求格式,固定值json
        certAlipayRequest.setCharset(charset);//设置字符集
        certAlipayRequest.setSignType(signType); //设置签名类型
        certAlipayRequest.setCertPath(certPath);//设置应用公钥证书路径 ,一定是本地的绝对路径
        certAlipayRequest.setAlipayPublicCertPath(alipayPublicCertPath); //设置支付宝公钥证书路径,一定是本地的绝对路径
        certAlipayRequest.setRootCertPath(rootCertPath);//设置支付宝根证书路径,一定是本地的绝对路径
        //获得初始化的alipayClient,构造client
        AlipayClient alipayClient = null;
        String result = "";
        try {
            //公钥证书,一定要使用这个构造方法
            alipayClient = new DefaultAlipayClient(certAlipayRequest);
            //实例化具体API对应的request类,
            AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
            //按照需要传入参数,以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
            AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
            model.setSubject(bodyMall);//订单标题
            model.setOutTradeNo(orderNo);//商户订单号,商家自定义
            model.setTotalAmount(totalAmount+"");//金额,string类型
            request.setBizModel(model);
            request.setNotifyUrl(notifyUrl);//异步回调地址
            AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
            result = response.getBody();
            return R.success(result);
        } catch (AlipayApiException e) {
            e.printStackTrace();
            return R.fail("预下单失败!");
        }
    }


    /**
     * 商城订单的支付宝预下单
     *
     * @param memberId    用户id
     * @param totalAmount 金额
     * @return
     */
    @Override
    public R<String> aliPayMallOrder(Integer memberId, BigDecimal totalAmount,Integer orderId) {
        String orderNo = OrderNoUtil.getOrderId();
        R<String> pay = aliPrePay(totalAmount, orderNo,notifyUrlMallOrder);
        if(!pay.getIsSuccess()){ //失败直接返回上一级返回的内容
            return pay;
        }
        //生成支付宝的预下单对象
        ALPrePay prePay = new ALPrePay();
        prePay.setMemberId(memberId);//用户id
        prePay.setOrderNo(orderNo);//订单编号
        prePay.setOrderId(orderId);//订单id
        prePay.setOrderType(MallEmums.PRE_PAY_TYPE_MALL.getCode());//订单支付类别
        prePay.setTotalAmount(totalAmount.multiply(new BigDecimal(100)).intValue());//金额已分展示
        baseMapper.insert(prePay);
        return pay;
    }

拉起支付宝的回调以后,就要用写回调方法

    /**
     * 支付宝回调
     *  接口封装好, 统一验证签名,并返回自定义的商户编号 outTradeNo
     * @param request
     * @return outTradeNo
     */
    public R<String> verification(HttpServletRequest request){
        //回调的待验签字符串
        String resultInfo = convertRequestParamsToString(request).toString();
        //对待签名字符串数据通过&进行拆分
        String [] temp = resultInfo.split("&");
        LinkedHashMap<String, String> map =  new LinkedHashMap<String, String>();
        //把拆分数据放在map集合内
        for (int i = 0; i < temp.length; i++) {
            String[] arr = temp[i].split("=", 2); //通过"="号分割成2个数据
            String[] tempAagin = new String[arr.length]; //再开辟一个数组用来接收分割后的数据
            for (int j = 0; j < arr.length; j++) {
                tempAagin[j] = arr[j];
            }
            map.put(tempAagin[0], tempAagin[1]);
        }
        System.out.println(map);
        //验签方法
        boolean signVerified= false;
        try {
            signVerified = AlipaySignature.rsaCertCheckV1(map, alipayPublicCertPath, charset,signType);
            if(signVerified){
                System.out.println("支付宝回调签名认证成功");
                String outTradeNo = map.get("out_trade_no");//商户自定义的订单编号
                String tradeNo = map.get("trade_no");//支付宝交易凭证号
                String buyerLogonId = map.get("buyer_logon_id");//支付宝交易凭证号
                System.out.println("买家支付宝账号:"+buyerLogonId);
                ALPrePay prePay = prePayService.getALPrePayByOutTradeNo(outTradeNo);
                prePay.setTradeNo(tradeNo);
                prePayMapper.updateById(prePay);
                return R.success(outTradeNo).setMsg("支付成功");
            }else{
                System.out.println("支付宝回调签名认证失败");
                return R.fail("支付失败");
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
            return R.fail("支付失败");
        }
    }



    // 将request中的参数转换成Map
    private  StringBuffer  convertRequestParamsToString(HttpServletRequest request) {
        StringBuffer info = new StringBuffer();
        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) {
                info.append(name).append("=").append(values[0]).append("&");
            } else if (valLen > 1) {
                StringBuilder sb = new StringBuilder();
                for (String val : values) {
                    sb.append(",").append(val);
                }
                info.append(name).append("=").append(sb.toString().substring(1)).append("&");
            } else {
                info.append(name).append("=").append("").append("&");
            }
        }

        return info;
    }
 /**
     * 商城的支付宝回调
     * 1.从请求中找到商户自定义的outTradeNo,
     * 2.根据商户自定义的outTradeNo去找预下单表中的orderId
     * 3.找到对应的订单数据,然后在调用对应的修改订单接口
     * @param request
     * @return
     */
    @Override
    public R aliPayMallOrderCallBack(HttpServletRequest request) {
        R verification = verification(request);
        Boolean isSuccess = verification.getIsSuccess();
        if(isSuccess){
            //验证签名正确,开始处理订单的业务逻辑
            //1.取出outTradeNo
             String outTradeNo= verification.getData().toString();
             //2.根据outTradeNo从预下单中取出orderId
            ALPrePay prePay = prePayService.getALPrePayByOutTradeNo(outTradeNo);
            //订单id
            Integer orderId = prePay.getOrderId();
            //订单no
            String orderNo = prePay.getOrderNo();
            //因为回调会依次调用很多次,所有每一次更改订单状态要判断他是否支付过,如果支付过了,就不可以在支付了
            Boolean b = orderFeignService.hasPayByOrderId(orderId).getData();
            if (!b) { //false,已支付
                return R.success().setMsg("支付成功");
            }
            //支付成功,调用更改订单的状态等数据
            AyjMallOrder order = orderFeignService.getOrder(orderId).getData();
            if (order.getOrderStatus() == MallEmums.ORDER_STATUS_NOT.getCode()) { //订单未支付
                 orderFeignService.updatePaymentOrder(orderId, orderNo, MallEmums.ORDER_PAY_TYPE_ALIPAY.getCode()).getData();
            } else { //优惠买单未支付
                orderFeignService.updatePaymentDiscounts(orderId, orderNo, MallEmums.ORDER_PAY_TYPE_ALIPAY.getCode());
            }
            return R.success().setMsg("支付成功");
        }else{
            return verification;
        }
    }

退款

/**
     * 支付宝商城退款
     * @param orderNo
     * @return
     */
    @Override
    public R aliPayRefund(String orderNo) {
        ALPrePay prePay = prePayService.getALPrePayByOutTradeNo(orderNo);
        AlipayTradeRefundRequest alipay_request = new AlipayTradeRefundRequest();
        AlipayTradeRefundModel model=new AlipayTradeRefundModel();
        model.setOutTradeNo(orderNo);//商户自定义的单号
        model.setTradeNo(prePay.getTradeNo());//支付宝交易凭证号
        model.setRefundAmount(new BigDecimal(prePay.getTotalAmount()).divide(new BigDecimal(100))+"");//金额
        model.setRefundReason(refundBodyMall);//退款原因
        alipay_request.setBizModel(model);
        CertAlipayRequest certAlipayRequest = new CertAlipayRequest();
        certAlipayRequest.setServerUrl(getwayUrl);//设置网关地址
        certAlipayRequest.setAppId(appId);//设置应用Id
        certAlipayRequest.setPrivateKey(merchantPrivateKey); //设置应用私钥
        certAlipayRequest.setFormat("json"); //设置请求格式,固定值json
        certAlipayRequest.setCharset(charset);//设置字符集
        certAlipayRequest.setSignType(signType); //设置签名类型
        certAlipayRequest.setCertPath(certPath);//设置应用公钥证书路径 ,一定是本地的绝对路径
        certAlipayRequest.setAlipayPublicCertPath(alipayPublicCertPath); //设置支付宝公钥证书路径,一定是本地的绝对路径
        certAlipayRequest.setRootCertPath(rootCertPath);//设置支付宝根证书路径,一定是本地的绝对路径
        //获得初始化的alipayClient,构造client
        AlipayClient alipayClient = null;
        try {
            //公钥证书,一定要使用这个构造方法
            alipayClient = new DefaultAlipayClient(certAlipayRequest);
            AlipayTradeRefundResponse alipay_response = alipayClient.certificateExecute(alipay_request);
            String alipayRefundStr = alipay_response.getBody();
            System.out.println(alipayRefundStr);
            prePay.setHasRefund(MallEmums.YES.getCode());//已退款
            prePayMapper.updateById(prePay);
            return R.success().setMsg("退款成功");
        } catch (AlipayApiException e) {
            e.printStackTrace();
            return R.fail("服务器异常,退款失败");
        }
    }

普通公钥模式

   @Value("${ayj.alipay.appId}")
    private String appId;

    @Value("${ayj.alipay.merchantPrivateKey}")
    private String merchantPrivateKey;

    @Value("${ayj.alipay.merchantPublicKey}")
    private String merchantPublicKey;

    @Value("${ayj.alipay.alipayPublicKey}")
    private String alipayPublicKey;

    @Value("${ayj.alipay.signType}")
    private String signType;

    @Value("${ayj.alipay.charset}")
    private String charset;

    @Value("${ayj.alipay.getwayUrl}")
    private String getwayUrl;

    @Value("${ayj.alipay.certPath}")
    private String certPath;

    @Value("${ayj.alipay.alipayPublicCertPath}")
    private String alipayPublicCertPath;

    @Value("${ayj.alipay.rootCertPath}")
    private String rootCertPath;

    @Value("${ayj.alipay.bodyMall}")
    private String bodyMall;

    @Value("${ayj.alipay.notifyUrlMallOrder}")
    private String notifyUrlMallOrder;

    @Value("${ayj.alipay.notifyUrlMallOrderQqh}")
    private String notifyUrlMallOrderQqh;

    @Value("${ayj.alipay.notifyUrlMallOrderZwy}")
    private String notifyUrlMallOrderZwy;

    @Value("${ayj.alipay.notifyUrlCharity}")
    private String notifyUrlCharity;

    @Value("${ayj.alipay.notifyUrlChatGift}")
    private String notifyUrlChatGift;   


 /**
     * 把预下单封装成一个对象,共同调用这个
     * @param totalAmount 金额,以元为单位
     * @param orderNo 商户自定义编号
     * @return
     */
    public R<String> aliPrePay( BigDecimal totalAmount,String  orderNo,String  notifyUrl){
        //实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.app.pay
        AlipayClient alipayClient = new DefaultAlipayClient(getwayUrl, appId,merchantPrivateKey , "json", charset,
                alipayPublicKey, signType);
        String result = "";
        try {
            //实例化具体API对应的request类,
            AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
            //按照需要传入参数,以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
            AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
            model.setSubject(bodyMall);//订单标题
            model.setOutTradeNo(orderNo);//商户订单号,商家自定义
            model.setTotalAmount(totalAmount+"");//金额,string类型
            request.setBizModel(model);
            request.setNotifyUrl(notifyUrl);//异步回调地址
            AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
            result = response.getBody();
            return R.success(result);
        } catch (AlipayApiException e) {
            e.printStackTrace();
            return R.fail("预下单失败!");
        }
    }



    /**
     * 商城订单的支付宝预下单
     *
     * @param memberId    用户id
     * @param totalAmount 金额
     * @return
     */
    @Override
    public R<String> aliPayMallOrder(Integer memberId, BigDecimal totalAmount,Integer orderId) {
        String orderNo = OrderNoUtil.getOrderId();
        R<String> pay = aliPrePay(totalAmount, orderNo,notifyUrlMallOrder);
        if(!pay.getIsSuccess()){ //失败直接返回上一级返回的内容
            return pay;
        }
        //生成支付宝的预下单对象
        ALPrePay prePay = new ALPrePay();
        prePay.setMemberId(memberId);//用户id
        prePay.setOrderNo(orderNo);//订单编号
        prePay.setOrderId(orderId);//订单id
        prePay.setOrderType(MallEmums.PRE_PAY_TYPE_MALL.getCode());//订单支付类别
        prePay.setTotalAmount(totalAmount.multiply(new BigDecimal(100)).intValue());//金额已分展示
        baseMapper.insert(prePay);
        return pay;
    }

回调方法

    /**
     * 支付宝回调
     *  接口封装好, 统一验证签名,并返回自定义的商户编号 outTradeNo
     * @param request
     * @return outTradeNo
     */
    public R<String> verification(HttpServletRequest request){
        //回调的待验签字符串
        String resultInfo = convertRequestParamsToString(request).toString();
        //对待签名字符串数据通过&进行拆分
        String [] temp = resultInfo.split("&");
        LinkedHashMap<String, String> map =  new LinkedHashMap<String, String>();
        //把拆分数据放在map集合内
        for (int i = 0; i < temp.length; i++) {
            String[] arr = temp[i].split("=", 2); //通过"="号分割成2个数据
            String[] tempAagin = new String[arr.length]; //再开辟一个数组用来接收分割后的数据
            for (int j = 0; j < arr.length; j++) {
                tempAagin[j] = arr[j];
            }
            map.put(tempAagin[0], tempAagin[1]);
        }
        System.out.println(map);
        //验签方法
        boolean signVerified= false;
        try {
            signVerified = AlipaySignature.rsaCheckV1 (map,alipayPublicKey, charset,signType); //这里采用的普通公钥方式
            if(signVerified){
                System.out.println("支付宝回调签名认证成功");
                String outTradeNo = map.get("out_trade_no");//商户自定义的订单编号
                String tradeNo = map.get("trade_no");//支付宝交易凭证号
                String buyerLogonId = map.get("buyer_logon_id");//支付宝交易凭证号
                System.out.println("买家支付宝账号:"+buyerLogonId);
                ALPrePay prePay = prePayService.getALPrePayByOutTradeNo(outTradeNo);
                prePay.setTradeNo(tradeNo);
                prePayMapper.updateById(prePay);
                return R.success(outTradeNo).setMsg("支付成功");
            }else{
                System.out.println("支付宝回调签名认证失败");
                return R.fail("支付失败");
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
            return R.fail("支付失败");
        }
    }



    // 将request中的参数转换成Map
    private  StringBuffer  convertRequestParamsToString(HttpServletRequest request) {
        StringBuffer info = new StringBuffer();
        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) {
                info.append(name).append("=").append(values[0]).append("&");
            } else if (valLen > 1) {
                StringBuilder sb = new StringBuilder();
                for (String val : values) {
                    sb.append(",").append(val);
                }
                info.append(name).append("=").append(sb.toString().substring(1)).append("&");
            } else {
                info.append(name).append("=").append("").append("&");
            }
        }

        return info;
    }
  /**
     * 商城的支付宝回调
     * 1.从请求中找到商户自定义的outTradeNo,
     * 2.根据商户自定义的outTradeNo去找预下单表中的orderId
     * 3.找到对应的订单数据,然后在调用对应的修改订单接口
     * @param request
     * @return
     */
    @Override
    public R aliPayMallOrderCallBack(HttpServletRequest request) {
        R verification = verification(request);
        Boolean isSuccess = verification.getIsSuccess();
        if(isSuccess){
            //验证签名正确,开始处理订单的业务逻辑
            //1.取出outTradeNo
             String outTradeNo= verification.getData().toString();
             //2.根据outTradeNo从预下单中取出orderId
            ALPrePay prePay = prePayService.getALPrePayByOutTradeNo(outTradeNo);
            //订单id
            Integer orderId = prePay.getOrderId();
            //订单no
            String orderNo = prePay.getOrderNo();
            //因为回调会依次调用很多次,所有每一次更改订单状态要判断他是否支付过,如果支付过了,就不可以在支付了
            Boolean b = orderFeignService.hasPayByOrderId(orderId).getData();
            if (!b) { //false,已支付
                return R.success().setMsg("支付成功");
            }
            //支付成功,调用更改订单的状态等数据
            //.....业务逻辑
           
            }
            return R.success().setMsg("支付成功");
        }else{
            return verification;
        }
    }

退款(这个普通公钥方式的退款,字符集一定要用GBK,不能用utf8)

    /**
     * 支付宝商城退款
     * @param orderNo
     * @return
     */
    @Override
    public R aliPayRefund(String orderNo) {
        //普通公钥方式构造
        AlipayClient alipayClient = new DefaultAlipayClient(getwayUrl,appId,merchantPrivateKey,
                "json","GBK",alipayPublicKey,signType);//这的字符集,一定要是GBK,不能是utf-8
        AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
        ALPrePay prePay = prePayService.getALPrePayByOutTradeNo(orderNo);
        JSONObject bizContent = new JSONObject();
      //  bizContent.put("out_trade_no", orderNo); //商户自定义的单号
        bizContent.put("trade_no", prePay.getTradeNo()); //支付宝交易凭证号
        bizContent.put("refund_amount",new BigDecimal(prePay.getTotalAmount()).divide(new BigDecimal(100))+"");//金额
        bizContent.put("refund_reason", "refundBodyMall"); //退款原因
        request.setBizContent(bizContent.toString());
        try {
            AlipayTradeRefundResponse alipay_response = alipayClient.execute(request);
            String alipayRefundStr = alipay_response.getBody();
            System.out.println(alipayRefundStr);
            prePay.setHasRefund(MallEmums.YES.getCode());//已退款
            prePayMapper.updateById(prePay);
            return R.success().setMsg("退款成功");
        } catch (AlipayApiException e) {
            e.printStackTrace();
            return R.fail("服务器异常,退款失败");
        }
    }

猜你喜欢

转载自blog.csdn.net/yuzheh521/article/details/120996452