Springboot集成支付宝沙箱支付(完整版)

开发前准备

easy支付官方文档:https://opendocs.alipay.com/open/009ys9
通用版文档:https://opendocs.alipay.com/open/02np94

支付宝沙箱的配置

注册支付宝开发者账户,进入开发者控制台
https://openhome.alipay.com/platform/developerIndex.htm

进入沙箱:
img
沙箱的界面:
img

Java集成沙箱支付

下载依赖

<dependency><groupId>com.alipay.sdk</groupId><artifactId>alipay-easysdk</artifactId><version>2.2.0</version>
</dependency>

在 application.yml 里面进行配置:

alipay:appId: appPrivateKey: alipayPublicKey: notifyUrl: 

alipay的java配置:AplipayConfig.java

import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.kernel.Config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;import javax.annotation.PostConstruct;@Data
@Component
@ConfigurationProperties(prefix = "alipay")
public class AliPayConfig {private String appId;private String appPrivateKey;private String alipayPublicKey;private String notifyUrl;@PostConstructpublic void init() {// 设置参数(全局只需设置一次)Config config = new Config();config.protocol = "https";config.gatewayHost = "openapi.alipaydev.com";config.signType = "RSA2";config.appId = this.appId;config.merchantPrivateKey = this.appPrivateKey;config.alipayPublicKey = this.alipayPublicKey;config.notifyUrl = this.notifyUrl;Factory.setOptions(config);System.out.println("=======支付宝SDK初始化成功=======");}}

支付接口

新建一个 AliPayController.java

import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.payment.page.models.AlipayTradePagePayResponse;
import com.example.springboot.controller.dto.AliPay;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.net.URLEncoder;@GetMapping("/pay") // &subject=xxx&traceNo=xxx&totalAmount=xxxpublic String pay(AliPay aliPay) {AlipayTradePagePayResponse response;try {//  发起API调用(以创建当面付收款二维码为例)response = Factory.Payment.Page().pay(URLEncoder.encode(aliPay.getSubject(), "UTF-8"), aliPay.getTraceNo(), aliPay.getTotalAmount(), "");} catch (Exception e) {System.err.println("调用遭遇异常,原因:" + e.getMessage());throw new RuntimeException(e.getMessage(), e);}return response.getBody();}

参数 Alipay.java

import lombok.Data;@Data
public class AliPay {private String traceNo;private double totalAmount;private String subject;private String alipayTraceNo;
}

**注意:在拦截器里面加上 忽略alipay接口的配置,这很重要!**
img

接口测试

然后我们访问URL进行测试,测试的url格式:http://localhost:9090/alipay/pay?subject=xxx&traceNo=xxx&totalAmount=1000

大坑!!!:url中文问题

错误截图:
img
类似这样的url:http://localhost:9090/alipay/pay?subject=中文&traceNo=121313123&totalAmount=1000
在请求后就会出现上面的错误!

解决方式:暂时替换url中的中文字符,换成这样的:
http://localhost:9090/alipay/pay?subject=112233&traceNo=121313123&totalAmount=1000

这样就正常了:
在这里插入图片描述

然后使用沙箱账号登录,支付就可以
https://open.alipay.com/platform/appDaily.htm?tab=account
img

回调接口

import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.payment.page.models.AlipayTradePagePayResponse;
import com.example.springboot.controller.dto.AliPay;
import com.example.springboot.mapper.OrdersMapper;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;@RestController
@RequestMapping("/alipay")
public class AliPayController {@PostMapping("/notify")  // 注意这里必须是POST接口public String payNotify(HttpServletRequest request) throws Exception {if (request.getParameter("trade_status").equals("TRADE_SUCCESS")) {System.out.println("=========支付宝异步回调========");Map<String, String> params = new HashMap<>();Map<String, String[]> requestParams = request.getParameterMap();for (String name : requestParams.keySet()) {params.put(name, request.getParameter(name));// System.out.println(name + " = " + request.getParameter(name));}String tradeNo = params.get("out_trade_no");String gmtPayment = params.get("gmt_payment");String alipayTradeNo = params.get("trade_no");// 支付宝验签if (Factory.Payment.Common().verifyNotify(params)) {// 验签通过System.out.println("交易名称: " + params.get("subject"));System.out.println("交易状态: " + params.get("trade_status"));System.out.println("支付宝交易凭证号: " + params.get("trade_no"));System.out.println("商户订单号: " + params.get("out_trade_no"));System.out.println("交易金额: " + params.get("total_amount"));System.out.println("买家在支付宝唯一id: " + params.get("buyer_id"));System.out.println("买家付款时间: " + params.get("gmt_payment"));System.out.println("买家付款金额: " + params.get("buyer_pay_amount"));// 更新订单未已支付ordersMapper.updateState(tradeNo, "已支付", gmtPayment, alipayTradeNo);}}return "success";}}

内网穿透:https://natapp.cn/

配置免费的隧道,端口:9090:
img
软件下载地址:
https://pan.baidu.com/s/192MYFg0Gh3P87wW-Tj4ivQ?pwd=uuqu

下载好软件后,打开配置下authtoken:
在这里插入图片描述
img
然后双击启动 start.bat 即可。

看到这个表示你启动成功了:
img

idea里面配置notify接口并测试

更改 application.yml 里的配置:
img
我们可以在 idea里面对回调的notifyUrl进行debug测试,看看支付成功之后会不会回调:
在这里插入图片描述

附:AlipayController完整代码

import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.payment.page.models.AlipayTradePagePayResponse;
import com.example.springboot.controller.dto.AliPay;
import com.example.springboot.mapper.OrdersMapper;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;@RestController
@RequestMapping("/alipay")
public class AliPayController {@Resourceprivate OrdersMapper ordersMapper;@GetMapping("/pay") // &subject=xxx&traceNo=xxx&totalAmount=xxxpublic String pay(AliPay aliPay) {AlipayTradePagePayResponse response;try {//  发起API调用(以创建当面付收款二维码为例)response = Factory.Payment.Page().pay(URLEncoder.encode(aliPay.getSubject(), "UTF-8"), aliPay.getTraceNo(), aliPay.getTotalAmount(), "");} catch (Exception e) {System.err.println("调用遭遇异常,原因:" + e.getMessage());throw new RuntimeException(e.getMessage(), e);}return response.getBody();}@PostMapping("/notify")  // 注意这里必须是POST接口public String payNotify(HttpServletRequest request) throws Exception {if (request.getParameter("trade_status").equals("TRADE_SUCCESS")) {System.out.println("=========支付宝异步回调========");Map<String, String> params = new HashMap<>();Map<String, String[]> requestParams = request.getParameterMap();for (String name : requestParams.keySet()) {params.put(name, request.getParameter(name));// System.out.println(name + " = " + request.getParameter(name));}String tradeNo = params.get("out_trade_no");String gmtPayment = params.get("gmt_payment");String alipayTradeNo = params.get("trade_no");// 支付宝验签if (Factory.Payment.Common().verifyNotify(params)) {// 验签通过System.out.println("交易名称: " + params.get("subject"));System.out.println("交易状态: " + params.get("trade_status"));System.out.println("支付宝交易凭证号: " + params.get("trade_no"));System.out.println("商户订单号: " + params.get("out_trade_no"));System.out.println("交易金额: " + params.get("total_amount"));System.out.println("买家在支付宝唯一id: " + params.get("buyer_id"));System.out.println("买家付款时间: " + params.get("gmt_payment"));System.out.println("买家付款金额: " + params.get("buyer_pay_amount"));// 更新订单未已支付ordersMapper.updateState(tradeNo, "已支付", gmtPayment, alipayTradeNo);}}return "success";}
}

至此,集成完毕!撒花!坑太多了!@!!

------------------------------------更新--------------------------------------------

解决subject中文问题

貌似这是 easy-sdk 本身的问题,它不支持中文的subject,否则 biz_content就会乱码,那我索性就用了 alipay-sdk 完整版的

pom:

<dependency><groupId>com.alipay.sdk</groupId><artifactId>alipay-sdk-java</artifactId><version>4.22.110.ALL</version>
</dependency>

我们把AplipayController.java 改造下:

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.easysdk.factory.Factory;
import com.example.springboot.config.AliPayConfig;
import com.example.springboot.controller.dto.AliPay;
import com.example.springboot.mapper.OrdersMapper;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;// 完整版 sdk 解决了  subject中文乱码问题
@RestController
@RequestMapping("/alipay")
public class AliPayController {@GetMapping("/pay") // &subject=xxx&traceNo=xxx&totalAmount=xxxpublic void pay(AliPay aliPay, HttpServletResponse httpResponse) throws Exception {AlipayClient alipayClient = new DefaultAlipayClient(GATEWAY_URL, aliPayConfig.getAppId(),aliPayConfig.getAppPrivateKey(), FORMAT, CHARSET, aliPayConfig.getAlipayPublicKey(), SIGN_TYPE);AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();request.setNotifyUrl(aliPayConfig.getNotifyUrl());request.setBizContent("{\"out_trade_no\":\"" + aliPay.getTraceNo() + "\","+ "\"total_amount\":\"" + aliPay.getTotalAmount() + "\","+ "\"subject\":\"" + aliPay.getSubject() + "\","+ "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");String form = "";try {form = alipayClient.pageExecute(request).getBody(); // 调用SDK生成表单} catch (AlipayApiException e) {e.printStackTrace();}httpResponse.setContentType("text/html;charset=" + CHARSET);httpResponse.getWriter().write(form);// 直接将完整的表单html输出到页面httpResponse.getWriter().flush();httpResponse.getWriter().close();}}

然后再重启,试试:
img
可以看到 url 中的中文已经正常了,并且支付页面出来了:
img

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/554911.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Springboot集成支付宝沙箱支付(退款功能)

包括&#xff1a; 支付宝沙箱 支付 异步通知 退款功能 正式版本的sdk 通用版本SDK文档&#xff1a;https://opendocs.alipay.com/open/02np94 <dependency><groupId>com.alipay.sdk</groupId><artifactId>alipay-sdk-java</artifactId><…

Java递归生成树

1.建菜单表 CREATE TABLE t_menu (id int(11) NOT NULL AUTO_INCREMENT,pid int(11) NOT NULL,name varchar(255) DEFAULT NULL,PRIMARY KEY (id) ) ENGINEInnoDB AUTO_INCREMENT11 DEFAULT CHARSETutf8mb4;2.造一些数据 注意&#xff1a;根节点的pid0&#xff0c;其他节点的p…

Springboot获取公网IP和当前所在城市(非常简单)

最近我们发现各大社交平台都出现了一个新的功能&#xff1a;IP属地。 比如某乎&#xff1a; 这个IP属地是怎么做到的呢&#xff1f;今天我来教教你&#xff0c;保证你看完直呼Easy~ 百度搜索 打开百度&#xff0c;搜索IP&#xff0c;你就能看到你当前的IP地址&#xff0c;类…

线程死锁——死锁产生的条件

什么是线程死锁 线程死锁是指由于两个或者多个线程互相持有对方所需要的资源&#xff0c;导致这些线程处于相互等待状态&#xff0c;若无外力作用&#xff0c;它们将无法继续执行下去。 造成死锁的原因可以概括成三句话&#xff1a; 当前线程拥有其他线程需要的资源当前线程…

TortoiseGit的使用详解

Git是什么&#xff0c;相信大家都很清楚。Git不就是分布式版本控制系统嘛&#xff1f;那你知道TortoiseGit是什么吗&#xff1f;下面我们就介绍一下TortoiseGit它是什么&#xff1f;如何使用&#xff1f;   TortoiseGit其实是一款开源的git的版本控制系统&#xff0c;也叫海龟…

将项目上传到Gitee上(命令方式使用TortoiseGit方式)

如何将项目上传到Gitee上&#xff08;命令方式&#xff09; 目录 将项目上传到Gitee是我们经常需要使用到的操作&#xff0c;因此我们要熟悉这些步骤 一、首先保证本机已经安装了Git git官网安装完成之后&#xff0c;鼠标右键会出现Git GUI Here和Git Bash Here 二、上传代…

BufferedImage类、Image类、Graphics类

BufferedImage Image是一个抽象类&#xff0c;BufferedImage是其实现类&#xff0c;是一个带缓冲区图像类&#xff0c;主要作用是将一幅图片加载到内存中&#xff08;BufferedImage生成的图片在内存里有一个图像缓冲区&#xff0c;利用这个缓冲区我们可以很方便地操作这个图片&…

Vue this.$refs的作用

案例一、ref 写在标签上时 <!-- ref 写在标签上时&#xff1a;this.$refs.名字 获取的是标签对应的dom元素ref 写在组件上时&#xff1a;这时候获取到的是 子组件&#xff08;比如counter&#xff09;的引用--><div id"root"><!-- ref hello&#…

linux电脑合盖后卡住了,解决ubuntu合盖后无法唤醒

解决办法&#xff1a;安装laptop-mode-tools工具包。1.检查是否安装了grep laptop-mode-tools 工具包$ dpkg -l | grep laptop-mode-tools如果执行命令无结果输出&#xff0c;表示未安装(如果已安装&#xff0c;忽略第2步)2.安装laptop-mode执行命令&#xff1a;$ sudo apt-get…

三列布局 css

实现如下图的三列布局&#xff1a; .box {width:1400px;margin:0 auto;padding-bottom:40px;> .left {float:left;width:180px;margin-top:100px;text-align:center;}> .center {float:left;margin-top:100px;margin-left:130px;item-box {float:left;text-align:left;…

axios和ajax的区别是什么

axios和ajax的区别&#xff1a; 1、axios是一个基于Promise的HTTP库&#xff0c;而ajax是对原生XHR的封装&#xff1b; 2、ajax技术实现了局部数据的刷新&#xff0c;而axios实现了对ajax的封装。 axios和ajax的区别是什么? axios和ajax的区别及优缺点: ajax&#xff1a; 1…

VUE学习笔记详细

VUE学习笔记 本文章以vue3来记录的&#xff0c;但并非记录vue3所有变化&#xff01; 1、ES6语法 1.1、let变量声明 let用于声明变量有局部作用域let声明的变量不会提升&#xff08;只能先定义后使用&#xff09; 1.2、const变量声明 const用于声明常量const声明的常量也不会…

Centos7配置gitlab服务器

Centos7配置gitlab服务器 1、安装SSH yum install -y curl policycoreutils-pythonopenssh-server设置开机自启 sudo systemctl enable sshd启动服务 sudo systemctl start sshd2、安装postfix 邮件服务 sudo yum install postfix设置开机自启 sudo systemctl enable po…

Jenkins学习笔记详细

最近接触了jenkins这个东西&#xff0c;所以花点时间了解了下。它可以在代码上传仓库&#xff08;如github,gitee&#xff0c;gitlab&#xff09;后&#xff0c;在jenkins&#xff08;一个网站界面&#xff09;中通过获取代码仓库中最新代码&#xff0c;进行自动化部署&#xf…

Form Data与Request Payload,你真的了解吗?

前言 做过前后端联调的小伙伴&#xff0c;可能有时会遇到一些问题。例如&#xff0c;我明明传递数据给后端了&#xff0c;后端为什么说没收到呢&#xff1f;这时候可能就会就会有小伙伴陷入迷茫&#xff0c;本文从chrome-dev-tools&#xff08;F12调试器&#xff09;中看到的F…

计算机网络知识点复习

基础 1.说下计算机网络体系结构 计算机网络体系结构&#xff0c;一般有三种&#xff1a;OSI 七层模型、TCP/IP 四层模型、五层结构。 简单说&#xff0c;OSI是一个理论上的网络通信模型&#xff0c;TCP/IP是实际上的网络通信模型&#xff0c;五层结构就是为了介绍网络原理而折…

n个1组成的整数能被2013整除c语言,求大神解算法,“编写程序,求n至少为多大时,n个1组成的整数能被2013 整除。”...

编写程序&#xff0c;求n至少为多大时&#xff0c;n个1组成的整数能被2013 整除。使用python黑科技:i 1while int(1 * i) % 2013:i 1print(i)不使用黑科技:i s t 1while s % 2013:i 1t t * 10 % 2013s (s t) % 2013print(i)而事实上可以从数论的角度看。20133*11*61&a…

Java基础知识点复习

转载&#xff1a;https://mp.weixin.qq.com/s/M-6RSRcRd3X93cR7VXpanw Java概述 1.什么是Java&#xff1f; Java是一门面向对象的编程语言&#xff0c;不仅吸收了C语言的各种优点&#xff0c;还摒弃了C里难以理解的多继承、指针等概念&#xff0c;因此Java语言具有功能强大和…

为什么都说Dubbo不适合传输大文件?Dubbo支持的协议

背景 之前公司有一个 Dubbo 服务&#xff0c;内部封装了腾讯云的对象存储服务 SDK&#xff0c;是为了统一管理这种三方服务的SDK&#xff0c;其他系统直接调用这个对象存储的 Dubbo 服务。用来避免因平台 SDK 出现不兼容的大版本更新&#xff0c;导致公司所有系统修改跟着升级…

c语言编写劫持dll,c语言-----劫持自己02

在上一节 c语言-----劫持原理01 已经叙述了劫持原理&#xff0c;下边正式进入劫持实战1. 需要实现的功能在c语言中system("notepad") 可以打开一个记事本system("mspaint") 可以打开画图工具所以这次我们需要把 可以打开一个记事本 这个功能更改为 在控制…