支付宝对接文档

一、准备工作

1. 首先要到 蚂蚁金服开发者中心 https://openhome.alipay.com/platform/home.htm 注册商家账户,并认证。

2.下载java版的sdk和demo sdk&demo https://docs.open.alipay.com/270/106291/ 下载地址
3.将sdk加入到项目中,在项目根路径下新建libs文件夹,将jar包复制进去,我使用的是maven,用maven打包并上传到公司的jar包管理。

4.利用RSARSA签名验签工具生成公钥、私钥并保存。生成公钥放到如图应用公钥的位置 https://docs.open.alipay.com/291/105971/  。详细操作按照官网教程操作,很简单的,这里就不上图片了。

二、开发接口

1、因为开发环境是使用沙箱环境,上线后会使用真实环境,所以支付宝的一些参数我们放到配置文件里 pay-dev.properties appid和支付宝公钥上面图片中有,直接在网页上复制就好。

2、支付宝配置可以选择配置类也可以选择配置参数

#支付宝配置
#支付同步返回地址
ali_return_url =
#支付异步通知地址
ali_notify_url =
#产品码
product_no = FAST_INSTANT_TRADE_PAY
#超时时间
time_express = 15m
#支付网关
url = https://openapi.alipaydev.com/gateway.do
#商户号
appid = 2016091500519530
#私钥
private_key =
#公钥
ali_public_key =
#加密方式
sign_type = RSA2

3、开始编写写接口
这里支付宝要用的一些参数,我是通过@Value自动注入进来的,官方给的demo是,定义个AlipayConfig类,然后全部定义成静态变量,根据个人喜好问题选择,官方的demo中有,可以直接复制,然后修改为你自己的参数即可

注意:并非配置文件中写全部参数,具体参数设置可以参开官网参数列表

数据库操作:根据自己的业务需求,我这里是支付提交创建现金表,每次交互要记录支付过程产生的日志信息,我这里还需要创建交易日志表。

Param:

public class AlipayParam implements Param {

    @ApiModelProperty(value = "金额", required = true)
    @NotNull(message = "金额不能为空}")
    private String amount;     @ApiModelProperty(value = "订单名称", required = true)
    @NotNull(message = "订单名称 不能为空}")
    private String orderName;     @ApiModelProperty(value = "订单号", required = true)
    @NotNull(message = "订单号 不能为空}")
    private String orderId;
}
public class AlipayOrderParam implements Param {     private String out_trade_no;//商户订单号
    private String product_code;//销售产品码
    private String total_amount;//总金额
    private String subject;//订单标题
    private String timeout_express;//该笔订单允许的最晚付款时间,逾期将关闭交易
    private String passback_params;//公共校验参数
}

Controller:

public class AlipayController {
    @Resource
    private AlipayService alipayService;     //1.申请付款
    @ApiOperation("申请付款")
    @RequestMapping(value = "/order", method = RequestMethod.POST)
    public String alipay(@Valid AlipayParam alipayParam, BindingResult result) {
        return alipayService.alipay(alipayParam);
    }
    //2.a1lipay支持同步返回地址
    @ApiOperation("同步")
    @RequestMapping(value = "/getReturnUrlInfo",method = RequestMethod.GET)
    public String alipayReturnUrlInfo(HttpServletRequest request) {
     return alipayService.synchronous(request);
    }
    //3.alipay异步通知调用地址
    @ApiOperation("异步通知")
    @RequestMapping(value = "/getNotifyUrlInfo",method = RequestMethod.POST)
    public void alipayNotifyUrlInfo(HttpServletRequest request,HttpServletResponse response){
      alipayService.notify(request,response);
    }
}

Service:

/**
 * 付款
 * @param alipayParam 付款参数
 * @return 付款返回值
 */
String alipay(AlipayParam alipayParam); /**
 * 付款同步返回地址
 * @param request
 * @return
 */ String synchronous(HttpServletRequest request);
/**
 * 付款异步通知调用地址
 * @param request 新增参数
 * @return 新增返回值
 */
void notify(HttpServletRequest request,HttpServletResponse response);

ServiceImpl:

public class AlipayServiceImpl implements AlipayService {

