支付宝手机网页版支付、支付异步回调、退款

一.微信小程序订单生成支付宝链接至浏览器支付

1.场景需求

最近是做了一款和阿里合作的企业商城,形式是微信小程序。但是和阿里合作模式中,是通过支付宝支付(其中链路比较复杂,不说了)。总之用了手机网页版链接支付

2.准备工作

2.1创建应用
在这里插入图片描述

2.2配置密钥等信息
在这里插入图片描述
密钥生成很简单的,这里就不多说了。

注意:只有配置完环境以后才能提交审核,审核过就能签约手机网页版支付了

2.3签约手机网页版支付
在这里插入图片描述

准备工作就ok 了

3.搭建项目环境以及实现

3.1支付流程:
在这里插入图片描述

3.2配置properties

在这里插入图片描述
就是一些简单的公共的参数

3.3代码

这里参数的话可以参考支付宝开发文档来,必传项是:out_trade_no 订单号 ,total_amount:支付的金额,subject:订单商品描述,body:规格属性(也可不传)

注意:

   AlipayTradeCreateResponse response = alipayClient.pageExecute(request,“get”);
   “get”的话,就是生成支付宝支付链接,或者post就是生成from表单。我们这里需要的是链接
 //实例化客户端
            AlipayClient alipayClient = new DefaultAlipayClient(ResourceUtil.getConfigByName("application.appconfig.gateway"), ResourceUtil.getConfigByName("my.appid"), ResourceUtil.getConfigByName("my.privatekey"), "json", "utf-8", ResourceUtil.getConfigByName("my.publickey"), "RSA2");
//实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.create.
            AlipayTradeCreateRequest request = new AlipayTradeCreateRequest();
            request.setNotifyUrl(ResourceUtil.getConfigByName("my.notifyUrl"));
            String nonceStr = CharUtil.getRandomString(32);
//SDK已经封装掉了公共参数,这里只需要传入业务参数。
            request.setBizContent("{" +
                    "\"out_trade_no\":\"" + allOrderId + "\"," +
                    "\"total_amount\":" + allPrice + "," +
                    "\"subject\":\"" + (body.length() > 128 ? body.substring(0, 128) : body) + "\"," +
                    "\"body\":\"" + (body.length() > 128 ? body.substring(0, 128) : body) + "\"," +
                    "  }");
            try {
                //使用的是execute AlipayTradeCreateResponse response
                AlipayTradeCreateResponse response = alipayClient.pageExecute(request,“get”);
                String trade_no = response.getTradeNo();//获取返回的tradeNO。
                if (!"10000".equals(response.getCode())) {
                    return toResponsFail("支付失败," + response.getSubMsg());
                } else {
                    resultObj.put("appId", ResourceUtil.getConfigByName("my.appid"));
                    resultObj.put("timeStamp", System.currentTimeMillis() / 1000 + "");
                    resultObj.put("nonceStr", nonceStr);
                    resultObj.put("package", "prepay_id=" + trade_no);
                    //这个地方就是阿里云返回的支付链接
                    resultobj.put("alipaylink",response.getbody)
                    return toResponsObject(0, "支付宝统一下单成功", resultObj);
                }
            } catch (AlipayApiException e) {
                e.printStackTrace();
                return toResponsFail("下单失败,error=" + e.getMessage());
            }
        }

支付总体来说还是挺简单的

二.支付宝支付异步通知

1. 对于手机网站支付产生的交易,支付宝会根据原始支付API中传入的异步通知地址notify_url,通过POST请求的形式将支付结果作为参数通知到商户系统。

2.代码

注意:这是异步回调时,沙箱环境支付成功后,trade_status得到的不是TRADE_SUCCESS,换成正式环境就ok了。这里有点懒,把回调的代码拿过来了。

