第三方支付——支付宝web端支付(java)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sinat_19671783/article/details/79299879

这段时间把支付基本搞完了,因为做的过程中遇到许多问题,特地记录下来,同时方便其他java coder,废话少说,下面开始。

整体思路:在后台,根据参数创建支付宝客户端AlipayClient,发送参数到支付宝,支付宝直接返回一个表单,我们只需要将表单输出到页面上,后续支付宝异步通知,比较重要是验签,支付宝也提供的工具,比较方便。

(jar包或maven的引入这里省略)

1、申请支付宝支付,这里大家自己研究,网上很多教程。

2、创建支付

/**
 * 调用支付宝支付alipay.trade.page.pay
 * 商户系统请求支付宝接口alipay.trade.page.pay,支付宝对商户请求参数进行校验,而后重定向至用户登录页面。
 *
 * @param model
 * @return
 * @throws Exception
 */
public String createAlipay(Model model, String order_no, BigDecimal amount, Integer resource_trad_id, String trad_type, HttpServletResponse response) throws Exception {
    String form = "";
    User user = (User) model.asMap().get("user");
    //生成一笔预付订单流水
    String trad_no = "PC_ALIPAY" + OrderNoUtil.leadsNo();//订单流水号
    ShareUserTrad trad = new ShareUserTrad();
    trad.setResourceTradId(resource_trad_id);
    trad.setUserId(user.getId());
    trad.setCreatedBy(user.getId());
    trad.setLastUpdBy(user.getId());
    trad.setOnlineOfflineFlag("0");//线上
    trad.setOrderNo(order_no);
    trad.setUserTradAmount(amount);
    trad.setTradMethod("3");//支付宝
    trad.setPayReceiveFlag("2");//支出
    trad.setSuccessFlag("0");//交易进行中
    trad.setTradType("1");//订单支付
    trad.setTradNo(trad_no);
    trad.setModifyNum(0);
    shareUserTradMapper.insertSelective(trad);
    try {
        //初始化客户端
        AlipayClient alipayClient = new DefaultAlipayClient(Config.alipay_url, Config.alipay_appid, Config.alipay_app_private_key, Config.alipay_format, Config.alipay_charset, Config.alipay_app_public_key, Config.alipay_sign_type);
        //创建API对应的request
        AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
        alipayRequest.setReturnUrl("");//回退到订单列表页面
        alipayRequest.setNotifyUrl("");//在公共参数中设置回跳和通知地址
        alipayRequest.setBizContent("{" +
                "    \"out_trade_no\":\"" + trad_no + "\"," +
                "    \"product_code\":\"FAST_INSTANT_TRADE_PAY\"," +
                //"    \"total_amount\":" + amount.toString() + "," +
                "\"total_amount\":\"0.01\"," +
                "    \"subject\":\"订单支付\"," +
                "    \"body\":\"订单:" + order_no + "支付\"," +
                "    \"passback_params\":\"" + order_no + "\"" +
                "  }");//填充业务参数
        form = alipayClient.pageExecute(alipayRequest).getBody(); //调用SDK生成表单
    } catch (Exception e) {
        e.printStackTrace();
        String sOut = "";
        StackTraceElement[] trace = e.getStackTrace();
        for (StackTraceElement s : trace) {
            sOut += "\tat " + s + "\r\n";
        }
        model.addAttribute("failMsg", sOut + "alipay_url:" + Config.alipay_url);
        return "/pay/payFail";
    }
    response.setContentType("text/html;charset=" + Config.alipay_charset);
    response.getWriter().write(form);//直接将完整的表单html输出到页面
    response.getWriter().flush();
    response.getWriter().close();
    return null;
}

这里注意几点:

        ①上面那个创建预付订单流水,主要用于后面支付宝异步通知,订单流水号需要传给支付宝,这样支付宝回调通知的时候,会把这个参数传回来。

        ②

alipayRequest.setReturnUrl("");//回退到订单列表页面

这个地址为用户扫码成功后,支付宝会在五秒后从支付页面跳转到的页面。

        ③

alipayRequest.setNotifyUrl("");//在公共参数中设置回跳和通知地址

这个地址为支付宝支付异步通知的地址。这个地址必须要是外网可访问的,如果大家在本地测试,需要把本机映射到外网上去,这里推荐大家使用ngrok,注册后是可以免费使用的。

上面两个地址出于隐私考虑我这里是空的,大家要加上。

3、支付宝异步通知

/**
 * 接受支付宝异步通知
 */
@RequestMapping(value = "/notify", method = RequestMethod.POST)
@Transactional(readOnly = false)
public void alipayNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
    Map<String, String> map = 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] + ",";
        }
        //乱码解决,这段代码在出现乱码时使用。如果mysignsign不相等也可以使用这段代码转化
        //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "gbk");
        map.put(name, valueStr);
    }
    System.out.println("支付结果---" + map.toString());
    //调用SDK验证签名
    boolean signVerified = false;
    try {
        signVerified = AlipaySignature.rsaCheckV1(map, Config.alipay_app_public_key, Config.alipay_charset, Config.alipay_sign_type);
    } catch (Exception e) {
        e.printStackTrace();
    }
    if (signVerified) {
        System.out.println("支付结果---" + map.toString());
        String trad_no = map.get("out_trade_no");
        //根据交易流水号查询交易信息
        if ("TRADE_SUCCESS".equals(map.get("trade_status"))) {//交易成功
            DealUserTradModel dealUserTradModel = new DealUserTradModel();
            dealUserTradModel.setUser_account_name("");
            dealUserTradModel.setUser_account(map.get("buyer_id"));
            dealUserTradModel.setTrad_no(trad_no);
            dealUserTradModel.setPay_amount(new BigDecimal(map.get("total_amount")));
            dealUserTradModel.setCompany_amount(new BigDecimal(map.get("receipt_amount")));
            dealUserTradModel.setOut_trad_no(map.get("trade_no"));
            payService.dealTrad(dealUserTradModel);
        }
        try {
            PrintWriter out = response.getWriter();
            out.print("success");
            out.flush();
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        // TODO 验签成功后,按照支付结果异步通知中的描述,对支付结果中的业务内容进行二次校验,校验成功后在response中返回success并继续商户自身业务处理,校验失败返回failure
    } else {
        // TODO 验签失败则记录异常日志,并在response中返回failure.
        try {
            PrintWriter out = response.getWriter();
            out.print("failure");
            out.flush();
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

收到通知,将交易流水的状态更新就可以了,这里用到支付宝回传的交易流水号。

4、几个参数

Config.alipay_url

这个参数是支付宝API地址,如果大家是在沙箱上面测试,则地址为:https://openapi.alipaydev.com/gateway.do,如果是正式环境,为:https://openapi.alipay.com/gateway.do.

Config.alipay_appid

这个参数是支付宝分配的APP ID,如果是沙箱环境,则在https://openhome.alipay.com/platform/appDaily.htm?tab=info这里看:


如果是正式环境,则在蚂蚁金服开方平台-->开发者中心-->网页&移动应用,选择应用点查看,左上角的icon旁边.

Config.alipay_app_public_key


这个参数是支付宝公钥,如果是沙箱环境,在这里看:


正式环境,地方跟上面的差不多。

Config.alipay_charset

这个参数是编码格式,推荐跟你的项目编码一致。

Config.alipay_sign_type

这个参数是签名类型,推荐使用RSA2。

Config.alipay_app_private_key

这个参数是你的应用私钥,用支付宝提供的秘钥生成工具生成的应用私钥。

Config.alipay_format

这个参数就是字符串json。

猜你喜欢

转载自blog.csdn.net/sinat_19671783/article/details/79299879