    @Value("${ali_return_url}")
    private String ali_return_url;     @Value("${ali_notify_url}")
    private String ali_notify_url;     @Value("${product_no}")
    private String product_no;     @Value("${time_express}")
    private String time_express;     @Value("${url}")
    private String url;     @Value("${appid}")
    private String appid;     @Value("${private_key}")
    private String private_key;     @Value("${ali_public_key}")
    private String ali_public_key;     @Value("${sign_type}")
    private String sign_type;     @Resource
    private CashLogMapper cashLogMapper;     @Resource
    private CashMapper cashMapper;     @Resource
    private OrderMapper orderMapper;
    public static final String TRADE_SUCCESS = "TRADE_SUCCESS"; //支付成功标识
    public static final String TRADE_CLOSED = "TRADE_CLOSED";//交易关闭     @Override
    public String alipay(AlipayParam param) {
        // 从 session 中获取用户
        UserData userData = UserContext.getUserData();
        if (userData == null || userData.getUserId() == null) {
            return WebUtils.buildPage("登录失效, 请重新登录");
        }
        if (!BusinessTypeConstant.USER_CATEGORY_SELLER.equals(userData.getUserCategory())) {
            log.info("卖家用户才可以进行支付");
            return WebUtils.buildPage("卖家用户才可以进行支付");
        }
        // 订单已支付
        Cash cash = cashMapper.getCashByOrderId(param.getOrderId());
        if (cash != null && "3".equals(cash.getStatus())) {
            log.info("订单已支付");
            return WebUtils.buildPage("订单已支付");
        }
        String merchantOrderNo;
        Boolean isRetry = false;
        if (cash != null && new Date(System.currentTimeMillis() - 7800000).before(cash.getCreateTime())) {
            merchantOrderNo = cash.getMerchantOrderNo();
            isRetry = true;
        } else {
            merchantOrderNo = param.getOrderId() + new SimpleDateFormat("HHmmss").format(new Date());
        }
        String urlEncodeOrderNum = "";
        try {
            urlEncodeOrderNum = URLEncoder.encode(merchantOrderNo, "UTF-8");//公告参数订单号
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        //向支付宝发送支付请求
        AlipayClient alipayClient = new DefaultAlipayClient(url, appid
                , private_key, "json", "UTF-8"
                , ali_public_key, sign_type);
        //创建Alipay支付请求对象
        AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
        request.setReturnUrl(ali_return_url); //同步通知url
        request.setNotifyUrl(ali_notify_url);//异步通知url
        AlipayOrderParam alipayOrderParam = new AlipayOrderParam();
        alipayOrderParam.setOut_trade_no(merchantOrderNo);//唯一标识
        alipayOrderParam.setProduct_code(product_no);
        alipayOrderParam.setSubject(param.getOrderName());
        alipayOrderParam.setTotal_amount(param.getAmount());
        alipayOrderParam.setTimeout_express(time_express);
        alipayOrderParam.setPassback_params(urlEncodeOrderNum);
        request.setBizContent(JSON.toJSONString(alipayOrderParam));//设置参数
        String webForm = "";//输出页面的表单
        try {
            webForm = alipayClient.pageExecute(request).getBody(); //调用SDK生成表单
        } catch (Exception e) {
            log.info("支付请求发送失败");
            return WebUtils.buildPage("支付请求发送失败,请联系我们客服协助处理");
        }         // 记录下发起付款
        if (isRetry) {
            cashLogMapper.add(merchantOrderNo, "RETRY", JSON.toJSONString(alipayOrderParam), new Date());
        } else {
            cashLogMapper.add(merchantOrderNo, "ADD", JSON.toJSONString(alipayOrderParam), new Date());
        }
        // 创建一条支付状态记录
        cashMapper.add(param.getOrderId(), merchantOrderNo, new Date());
        return webForm;
    }     @Override
    public String synchronous(HttpServletRequest request) {         Map<String, String> parameters = new HashMap<>();
        Map<String, String[]> requestParams = request.getParameterMap();
        log.info("支付宝同步参数", requestParams);
        for (Map.Entry<String, String[]> entry : requestParams.entrySet()) {
            String key = entry.getKey();
            String[] values = entry.getValue();
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
            }
            parameters.put(key, valueStr);
        }
        //记录日志
        String merchantOrderNo = request.getParameter("out_trade_no");//商户订单号
            cashLogMapper.add(request.getParameter("out_trade_no"), "SYNCHRONOUS", JSON.toJSONString(parameters), new Date());
        return "<html>\n" +
                "<head>\n" +
                "<script type=\"text/javascript\"> function load() { window.close(); } </script>\n" +
                "</head>\n" +
                "<body onload=\"" +
                "load()\"> </body>\n" +
                "</html>";
    }     @Override
    public void notify(HttpServletRequest request, HttpServletResponse response) {
        //接收参数进行校验
        Map<String, String> parameters = new HashMap<>();
        Map<String, String[]> requestParams = request.getParameterMap();
        for (Map.Entry<String, String[]> entry : requestParams.entrySet()) {
            String key = entry.getKey();
            String[] values = entry.getValue();
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
            }
            parameters.put(key, valueStr);
        }
        log.info("parameters is [parameters={}]", parameters);
        String appId = request.getParameter("app_id");//appid
        String merchantOrderNo = request.getParameter("out_trade_no");//商户订单号         String orderId = cashMapper.getCashByMerchantOrderNo(merchantOrderNo).getOrderId();
        if (orderId == null) {
            log.error("orderId is null");
            ReturnData.fail(ReturnCode.SERVER_EXCEPTION);
        }
        log.info("orderId: {}", orderId);
        String payState = request.getParameter("trade_status");//交易状态
        String encodeOrderNum = null;
        cashLogMapper.add(request.getParameter("out_trade_no"), "NOTIFY", JSON.toJSONString(parameters), new Date());
        try {
            encodeOrderNum = URLDecoder.decode(request.getParameter("passback_params"), "UTF-8");
            log.info("encodeOrderNum is [encodeOrderNum={}]", encodeOrderNum);             boolean signVerified;
            signVerified = AlipaySignature.rsaCheckV1(parameters, ali_public_key, "UTF-8", sign_type);//验证签名
            log.info("signVerified is [signVerified={}]", signVerified);
            if (signVerified) { //通过验证
                log.info("payState: {}", payState);
                if (payState.equals(TRADE_SUCCESS)) {
                    //判断订单号与插入的订单号是否一样
                    if (merchantOrderNo.equals(encodeOrderNum) == false || appid.equals(appId) == false) {
                        log.info("vali failure");
                        cashMapper.update(merchantOrderNo, 4);                         response.getOutputStream().print("failure");
                        return;
                    }
                    cashMapper.update(merchantOrderNo, 3);
                    orderMapper.afterPay(orderId
                    );
                    response.getOutputStream().print("success");
                    return;
                } else if (payState.equals(TRADE_CLOSED)) { //交易关闭
                    cashMapper.update(merchantOrderNo, 7);
                } else {
                    cashMapper.update(merchantOrderNo, 4);
                    response.getOutputStream().print("failure");
                    return;
                }
            } else {
                //签名校验失败更状态
                cashMapper.update(merchantOrderNo, 4);
                response.getOutputStream().print("failure");
                return;
            }
            log.info("encodeOrderNum is  [encodeOrderNum={}]", encodeOrderNum);
            cashMapper.update(merchantOrderNo, 4);
            response.getOutputStream().print("failure");
            return;
        } catch (AlipayApiException e) {
            log.error(e.getErrMsg());
            throw new RuntimeException("调用支付宝接口发生异常");
        } catch (UnsupportedEncodingException e) {
            log.error(e.getMessage());
            throw new RuntimeException("URLDecoderf发生异常");
        } catch (IOException e) {
            log.error(e.getMessage());
            throw new RuntimeException("IO发生异常");
        }     }
}

