支付宝支付项目
文章目录
- 🚏 支付宝支付项目
- 🚀 支付宝介绍
- 🚬 1、支付宝平台
- 🚬 2、支付宝开放平台
- 🚬 3、支付能力
- 🚭 条码支付应用场景
- 🚭 扫码支付应用场景
- 🚭 App 支付
- 🚭 手机网站支付
- 🚭 电脑网站支付
- 🚄 支付宝介入指引
- 🚬 1、入住平台
- 🚬 2、使用沙箱支付
- 🚬 3、配置秘钥
- 🚒 支付宝入门案例
- 🚬 1、需要描述
- 🚬 2、支付请求ApI描述
- 🚬 3、搭建环境
- 🚬 4、编写Application
- 🚬 5、编写工具类
- 🚬 6、Controller 请求处理
- 🚬 7、配置异步通知处理器
- 🚬 8、内网穿透配置
- 🚬 9、添加同步通知处理类
- 🚬 10、编写支付前台页面
- 🚬 11、支付测试
- 🚤 支付宝项目
- 🚬 1、项目构建
- 🚬 2、搭建持久层
- 🚭 1、数据库表结构
- 🚭 2、创建实体
- 🚭 3、统一返回对象(工具类)
- 🚭 4、整合mybatis-plus
- 🚭 5、测试结果
- 🚬 3、引入支付宝
- 🚭 1、引入依赖
- 🚭 2、添加配置
- 🚭 3、编写配置类
- 🚭 4、编写工具类
- 🚬 4、支付功能
- 🚭 1、OrderService接口
- 🚭 2、支付ApiPayService
- 🚭 3、ApiPayController控制器
😹 作者: gh-xiaohe
😻 gh-xiaohe的博客
😽 觉得博主文章写的不错的话,希望大家三连(✌关注,✌点赞,✌评论),多多支持一下!!!
🚏 支付宝支付项目
🚀 支付宝介绍
🚬 1、支付宝平台
官网链接:https://opendocs.alipay.com/common/02fwvj
支付宝开放平台将强⼤的支付、营销、数据能力,通过接口等形式开放给自研商家与服务商(ISV),帮助商家创建更具竞争力的应用。还可协助商家进行推⼴营销。
商家接入开放平台后,基于支付宝海量用户,可以获得更多的流量、用户和收益,同时用户通过商家提供的服务获得了更丰富的体验,平台生态更加繁荣,最终实现多方共赢。
开发者是开放生态的主要组成部分,通过与商家、消费者的合作,提升商家的服务效率和营收,降低运营成本,使消费者的体验更便捷、更愉悦、更完美。无论是服务商开发者还是商家,都能基于开放平台找到适合自己的角色和方向。
通过平台能做什么?
开发者是开放生态的主要组成部分,通过与商家、消费者的合作,提升商家的服务
效率和营收,降低运营成本,使消费者的体验更便捷、更愉悦、更完美。无论是服务商开发者还是商家,都能基于开放平台找到适合自己的角色和方向。
1、自研商家
拥有研发能力的商家,可通过开放能力接口,将支付宝提供的各项功能集成至自身系统中。定制化开发,丰富服务范围,提升用户体验及自身竞争力。
2、服务商(ISV)
ISV 不仅可以进行自研开发,还能为用户提供小程序、生活号、网页、移动等应用,接入平台提供的支付、营销、数据等开放能力,为用户提供系统服务。
插件提供商
通过支付宝提供的丰富的 API 接口,开发者可以开发并在应用市场上线各类插件,
解决⻔店管理、支付核销、会员营销、数据分析等方面的问题。开放平台还为各种应用提供了清晰的盈利模式,通过应用市场的销售获得回报。
服务提供商
在应用市场之外,ISV 还可以通过服务市场为商家提供店铺装修、拍摄修图、地面推⼴、⻔店代运营等服务。实现线上订购,线下服务。
场景分销商
第三方APP 或媒介可以借助支付宝开放平台的分销能力为商家提供基于⻔店、卡
券、内容的分销服务,为商家的流量导入、品牌推⼴提供平台。分销商可以通过所
提供的服务获取收入。
🚬 2、支付宝开放平台
开放平台:https://open.alipay.com/
沙箱环境:https://openhome.alipay.com/platform/appDaily.htm?tab=info
文档中心:https://openhome.alipay.com/docCenter/docCenter.htm
API中心:https://opendocs.alipay.com/apis
🚬 3、支付能力
当面付帮助商家在线下消费场景中实现快速收款,支持 条码支付 和 扫码支付 两种付款方式。商家可通过以下两种任⼀方式进行收款,提升收银效率,实现资金实时到账。
-
条码支付:买家出示支付宝钱包中的条码、二维码,商家扫描用户条码即可完成 条码支付收款
-
扫码支付:买家通过使用支付宝 扫⼀扫 功能,扫描商家收款二维码即可完成扫码支付 付款。
产品特色
- 用户仅出示 付款码 或 扫⼀扫 即可完成付款,方便快捷。
- 用户手机无网络要求,可离线支付。
- 支付宝会根据交易金额、登录状态等信息判断是否需要用户输入密码,保障安
全。 - 商家收款资金实时到账,无现金流压力。
🚭 条码支付应用场景
使用流程:
使用说明:
1、收银员在商家收银系统操作生成订单,输入收款金额;
2、用户登录支付宝,点击⾸页付钱/收钱,进入付款码界面,出示给商家;
3、收银员通过扫码设备来扫描用户手机上的条码/二维码后,商家收银系统提交
支付;
4、支付后商家收银系统会拿到支付成功或者失败的结果,用户支付宝 App 显示
收单支付引导或成功结果。
🚭 扫码支付应用场景
适用于单件商品单独定价、无⼈值守、自助售货机等商家。用户打开支付宝中的扫⼀扫 功能,扫描商家展示的二维码进行支付。该模式适用于线下实体店支付、面对面支付、自助售货机等场景。
使用流程:
使用说明:
- 1、收银员在商家收银系统操作生成支付宝订单,并生成二维码;
- 2、用户登录支付宝,点击⾸页 扫⼀扫 或点击 付钱 > 扫码付,进入扫码界面;
- 3、用户扫收银员提供的二维码,核对金额并确认支付;
- 4、用户付款支付宝提示成功或失败,商家收银系统会拿到支付成功或者失败的结果。
🚭 App 支付
App 支付适用于商家在 App 应用中集成支付宝支付功能。商家 App 调用支付宝提
供的 SDK,SDK 再调用支付宝 App 内的支付模块。
- 1、如果用户已安装支付宝 App,商家 App 会跳转到支付宝中完成支付,支付完后
跳回到商家 App 内,最后展示支付结果。 - 2、如果用户没有安装支付宝 App,商家 App 内会调起支付宝网页支付收银台,用
户登录支付宝账户,支付完后展示支付结果。 ⽬前支持手机系统有:iOS(苹
果)、Android(安卓)。
应用案例:
⽬前已上线支付案例,商家可进行实际体验:饿了么 App、优酷 App、携程 App。
🚭 手机网站支付
为方便商家在移动端网页应用中集成支付宝支付功能,支付宝提供了手机网站支付
能力。
说明:手机网站支付产品不建议在 App 端使用;如果需要在 App 端中使用支付,
请接入 App 支付产品,接入文档详见App 支付 开发文档。
业务逻辑:
适用于商家在移动端网页应用中集成支付宝支付功能。 商家在网页中调用支付宝提供的网页支付接口调起支付宝客户端内的支付模块,商家网页会跳转到支付宝中完成支付,支付完后跳回到商家网页内,最后展示支付结果。若无法唤起支付宝客户端,则在⼀定的时间后会自动进入网页支付流程。
🚭 电脑网站支付
为方便网页应用商家接入支付宝支付功能,支付宝提供了电脑网站支付能力,商家可通过开放接口快速集成接入支付宝支付功能。电脑网站为即时到账升级而来的能力。
用户在 PC 端访问商家网站进行消费,通过电脑网站支付,可直接跳转到支付宝 PC网站收银台完成付款。 交易资金直接打入商家支付宝账户,实时到账。 用户交易款项即时到账,交易订单三个月内可退款,提供退款、清结算、对账等配套服务。
基本流程:双十一购物流程
🚄 支付宝介入指引
🚬 1、入住平台
-
①首先登录支付宝平台
-
②选入接入类型
-
③填写接入信息
-
如果是第一次,需要注册,具体按照下面要求进行填写
-
-
④注册成功
-
⑤编写对接的应用名称
-
⑥进入控制台
🚬 2、使用沙箱支付
- 沙箱环境是支付宝开放平台为开发者提供的与生产环境完全隔离的联调测试环境, 开发者在沙箱环境中完成的接口调用不会对生产环境中的数据造成任何影响。
- 支付宝提供的沙箱环境(https://open.alipay.com/develop/sandbox/app)
- 沙箱为开放的产品提供有限功能范围的支持,可以覆盖产品的绝大部分核心链路和 对接逻辑,便于开发者快速学习/尝试/开发/调试。
- 沙箱环境会自动完成或忽略一些场景的业务门槛,
- 例如:开发者无需等待产品开 通,即可直接在沙箱环境调用接口,使得开发集成工作可以与业务流程并行,从而 提高项目整体的交付效率。
注意:
- 由于沙箱环境并非100%与生产环境一致,接囗的实际响应逻辑请以生产环境为准,沙箱环境开发调试完成后,仍然需要在生产环境进行测试验收。
- 沙箱环境拥有完全独立的数据体系,沙箱环境下返回的数据(例如用户ID等) 在生产环境中都是不存在的,开发者不可将沙箱环境返回的数据与生产环境中 的数据混淆。
- ⑦申请成功,支付宝已经给你分配好了模拟的商家号,以及一系列所需要用到的AppID
- 由于使用的是沙盒环境,应用程序的私钥和公钥都已经有了默认配置,我们可以使用默认的公私钥
🚬 3、配置秘钥
APPID是自动帮我们创建了,网关也不用管。我们要做的就是设置那个密钥, 这里RSA2需要设置公钥。推荐使用RSA2
安装阿里支付助手AlipayDevelopmentAssistant工具。生成秘钥
🚒 支付宝入门案例
🚬 1、需要描述
点击进入在支付页面点击付款,完成沙箱支付操作
🚬 2、支付请求ApI描述
🚬 3、搭建环境
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<!--springBoot依赖包-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 支付功能SDK -->
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>4.10.124.ALL</version>
</dependency>
<!--springBoot支持jsp-->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
🚬 4、编写Application
# 应用名称
spring.application.name=ALiPayDemo1
# 页面的默认前缀
spring.mvc.view.prefix=/
# 响应页面默认的后缀
spring.mvc.view.suffix=.jsp
# 端口号
server.port=8080
# 项目访问路径
server.servlet.context-path=/
🚬 5、编写工具类
utils - AppUtils
public class AppUtils {
// 定义应用的id ,AppId 就是对应的支付宝账号
public static String app_id = "2021000121695303";
// 定义商户的私钥
public static String merchant_private_key ="xxx";
// 定义商户的公钥 PKCS8格式RSA2私钥
public static String align_public_key= "xxx";
// 服务器异步通知页面路径
// 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
public static String notify_url= "";
// 页面跳转同步通知页面路径
// 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
public static String return_url= "";
// 签名方式
public static String sign_type = "RSA2";
// 字符的编码格式
public static String charset = "utf-8";
// 支付宝网关,注意这些使用的是沙箱的支付宝网关,与正常网关的区别是多了dev
public static String gatewayUrl= "https://openapi.alipaydev.com/gateway.do";
// 日志地址
public static String log_path = "F:\\桌面\\";
/**
* 写⽇志,方便测试(看网站需求,也可以改成把记录存入数据库)
* @param sWord 要写入⽇志⾥的文本内容
*/
public static void logResult(String sWord){
// 创建一个文件流
FileWriter fieldWriter = null;
try {
fieldWriter = new FileWriter(log_path + "alipay_log" + System.currentTimeMillis() + ".text");
fieldWriter.write(sWord);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (fieldWriter != null) {
try {
fieldWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
utils - BeanUtils
/**
* 提供支付宝相关的一些对象
*/
@Configuration
public class BeanUtils {
// 创建支付宝需要的客户端对象
@Bean
public AlipayClient alipayClient(){
return new DefaultAlipayClient(
AppUtils.gatewayUrl, // 网关
AppUtils.app_id, // appid
AppUtils.merchant_private_key, // 私钥
"json", // 数据格式
AppUtils.charset, // 编码方式
AppUtils.align_public_key, // 公钥
AppUtils.sign_type // 签名类型
);
}
// 创建一个支付宝的请求对象
@Bean
public AlipayTradePagePayRequest alipayTradePagePayRequest() {
return new AlipayTradePagePayRequest();
}
}
🚬 6、Controller 请求处理
/**
* 支付的控制器
*/
@Controller
public class PayController {
@Autowired
private AlipayClient alipayClient;
@Autowired
private AlipayTradePagePayRequest alipayTradePagePayRequest;
/**
* 接收页面传递传递过来的参数
*
* @param WIdOut_trade_no 订单号
* @param WIdSubject 金额
* @param WIdTotal_amount 名称
* @param WIdBody 商品描述
* @param response 表单中的其他参数信息 name值 = 参数名
* @throws Exception
*/
@RequestMapping("/pay")
public void pay(String WIdOut_trade_no, String WIdSubject,
String WIdTotal_amount, String WIdBody, HttpServletResponse response)
throws Exception {
// 1、设置参数
// 设置响应的地址(支付宝返回给商户的响应地址)
alipayTradePagePayRequest.setNotifyUrl(AppUtils.notify_url); // 内网穿透 支付宝像我们的应用发送一个消息,支付成功还是失败的消息
alipayTradePagePayRequest.setReturnUrl(AppUtils.return_url); // 通知页面
// 设置其他参数 (传递给支付宝的数据)
alipayTradePagePayRequest.setBizContent(
"{\"out_trade_no\":\""+ WIdOut_trade_no +"\","
+ "\"total_amount\":\""+ WIdTotal_amount +"\","
+ "\"subject\":\""+ WIdSubject +"\","
+ "\"body\":\""+ WIdBody +"\","
+ "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}"); // 产品的编码
// 2、发送请求 调用 pageExecute 传递 请求 getBody 将结果以字符串的方式返回回来
String result = alipayClient.pageExecute(alipayTradePagePayRequest).getBody();
// 3、将响应结果返回给前端
response.setContentType("text/html;charset=utf-8");
response.getWriter().println(result);
}
/**
* 流程:
*
* 1、封装参数,封装到alipayTradePagePayRequest参数中,
* 2、封装好之后发送请求,调用pageExecute()方法,调用getBody()返回信息
* 3、可以把支付宝返回的信息,通过流的方式发送给页面
*/
}
🚬 7、配置异步通知处理器
异步通知: 其实是双保险机制,如果同步通知后没有跳转到你的网址,可能用户关了,可能网速慢,即无法触发你更新订单状态为已支付的controller,这时候异步通知就有作用了,不过你要判断一下,如果订单已经变为已支付,则不必再更新一次了,只返回给支付宝success即可,否则他会一直异步通知你
异步通知参数说明文档: https://opendocs.alipay.com/open/203/105286
/**
* 异步通知控制器
*/
@Controller
public class NotifyController {
/**
* 接收支付宝返回的异步通知信息
*
* @param request
* @param response
*/
@RequestMapping("/getNotify")
public void getNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 获取⽀付宝POST过来反馈信息
Map<String, String> params = new HashMap<>();
Map<String, String[]> parameterMap = request.getParameterMap(); // 获取参数
/**
keySet()和entrySet(),是Map集合中的两种取值方法。
与get(Object key)相比,
get(Object key)只能返回到指定键所映射的值,不能一次全部取出
keySet()和entrySet()可以。
Map集合中没有迭代器,Map集合取出键值的原理:将map集合转成set集合,再通过迭代器取出。
*/
Iterator<String> iterator = parameterMap.keySet().iterator();// iterator 迭代器
while (iterator.hasNext()) {
String name = iterator.next();
String[] values = parameterMap.get(name);
String valueStr = "";
for (int i = 0; i < values.length; i++) {
// 拼接 values信息 如果是最后一个值, 不拼接 ,号
valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
}
// 乱码解决,这段代码在出现乱码时使⽤
// valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
params.put(name, valueStr);
}
// 调用支付宝的SDK验证签名
boolean signVerified = AlipaySignature.rsaCheckV1(
params, // 参数
AppUtils.align_public_key, // 公钥
AppUtils.charset, // 编码方式
AppUtils.sign_type); // 签名类型
/**
* 主要用途:
* 判断信息有没有被篡改
* 1、需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号,
* 2、判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额)
* 3、校验通知中的seller_id(或者seller_email) 是否为out_trade_no这笔单据的对应的操作⽅(有的时候,⼀个商户可能有多个seller_id/seller_email)
* 4、验证app_id是否为该商户本身。
*/
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
if (signVerified) {//验证成功
String out_trade_no = request.getParameter("out_trade_no"); // 商户订单号
String trade_no = request.getParameter("trade_no"); // ⽀付宝交易号
String trade_status = request.getParameter("trade_status"); // 交易状态
/**
* 支付宝Api 交易状态说明
* 枚举名称 枚举说明
* WAIT_BUYER_PAY 创建交易,等待买家付款
* TRADE_CLOSED 未付款交易超时关闭
* TRADE_SUCCESS 交易支付成功
* TRADE_FINISHED 交易结束,不可退款
*/
if (trade_status.equals("TRADE_FINISHED")) {
System.out.println("交易结束,不可退款");
out.println("finished");
} else if (trade_status.equals("TRADE_SUCCESS")) {
System.out.println("交易支付成功");
out.println("success");
}
} else {//验证失败
System.out.println("验证失败");
out.println("fail");
}
}
}
🚬 8、内网穿透配置
由于我们的项目是内网,支付宝通知不能通知支付信息,因此我们需要是用内网穿透技术将ip映射为一个支付宝可以通知到的外网地址。
自行配置:
命令:natapp -authtoken=404390a06dca8d75
添加异步通知地址
# AppUtils 异步通知的地址
public class AppUtils {
public static String notify_url= "http://cwgmzt.natappfree.cc/getNotify";
}
🚬 9、添加同步通知处理类
同步返回页面控制器
# AppUtils 同步通知的地址
public class AppUtils {
public static String notify_url= "http://cwgmzt.natappfree.cc/getReturn";
}
/**
* 同步返回页面控制器
*/
@Controller
public class ReturnController {
/**
* 接收支付宝返回的同步通知信息
*
* @param request
* @param response
*/
@RequestMapping("/getReturn")
public void getReturn(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 获取⽀付宝POST过来反馈信息
Map<String, String> params = new HashMap<>();
Map<String, String[]> parameterMap = request.getParameterMap(); // 获取参数
/**
keySet()和entrySet(),是Map集合中的两种取值方法。
与get(Object key)相比,
get(Object key)只能返回到指定键所映射的值,不能一次全部取出
keySet()和entrySet()可以。
Map集合中没有迭代器,Map集合取出键值的原理:将map集合转成set集合,再通过迭代器取出。
*/
Iterator<String> iterator = parameterMap.keySet().iterator();// iterator 迭代器
while (iterator.hasNext()) {
String name = iterator.next();
String[] values = parameterMap.get(name);
String valueStr = "";
for (int i = 0; i < values.length; i++) {
// 拼接 values信息 如果是最后一个值, 不拼接 ,号
valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
}
// 乱码解决,这段代码在出现乱码时使⽤
// valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
params.put(name, valueStr);
}
// 调用支付宝的SDK验证签名
boolean signVerified = AlipaySignature.rsaCheckV1(
params, // 参数
AppUtils.align_public_key, // 公钥
AppUtils.charset, // 编码方式
AppUtils.sign_type); // 签名类型
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
if (signVerified) {//验证成功
String out_trade_no = request.getParameter("out_trade_no"); // 商户订单号
String trade_no = request.getParameter("trade_no"); // ⽀付宝交易号
String trade_amount = request.getParameter("trade_amount"); // 交易状态
// 金额
out.println("out_trade_no" + out_trade_no + "trade_no" + trade_no + "trade_amount" + trade_amount);// 返回到浏览器
} else {//验证失败
System.out.println("验证失败");
out.println("fail");
}
}
}
🚬 10、编写支付前台页面
🚬 11、支付测试
编写登录控制器方法
# PayController
/**
* 跳转到index.html页面
*
* @return
*/
@RequestMapping("/index")
public String index() {
return "index";
}
成功
🚤 支付宝项目
🚬 1、项目构建
🚬 2、搭建持久层
🚭 1、数据库表结构
🚭 2、创建实体
🚭 3、统一返回对象(工具类)
存放常量的接口
/**
* 存放常量的接口
*/
public interface SysConstant {
/**
* 默认的成功状态
*/
int STATUS_SUCCESS = 200;
/**
* 默认的成功消息
*/
String SUCCESS_MESSAGE = "success";
/**
* 默认的失败消息
*/
int STATUS_ERROR = 500;
/**
* 默认的失败消息
*/
String ERROR_MESSAGE = "error";
/**
* 订单的状态 - 代付款
*/
String WAIT_BUYER_PAY = "WAIT_BUYER_PAY";
/**
* 订单的状态 - 交易成功
*/
String TRADE_SUCCESS = "TRADE_SUCCESS";
/**
* 订单的状态 - 订单取消
*/
String CANCEL_SUCCESS = "CANCEL_SUCCESS";
/**
* 订单的状态 - 退款成功
*/
String REFUND_SUCCESS = "REFUND_SUCCESS";
/**
* 订单的状态 - 退款失败
*/
String REFUND_FAIL = "REFUND_FAIL";
/**
* 订单的状态 - 订单已关闭
*/
String TRADE_CLOSED = "TRADE_CLOSED";
/**
* 订单的状态 - 支付的数据格式
*/
String FORMAT = "json";
}
统一的返回的对象
/**
* 统一的返回的对象
*/
@Data
public class BaseResult {
// 返回的状态码
private int status;
// 返回消息
private String message;
// 返回数据
private Object result;
// 返回时间
private long timestamp = System.currentTimeMillis();
// 返回创建的对象
private static BaseResult createResult(int status, String message, Object result) {
BaseResult baseResult = new BaseResult();
baseResult.setStatus(status);
baseResult.setMessage(message);
baseResult.setResult(result);
return baseResult;
}
// 返回成功的方法,带数据
public static BaseResult success(Object result) {
return BaseResult.createResult(SysConstant.STATUS_SUCCESS, SysConstant.SUCCESS_MESSAGE,result);
}
// 返回成功的方法,不带数据
public static BaseResult success() {
return BaseResult.createResult(SysConstant.STATUS_SUCCESS, SysConstant.SUCCESS_MESSAGE,null);
}
// 返回失败的方法,带数据
public static BaseResult error(Object result) {
return BaseResult.createResult(SysConstant.STATUS_ERROR, SysConstant.ERROR_MESSAGE,result);
}
// 返回失败的方法,不带数据
public static BaseResult error() {
return BaseResult.createResult(SysConstant.STATUS_ERROR, SysConstant.ERROR_MESSAGE,null);
}
}
🚭 4、整合mybatis-plus
MyBatisPlus 配置类
/**
* MyBatisPlus 配置类
*/
@MapperScan("com.gh.mapper")
@EnableTransactionManagement // 开启事务管理器
@Configuration
public class MyBatisConfig {
}
🚭 5、测试结果
查询订单表中的数据
/**
* 订单控制器
*/
@Controller
@RequestMapping("order")
public class OrderController {
@Autowired
private OrderService orderService;
@RequestMapping("/list")
@ResponseBody
public BaseResult list() {
List<Order> list = orderService.list();
return BaseResult.success(list);
}
}
成功
🚬 3、引入支付宝
🚭 1、引入依赖
<!-- 支付功能SDK -->
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>4.10.124.ALL</version>
</dependency>
🚭 2、添加配置
#支付宝的配置信息
alipay:
app_id: 2021000121695303
merchant_private_key: # 私钥
alipay_public_key: # 公钥
notify_url: http://dnut8g.natappfree.cc/alipay/trade/notify # 异步通知地址
return_url: http://localhost:8080/success # 同步返回地址
sign_type: RSA2 # 签名的方式
charset: utf-8 # 编码方式
gatewayUrl: https://openapi.alipaydev.com/gateway.do # 网关
🚭 3、编写配置类
@Data
@NoArgsConstructor
@AllArgsConstructor
@Component
@ToString
@ConfigurationProperties(prefix = "alipay") // 读取配置文件 给一个前缀
public class AlipayConfig {
//应用的id app_id
@Value("${alipay.app_id}")
public String app_id;
//商户的私钥 merchant_private_key
@Value("${alipay.merchant_private_key}")
public String merchant_private_key;
//支付宝的公钥
@Value("${alipay.alipay_public_key}")
public String alipay_public_key;
//异步通知的地址
@Value("${alipay.notify_url}")
public String notify_url;
//同步跳转的页面
@Value("${alipay.return_url}")
public String return_url;
//签名方式
@Value("${alipay.sign_type}")
public String sign_type;
//字符的编码
@Value("${alipay.charset}")
public String charset;
//网关地址
@Value("${alipay.gatewayUrl}")
public String gatewayUrl;
//定义一个方法返回AlipayConfig对象
@Bean
public AlipayConfig getAlipayConfig(){
AlipayConfig alipayConfig = new AlipayConfig();
alipayConfig.setApp_id(app_id);
alipayConfig.setApp_id(merchant_private_key);
alipayConfig.setApp_id(alipay_public_key);
alipayConfig.setApp_id(notify_url);
alipayConfig.setApp_id(return_url);
alipayConfig.setApp_id(sign_type);
alipayConfig.setApp_id(charset);
alipayConfig.setApp_id(gatewayUrl);
return alipayConfig;
}
}
🚭 4、编写工具类
/**
* 支付的工具类
*/
public class StringUtils {
public static void main(String[] args) {
}
/**
* 生成订单
*/
public static String createOderNum() {
String date = new SimpleDateFormat("yyyyMMdd").format(new Date());
String seconds = new SimpleDateFormat("HHmmss").format(new Date());
System.out.println(date);
System.out.println(seconds);
String result = date + "000010000" + getTwo() + "00" + seconds + getTwo();
return result;
}
/**
* 生成一个随机的两位数
*/
public static String getTwo() {
Random random = new Random();
String result = random.nextInt(100) + "";
if (result.length() == 1) {
result = "0" + result; // 如果随机的是一位数,则加上 0
}
return result;
}
}
🚬 4、支付功能
支付流程
统一收单下单并支付页面接口
参考链接 https://opendocs.alipay.com/open/028r8t?ref=api&scene=22
🚭 1、OrderService接口
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order>
implements OrderService {
@Autowired
private OrderMapper orderMapper;
/**
* 创建订单
*/
@Override
public Order createOrder() {
// 1、生成订单编号
Order order = new Order();
order.setSubject("测试数据");
order.setOrder_no(StringUtils.createOderNum());
order.setTotal_amount(0.1D);
order.setStatus(SysConstant.WAIT_BUYER_PAY);
order.setCreate_time(new Timestamp(new Date().getTime()));
order.setUpdate_time(new Timestamp(new Date().getTime()));
// 写入数据
orderMapper.insert(order);
return order;
}
}
🚭 2、支付ApiPayService
- 1、创建订单 --> 根据订单支付
- 2、获取参数 (公共参数 和 请求参数)
- 3、获取客户端对象
- 4、创建支付 请求对象
- 5、组装biz_content请求参数的集合 JSON类型
- 参数要和 官网中的请求参数 一致
- 6、重点: 调用远程的支付宝支付接口
public interface AlipayService {
/**
* 创建支付
*/
String createTrade();
}
/**
* 阿里支付Service
*/
@Service
@Slf4j
public class AlipayServiceImpl implements AlipayService {
@Autowired
private OrderService orderService;
@Autowired
private AlipayConfig alipayConfig;
/**
* 创建支付
*/
@Override
public String createTrade() {
// 1、创建订单 --> 根据订单支付
log.info("创建订单");
Order order = orderService.createOrder();
// 2、获取参数 (公共参数 和 请求参数)
// 支付宝的appid
String app_id = alipayConfig.app_id;
// 获取商户私钥
String merchant_private_key = alipayConfig.merchant_private_key;
// 获取商户公钥
String alipay_public_key = alipayConfig.alipay_public_key;
// 支付宝异步通知地址
String notify_url = alipayConfig.notify_url;
// 同步通知地址
String return_url = alipayConfig.return_url;
// 编码
String charset = alipayConfig.charset;
// 签名方式
String sign_type = alipayConfig.sign_type;
// 网关
String gatewayUrl = alipayConfig.gatewayUrl;
// 3、获取客户端对象
AlipayClient alipayClient = new DefaultAlipayClient(
gatewayUrl,
app_id,
merchant_private_key,
SysConstant.FORMAT,// 数据格式类型json
charset,
alipay_public_key,
sign_type
);
// 4、创建支付 请求对象
AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
// 设置请求的异步通知路径
request.setNotifyUrl(notify_url);
// 设置请求的同步通知路径
request.setReturnUrl(return_url);
// 5、组装biz_content请求参数的集合 JSON类型
// 参数要和 官网中的请求参数 一致
JSONObject bizContent = new JSONObject();
bizContent.put("out_trade_no",order.getOrder_no()); // 商品的订单号
bizContent.put("total_amount",order.getTotal_amount()); // 订单金额
bizContent.put("subject",order.getSubject()); // 订单标题
bizContent.put("product_code","FAST_INSTANT_TRADE_PAY"); // 商品的产品码 固定值
// 存放到request 请求中
request.setBizContent(String.valueOf(bizContent));
// 6、重点: 调用远程的支付宝支付接口
AlipayTradePagePayResponse response = null;
try {
response = alipayClient.pageExecute(request);
// 判断是否支付成功
if (response.isSuccess()) {
log.info("支付成功");
}else {
log.info("支付失败");
}
} catch (AlipayApiException e) {
e.printStackTrace();
}
return response.getBody();
}
}
🚭 3、ApiPayController控制器
/**
* 支付控制器
*/
@Controller
@RequestMapping("alipay")
public class AlipayController {
@Autowired
private AlipayService alipayService;
/**
* 支付方法
*/
@RequestMapping("trade")
public void alipay(HttpServletResponse response) throws IOException {
// 1、创建支付
String trade = alipayService.createTrade();
response.setContentType("text/html;charset=utf-8");
response.getWriter().write(trade);
}
}