支付宝沙箱环境的坑

首先这是一个好东西,不需要商家认证那些,开发者可以直接整代码并且效果和实际上线效果是一样的。是一些技术研究者的福音。

好了如题,直接上步骤,百度也是遇到了不少坑。

1、首先登陆支付宝https://open.alipay.com

使用扫一扫登陆,然后选择沙箱环境

 

2、填写一些相关的信息就会进入沙箱应用里面,先别急找参数,先生成公匙和私匙。点击里面的生成方法,会下载一个文件。里面有使用说明。

  用里面的方法生成公匙后点击查看应用公匙(RSA2)把生成的公匙填进去。支付宝应用公匙就会自动生成。官方是推荐使用2048位的。

  生成的私匙也要保存,但是不用填写在该页面。下面的密匙应用不用管它。

3、提取相关应用参数:注意这个支付宝公匙不是你刚才填写的那个,是旁边系统自动生成的那一个。

 

 

 

4、根据这些参数提取到java应用程序中。我上面的图片是另一个项目的参考,所以回调地址与下面的参数不一致。实际应用中回调地址是要一致的。

在此改正:这是官方文档说明。也就是应用网关 和回调地址 沙箱测试不用设置。避免误导大家,本地部署项目并测试沙箱支付的就不用设置这两个值了,因为这两个值必须保证外网能访问。

