支付宝APP支付 ---服务器开发

写过微信支付再写支付宝支付就好理解了很多。而且支付宝提供的sdk很好用,几行代码就可以了~~,写的代码还没有测试,应该问题不大,如果有错误希望各位指正。

开发之前必要的配置请参考支付宝APP支付官方文档

对几个容易混淆的参数进行说明:
1. 应用私钥: 通过工具生成,生成之后请保存好,在支付宝开发平台找不到。
2. 应用公钥:通过工具生成,生成之后需要填写到支付宝开发平台中。
3. 支付宝公钥:支付宝生成的,可以在支付宝开发平台中看到。
如果对非对称加密算法很熟悉的应该很好理解这几个参数。

这个图是APP支付的一个流程说明,图画的比较详细就不再叙述了。
这里写图片描述
开始写代码,因为我只帮别人写一部分,所以只完成工具类,具体controller没有,下面是参数封装的工具类。

    /**
     * 请求参数组装
     * 
     * @param outTradeNo  商户网站唯一订单号
     * @param totalAmount  订单总金额,单位为元,精确到小数点后两位,取值范围[0.01,100000000]
     * @param subject  商品的标题/交易标题/订单标题/订单关键字等。
     * @param notifyUrl  回调地址
     * @throws UnsupportedEncodingException 
     */
    public static Map<String, String> setParam(String outTradeNo, String totalAmount, String subject,
            String notifyUrl) throws UnsupportedEncodingException {
        Map<String, String> map = new HashMap<String, String>();
        map.put("app_id", Config.APP_ID);
        map.put("method", Config.PAY_METHOD);
        map.put("charset", Config.CHARSET);
        map.put("sign_type", Config.SIGN_TYPE);
        map.put("timestamp", Config.geTtimestamp());
        map.put("version", "1.0");
        map.put("notify_url", notifyUrl);
        // 业务请求参数封装
        Map<String, Object> biz_content = new HashMap<>();
        biz_content.put("subject", URLEncoder.encode(subject, "UTF-8"));
        biz_content.put("out_trade_no", outTradeNo);
        biz_content.put("total_amount", totalAmount);
        biz_content.put("product_code", "QUICK_MSECURITY_PAY");
        map.put("biz_content", biz_content.toString());
        String sign = null;
        try {
            //调用支付宝SDK获取签名 RSA签名params 待签名参数map privateKey 私钥 charset 签名编码格式
            sign = AlipaySignature.rsaSign(map, Config.APP_PRIVATE_KEY, Config.CHARSET);
        } catch (AlipayApiException e) {
            e.printStackTrace();
            System.out.println(e.getMessage());
            logger.error("======签名错误=====" + e.getMessage());
        }
        map.put("sign", URLEncoder.encode(sign, "UTF-8"));
        return map;
    }

注意(很重要)

  • 商户在请求参数中,自己附属的一些额外参数,不要和支付宝系统中约定的key(下表中 公共请求参数\请求参数)重名,否则将可能导致未知的异常。需要对内容进行encode编码处理。
    商户支付请求参数的安全注意点:
  • 请求参数的sign字段请务必在服务端完成签名生成(不要在客户端本地签名);
  • 支付请求中的订单金额total_amount,请务必依赖服务端,不要轻信客户端上行的数据(客户端本地上行数据在用户手机环境中无法确保一定安全)。

服务器接收异步支付通知
对于App支付产生的交易,支付宝会根据原始支付API中传入的异步通知地址notify_url,通过POST请求的形式将支付结果作为参数通知到商户系统。
另外需要注意的:
1.必须保证服务器异步通知页面(notify_url)上无任何字符,如空格、HTML标签、开发系统自带抛出的异常提示信息等,
2.程序执行完后必须打印输出“success”(不包含引号)。如果商户反馈给支付宝的字符不是success这7个字符,支付宝服务器会不断重发通知,直到超过24小时22分钟。

在收到支付宝的通知时需要进行验签和业务处理,验签支付宝的SDK也提供了 ,是不是很方便,

    /**
     * 验签
     * 校验支付宝发过来的签名是否正确,使用支付宝的公钥验签
     * @param request
     * @return true 验签通过
     */
    public static boolean signVerified(HttpServletRequest request) {
        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, Config.ALIPAY_PUBLIC_KEY, Config.CHARSET); // 校验签名是否正确
            return signVerified;
        } catch (Exception e) {
            logger.error("============验签错误=============" + e.getMessage());
            System.out.println(e.getMessage());
            return false;
        }
    }

回调的controller 只写了一部分,仅供参考


    @RequestMapping(value = "/pay/notify", method = RequestMethod.POST)
    public void orderPayNotify(HttpServletRequest request, HttpServletResponse response) {
        logger.info("==============收到支付宝的异步通知==========================");
        // 获取到返回的所有参数 先判断是否交易成功trade_status 再做签名校验
        if ("TRADE_SUCCESS".equals(request.getParameter("trade_status"))) {
            try {
                boolean signVerified = PayUtils.signVerified(request);
                if (signVerified) {
                    //  验签成功后
                    // 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时,支付宝才会认定为买家付款成功。
                    // 对支付结果中的业务内容进行1\2\3\4二次校验,校验成功后在response中返回success,
                    logger.info("=====订单支付成功:====" + request.getParameterMap().toString()); 
                    //通知支付宝后台,已收到通知
                    response.getWriter().println("success");
                } else {
                    // TODO 验签失败则记录异常日志,
                    logger.info("======验签失败=======");
                }
            } catch (Exception e) {
                e.printStackTrace();
                logger.info("========通知处理失败=========="+e.getMessage());
            }
        }else{
            logger.info("========交易失败==========");
        }
     }

服务器写好了 ~

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值