总结:与支付宝对接,本地生成订单进行提交到支付宝同步处理完支付,支付宝会通过异步来获取用户给支付宝反馈的信息会最终确定是否支付成功,在开发过程中注意支付确认(异步)的逻辑处理即可,具体返回参数可以参开

4、进行沙箱环境的测试

访问接口地址 项目地址/alipay/pay 我的是 127.0.0.1/alipay/pay/order

如果后台没有报错的话,他会自动重定向到,支付宝的付款页面,如下图所示。这时候我们下载安装沙箱版的app,然后使用官方提供的账户扫描然后直接付款,付款成功后会回调后面那两个接口,在通知的那个接口里处理你的业务逻辑。查看沙箱app的登录帐户名和密码.

总结:沙箱环境每个人都可以开通支付账户并可以查看相应的买家和商家的账号,商家用户需要公司走相关流程大致一周多的时间。

springboot项目对接支付宝支付的更多相关文章

  1. Python对接支付宝支付自实现

    Python对接支付宝支付自实现 # -*- coding: utf-8 -*- import base64 import json import urllib.parse from datetime ...

  2. Django 对接 支付宝支付, 回调

    平台 点击这里进入 蚂蚁金服开放平台 沙箱 点击这里进入 沙箱环境 初始界面 设置公钥 下载创建秘钥工具 1.  进入文档中心 这里 2. 选中 电脑网站支付 3. 进入后选中 API 列表 中的 统 ...

  3. tp5对接支付宝支付简单集成

    对于每个刚开始工作的新手来说,无论支付宝支付还是微信支付都是跑不掉的一个小门槛. 在加上本人比较技术比较渣(比较懒导致的),不太喜欢引用那么大的SDK,于是就简单集成了一下支付宝的支付. 但也只是只有 ...

  4. SpringBoot中实现支付宝支付

    本文只介绍当面付(扫码支付)和APP支付 一. 接入准备 #这里分两种情况,正式环境和沙箱环境,本文使用沙箱环境 1.进入支付宝开放平台,创建应用 登录 支付宝开放平台,创建应用并提交审核,审核通过后 ...

  5. DUMP4 企业级电商项目 —— 对接支付宝扫码支付

    延展 <谈谈微信支付曝出的漏洞> [联调 DEMO下载地址]https://docs.open.alipay.com/194/105201/ [内置 一份 说明文档可做参考] [impor ...

  6. Thinkcmf对接支付宝支付和获取用户信息

    一.         登录支付宝开放平台 平台地址:https://open.alipay.com/ 二.         创建应用并申请上线 登录后,[进入我的开放平台],依次点击[开发者中心]-& ...

  7. PHP对接微信支付采坑

    第一次做PHP商城项目对接微信支付接口,踩了N次坑,这也不对,那也不对,搞了很久,查了一些资料,终于实现了支付功能,小小总结一下,万一下次遇到就不用到处找资料了. 微信扫码支付 前期准备: 1.微信公 ...

  8. Django对接支付宝Alipay支付接口

    最新博客更新见我的个人主页: https://xzajyjs.cn 我们在使用Django构建网站时常需要对接第三方支付平台的支付接口,这里就以支付宝为例(其他平台大同小异),使用支付宝开放平台的沙箱 ...

  9. App对接支付宝移动支付功能

    前段时间看了下app对接支付宝移动支付的功能,并自己总结了下支付宝移动支付的实现流程 一.申请流程          前提是已有现成的应用. 1.  申请地址            https://b ...

