支付宝对接文档

一、准备工作

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. 软件素材---C/C++格式化显示当前时间--标准函数strftime

    函数原型:size_t strftime (char* ptr, size_t maxsize, const char* format,const struct tm* timeptr ); 头文件: ...

  2. varnish缓存清理

    本篇日志应该较早该去写的,一直脱了好久,直到最近才写.在使用任务cache工具时,都会提到的一个问题.如何只清理想清理的那部分缓存,而其已缓存的部分不受影响 .这里就要用到varnishadm工具,先 ...

  3. Bean配置

    1.xml配置(摘抄自:https://www.cnblogs.com/zyx1301691180/p/7665971.html) 一.setter方法配置Bean: 1.创建一个 Spring Be ...

  4. python基础学习(七)

    14.return # print() 可以被执行 def doubelNumber(num): print() print() Afnum = doubelNumber() print(Afnum) ...

  5. (四)Spring Boot官网文档学习

    文章目录 关于默认包的问题 加载启动类 配置 Bean管理和依赖注入 @SpringBootApplication Developer Tools 关于 Developer Tools 的一些细节 原 ...

  6. 使用pyinstaller编译python文件

    1.安装pyinstaller pip install pyinstaller 2.编译 pyinstaller yourprogram.py 具体操作   1.编译 d: cd python pyi ...

  7. WUSTOJ 1321: Alphabet Cookies(Java)字符统计

    题目链接:1321: Alphabet Cookies Description Kitty likes cookies very much, and especially the alphabet c ...

  8. 1181: 零起点学算法88——偶数求和(C语言)

    一.题目: 题目来源WUSTOJ 二.源代码: #include<stdio.h> int main() { int n, m, num, sum, i, j, k; while (sca ...

  9. golang 上传文件(包括 gin 实现)

    golang web服务有时候需要提供上传文件的接口,以下就是具体示例.为了示例简单(吐槽下 golang 的错误处理), 忽略了所有的错误处理.本文会用两种方式(标准库和gin)详细讲解 golan ...

  10. SAS学习笔记49 生成前20个黄金分割数列到数据集

    黄金分割数列即斐波那契数列,该数列中后一个数与前一个数的比例越往后越接近于黄金比例(1+√5)/2 ,此数列分布表现出极致的均衡与和谐之美