springboot项目对接支付宝支付
支付宝对接文档
一、准备工作
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项目对接支付宝支付的更多相关文章
- Python对接支付宝支付自实现
Python对接支付宝支付自实现 # -*- coding: utf-8 -*- import base64 import json import urllib.parse from datetime ...
- Django 对接 支付宝支付, 回调
平台 点击这里进入 蚂蚁金服开放平台 沙箱 点击这里进入 沙箱环境 初始界面 设置公钥 下载创建秘钥工具 1. 进入文档中心 这里 2. 选中 电脑网站支付 3. 进入后选中 API 列表 中的 统 ...
- tp5对接支付宝支付简单集成
对于每个刚开始工作的新手来说,无论支付宝支付还是微信支付都是跑不掉的一个小门槛. 在加上本人比较技术比较渣(比较懒导致的),不太喜欢引用那么大的SDK,于是就简单集成了一下支付宝的支付. 但也只是只有 ...
- SpringBoot中实现支付宝支付
本文只介绍当面付(扫码支付)和APP支付 一. 接入准备 #这里分两种情况,正式环境和沙箱环境,本文使用沙箱环境 1.进入支付宝开放平台,创建应用 登录 支付宝开放平台,创建应用并提交审核,审核通过后 ...
- DUMP4 企业级电商项目 —— 对接支付宝扫码支付
延展 <谈谈微信支付曝出的漏洞> [联调 DEMO下载地址]https://docs.open.alipay.com/194/105201/ [内置 一份 说明文档可做参考] [impor ...
- Thinkcmf对接支付宝支付和获取用户信息
一. 登录支付宝开放平台 平台地址:https://open.alipay.com/ 二. 创建应用并申请上线 登录后,[进入我的开放平台],依次点击[开发者中心]-& ...
- PHP对接微信支付采坑
第一次做PHP商城项目对接微信支付接口,踩了N次坑,这也不对,那也不对,搞了很久,查了一些资料,终于实现了支付功能,小小总结一下,万一下次遇到就不用到处找资料了. 微信扫码支付 前期准备: 1.微信公 ...
- Django对接支付宝Alipay支付接口
最新博客更新见我的个人主页: https://xzajyjs.cn 我们在使用Django构建网站时常需要对接第三方支付平台的支付接口,这里就以支付宝为例(其他平台大同小异),使用支付宝开放平台的沙箱 ...
- App对接支付宝移动支付功能
前段时间看了下app对接支付宝移动支付的功能,并自己总结了下支付宝移动支付的实现流程 一.申请流程 前提是已有现成的应用. 1. 申请地址 https://b ...
随机推荐
- LeetCode 20. 有效的括号(Valid Parentheses)
20. 有效的括号 20. Valid Parentheses 题目描述 给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效. 有效字符串需满足: 左括号必须 ...
- e.g. i.e. etc. et al. w.r.t. i.i.d.英文论文中的缩写语
e.g. i.e. etc. et al. w.r.t. i.i.d. 用法:, e.g., || , i.e., || , etc. || et al., || w.r.t. || i.i.d. e ...
- Javascript 闭包何时回收?
定义 闭包是函数和声明该函数的词法环境的组合.闭包是指有权访问另一个函数作用域中的变量的函数,创建闭包的最常见的方式就是在一个函数内创建另一个函数,通过另一个函数访问这个函数的局部变量. 范例 fun ...
- stm32之中断响应优先级
1)中断响应分为:自然优先级.抢占优先级.响应优先级. 2)抢占优先级和响应优先级,其实是一个中断所包含的两个优先级,其中前者是抢占优先级之间的级别划分,后者是相同抢占优先级的优先级别的划分. 中断A ...
- php生成动态验证码 加减算法验证码 简单验证码
预览效果: <?php /** *ImageCode 生成包含验证码的GIF图片的函数 *@param $string 字符串 *@param $width 宽度 *@param $height ...
- 【并发】7、借助redis 实现多线程生产消费队列
1.这是第一个简单的初始化版本,看起来比使用fqueue似乎更好用 package queue.redisQueue; import queue.fqueue.vo.TempVo; import re ...
- Spring Boot使用@ConfigurationProperties注解获取配置文件中的属性值
注意:这种方式要提供属性的getter/setter方法—— 如果idea报错,提示没有相应的执行器,就需要在maven中添加: (虽然不配置代码也能正常运行,作用在下面会说明) 配置了该执行器后,在 ...
- FPS 游戏实现GDI透视
FPS游戏可以说一直都比较热门,典型的代表有反恐精英,穿越火线,绝地求生等,基本上只要是FPS游戏都会有透视挂的存在,而透视挂还分为很多种类型,常见的有D3D透视,方框透视,还有一些比较高端的显卡透视 ...
- io.ByteIO和open操作二进制流的区别(转)
转自Stack Overflow:https://stackoverflow.com/questions/42800250/difference-between-open-and-io-bytesio ...
- js入门之内置数组对象 Array
一. 数组 1. 创建数组的两种方式 1. 数组字面量 var array = [] 2. 数组的构造函数创建数组 var array = new Array(); 2. 如何判断一个变量是否是数组 ...