一篇文章帶你入門Springboot沙箱環(huán)境支付寶支付(附源碼)
0.前言
文章需求:
對于學(xué)生來說,目前網(wǎng)上確實(shí)沒有比較統(tǒng)一而且質(zhì)量好的支付教程。因?yàn)橹Ц秾€人開發(fā)者尤其是學(xué)生來說不太友好。因此,自己折騰兩天,算是整理了一篇關(guān)于支付寶沙箱支付的文章。
那么為什么不用微信沙箱支付呢?
微信支付我在另一篇文章中寫過,用的是別人的公眾號和開放平臺賬號,而微信的沙箱測試我自己也搞了好幾天了也沒弄好,確實(shí)沒有支付寶沙箱測試容易。因?yàn)橹Ц秾毺峁┝艘惶譸c客戶端和手機(jī)端的測試軟件(比如沙箱版支付寶)!
微信和支付寶官方為了開發(fā)者測試和學(xué)習(xí)方便,都提供了沙箱測試環(huán)境下模擬支付業(yè)務(wù)。這篇文章我們就來動手搭建一個支付寶沙箱環(huán)境支付的demo,如果想額外了解微信支付可以看下我的另一篇文章:Springboot整合微信登錄與微信支付(附源碼)
個人覺得,在沙箱測試支付方面,支付寶會相較于微信來說更簡單一些,文檔相對而言比較詳細(xì),有附帶沙箱支付寶APP,測試遠(yuǎn)比微信沙箱方便!
1.效果展示
說明:沙箱測試并不是真正的支付,所以付款金額也都是模擬的!
2.技術(shù)棧介紹
- 前端demo :
- 后端demo:SpringBoot2.x + (LomBook插件)
- 第三方支付:AliPay-SDK
3.前期準(zhǔn)備
第一步:申請一個沙箱測試賬號
支付寶沙箱測試賬號申請 進(jìn)入鏈接后掃碼登錄!
第二步:電腦下載一個支付寶提供的客戶端用于生成RSA2
下載安裝完成后,開始使用,使用參考文檔:幫助文檔
第三步:手機(jī)下載 【沙箱版支付寶】
可以自行掃碼下載,也可以手機(jī)點(diǎn)入鏈接下載,沙箱支付寶下載鏈接
下載后打開沙箱支付寶如下圖:
踩坑:沙箱支付寶登錄所用的賬號和密碼是以開放平臺提供的沙箱賬號為準(zhǔn),而不是我們的手機(jī)號或者淘寶賬號!如圖:
如果萌新沒有注意到這一點(diǎn),直接用自己的手機(jī)號登錄,是會出現(xiàn)超時或者操作頻繁的提示而登錄不了的!(沒錯,我就是這個萌新…)
哈哈,沙箱支付寶里的錢要能轉(zhuǎn)到支付寶中就好了!
4.后端搭建
項(xiàng)目目錄結(jié)構(gòu)
pom.xml
<dependencies> <!-- springboot新版本踩坑: 不加這個依賴的話,當(dāng)在配置類中 使用@ConfigurationProperties(prefix = "xxx")注解時, 我這個版本的spring boot會提示有問題 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artif <optional>true</optional> </dependency> <!-- 支付寶支付jar包 --> <dependency> <groupId>com.alipay.sdk</groupId> <artifactId>alipay-sdk-java</artifactId> <version>3.1.0</version> </dependency> <!-- fastjson --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.62</version> </dependency> <!-- web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- mybatis --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.3</version> </dependency> <!-- 熱部署 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <!-- mysql --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <!-- lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> </dependencies>
application.yml
由于只是demo 演示 所以可以不加數(shù)據(jù)庫和mybatis相關(guān)的配置,只留server相關(guān)配置即可
#=====================================server相關(guān)配置===================================== server: port: 8080 #=====================================數(shù)據(jù)庫相關(guān)配置===================================== spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://127.0.0.1:3306/alipay?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC username: root password: root # 使用Alibaba的druid數(shù)據(jù)源,默認(rèn)使用自帶的 type: com.alibaba.druid.pool.DruidDataSource #=====================================mybatis相關(guān)配置===================================== # 開啟控制臺打印sql日志 mybatis: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # mybatis 下劃線轉(zhuǎn)駝峰配置 map-underscore-to-camel-case: true # 配置mapper文件掃描 mapper-locations: com.haust.alipaydemoserver.mapper/*.xml # 配置實(shí)體類掃描 type-aliases-package: com.haust.alipaydemoserver.pojo
application-alipay.proerties
# APPID alipay.appId:2016110100784885 # 商戶私鑰, 即PKCS8格式RSA2私鑰 alipay.privateKey:MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCQiliwqcldz8Kb6HALM35rFNif0Tvg7qiywMzC5F8ySt5HgqN5VWIDC/ABTsUb6MlWhdGbC15r7uIwFB7mkDutG6vIZahhfWnCzisZuMebUkMGO9vJJiJDird20nOGyVuvxHYwQ+E777tZKnJM239psXL+o/vfWEtkVu1A6zEoseGc26gBp7Z6czAFGcOvorrWsj6Z93+ZE4LNAb21Hdc0KgILniYwKev38xACRjNn3a3lpRb+e4QQ24vPqIoLTGmw5DcpsEv3uKMRZwQBK8UB7b8ZwJP+yVSJdCVx+6LHP9VQd+RT5BlD8U6328VITsTr3WteHuPxP+t2a17/RWD1AgMBAAECggEATDHiFx8qG94OBQo/Jmh62BAhMf6mxiiJndGtH4Ar/uMg0im365prFJgSaV4Q4mmQ2Z+po0YW/GbtrdKth3W5P8Q6hmWwodPvENaGOgUClIqE8qBTeHI11c0mcej3JbK4NqwmccMW1PXHmXWa05FSVXFJ4ZqoiFCPTdHVOEfDnmN54DFgoEKYPk6q/xxQmIpwqHQH+s3S2eFSU0rt0aqiKBg2mqKSMYzLE+8vB7FWJS61Cy0mzYVugfgWx2KTQy8y1SC4i4mjQ50DQQ2AgbNr+k8l5G7p7Cja+KDQ6JbGv4nR8DC+sPNhxECDHrSpYDn6BYqw8aRwvN6nmaCdoU3GcQKBgQDheWn3kpJz8r8wdy15WaWzItZD+c8Qwou997bn3iBR7RdFi5INNXmlr5TRc3Lr3d5uidzl4ues2dLnqRYh7tYMQudB6HoweWoPlig6gXblamn6am5MvpFRK9Lsl1zNbN82DDvVH6oaDPvqD+KLPvZ1MIWRQiTz7eRvwo9NYTqKYwKBgQCkG+Q2N2U5g0t6baZ1/TlWpFKnb1t17JTHfwfmbwotnLcKQRVWzqayOdPsKtFHqyhmnhH7BlLt1a1QqK5d/a2KH80i7Y0jmv8Pglpt+gfxEQt87gD8+uZrvx33EpU8KCIwhFNshw4FUr5yB5BcLNQo92NsO0ujHhFC6Q/LxX9axwKBgH3WJS3mv5W2hL2nxdlUDwZLCwolAUt5SERdW9dMQP14NOS7YGe+0IWH2KaMqDa7PMi0aHRkjqgJaYug8pk9kniFXkuKU6d6G5dXVlxQpOqk2UDI5YYvVSrYKn+gekqr2GdxrHLlmSmw1WdsNiNAoIwG6ISJRdZdjoBRNWkaOnHBAoGADpa0KOWvx/cWBKIuxBpouH0PI/dQSCFp8Hood6GzY+6kjvLONNNWGk3tuvbrd9WNV+IBczFSufXe3GbCaXSdssO09r/rZhjnR7es1k392r5LKSX3TIX5aeapgUdToO9oaqu4xtMSugJrD7QAb1FE4wdq/TogNTX9DtetIc5Czg0CgYBGmAHwxJmvokrFmk8ZPkj544tZ9emY1aaUY0jqW21wWCHcRID2+56jsDXXb6IH/Hn9DgHndkl3v9ql6Ha2Y/j2t2Q9XA31QoUmKHU+6QA1aw+GP3VSaLTwlCMgGeWjA9imiFc3pEkS3JrNm3ASdwp+1TPIjcWcxa/ZU+JWrdM3bA== # 支付寶公鑰, 即對應(yīng)APPID下的支付寶公鑰 alipay.publicKey:MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlREBzwWQaJd6ZzSrYlnucsvlX3jV1swYdnymIRsbrObxftBFoKcvuMnqzCgRhvqZN4NEJvW+cQZkbk4otPvk+g+uIK1ZNjF+Cln/gePwHq3WRCrhWFwwBVWASJwPg/XISuaahjXicLb9z2AxvKcNZsLDL46HHO442mniGGOlD8PqK6LvvrhRUvhYgvY5SQ0RfRT0LUnxNl2evsdVOl3dlS6EuQVe4DrqpKS2WseVuXsA8nbXzBKwmR3vcqoxnDI/Nu8ldSLS+KEMEFh6MUL9OcTwhHr4/F8MdKtMSSWru+5m4q8BGNxW4PAP5GM3e1cBlxi/8FnBamL0jIlnhH/8qwIDAQAB # 服務(wù)器異步通知頁面路徑, 需http://格式的完整路徑 # 踩坑:不能加?type=abc這類自定義參數(shù) alipay.notifyUrl: # 頁面跳轉(zhuǎn)同步通知頁面路徑, 需http://格式的完整路徑 # 踩坑:不能加?type=abc這類自定義參數(shù) alipay.returnUrl:http://192.168.0.106:8084/#/paySuccess # 簽名方式 alipay.signType:RSA2 # 字符編碼格式 alipay.charset:utf-8 # 支付寶網(wǎng)關(guān) alipay.gatewayUrl:https://openapi.alipaydev.com/gateway.do # 日志打印地址 alipay.logPath:"F:\\"
Order訂單實(shí)體類
這里我使用了lombok插件,所以以注解的方式節(jié)省了setter/getter 以及構(gòu)造函數(shù)
package com.haust.alipaydemoserver.pojo; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.Accessors; /** * @Auther: csp1999 * @Date: 2020/11/13/21:49 * @Description: 商品訂單實(shí)體類(支付實(shí)體對象) */ @Data @AllArgsConstructor @NoArgsConstructor @Accessors(chain = true) public class Order { /** * 商戶訂單號,必填 */ private String out_trade_no; /** * 訂單名稱,必填 */ private String subject; /** * 付款金額,必填 * 根據(jù)支付寶接口協(xié)議,必須使用下劃線 */ private String total_amount; /** * 商品描述,可空 */ private String description; /** * 超時時間參數(shù) */ private String timeout_express = "10m"; /** * 產(chǎn)品編號 */ private String product_code = "FAST_INSTANT_TRADE_PAY"; }
Service層
/** * @Auther: csp1999 * @Date: 2020/11/13/21:55 * @Description: 支付 service */ public interface AliPayService { /** * 支付寶支付接口 * @param order * @return * @throws AlipayApiException */ String aliPay(Order order) throws AlipayApiException; }
/** * @Auther: csp1999 * @Date: 2020/11/13/21:56 * @Description: 支付service 實(shí)現(xiàn)類 */ @Service public class AliPayServiceImpl implements AliPayService { @Autowired private Alipay alipay; @Override public String aliPay(Order order) throws AlipayApiException { return alipay.pay(order); } }
Controller層
/** * @Auther: csp1999 * @Date: 2020/11/13/21:47 * @Description: 支付寶沙箱測試 controller */ @RestController public class PayController { @Autowired private AliPayService aliPayService; /** * 支付寶支付 api * * @param outTradeNo * @param subject * @param totalAmount * @param description * @return * @throws AlipayApiException */ @PostMapping(value = "/order/alipay") public String alipay(String outTradeNo, String subject, String totalAmount, String description) throws AlipayApiException { Order order = new Order(); order.setOut_trade_no(outTradeNo); order.setSubject(subject); order.setTotal_amount(totalAmount); order.setDescription(description); System.out.println(order); return aliPayService.aliPay(order); } }
配置類
支付寶支付配置類以及支付寶支付組件注入Spring容器
AliPayConfig.java
/** * @Auther: csp1999 * @Date: 2020/11/13/19:19 * @Description: 支付寶配置類(讀取配置文件) */ @Configuration @PropertySource("classpath:application-alipay.properties") @ConfigurationProperties(prefix = "alipay") @Data public class AliPayConfig { /** * APPID */ private String appId; /** * 商戶私鑰, 即PKCS8格式RSA2私鑰 */ private String privateKey; /** * 支付寶公鑰 */ private String publicKey; /** * 服務(wù)器異步通知頁面路徑,需http://格式的完整路徑 * 踩坑:不能加?type=abc這類自定義參數(shù) */ private String notifyUrl; /** * 頁面跳轉(zhuǎn)同步通知頁面路徑,需http://格式的完整路徑 * 踩坑:不能加?type=abc這類自定義參數(shù) */ private String returnUrl; /** * 簽名方式 */ private String signType; /** * 字符編碼格式 */ private String charset; /** * 支付寶網(wǎng)關(guān) */ private String gatewayUrl; /** * 日志打印地址 */ private String logPath; }
Alipay.java
/** * @Auther: csp1999 * @Date: 2020/11/13/21:57 * @Description: 調(diào)用支付寶支付的組件 */ @Component public class Alipay { @Autowired private AliPayConfig alipayConfig; /** * 支付接口 * * @param order * @return * @throws AlipayApiException */ public String pay(Order order) throws AlipayApiException { // 支付寶網(wǎng)關(guān) String serverUrl = alipayConfig.getGatewayUrl(); // APPID String appId = alipayConfig.getAppId(); // 商戶私鑰, 即PKCS8格式RSA2私鑰 String privateKey = alipayConfig.getPrivateKey(); // 格式化為 json 格式 String format = "json"; // 字符編碼格式 String charset = alipayConfig.getCharset(); // 支付寶公鑰, 即對應(yīng)APPID下的支付寶公鑰 String alipayPublicKey = alipayConfig.getPublicKey(); // 簽名方式 String signType = alipayConfig.getSignType(); // 頁面跳轉(zhuǎn)同步通知頁面路徑 String returnUrl = alipayConfig.getReturnUrl(); // 服務(wù)器異步通知頁面路徑 String notifyUrl = alipayConfig.getNotifyUrl(); // 1、獲得初始化的AlipayClient AlipayClient alipayClient = new DefaultAlipayClient( serverUrl, appId, privateKey, format, charset, alipayPublicKey, signType); // 2、設(shè)置請求參數(shù) AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest(); // 頁面跳轉(zhuǎn)同步通知頁面路徑 alipayRequest.setReturnUrl(returnUrl); // 服務(wù)器異步通知頁面路徑 alipayRequest.setNotifyUrl(notifyUrl); // 封裝參數(shù)(以json格式封裝) alipayRequest.setBizContent(JSON.toJSONString(order)); // 3、請求支付寶進(jìn)行付款,并獲取支付結(jié)果 String result = alipayClient.pageExecute(alipayRequest).getBody(); // 返回付款信息 return result; } }
跨域攔截器配置以及注冊
CorsInterceptor.java
/** * @Auther: csp1999 * @Date: 2020/10/21/12:06 * @Description: 跨域攔截器 */ public class CorsInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //表示接受任意域名的請求,也可以指定域名 response.setHeader("Access-Control-Allow-Origin", request.getHeader("origin")); //該字段可選,是個布爾值,表示是否可以攜帶cookie response.setHeader("Access-Control-Allow-Credentials", "true"); response.setHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS"); response.setHeader("Access-Control-Allow-Headers", "*"); // 預(yù)檢處理,方行所有非簡單請求方法 if (HttpMethod.OPTIONS.toString().equals(request.getMethod())) { return true; } return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { } }
InterceptorConfig.java
/** * @Auther: csp1999 * @Date: 2020/10/20/13:26 * @Description: 攔截器配置 */ @Configuration public class InterceptorConfig implements WebMvcConfigurer { /* * 將跨域攔截器交給spring容器托管 * @return: com.haust.online_class.interceptor.CorsInterceptor * @create: 2020/10/21 12:20 * @author: csp1999 */ @Bean public CorsInterceptor corsInterceptor() { return new CorsInterceptor(); } @Override public void addInterceptors(InterceptorRegistry registry) { // 跨域攔截器注冊(注意:跨域攔截器注冊要放在最上方) registry.addInterceptor(corsInterceptor()).addPathPatterns("/**"); WebMvcConfigurer.super.addInterceptors(registry); } }
啟動spirngboot項(xiàng)目
5.前端搭建
前端代碼就不展示了,demo源碼會提供給大家,來看下前端的樣子把:
支付操作的頁面:
支付完成后支付寶回調(diào)的頁面:
啟動前端項(xiàng)目:
端口自定義就行!
6. 支付測試
測試支付:
進(jìn)入支付寶支付頁面:
沙箱支付寶掃碼支付:(支付密碼默認(rèn)111111)
后臺查看打印訂單情況:
7. 總結(jié)
這篇文章就到這里了,也希望大家多多關(guān)注腳本之家的其他內(nèi)容!
相關(guān)文章
Java內(nèi)存模型(JMM)及happens-before原理
這篇文章主要介紹了java內(nèi)存模型(JMM)及happens-before原理,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-04-04SpringBoot搭建Dubbo項(xiàng)目實(shí)現(xiàn)斐波那契第n項(xiàng)詳解
這篇文章主要講解了“SpringBoot+Dubbo怎么實(shí)現(xiàn)斐波那契第N項(xiàng)”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)吧2022-06-06Spring Boot中Redis數(shù)據(jù)庫的使用實(shí)例
Spring Boot中除了對常用的關(guān)系型數(shù)據(jù)庫提供了優(yōu)秀的自動化支持之外,對于很多NoSQL數(shù)據(jù)庫一樣提供了自動化配置的支持。本篇文章主要介紹了Spring Boot中Redis的使用實(shí)例代碼,有興趣的開業(yè)了解一下。2017-04-04使用RequestBodyAdvice實(shí)現(xiàn)對Http請求非法字符過濾
這篇文章主要介紹了使用RequestBodyAdvice實(shí)現(xiàn)對Http請求非法字符過濾的操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-06-06Springboot+Hutool自定義注解實(shí)現(xiàn)數(shù)據(jù)脫敏
我們在項(xiàng)目中會處理敏感數(shù)據(jù)時,通常需要對這些數(shù)據(jù)進(jìn)行脫敏,本文主要使用了Springboot整合Hutool來自定義注解實(shí)現(xiàn)數(shù)據(jù)脫敏,感興趣的可以理解下2023-10-10SpringBoot實(shí)現(xiàn)國際化的操作步驟
國際化(Internationalization) 是指為了適應(yīng)不同語言、文化和地區(qū)的用戶,使軟件能夠方便地進(jìn)行本地化修改的過程,本文介紹了SpringBoot 國際化功能的簡單使用,感興趣的朋友可以參考下2024-02-02Java.toCharArray()和charAt()的效率對比分析
這篇文章主要介紹了Java.toCharArray()和charAt()的效率對比分析,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-10-10Java實(shí)現(xiàn)簡單班級管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)簡單班級管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-02-02Java字符串拼接的五種方法及性能比較分析(從執(zhí)行100次到90萬次)
字符串拼接一般使用“+”,但是“+”不能滿足大批量數(shù)據(jù)的處理,Java中有以下五種方法處理字符串拼接及性能比較分析,感興趣的可以了解一下2021-12-12