随机推荐

  1. 使用qt creator来编译 调试 用CMakeLists组织的工程

                                                   爱情原如树叶一样,在人忽视里绿了,在忍耐里露出蓓蕾. -- 何其芳 使用CMake作为构建系统,需要自己写 ...

  2. use selenium+chromedriver to taobao automatically

    原理 利用chromedriver来驱动chrome进行各种模拟各种行为操作, 然后利用selenium提供的接口来操作chromedriver. 安装ChromeDriver 当然这个的默认前提是你 ...

  3. HTTP_HOST , SERVER_NAME 区别

    当端口是80的时候,他们的内容是一样的. 但是当端口不是80的时候,就不一样了. # HTTP_HOST = SERVER_NAME:SERVER_PORT /** * 获取当前的host */ pu ...

  4. LeetCode 230. 二叉搜索树中第K小的元素(Kth Smallest Element in a BST)

    230. 二叉搜索树中第K小的元素 230. Kth Smallest Element in a BST 题目描述 给定一个二叉搜索树,编写一个函数 kthSmallest 来查找其中第 k 个最小的 ...

  5. WiFi、ZigBee、BLE用哪个?

    小米是这么选的: 1) 插电的设备,用WiFi: 2) 需要和手机交互的,用BLE: 3) 传感器用ZigBee. WIFI,WIFI是目前应用最广泛的无线通信技术,传输距离在100-300M,速率可 ...

  6. Java基础笔试练习(二)

    1. HashMap的数据结构是怎样的? A.数组 B.链表 C.数组+链表 D.二叉树 答案: C 解析: JDK8以后,HashMap的数据结构是数组+链表+红黑树 2. 在 JAVA 编程中,J ...

  7. MYSQL 八大优化方案

    1.选取最适用的字段属性 ​ MySQL可以很好的支持大数据量的存取,但是一般说来,数据库中的表越小,在它上面执行的查询也就会越快.因此,在创建表的时候,为了获得更好的性能,我们可以将表中字段的宽度设 ...

  8. struts下载文件错误,想不明白为什么更改变量名就不报错了

    java.lang.IllegalArgumentException: Can not find a java.io.InputStream with the name [is] in the inv ...

  9. 八皇后问题——列出所有的解,可推至N皇后

    <数据结构>--邓俊辉版本 读书笔记 今天学习了回溯法,有两道习题,一道N皇后,一道迷宫寻径.今天,先解决N皇后问题.由于笔者 擅长java,所以用java重现了八皇后问题. 注意是jav ...

  10. smarty中常用的流程控制逻辑

    if else {if $age > 18} <div>年满十八岁!</div> {else if $age > 16} <div>年满十六岁!< ...