因此本地项目测试支付能成功 但是回调不能成功也就没什么好纠结的了。然而我支付宝沙箱页面没设置,只是项目中设置了上面的同步和异步地址还是回调成功了!

  • 应用网关:该地址用于接收开放平台的异步通知。目前沙箱环境不需要配置此参数;
  • 授权回调地址;第三方应用授权或获取用户信息中用于接收授权回调信息的地址。使用相关产品时再进行配置;

         1. 第三方应用授权:

             授权url中的redirect_uri必须与此值相同。

         2. 获取用户信息:

             授权url中的redirect_uri的域名必须与此值相同。(例如:授权回调地址配置:https://auth.example.com/authCallBack 高亮部分需和授权url相同)

  • RSA(SHA1)密钥:目前推荐使用RSA2(SHA256)密钥,请参考第1步进行配置;
  • AES密钥:目前不再使用;

 

5、继续下一步,下载沙箱钱包。不过有点坑,我用手机扫一扫没能下载,是在电脑端下载了再安装到手机上的。

6、下载安装了沙箱钱包。还要解决登录账号的问题,这点支付宝都没有直接说明有点奇葩。

https://openhome.alipay.com/platform/appDaily.htm?tab=account

进这个地址,支付宝扫一扫就有了,使用下面的账号登录测试支付就好了

7、测试成功

 

支付宝沙箱环境还有一个很大的功能,那就是余额,你的沙箱支付宝余额几百万。

你把这余额给老丈人、小妹妹一看,瞬间被你征服啊。真是程序员泡妞把妹的神器啊,哈哈哈!

 

下面把支付宝支付的代码贴一下,萌新可以看看,也就是两个类。有时候失败可能是沙箱设置的参数和项目不一致,公私匙。因为实际线上环境就有重新生成公私匙解决了问题的例子。

配置文件类AlipayConfig,这个自己换成沙箱支付的请求网关:https://openapi.alipaydev.com/gateway.do

package com.sanyi.qibaobusiness.framework.payment.ali.config;

public class AlipayConfig {
    //发起请求的应用ID。沙箱与线上不同,请更换代码中配置;
    public static String app_id ="";
    //支付宝私匙
    public static String merchant_private_key = "";
    //支付宝公匙
    public static String alipay_public_key = "";
    //服务器异步通知路径
    public static String notify_url = "http://127.0.01/alipay/alipayNotifyNotice.action";
    //服务器同步通知路径
    public static String return_url = "http://127.0.0.1/alipay/alipayReturnNotice.action";
    //公匙类型/签名类型
    public static String sign_type = "RSA2";
    //编码格式
    public static String charset = "utf-8";
    //向支付宝发起请求的网关。沙箱与线上不同,请更换代码中配置;沙箱:https://openapi.alipaydev.com/gateway.do上线https://openapi.alipay.com/gateway.do
    public static String gatewayUrl = "https://openapi.alipay.com/gateway.do";
}
View Code
AlipayController发起支付请求的类
package com.sanyi.qibaobusiness.framework.payment.ali.controller;


import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradePagePayRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * 阿里支付
 */
@Controller
@RequestMapping("/alipay")
public class AlipayController {

    final static Logger log = LoggerFactory.getLogger(AlipayController.class);

    @Resource
    private RentingtoolsBiz rentingtoolsBiz; //暂时只有出租工具的订单在这里支付
    @Resource
    private CustomerOrderBiz customerOrderBiz;
    @Resource
    private BrowseRecordsCommonUtil browseRecordsCommonUtil;

    /**
     * 前往支付宝第三方网关进行支付
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/goAlipay", produces = "text/html; charset=UTF-8")
    @ResponseBody
    public String goAlipay( HttpServletRequest request, HttpServletRequest response) throws Exception {
        BrowseRecordsUtil browseRecordsUtil= browseRecordsCommonUtil.getBrowseRecords(request);
        Order order=browseRecordsUtil.getPayOrder();
        //获得初始化的AlipayClient
        AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.gatewayUrl, AlipayConfig.app_id, AlipayConfig.merchant_private_key, "json", AlipayConfig.charset, AlipayConfig.alipay_public_key, AlipayConfig.sign_type);

        //设置请求参数
        AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
        alipayRequest.setReturnUrl(AlipayConfig.return_url);
        alipayRequest.setNotifyUrl(AlipayConfig.notify_url);

        String out_trade_no =null;
        //付款金额,必填
        String total_amount = null;
        //订单名称,必填
        String subject = null;
        //商品描述,可空
        String body = null;
        // 该笔订单允许的最晚付款时间,逾期将关闭交易。取值范围:1m~15d。m-分钟,h-小时,d-天,1c-当天(1c-当天的情况下,无论交易何时创建,都在0点关闭)。 该参数数值不接受小数点, 如 1.5h,可转换为 90m。
        String timeout_express = "1c";
        if(null!=total_amount){ //支付金额不等于空
            alipayRequest.setBizContent("{\"out_trade_no\":\""+ out_trade_no +"\","
                    + "\"total_amount\":\""+ total_amount +"\","
                    + "\"subject\":\""+ subject +"\","
                    + "\"body\":\""+ body +"\","
                    + "\"timeout_express\":\""+ timeout_express +"\","
                    + "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");

            //请求
            String result = alipayClient.pageExecute(alipayRequest).getBody();
            return result;
        }
        return "订单信息错误!";
    }

    /**
     * 支付宝同步通知页面,成功返回首页
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/alipayReturnNotice")
    public String alipayReturnNotice(Model model,HttpServletRequest request, HttpServletRequest response) throws Exception {

        log.info("支付成功, 进入同步通知接口...");

        //获取支付宝GET过来反馈信息
        Map<String,String> params = new HashMap<String,String>();
        Map<String,String[]> requestParams = request.getParameterMap();
        for (Iterator<String> 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");
            params.put(name, valueStr);
        }
        boolean signVerified = AlipaySignature.rsaCheckV1(params, AlipayConfig.alipay_public_key, AlipayConfig.charset, AlipayConfig.sign_type); //调用SDK验证签名
        //——请在这里编写您的程序(以下代码仅作参考)——
        if(signVerified) {
            //商户订单号
            String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"),"UTF-8");

            //支付宝交易号
            String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"),"UTF-8");

            //付款金额,这里获取到三个参数就可以了,后面逻辑代码自己创作
            String total_amount = new String(request.getParameter("total_amount").getBytes("ISO-8859-1"),"UTF-8");

            int result=0;
            //这里根据自身的业务写代码,我这里删掉了
            
            if(result==0){
                model.addAttribute("resultinfo","更新订单失败!请业务员联系后台管理员!");
            }else {
                model.addAttribute("resultinfo","出租工具成功!");
            }
            log.info("********************** 支付成功(支付宝同步通知) **********************");
            log.info("* 订单号: {}", out_trade_no);
            log.info("* 支付宝交易号: {}", trade_no);
            log.info("* 实付金额: {}", total_amount);
            log.info("***************************************************************");
        }else {
            log.info("支付, 验签失败...");
        }
        return "/business/index";//成功返回首页
    }

    /**
     * 支付宝异步 通知页面
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/alipayNotifyNotice")
    @ResponseBody
    public String alipayNotifyNotice(HttpServletRequest request, HttpServletRequest response) throws Exception {

        log.info("支付成功, 进入异步通知接口...");

        //获取支付宝POST过来反馈信息
        Map<String,String> params = new HashMap<String,String>();
        Map<String,String[]> requestParams = request.getParameterMap();
        for (Iterator<String> 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");
            params.put(name, valueStr);
        }
        boolean signVerified = AlipaySignature.rsaCheckV1(params, AlipayConfig.alipay_public_key, AlipayConfig.charset, AlipayConfig.sign_type); //调用SDK验证签名
        //——请在这里编写您的程序(以下代码仅作参考)——
        /* 实际验证过程建议商户务必添加以下校验:
        1、需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号,
        2、判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额),
        3、校验通知中的seller_id(或者seller_email) 是否为out_trade_no这笔单据的对应的操作方(有的时候,一个商户可能有多个seller_id/seller_email)
        4、验证app_id是否为该商户本身。
        */
        if(signVerified) {//验证成功
            //商户订单号
            String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"),"UTF-8");

            //支付宝交易号
            String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"),"UTF-8");

            //交易状态
            String trade_status = new String(request.getParameter("trade_status").getBytes("ISO-8859-1"),"UTF-8");

            //付款金额 到这里获取到这些信息就可以了,下面的不用看
            String total_amount = new String(request.getParameter("total_amount").getBytes("ISO-8859-1"),"UTF-8");

            if(trade_status.equals("TRADE_FINISHED")){
                //判断该笔订单是否在商户网站中已经做过处理
                //如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
                //如果有做过处理,不执行商户的业务程序

                //注意: 尚自习的订单没有退款功能, 这个条件判断是进不来的, 所以此处不必写代码
                //退款日期超过可退款期限后(如三个月可退款),支付宝系统发送该交易状态通知
            }else if (trade_status.equals("TRADE_SUCCESS")){
                //判断该笔订单是否在商户网站中已经做过处理
                //如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
                //如果有做过处理,不执行商户的业务程序

                //注意:
                //付款完成后,支付宝系统发送该交易状态通知

                int result=0;
                //这里根据自身的业务写代码,我这里删掉了
                
                if(result==0){
                    log.info("resultinfo","更新订单失败!请业务员联系后台管理员!");
                }else {
                    log.info("resultinfo","出租工具成功!");
                }

                log.info("********************** 支付成功(支付宝同步通知) **********************");
                log.info("* 订单号: {}", out_trade_no);
                log.info("* 支付宝交易号: {}", trade_no);
                log.info("* 实付金额: {}", total_amount);
                log.info("***************************************************************");
            }
            log.info("支付成功...");
        }else {//验证失败
            log.info("支付, 验签失败...");
        }
        return "success";
    }

}
View Code

 

posted @ 2019-01-08 11:28  别动我的猫  阅读(50167)  评论(10编辑  收藏  举报