@ApiOperation(value = "支付宝网站订单回调接口")
    @RequestMapping(value = "/alipaywapnotify", method = RequestMethod.POST, produces = "text/html;charset=UTF-8")
    @IgnoreAuth
    @ResponseBody
    public String alipaywapnotify(HttpServletRequest request) {
        Map<String, String> params = convertRequestParamsToMap(request); // 将异步通知中收到的待验证所有参数都存放到map中
        String paramsJson = JSON.toJSONString(params);

        try {

            // 调用SDK验证签名
            boolean signVerified = AlipaySignature.rsaCheckV1(params, ResourceUtil.getConfigByName("my.publickey"),
                    "utf-8",ResourceUtil.getConfigByName("my.privatekey"));
            if (signVerified) {
                logger.info("支付宝回调签名认证成功");
                // 按照支付结果异步通知中的描述,对支付结果中的业务内容进行1\2\3\4二次校验,校验成功后在response中返回success,校验失败返回failure
                this.check(params);
                // 处理业务

                AlipayNotifyParam param = buildAlipayNotifyParam(params);
                        String trade_status = param.getTradeStatus();
                //处理订单的redis状态
                String value = RedisUtils.get(param.getOutTradeNo());
                if (value != null && "51".equals(value)) {
                    RedisUtils.del(param.getOutTradeNo());
                } else {
                    //查询支付已结操作过
                    logger.info("SUCCSEE");
                    return "success";
                }
                // 支付成功
                        if (trade_status.equals("TRADE_SUCCESS")
                                || trade_status.equals("TRADE_FINISHED")) {
                            // 处理支付成功逻辑
                            try {
                  // 处理业务逻辑。
                  // 更改订单状态
                     ...........................
                     ...........................
                    }
                }
                            } catch (Exception e) {
                                logger.error("支付宝回调业务处理报错,params:" + paramsJson, e);
                            }
                        } else {
                            logger.error("没有处理支付宝回调业务,支付宝交易状态:{},params:{}");
                        }


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


    }


    // 将request中的参数转换成Map
    private static Map<String, String> convertRequestParamsToMap(HttpServletRequest request) {
        Map<String, String> retMap = new HashMap<String, String>();

        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 sb = new StringBuilder();
                for (String val : values) {
                    sb.append(",").append(val);
                }
                retMap.put(name, sb.toString().substring(1));
            } else {
                retMap.put(name, "");
            }
        }

        return retMap;
    }




    /**
     * 1、商户需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号,
     * 2、判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额),
     * 3、校验通知中的seller_id(或者seller_email)是否为out_trade_no这笔单据的对应的操作方(有的时候,一个商户可能有多个seller_id/seller_email),
     * 4、验证app_id是否为该商户本身。上述1、2、3、4有任何一个验证不通过,则表明本次通知是异常通知,务必忽略。
     * 在上述验证通过后商户必须根据支付宝不同类型的业务通知,正确的进行不同的业务处理,并且过滤重复的通知结果数据。
     * 在支付宝的业务通知中,只有交易通知状态为TRADE_SUCCESS或TRADE_FINISHED时,支付宝才会认定为买家付款成功。
     *
     * @param params
     * @throws AlipayApiException
     */
    private void check(Map<String, String> params) throws AlipayApiException {
        String outTradeNo = params.get("out_trade_no");

        // 1、商户需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号,
        List<OrderVo> orderVos = orderService.queryByAllOrderId(outTradeNo);// 这个方法自己实现
        if (orderVos.isEmpty()) {
            throw new AlipayApiException("out_trade_no错误");
        }

        // 2、判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额),
        long total_amount = new BigDecimal(params.get("total_amount")).multiply(new BigDecimal(100)).longValue();
        if (total_amount != orderVos.get(0).getActual_price().multiply(new BigDecimal(100)).longValue()){
            throw new AlipayApiException("error total_amount");
        }

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

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

    private AlipayNotifyParam buildAlipayNotifyParam(Map<String, String> params) {
        String json = JSON.toJSONString(params);
        return JSON.parseObject(json, AlipayNotifyParam.class);
    }



}
 class AlipayNotifyParam implements Serializable {
     public String getAppId() {
         return appId;
     }

     public void setAppId(String appId) {
         this.appId = appId;
     }

     public String getTradeNo() {
         return tradeNo;
     }

     public void setTradeNo(String tradeNo) {
         this.tradeNo = tradeNo;
     }

     public String getOutTradeNo() {
         return outTradeNo;
     }

     public void setOutTradeNo(String outTradeNo) {
         this.outTradeNo = outTradeNo;
     }

     public String getOutBizNo() {
         return outBizNo;
     }

     public void setOutBizNo(String outBizNo) {
         this.outBizNo = outBizNo;
     }

     public String getBuyerId() {
         return buyerId;
     }

     public void setBuyerId(String buyerId) {
         this.buyerId = buyerId;
     }

     public String getBuyerLogonId() {
         return buyerLogonId;
     }

     public void setBuyerLogonId(String buyerLogonId) {
         this.buyerLogonId = buyerLogonId;
     }

     public String getSellerId() {
         return sellerId;
     }

     public void setSellerId(String sellerId) {
         this.sellerId = sellerId;
     }

     public String getSellerEmail() {
         return sellerEmail;
     }

     public void setSellerEmail(String sellerEmail) {
         this.sellerEmail = sellerEmail;
     }

     public String getTradeStatus() {
         return tradeStatus;
     }

     public void setTradeStatus(String tradeStatus) {
         this.tradeStatus = tradeStatus;
     }

     public BigDecimal getTotalAmount() {
         return totalAmount;
     }

     public void setTotalAmount(BigDecimal totalAmount) {
         this.totalAmount = totalAmount;
     }

     public BigDecimal getReceiptAmount() {
         return receiptAmount;
     }

     public void setReceiptAmount(BigDecimal receiptAmount) {
         this.receiptAmount = receiptAmount;
     }

     public BigDecimal getBuyerPayAmount() {
         return buyerPayAmount;
     }

     public void setBuyerPayAmount(BigDecimal buyerPayAmount) {
         this.buyerPayAmount = buyerPayAmount;
     }

     public BigDecimal getRefundFee() {
         return refundFee;
     }

     public void setRefundFee(BigDecimal refundFee) {
         this.refundFee = refundFee;
     }

     public String getSubject() {
         return subject;
     }

     public void setSubject(String subject) {
         this.subject = subject;
     }

     public String getBody() {
         return body;
     }

     public void setBody(String body) {
         this.body = body;
     }

     public Date getGmtCreate() {
         return gmtCreate;
     }

     public void setGmtCreate(Date gmtCreate) {
         this.gmtCreate = gmtCreate;
     }

     public Date getGmtPayment() {
         return gmtPayment;
     }

     public void setGmtPayment(Date gmtPayment) {
         this.gmtPayment = gmtPayment;
     }

     public Date getGmtRefund() {
         return gmtRefund;
     }

     public void setGmtRefund(Date gmtRefund) {
         this.gmtRefund = gmtRefund;
     }

     public Date getGmtClose() {
         return gmtClose;
     }

     public void setGmtClose(Date gmtClose) {
         this.gmtClose = gmtClose;
     }

     public String getFundBillList() {
         return fundBillList;
     }

     public void setFundBillList(String fundBillList) {
         this.fundBillList = fundBillList;
     }

     public String getPassbackParams() {
         return passbackParams;
     }

     public void setPassbackParams(String passbackParams) {
         this.passbackParams = passbackParams;
     }

     private String appId;
    private String tradeNo; // 支付宝交易凭证号
    private String outTradeNo; // 原支付请求的商户订单号
    private String outBizNo; // 商户业务ID,主要是退款通知中返回退款申请的流水号
    private String buyerId; // 买家支付宝账号对应的支付宝唯一用户号。以2088开头的纯16位数字
    private String buyerLogonId; // 买家支付宝账号
    private String sellerId; // 卖家支付宝用户号
    private String sellerEmail; // 卖家支付宝账号
    private String tradeStatus; // 交易目前所处的状态,见交易状态说明
    private BigDecimal totalAmount; // 本次交易支付的订单金额
    private BigDecimal receiptAmount; // 商家在交易中实际收到的款项
    private BigDecimal buyerPayAmount; // 用户在交易中支付的金额
    private BigDecimal refundFee; // 退款通知中,返回总退款金额,单位为元,支持两位小数
    private String subject; // 商品的标题/交易标题/订单标题/订单关键字等
    private String body; // 该订单的备注、描述、明细等。对应请求时的body参数,原样通知回来
    private Date gmtCreate; // 该笔交易创建的时间。格式为yyyy-MM-dd HH:mm:ss
    private Date gmtPayment; // 该笔交易的买家付款时间。格式为yyyy-MM-dd HH:mm:ss
    private Date gmtRefund; // 该笔交易的退款时间。格式为yyyy-MM-dd HH:mm:ss.S
    private Date gmtClose; // 该笔交易结束时间。格式为yyyy-MM-dd HH:mm:ss
    private String fundBillList; // 支付成功的各个渠道金额信息,array
    private String passbackParams; // 公共回传参数,如果请求时传递了该参数,则返回给商户时会在异步通知时将该参数原样返回。

}

三.退款

1.退款

注意参数就ok 了

AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", APP_ID, APP_PRIVATE_KEY, "json", CHARSET, ALIPAY_PUBLIC_KEY, "RSA2"); //获得初始化的AlipayClient
AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();//创建API对应的request类
request.setBizContent("{" +
" \"out_trade_no\":\"20150320010101001\"," +
" \"trade_no\":\"2014112611001004680073956707\"," +
" \"out_request_no\":\"1000001\"," +
" \"refund_amount\":\"2014112611001004680073956707\"" +
" }");//设置业务参数
AlipayTradeRefundResponse response = alipayClient.execute(request);//通过alipayClient调用API,获得对应的response类
System.out.print(response.getBody());
//根据response中的结果继续业务逻辑处理
  • 3
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值