支付宝H5支付

一、背景

最近在公司做支付平台相关的工作,涉及到微信、支付宝、建设银行、平安银行、云闪付相关的支付对接,在这里总结下在实际工作中涉及到的与第三方渠道的对接,以及如何融入到自己项目的业务流程中。今天先总结下支付H5的支付流程。

       由于H5支付我们这边目前集成了微信、支付宝和银联,这个三个渠道支付,今天主要是总结支付宝H5支付,所以微信和银联的处理先省去了。

二、技术实现

       下面这个部分代码是通过扫码付进入的(由于我们的业务是针对社康和医院的扫码支付)。

 @RequestMapping("/H5PayPageScan")
    public String H5PayPageScan(@Valid PayH5PageScaVo payPageScaVo, BindingResult bindingResult, Model model, HttpServletRequest request, HttpServletResponse response) throws IOException {
        logger.info("公众号,支付宝H5预下单入参:{}",JSON.toJSONString(payPageScaVo));
        pageEnv.build(model);
        payPageScaVo.setToken(payPageScaVo.getToken().replaceAll(" ", "+"));
        String clientType = "";
        String userAgent = request.getHeader("user-agent");
        logger.info("#############################################H5支付");
        if (userAgent != null && userAgent.contains("AlipayClient")) {
            //支付宝支付
            clientType = "AlipayClient";
        } else if (userAgent != null && userAgent.contains("MicroMessenger")) {
            //微信支付
            clientType = "MicroMessenger";
        } else if (userAgent != null && userAgent.contains("UnionPay")) {
            //智慧医疗支付
            clientType = "UnionPay";

        } else {
            //支付宝支付
            clientType = "AlipayClient";
        }
        ZfOrderInfoDO zoi;
        String orderToken = payPageScaVo.getToken();
        if (!StringUtils.isEmpty(orderToken)) {
            orderToken = orderToken.replaceAll(" ", "+");
        }
        PayTokenUtil ttk = new PayTokenUtil(orderToken);
        if (!ttk.checkToken()) {
            model.addAttribute("retcode", "PYO209");
            model.addAttribute("retmsg", errCode.getShowMsg("PYO209"));
            return "h5/error";
        }
        zoi = zfOrderInfoService.getById(ttk.getOrderId());
        if (zoi == null) {
            model.addAttribute("retcode", "PYO219");
            model.addAttribute("retmsg", errCode.getShowMsg("PYO219"));
            return "h5/error";
        }
        if (DateUtils.getCurrentDateTime().after(zoi.getTradeTimeout())) {
            model.addAttribute("retcode", "PYO211");
            model.addAttribute("retmsg", errCode.getShowMsg("PYO211"));
            return "h5/error";
        }
        if (!zoi.getOrderPayStatus().equals(PayCodeConstants.ZF_ORDER_INFO_ORDER_PAY_STATUS.待支付.getDictValue()) ||
                !zoi.getOrderStatus().equals(PayCodeConstants.ZF_ORDER_INFO_ORDER_STATUS.待支付.getDictValue())) {
            model.addAttribute("retcode", "PYO221");
            model.addAttribute("retmsg", errCode.getShowMsg("PYO221"));
            return "h5/error";
        }
        if (!StringUtils.isBlank(payPageScaVo.getMerchId()) && !payPageScaVo.getMerchId().equals(zoi.getMerId())) {
            model.addAttribute("retcode", "PYO223");
            model.addAttribute("retmsg", errCode.getShowMsg("PYO223"));
            return "h5/error";
        }
      
        //支付流程处理
        PayOrderVo vo = new PayOrderVo();
        vo.setMerchId(zoi.getMerId());
        vo.setCommVer(zoi.getCommVer());
        vo.setToken(orderToken);
        vo.setOrderTime(DateUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
        vo.setOrderAmount(zoi.getOrderAmt().toString());
        vo.setOrderId(zoi.getPlatOrderId());
        if ("AlipayClient".equalsIgnoreCase(clientType)) {
           
            //支付宝自费下单
            AlipayWapPayResult result = extPayOrderService.setAliPayOrder(vo);
            if (!result.isSuccess()) {
                model.addAttribute("retcode", "PYP714");
                model.addAttribute("retmsg", errCode.getShowMsg("PYP714"));
                return "h5/error";
            }
            StringBuffer commitHtml = new StringBuffer();
            commitHtml.append("<html><head><meta charset=\"utf-8\"></head><body>").append(result.getFormData()).append("</body></html>");
            PrintWriter write = null;
            response.setCharacterEncoding("utf-8");
            try {
                write = response.getWriter();
                write.write(commitHtml.toString());
                write.flush();
            } catch (IOException e) {
                logger.error(e.getMessage());
                if (write != null) {
                    write.close();
                }
            }
            return null;
        } else if ("MicroMessenger".equalsIgnoreCase(clientType)) {
        //微信支付
        } else if ("UnionPay".equalsIgnoreCase(clientType)) {
            //银联支付
        }
        return null;
    }

下面这部分代码,是支付宝的预下单处理,支付宝预下单完成后,插入渠道支付记录到自己的支付平台。

public AlipayWapPayResult setAliPayOrder(PayOrderVo vo) {
        AlipayWapPayResult result = new AlipayWapPayResult();
        try {
            PayOrderVo payOrderVo = vo;
            JSONObject obj = JSONObject.parseObject(validPayOrder(payOrderVo)).getJSONObject("head");
            if (!obj.get("code").equals("0000")) {
                result.setSuccess(false);
                result.setErrorMsg(obj.get("msg").toString());
                return result;
            }
            PayTokenUtil p = new PayTokenUtil(payOrderVo.getToken());
            if (!p.checkToken()) {
                result.setSuccess(false);
                result.setErrorMsg("token校验失败");
                return result;
            }
            ZfOrderInfoDO orderInfoDO = zfOrderInfoService.getById(p.getOrderId());
            ZfAlipayWapPayReq req = new ZfAlipayWapPayReq();
            req.setOutTradeNo(orderInfoDO.getPlatOrderId());
            req.setSubject("预约挂号订单");
            req.setTotalAmount(orderInfoDO.getOrderAmt().toString());
            req.setTimeoutExpress("5m");
            req.setProductCode("QUICK_WAP_WAY");
            req.setNotifyUrl(Constant.getDomainUrl()+tyPubSysParamCacheClient.getParamValue("ALNOTIFY_URL",""));
            req.setReturnUrl(Constant.getDomainUrl()+tyPubSysParamCacheClient.getParamValue("RETURN_URL",""));
            result = zfAlipayService.wapPay(req);
            //添加订单渠道支付记录
            orderInfoDO.setChnPayId("ALIPAY");
            boolean b = InsertOrderChnPay(orderInfoDO);
            if(!b){
                logger.info("订单渠道支付记录增加失败");
            }
           return result;
        } catch (Exception e) {
            LogUtils.error(logger, "异常",e);
            result.setSuccess(false);
            result.setErrorMsg(e.getMessage());
            return result;
        }

预约下单成功后,支付宝会返回一个支付的form表单,直接将支付返回的form表单以html的形式输出到前端页面,然后前端页面点解支付按钮、输入支付密码就可以直接支付;支付完成后,支付宝会异步通知我们平台,平台接到通知后修改订单状态,修改渠道订单状态,然后平台会异步通知接入到我们平台的商户,告知该笔订单已经支付成功,最后返回“seccess”给支付宝,告知支付宝我们平台已经接收成功这笔订单的异步通知。下面是支付成功后异步回调的处理流程。

@RequestMapping("/alnotifyCall")
    @ResponseBody
    public String alnotifyCall(HttpServletRequest request, HttpServletResponse response) {
        try {
            return extNotfyCallService.alnotifyCall(request);
        } catch (Exception e) {
            LogUtils.error(logger, "支付宝异步回调异常", e);
            return "success";
        }
    }  
public String alnotifyCall(HttpServletRequest request) {
        try {
            //获取支付宝POST过来反馈信息
            Map<String, String> maps = new HashMap<String, String>();
            Map requestParams = request.getParameterMap();
            for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) {
                String name = (String) iter.next();
                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] + ",";
                }
                // 乱码解决,这段代码在出现乱码时使用。
                //valueStr = new String(valueStr.getBytes("ISO-8859-1"),"utf-8");\

                maps.put(name, valueStr);
            }
            logger.info("支付宝渠道通知参数集合:{}", maps.toString());
            // 调用SDK验证签名
            boolean signVerified = false;
            if (maps.get("app_id").equals("2016073000127980")) {
                //沙箱环境
                logger.info("########沙箱验签");
                signVerified = AlipayUtils.signatureWithRsaMock(request,false);
            } else if(maps.get("app_id").equals(tyPubSysParamCacheClient.getParamValue("ALI_PAY_MINI_APPID", ""))){
                //小程序验签
                logger.info("########小程序验签");
                signVerified = AlipayUtils.signatureWithRsaMini(request,false);
            } else {
                logger.info("########非沙箱验签");
                signVerified = AlipayUtils.signatureWithRsa(request,false);
            }
            logger.info("验签结果,{}"+signVerified);
           if (!signVerified) {
                logger.info("支付宝回调签名认证失败,signVerified=false, paramsJson:{}");
                return "failure";
            }
            logger.info("支付宝回调签名认证成功");
            logger.info("==================收到支付宝异步回调=======================");

            ZfOrderInfoDO orderInfo = zfOrderInfoService.getById(maps.get("out_trade_no"));
            if (null == orderInfo) {
                logger.info("支付结果通知订单:{}不存在", maps.get("out_trade_no"));
                return "success";
            }
            if(!StringUtils.isBlank(orderInfo.getOrderStatus()) &&
                    orderInfo.getOrderStatus().equals(ZF_ORDER_INFO_ORDER_STATUS.已支付.getDictValue())){
                logger.info("支付宝重复回调");
                return "success";
            }

            if (orderInfo.getOrderStatus().equals(ZF_ORDER_INFO_ORDER_STATUS.超时作废.getDictValue()) ||
                    orderInfo.getOrderStatus().equals(ZF_ORDER_INFO_ORDER_STATUS.关闭作废.getDictValue())) {
                return "success";
            }

            if(!StringUtils.isBlank(maps.get("trade_status")) &&
                    ("TRADE_CLOSED").equals(maps.get("trade_status"))){
                logger.info("支付宝退费回调{}",maps.toString());
                return "success";
            }
            if(!StringUtils.isBlank(maps.get("trade_status")) &&
                    ("WAIT_BUYER_PAY").equals(maps.get("trade_status"))){
                logger.info("等待用户支付:[{}]",maps.toString());
                return "success";
            }
            if(!StringUtils.isBlank(maps.get("trade_status")) &&
                    !("TRADE_SUCCESS").equals(maps.get("trade_status"))){
                logger.info("交易不成功:[{}]",maps.toString());
                return "success";
            }
            String time = DateUtils.format(maps.get("gmt_payment"), "yyyy-MM-dd HH:mm:ss", "yyyyMMddHHmmss");
            /** 更新支付平台表 **/
            orderInfo.setChnPayId("ALIPAY");
            String payAppid = tyPubSysParamCacheClient.getParamValue("ALIPAY_APPID","");
            if(maps.containsKey("buyer_id")){
                orderInfo.setPayUserId(maps.get("buyer_id"));
            }
            orderInfo.setPayAppid(payAppid);
            if(!StringUtils.isBlank(orderInfo.getOrderSource()) && orderInfo.getOrderSource().equals("2")){
                orderInfo.setPayWay(ZF_ORDER_INFO_PAY_WAY.支付宝H5.getDictValue());
            }else if(!StringUtils.isBlank(orderInfo.getOrderSource()) && orderInfo.getOrderSource().equals("3")){
                orderInfo.setPayWay(ZF_ORDER_INFO_PAY_WAY.支付宝APP.getDictValue());
            }else if(!StringUtils.isBlank(orderInfo.getOrderSource()) && "9".equals(orderInfo.getPayWay())){
                orderInfo.setPayWay(ZF_ORDER_INFO_PAY_WAY.支付宝免密支付.getDictValue());
            }else if(!StringUtils.isBlank(orderInfo.getOrderSource()) && orderInfo.getOrderSource().equals("7")){
                orderInfo.setPayWay(ZF_ORDER_INFO_PAY_WAY.支付宝小程序支付.getDictValue());
            } else{
                orderInfo.setPayWay(ZF_ORDER_INFO_PAY_WAY.支付宝当面付.getDictValue());
            }
            
            //自费支付金额 = 订单金额-医保支付金额
            orderInfo.setSelfPayAmt(orderInfo.getOrderAmt().subtract(orderInfo.getSiPayAmt()));
            UpdateOrderChnPay(orderInfo, time, maps.get("trade_no"));
          
            /** 回调业务平台 **/
            //这里根据自己的业务处理
            return "success";
        } catch (Exception e) {
            LogUtils.error(logger, "支付宝支付回调异常{}"+e.getMessage(),e);
            return "success";
        }
  }

由于支付宝H5支付、支付宝app、支付宝小程序、支付宝免密支付返回的报文都是一样的,我们平台把这几种支付宝的支付方式都集成了,所有在异步回调中会看到设置这几种的支付方式。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JAVA菜鸟程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值