支付宝对接文档

一、准备工作

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. 探索typescript的必经之路-----接口(interface)

    TypeScript定义接口 熟悉编程语言的同学都知道,接口(interface)的重要性不言而喻. 很多内容都会运用到接口.typescrip中的接口类似于java,同时还增加了更灵活的接口类型,包 ...

  2. [转帖]使用Nginx转发TCP/UDP数据

    使用Nginx转发TCP/UDP数据 https://www.cnblogs.com/guigujun/p/8075620.html 编译安装Nginx 从1.9.0开始,nginx就支持对TCP的转 ...

  3. STM32之中断函数

    本文做中断函数的索引,帮助我们找到中断函数名.中断函数参数以及中断服务函数他们的来源,以便我们编程. 1)如果一个工程只有一个中断,则我们可以进行两个步骤就可以了: 使能中断通道 编写中断服务函数 2 ...

  4. fpga基础

    1.FPGA 的分类: 根据 FPGA 基本结构,可将其分为基于乘积项(Product-Term)技术的 FPGA 和基于查找表(Look-Up-Table)技术的 FPGA 两种. (1)基于乘积项 ...

  5. python学习-40 生产者和消费者模型

    import time def buy(name): # 消费者 print('%s上街去买蛋' %name) while True: eggs=yield print('%s买了%s' %(name ...

  6. Django REST framework 基本组件

    一.序列化组件 简单使用 开发我们的Web API的第一件事是为我们的Web API提供一种将代码片段实例序列化和反序列化为诸如json之类的表示形式的方式.我们可以通过声明与Django forms ...

  7. Python中turtle库的使用

    Turtle图形库 Turtle库是Python内置的图形化模块,属于标准库之一,位于Python安装目录的lib文件夹下,常用函数有以下几种: 画笔控制函数 penup():抬起画笔: pendow ...

  8. 机器学习支持向量机SVM笔记

    SVM简述: SVM是一个线性二类分类器,当然通过选取特定的核函数也可也建立一个非线性支持向量机.SVM也可以做一些回归任务,但是它预测的时效性不是太长,他通过训练只能预测比较近的数据变化,至于再往后 ...

  9. 多线程面试题之【三线程按顺序交替打印ABC的方法】

    建立三个线程,线程名字分别为:A.B.C,要求三个线程分别打印自己的线程名字,但是要求三个线程同时运行,并且实现交替打印,即按照ABCABCABC的顺序打印.打印10轮,打印完毕控制台输出字符串:&q ...

  10. AJAX 调用WebService 、WebApi 增删改查

    WebService 页面: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 3 ...