支付宝对接文档

一、准备工作

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. shrio学习笔记

    Thymeleaf扩展坐标 <!--thyemleaf对shrio的扩展坐标--> <dependency> <groupId>com.github.thebora ...

  2. CSS3 实现别样图型

    1.爱心 利用 div 的正方形和伪类的圆型组合而成 <!DOCTYPE html> <html> <head> <meta charset="UT ...

  3. Python——多态、检查类型

    一.多态 Python变量并不需要声明类型,同一个变量可以在不同的时间引用不同的对象,当一个变量在调用同一个方法,可以呈现出多种行为,而具体呈现出哪种行为由该变量引用的对象来决定,这就是多态. 先看一 ...

  4. PAT(B) 1034 有理数四则运算(Java)

    题目链接:1034 有理数四则运算 (20 point(s)) 题目描述 本题要求编写程序,计算 2 个有理数的和.差.积.商. 输入格式 输入在一行中按照 a1/b1 a2/b2 的格式给出两个分数 ...

  5. Ubuntu中更改默认的root用户密码,以及怎样修改用户密码

    新安装的Ubuntu系统中默认的root用户密码是多少?该怎么修改? 如题,相信许多刚接触Ubuntu系统的新手大多会遇到这个问题,那么我们该如何解决这个问题呢?Ubuntu在安装过程中并没有让我们设 ...

  6. Mongodb命令行导入导出数据

    第一步,找到mongodb安装目录第二步,从命令行进入mongodb安装目录下的bin目录第三步(1),导出数据命令(导出的文件有两种格式:json/csv,此处导出的是json文件,对于导出CSV文 ...

  7. ZooKeeper学习笔记(四)——shell客户端命令操作

    ZooKeeper客户端命令行操作 启动服务端 [simon@hadoop102 zookeeper-3.4.10]$ bin/zkServer.sh start 查看状态信息 Using confi ...

  8. python多线程爬取斗图啦数据

    python多线程爬取斗图啦网的表情数据 使用到的技术点 requests请求库 re 正则表达式 pyquery解析库,python实现的jquery threading 线程 queue 队列 ' ...

  9. Python初识面向对象

    初识面向对象 面向过程 VS 面向对象 面向过程的圣墟设计的核心是过程(流水线式思维),过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西 优点是:极大的降低 ...

  10. 【转载】 C#中使用Count方法获取List集合中符合条件的个数

    很多时候操作List集合的过程中,我们需要根据特定的查询条件,获取List集合中有多少个实体对象符合查询条件,例如一批产品的对象List集合,如果这批产品的不合格数量大于10则重点备注.在C#中可以自 ...