SpringBoot中实现支付宝支付
本文只介绍当面付(扫码支付)和APP支付
一. 接入准备
#这里分两种情况,正式环境和沙箱环境,本文使用沙箱环境
1.进入支付宝开放平台,创建应用
登录 支付宝开放平台,创建应用并提交审核,审核通过后会生成应用唯一标识 APPID,并且可以申请开通开放产品使用权限。通过 APPID 应用才能调用开放产品的接口能力。详情请参考 创建应用。
2.配置应用
应用创建完成后,系统会自动跳转到应用详情页面。您可以在 能力列表 中点击 添加能力 来添加 当面付 功能。详情请参见 添加应用功能。 添加需要的能力
3.开发设置
进入开发设置中完成接口加签方式、IP白名单、应用网关、接口内容加密方式开发信息设置。详情请参见 配置应用环境
- 接口加签方式:必填。用于保障商户应用和支付宝交互的安全性,配置详情参见 接口加签方式配置说明。
IP白名单:选填。用于保障用户资金安全,说明详情参见 IP 白名单接入指南。
应用网关:选填。用于接收支付宝异步通知消息,说明详情参见 应用网关。
接口内容加密方式:选填。用于加/解密 OpenAPI bizContent 报文内容及加/解密部分用户隐私信息,说明详情参见 接口内容加密方式。
授权回调地址:选填。第三方应用授权 或 用户信息授权 后回调地址。授权链接中配置的 redirect_uri 的值必须与此值保持一致 (如:https://www.alipay.com) ,用户成功授权后将在该 url 后携带授权码等信息并跳转至该页。当填入该地址时,系统会自动进行安全检测,详情请参考 安全检测。
4.设置接口加签方式
支付宝开放平台的应用管理体系,使用了公私钥的机制,商户可通过设置接口加签方式为自身应用配置 公私钥/公私钥证书 来保障商户应用和支付宝交互的安全性。密钥的获取方式请参见 生成密钥。
公钥证书与公钥的区别请参见 普通公钥与公钥证书区别。
简单说一下公钥私钥
使用支付宝支付加密方式有两种:1. 公钥私钥 2. 证书
1. 可使用支付宝提供的开发助手生成证书,生成后,支付宝会提供给你三个证书,分别为:私钥证书、公钥证书、支付宝公钥证书,
将生成的公钥证书配置到支付宝平台中,剩下的私钥证书和支付宝公钥留在本地使用
2. 同上使用支付宝开发助手生成密钥,将生成的公钥配置到支付宝,将支付宝公钥复制到本地。
密钥的作用:私钥签名,公钥验签;公钥加密,私钥解密;私钥是不能公开的。
为什么有两套密钥:开发者生成的私钥公钥、支付宝公钥-支付宝私钥;开发者需要签名,支付宝平台也需要签名。
其他步骤参照支付宝开放平台接入流程。
二. 编码阶段
1. 下载支付宝sdk
java使用maven引入即可
2.编码
封装配置类
1 @Data
2 @Configuration
3 @ConfigurationProperties(prefix = "alipay")
4 public class AliPayConfig implements Serializable {
5
6 private static final long serialVersionUID = -4736760736935998953L;
7
8 public AliPayConfig(){}
9
10 public AlipayClient build(){
11 if(this.alipayClient == null){
12 return new DefaultAlipayClient(this.getGatewayUrl(),
13 this.getAppId(),
14 this.getPrivateKey(),
15 this.getFormat(),
16 this.getCharset(),
17 this.getAliPublicKey(),
18 this.getSignType());
19 }
20 return this.alipayClient;
21 }
22
23 /**
24 * 支付宝网关
25 */
26 private String gatewayUrl;
27
28 /**
29 * 新版本
30 */
31 private String newGatewayUrl;
32
33 /**
34 * AppId
35 */
36 private String appId;
37
38 /**
39 * 应用私钥
40 */
41 private String privateKey;
42
43 /**
44 * 请求使用的编码格式,如utf-8,gbk,gb2312等
45 */
46 private String charset;
47
48 /**
49 * 仅支持JSON
50 */
51 private String format;
52
53 /**
54 * 支付宝公钥
55 */
56 private String aliPublicKey;
57
58 /**
59 * 加密方式 目前支持RSA2和RSA,推荐使用RSA2
60 */
61 private String signType;
62
63 /**
64 * 回调地址
65 */
66 private String notifyUrl;
67
68 /**
69 * ali 客户端
70 */
71 private AlipayClient alipayClient;
72
73 /**
74 * 获取Config配置类
75 * @return Config
76 */
77 public Config getConfig(){
78 Config config = new Config();
79 config.protocol = "https";
80 config.gatewayHost = this.getNewGatewayUrl();
81 config.signType = this.getSignType();
82 config.appId = this.getAppId();
83 config.merchantPrivateKey = this.getPrivateKey();
84 config.alipayPublicKey = this.getAliPublicKey();
85 config.notifyUrl = this.getNotifyUrl();
86 return config;
87 }
88 }
老版支付宝sdk
1 @Slf4j
2 public class AliPayApi {
3
4 /**
5 * 统一收单线下交易预创建 (老版本sdk)
6 * 扫码支付
7 * @param model
8 * @param aliPayConfig
9 * @return
10 */
11 public static AlipayTradePrecreateResponse tradePayToScanCode(AlipayTradePrecreateModel model, AliPayConfig aliPayConfig){
12 log.info("扫码支付:"+model.getOutTradeNo());
13 // 1.实例化API对应的request类
14 AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();
15 request.setBizModel(model);
16 // 2.发起请求
17 AlipayTradePrecreateResponse response = null;
18 try {
19 response = aliPayConfig.getAlipayClient().execute(request);
20 // 3.是否调用成功
21 if(response.isSuccess()){
22 log.info("扫码支付调用成功:" + response.getBody());
23 return response;
24 }
25 } catch (AlipayApiException e) {
26 log.info("扫码支付调用失败:" + e.getErrMsg());
27 throw new RuntimeException(e);
28 }
29 log.debug("扫码支付调用失败:" + response.getMsg());
30 return null;
31 }
32 }
新版支付宝sdk
1 /**
2 * 支付宝支付 新版sdk
3 * Create by Echo<php637.com> on 2021/1/22 0022
4 */
5 @Slf4j
6 public class AliPayNewApi {
7
8 /**
9 * 统一收单线下交易预创建
10 * 扫码支付
11 * @param model
12 * @param aliPayProperties
13 * @return
14 */
15 public static AlipayTradePrecreateResponse tradePayToScanCode(AlipayTradePrecreateModel model, AliPayConfig aliPayProperties){
16 log.info("扫码支付:" + model.getOutTradeNo());
17 // 1. 设置参数
18 Factory.setOptions(aliPayProperties.getConfig());
19 AlipayTradePrecreateResponse response = null;
20 try{
21 // 2. 发起Api调用
22 response = Factory.Payment.FaceToFace().preCreate(model.getSubject(), model.getOutTradeNo(), model.getTotalAmount());
23 dumpResponse(response);
24 // 3. 处理响应
25 if(ResponseChecker.success(response)){
26 log.info("扫码支付调用成功:" + response.getHttpBody());
27 return response;
28 }
29 } catch (Exception e) {
30 log.debug("扫码支付调用异常:" + e.getMessage());
31 throw new RuntimeException(e);
32 }
33 log.debug("扫码支付调用失败:" + response.getMsg());
34 return null;
35 }
36
37 /**
38 * App支付
39 * @param model
40 * @param aliPayConfig
41 * @return
42 */
43 public static AlipayTradeAppPayResponse tradePayToApp(AlipayTradeAppPayModel model, AliPayConfig aliPayConfig){
44 log.info("支付宝app支付:" + model.getOutTradeNo());
45 // 1. 设置参数
46 Factory.setOptions(aliPayConfig.getConfig());
47 AlipayTradeAppPayResponse response = null;
48 try{
49 // 2. 发起Api调用
50 response = Factory.Payment.App().pay(model.getSubject(), model.getOutTradeNo(), model.getTotalAmount());
51 // 3. 处理响应
52 if (ResponseChecker.success(response)){
53 return response;
54 }
55 } catch (Exception e) {
56 log.debug("支付宝app支付调用异常:" + e.getMessage());
57 throw new RuntimeException(e);
58 }
59 log.debug("支付宝app支付调用失败:" + response.getBody());
60 return null;
61 }
62
63 // 简单打印应答
64 private static void dumpResponse(AlipayTradePrecreateResponse response) {
65 if (response != null) {
66 log.info(String.format("code:%s, msg:%s", response.getCode(), response.getMsg()));
67 if (StringUtils.isNotEmpty(response.getSubCode())) {
68 log.info(String.format("subCode:%s, subMsg:%s", response.getSubCode(),
69 response.getSubMsg()));
70 }
71 log.info("body:" + response.getHttpBody());
72 }
73 }
74 }
测试和回调
1 @Autowired
2 private AliPayConfig aliPayProperties;
3
4 @Autowired
5 private SmsUtils smsUtils;
6
7 /**
8 * 扫码支付测试 老版本
9 * @return
10 */
11 @RequestMapping("/test1")
12 public Object test1(){
13 AlipayTradePrecreateModel model = new AlipayTradePrecreateModel();
14 model.setOutTradeNo("123456789");
15 model.setSubject("测试商品");
16 model.setTotalAmount("20");
17 System.out.println(AliPayApi.tradePayToScanCode(model, aliPayProperties));
18 return new Return().success();
19 }
20
21 /**
22 * 扫码支付测试 新版本
23 * @return
24 */
25 @RequestMapping("/test2")
26 public Object test2(){
27 AlipayTradePrecreateModel model = new AlipayTradePrecreateModel();
28 model.setOutTradeNo("12341234");
29 model.setSubject("新版支付");
30 model.setTotalAmount("10");
31 System.out.println(AliPayNewApi.tradePayToScanCode(model, aliPayProperties));
32 return new Return().success();
33 }
34
35 /**
36 * app支付测试 新版本
37 * @return
38 */
39 @RequestMapping("/test3")
40 public Object test3(){
41 AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
42 model.setOutTradeNo("123412314");
43 model.setSubject("新版app支付");
44 model.setTotalAmount("10");
45 return new Return().success(AliPayNewApi.tradePayToApp(model, aliPayProperties));
46 }
47
48 /**
49 * 回调
50 * @param request
51 * @return
52 */
53 @RequestMapping("/notify")
54 public Object alinNotify(HttpServletRequest request){
55 // 1.获取回调参数
56 Map<String, String> params = new HashMap<>();
57 Map requestParams = request.getParameterMap();
58 for (Iterator iterable = requestParams.keySet().iterator(); iterable.hasNext();){
59 String name = (String) iterable.next();
60 String[] values = (String[]) requestParams.get(name);
61 StringBuffer valueStr = new StringBuffer();
62 for (int i = 0; i < values.length; i++){
63 if(i == values.length - 1){
64 valueStr.append(values[i]);
65 }else{
66 valueStr.append(values[i]);
67 valueStr.append(",");
68 }
69 params.put(name, valueStr.toString());
70 }
71 }
72 log.info("支付宝回调,sign:{},trade_status:{},参数:{}",params.get("sign"),params.get("trade_status"),params.toString());
73 // 2.验签
74 params.remove("sign");
75 params.remove("sign_type");
76 try {
77 boolean checkRes = AlipaySignature.rsaCheckV1(params, aliPayProperties.getAliPublicKey(), aliPayProperties.getCharset(), aliPayProperties.getSignType());
78 if (!checkRes){
79 return new Return().failed("非法请求,验证失败");
80 }
81 } catch (AlipayApiException e) {
82 log.debug("支付宝验签异常:{}", e.getErrMsg());
83 }
84 // 3.服务端订单参数验证及其他逻辑
85 // TODO
86 return "SUCCESS";
87 }
SpringBoot中实现支付宝支付的更多相关文章
- iOS中 最新支付宝支付(AliPay) 韩俊强的博客
每日更新关注:http://weibo.com/hanjunqiang 新浪微博 现在的支付方式一般有三种, 支付宝, 微信, 网银. 个人觉得最简单易用的还是支付宝, 微信虽然看起来币支付宝要简单 ...
- 在django中实现支付宝支付(支付宝接口调用)
支付宝支付 正式环境:用营业执照,申请商户号,appid 测试环境:沙箱环境:https://openhome.alipay.com/platform/appDaily.htm?tab=info 支付 ...
- 微信公众号中的支付宝支付与微信支付 && 支付宝支付问题(微信bug)
一般,在微信公众号中的商城都是需要支持微信支付和支付宝支付的,当然,较大的公司对于鹅厂和阿里的站队就不说了,所以这里简单记录一下支付宝支付和微信支付的主要流程.说是简单介绍,这是因为确实不难,因为前端 ...
- 【zhifu】web开发中的支付宝支付和微信支付
一.支付类型: 支付宝支付: 支付宝app内的网页支付: app外(即普通浏览器)网页支付: 微信支付: 微信app内的支付(在这里叫公众号支付) app外的支付(微信H5支付): 微信公众号的支付宝 ...
- TP5 中实现支付宝支付 利用model层调用支付宝类库
<?php /** * Created by PhpStorm. * User: admin * Date: 2017/8/16 * Time: 09:16 */ namespace app\a ...
- springboot项目对接支付宝支付
支付宝对接文档 一.准备工作 1. 首先要到 蚂蚁金服开发者中心 https://openhome.alipay.com/platform/home.htm 注册商家账户,并认证. 2.下载java版 ...
- web开发中的支付宝支付和微信支付
https://www.jianshu.com/p/155757d2b9eb <!-- wxPay --SDK--> <script src="https://res.wx ...
- iOS开发笔记14:微博/微信登录与分享、微信/支付宝支付
产品中接入了微博/微信的第三方登录分享功能.微信和支付宝的第三方支付功能,之前在开发过程中涉及到这些部分,于是抽空将接入过程梳理了一遍. 1.微博.微信.支付宝SDK相关接入设置 (1)微博SDK S ...
- laravel实现支付宝支付功能
起因 前段时间因为项目中需要实现支付宝手机网站支付功能,所以写下这篇文章以作记录,不足之处,欢迎指教. 后端框架:Laravel 5.5 业务功能 适用于商家在移动端网页应用中集成支付宝支付功能.商家 ...
随机推荐
- 深入理解索引和AVL树、B-树、B+树的关系
目录 什么是索引 索引的分类 索引和AVL树.B-树.B+树的关系 AVL树.红黑树 B-树 B+树 SQL和NoSQL索引 什么是索引 索引时数据库的一种数据结构,数据库与索引的关系可以看作书籍和目 ...
- SpringBoot 如何统一后端返回格式?老鸟们都是这样玩的!
大家好,我是飘渺. 今天我们来聊一聊在基于SpringBoot前后端分离开发模式下,如何友好的返回统一的标准格式以及如何优雅的处理全局异常. 首先我们来看看为什么要返回统一的标准格式? 为什么要对Sp ...
- MySQL | 使用Xtrabackup进行备份和备份恢复
备份 进行备份前需要先创建备份用户,直接使用 root 用户进行备份也行,但是这样不太规范. create user backup@'localhost' identified by '123456' ...
- QT从入门到入土(三)——信号和槽机制
摘要 信号槽是 Qt 框架引以为豪的机制之一.所谓信号槽,实际就是观察者模式.当某个事件发生之后,比如,按钮检测到自己被点击了一下,它就会发出一个信号 (signal).这种发出是没有目的的,类似广播 ...
- Node性能如何进行监控以及优化?
一. 是什么 Node作为一门服务端语言,性能方面尤为重要,其衡量指标一般有如下: CPU 内存 I/O 网络 CPU 主要分成了两部分: CPU负载:在某个时间段内,占用以及等待CPU的进程总数 C ...
- 【剑指offer】50.数组中重复出现的数字
50.数组中重复出现的数字 知识点:数组:Set的不可重复性 题目描述 在一个长度为n的数组里的所有数字都在0到n-1的范围内. 数组中某些数字是重复的,但不知道有几个数字是重复的.也不知道每个数字重 ...
- PAT乙级:1087 有多少不同的值 (20分)
PAT乙级:1087 有多少不同的值 (20分) 当自然数 n 依次取 1.2.3.--.N 时,算式 ⌊n/2⌋+⌊n/3⌋+⌊n/5⌋ 有多少个不同的值?(注:⌊x⌋ 为取整函数,表示不超过 x ...
- SQL慢查询排查思路
前言 平时在工作中每天都会做巡检,将前一天所有超过500ms的慢SQL排查出来 查找原因,是否能进行优化.慢慢中,在形成了一套思路方法论. 我个人认为对于排查慢SQL还是有一定的帮助 (一).是否是S ...
- tomcat与springmvc 结合 之---第18篇 StandContext容器和SpringMVC的监听器的模型
writedby张艳涛 如何使用tomcat的监听器 public class BootStrap_ex06 { public static void main(String[] args) { Ht ...
- 深入刨析tomcat 之---第14篇 对应19章,使用manager管理 web应用
writedby 张艳涛 第19章讲的是管理程序,当一个tomcat启动的时候,能通过远程浏览器能访问tomcat,启动web应用,关闭web应用,查看web应用 怎么实现的呢? 在webapp 文件 ...