From f082ca61b94ddfef5276a1e25c284480829d1a79 Mon Sep 17 00:00:00 2001
From: JMY <1960978976qq.com>
Date: Fri, 15 Aug 2025 19:05:57 +0800
Subject: [PATCH 1/5] =?UTF-8?q?build(yudao-server):=20=E6=B7=BB=E5=8A=A0?=
=?UTF-8?q?=E5=BE=AE=E4=BF=A1=E6=94=AF=E4=BB=98=20Java=20SDK=20=E4=BE=9D?=
=?UTF-8?q?=E8=B5=96?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 添加 io.swagger 的 swagger-annotations 依赖,版本 1.6.6
- 添加 com.github.wechatpay-apiv3 的 wechatpay-java 依赖,版本 0.2.7
---
yudao-server/pom.xml | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/yudao-server/pom.xml b/yudao-server/pom.xml
index 97ee0daf38..f997dbba8c 100644
--- a/yudao-server/pom.xml
+++ b/yudao-server/pom.xml
@@ -114,6 +114,18 @@
+
+ io.swagger
+ swagger-annotations
+ 1.6.6
+
+
+
+ com.github.wechatpay-apiv3
+ wechatpay-java
+ 0.2.7
+
+
--
Gitee
From 761c8177a087599d41a335b1b72ecf535144634c Mon Sep 17 00:00:00 2001
From: JMY <1960978976qq.com>
Date: Fri, 15 Aug 2025 19:35:41 +0800
Subject: [PATCH 2/5] =?UTF-8?q?build(module-system):=20=E6=B7=BB=E5=8A=A0?=
=?UTF-8?q?=20Sa-Token=E4=BE=9D=E8=B5=96=E5=B9=B6=E4=BC=98=E5=8C=96?=
=?UTF-8?q?=E5=AE=89=E5=85=A8=E9=85=8D=E7=BD=AE?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 在 yudao-module-system 模块中添加 Sa-Token 依赖,版本为 1.34.0
- 优化 yudao-server 的 pom.xml,注释掉未使用的依赖
- 改进 YudaoWebSecurityConfigurerAdapter 类的安全配置:
- 添加跨域配置解释
- 详细注释 CSRF 禁用和会话管理策略
- 增加异常处理和 iframe 嵌入相关配置的注释 - 明确 @PermitAll 注解的扫描和白名单设置
- 添加 Token 拦截器的解释
---
.../YudaoWebSecurityConfigurerAdapter.java | 31 ++++++++++++-------
yudao-module-system/pom.xml | 7 ++++-
yudao-server/pom.xml | 1 +
3 files changed, 27 insertions(+), 12 deletions(-)
diff --git a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoWebSecurityConfigurerAdapter.java b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoWebSecurityConfigurerAdapter.java
index bcf78f163b..d03ba88cea 100644
--- a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoWebSecurityConfigurerAdapter.java
+++ b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoWebSecurityConfigurerAdapter.java
@@ -110,19 +110,22 @@ public class YudaoWebSecurityConfigurerAdapter {
protected SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
// 登出
httpSecurity
- // 开启跨域
+ // 开启跨域 意思是:允许前端网页(比如 http://localhost:3000)访问这个后端(http://localhost:8080)
.cors(Customizer.withDefaults())
- // CSRF 禁用,因为不使用 Session
+ // CSRF 禁用,因为不使用 Session CSRF 是一种老式攻击方式,主要针对“用浏览器登录、靠 Cookie 维持登录状态”的系统。但我们用的是 token(比如 JWT),不是 Session + Cookie,所以可以安全地关掉它。
.csrf(AbstractHttpConfigurer::disable)
- // 基于 token 机制,所以不需要 Session
+ // 基于 token 机制,所以不需要 Session 普通网站登录后,服务器会创建一个“会话”(Session)来记住你。但我们不用这种方式,我们靠 token 来识别用户,所以设置为 STATELESS(无状态),表示“我不记录你是谁,你每次来都要带 token”。
.sessionManagement(c -> c.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
+ //有些页面需要被其他系统用
-
+
+
+ cn.dev33
+ sa-token-spring-boot-starter
+ 1.34.0
+
cn.iocoder.boot
diff --git a/yudao-server/pom.xml b/yudao-server/pom.xml
index f997dbba8c..793daa0a39 100644
--- a/yudao-server/pom.xml
+++ b/yudao-server/pom.xml
@@ -114,6 +114,7 @@
+
io.swagger
swagger-annotations
--
Gitee
From 26b7b0c8f6682f26e066512de83591e18075fd4e Mon Sep 17 00:00:00 2001
From: JMY <1960978976qq.com>
Date: Mon, 18 Aug 2025 09:44:06 +0800
Subject: [PATCH 3/5] =?UTF-8?q?feat(wx):=20=E6=B7=BB=E5=8A=A0=E5=BE=AE?=
=?UTF-8?q?=E4=BF=A1=E6=94=AF=E4=BB=98=E7=9B=B8=E5=85=B3=E5=8A=9F=E8=83=BD?=
=?UTF-8?q?=E5=92=8C=E5=AE=9E=E4=BD=93=E7=B1=BB?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 新增 CreateOrderReq 和 QueryOrderReq 类用于微信支付请求
- 添加 WxOrderEntity 和 WxPayLogEntity 实体类
- 新增 WxOrderDataService 和 WxPayLogDataService 接口
- 添加 WxPayConfig 配置类和 WxPayAutoCertificateConfig 证书配置
- 新增 Util 工具类和 WindowsUUIDFetcher 类
---
.../controller/Entity/WxOrderEntity.java | 56 ++
.../controller/Entity/WxPayLogEntity.java | 38 +
.../yudao/server/controller/Util/Util.java | 143 ++++
.../controller/ip/WindowsUUIDFetcher.java | 83 ++
.../server/controller/wx/CreateOrderReq.java | 31 +
.../controller/wx/CreateRefundController.java | 45 +
.../server/controller/wx/QueryOrderReq.java | 20 +
.../iocoder/yudao/server/controller/wx/R.java | 97 +++
.../controller/wx/SortablePageParam.java | 20 +
.../server/controller/wx/SortingField.java | 37 +
.../controller/wx/WxOrderDataService.java | 11 +
.../wx/WxPayAutoCertificateConfig.java | 35 +
.../server/controller/wx/WxPayConfig.java | 31 +
.../controller/wx/WxPayLogDataService.java | 7 +
.../server/controller/wx/WxPayService.java | 790 ++++++++++++++++++
15 files changed, 1444 insertions(+)
create mode 100644 yudao-server/src/main/java/cn/iocoder/yudao/server/controller/Entity/WxOrderEntity.java
create mode 100644 yudao-server/src/main/java/cn/iocoder/yudao/server/controller/Entity/WxPayLogEntity.java
create mode 100644 yudao-server/src/main/java/cn/iocoder/yudao/server/controller/Util/Util.java
create mode 100644 yudao-server/src/main/java/cn/iocoder/yudao/server/controller/ip/WindowsUUIDFetcher.java
create mode 100644 yudao-server/src/main/java/cn/iocoder/yudao/server/controller/wx/CreateOrderReq.java
create mode 100644 yudao-server/src/main/java/cn/iocoder/yudao/server/controller/wx/CreateRefundController.java
create mode 100644 yudao-server/src/main/java/cn/iocoder/yudao/server/controller/wx/QueryOrderReq.java
create mode 100644 yudao-server/src/main/java/cn/iocoder/yudao/server/controller/wx/R.java
create mode 100644 yudao-server/src/main/java/cn/iocoder/yudao/server/controller/wx/SortablePageParam.java
create mode 100644 yudao-server/src/main/java/cn/iocoder/yudao/server/controller/wx/SortingField.java
create mode 100644 yudao-server/src/main/java/cn/iocoder/yudao/server/controller/wx/WxOrderDataService.java
create mode 100644 yudao-server/src/main/java/cn/iocoder/yudao/server/controller/wx/WxPayAutoCertificateConfig.java
create mode 100644 yudao-server/src/main/java/cn/iocoder/yudao/server/controller/wx/WxPayConfig.java
create mode 100644 yudao-server/src/main/java/cn/iocoder/yudao/server/controller/wx/WxPayLogDataService.java
create mode 100644 yudao-server/src/main/java/cn/iocoder/yudao/server/controller/wx/WxPayService.java
diff --git a/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/Entity/WxOrderEntity.java b/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/Entity/WxOrderEntity.java
new file mode 100644
index 0000000000..45827905d5
--- /dev/null
+++ b/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/Entity/WxOrderEntity.java
@@ -0,0 +1,56 @@
+package cn.iocoder.yudao.server.controller.Entity;
+
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * 微信商品订单实体类
+ * 对应数据库表: t_wx_order
+ */
+@Data
+public class WxOrderEntity {
+ /** 主键UUID */
+ private String uuid;
+
+ /** 商品名称 */
+ private String tradeName;
+
+ /** 订单描述 */
+ private String description;
+
+ /** (商户)订单流水号 */
+ private String outTradeNo;
+
+ /** 微信订单号 */
+ private String transactionId;
+
+ /** 订单金额(单位:分) */
+ private Integer totalFee;
+
+ /** 支付成功后的随机32位字符串 */
+ private String payNonce;
+
+ /** 支付时间 */
+ private Date payTime;
+
+ /** 支付日期 */
+ private Date payDate;
+
+ /** 支付状态: 0:待支付,1:支付成功,2:支付失败,3:退款成功,4:正在退款中,5:未知 */
+ private Integer payStatus;
+
+ /** 微信小程序openid */
+ private String wxOpenId;
+
+ /** 状态: 0:未删除,1:已删除 */
+ private Integer status;
+
+ /** 创建订单时间 */
+ private Date createTime;
+
+ /** 修改订单时间 */
+ private Date updateTime;
+
+
+}
diff --git a/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/Entity/WxPayLogEntity.java b/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/Entity/WxPayLogEntity.java
new file mode 100644
index 0000000000..53a16a4fc7
--- /dev/null
+++ b/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/Entity/WxPayLogEntity.java
@@ -0,0 +1,38 @@
+package cn.iocoder.yudao.server.controller.Entity;
+
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * 微信用户支付记录实体类
+ * 对应数据库表: t_wx_pay_log
+ */
+@Data
+public class WxPayLogEntity {
+ /** 主键UUID */
+ private String uuid;
+
+ /** 微信用户openid */
+ private String wxOpenId;
+
+ /** (商户)订单流水号 */
+ private String outTradeNo;
+
+ /** (商户)退款流水号 */
+ private String outRefundNo;
+
+ /** 微信订单号 */
+ private String transactionId;
+
+ /** 支付金额(单位:分) */
+ private Integer totalFee;
+
+ /** 支付状态: 1:支付,2:退款 */
+ private Integer payStatus;
+
+ /** 创建时间 */
+ private Date createTime;
+
+
+}
diff --git a/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/Util/Util.java b/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/Util/Util.java
new file mode 100644
index 0000000000..3c88139338
--- /dev/null
+++ b/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/Util/Util.java
@@ -0,0 +1,143 @@
+package cn.iocoder.yudao.server.controller.Util;
+
+import org.apache.commons.codec.digest.DigestUtils;
+import org.apache.commons.lang3.RandomStringUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.time.DateFormatUtils;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.*;
+
+/**
+ * @program: publicpaydemo
+ * @description: 工具类
+ * @author: Mr.YS
+ * @CreatDate: 2019/5/17/017 13:24
+ */
+public class Util {
+
+ /**
+ * 获取到订单号
+ *
+ * @param msgSrcId 消息来源编号 1017
+ * @return 商户订单号 {来源编号(4位)}{时间(yyyyMMddmmHHssSSS)(17位)}{7位随机数}
+ */
+ public static String getMerOrderId(String msgSrcId) {
+ return msgSrcId + DateFormatUtils.format(new Date(), "yyyyMMddHHmmssSSS") + RandomStringUtils.randomNumeric(7);
+ }
+
+ /**
+ * 获取到流水号
+ *
+ * @return 商户订单号 {来源编号(4位)}{时间(yyyyMMddmmHHssSSS)(17位)}{7位随机数}
+ */
+ public static String getPaymentNo(String payType) {
+ return payType + DateFormatUtils.format(new Date(), "yyyyMMddHHmmssSSS") + RandomStringUtils.randomNumeric(7);
+ }
+
+ /**
+ * 获取到退货订单号refundOrderId
+ *
+ * @param msgSrcId 消息来源编号 1017
+ * @return 商户订单号 {来源编号(4位)}{时间(yyyyMMddmmHHssSSS)(17位)}{7位随机数}
+ */
+ public static String getRefundOrderId(String msgSrcId) {
+ return msgSrcId + DateFormatUtils.format(new Date(), "yyyyMMddHHmmssSSS") + RandomStringUtils.randomNumeric(7);
+ }
+
+
+
+ // 获取HttpServletRequest里面的参数
+ public static Map getRequestParams(HttpServletRequest request) {
+ Map params = request.getParameterMap();
+ Map params2 = new HashMap<>();
+ for (String key : params.keySet()) {
+ String[] values = params.get(key);
+ if (values.length > 0) {
+ params2.put(key, request.getParameter(key));
+ }
+ }
+ return params2;
+ }
+
+
+ public static String makeSign(String md5Key, Map params) {
+
+ String preStr = buildSignString(params); // 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
+ String text = preStr + md5Key;
+ System.out.println("待签名字符串:"+text);
+ return DigestUtils.md5Hex(getContentBytes(text)).toUpperCase();
+ //return DigestUtils.sha256Hex(getContentBytes(text)).toLowerCase();
+
+ }
+
+ // 构建签名字符串
+ public static String buildSignString(Map params) {
+
+ // params.put("Zm","test_test");
+
+ if (params == null || params.size() == 0) {
+ return "";
+ }
+
+ List keys = new ArrayList<>(params.size());
+
+ for (String key : params.keySet()) {
+ if ("sign".equals(key)) {
+ continue;
+ }
+ if (StringUtils.isEmpty(params.get(key))) {
+ continue;
+ }
+ keys.add(key);
+ }
+ //System.out.println(listToString(keys));
+
+ Collections.sort(keys);
+
+ StringBuilder buf = new StringBuilder();
+
+ for (int i = 0; i < keys.size(); i++) {
+ String key = keys.get(i);
+ String value = params.get(key);
+
+ if (i == keys.size() - 1) {// 拼接时,不包括最后一个&字符
+ buf.append(key + "=" + value);
+ } else {
+ buf.append(key + "=" + value + "&");
+ }
+ }
+
+ return buf.toString();
+ }
+
+ // 根据编码类型获得签名内容byte[]
+ public static byte[] getContentBytes(String content) {
+ try {
+ return content.getBytes("UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException("签名过程中出现错误");
+ }
+ }
+
+ /**
+ * 判断文件是否存在
+ * @param filePath
+ */
+ public static void createFolder(String filePath) {
+ Path directoryPath = Paths.get(filePath);
+ boolean exists = Files.exists(directoryPath);
+ try {
+ if (!exists){
+ Files.createDirectories(directoryPath);
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/ip/WindowsUUIDFetcher.java b/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/ip/WindowsUUIDFetcher.java
new file mode 100644
index 0000000000..c71b32f781
--- /dev/null
+++ b/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/ip/WindowsUUIDFetcher.java
@@ -0,0 +1,83 @@
+package cn.iocoder.yudao.server.controller.ip;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+
+public class WindowsUUIDFetcher {
+
+ /**
+ * 获取 Windows 主板的 UUID
+ * @return UUID 字符串,失败返回 null
+ */
+ public static String getWindowsUUID() {
+ try {
+ // 执行系统命令
+ Process process = Runtime.getRuntime().exec("wmic csproduct get uuid");
+
+ // 读取正常输出流
+ BufferedReader reader = new BufferedReader(
+ new InputStreamReader(process.getInputStream())
+ );
+
+ // 重要:读取错误流,防止进程卡死
+ BufferedReader errorReader = new BufferedReader(
+ new InputStreamReader(process.getErrorStream())
+ );
+
+ String line;
+ while ((line = reader.readLine()) != null) {
+ // 去除空行,并排除包含 "UUID" 的标题行
+ line = line.trim();
+ if (!line.isEmpty() && !line.equalsIgnoreCase("UUID")) {
+ // UUID 通常在第一行有效数据中
+ // 可能有多余空格,只取第一个非空部分
+ String[] parts = line.split("\\s+");
+ for (String part : parts) {
+ if (part.length() > 0 && !part.equalsIgnoreCase("UUID")) {
+ return part;
+ }
+ }
+ }
+ }
+
+ // 读取错误信息(用于调试)
+ String errorLine;
+ StringBuilder errorMsg = new StringBuilder();
+ while ((errorLine = errorReader.readLine()) != null) {
+ errorMsg.append(errorLine).append("\n");
+ }
+ if (errorMsg.length() > 0) {
+ System.err.println("WMIC 错误: " + errorMsg.toString());
+ }
+
+ // 等待命令执行完成
+ int exitCode = process.waitFor();
+ if (exitCode != 0) {
+ System.err.println("WMIC 命令执行失败,退出码: " + exitCode);
+ }
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ // ✅ 测试入口
+ public static void main(String[] args) {
+ System.out.println("开始获取 Windows UUID...");
+
+ String uuid = getWindowsUUID();
+
+ if (uuid != null) {
+ System.out.println("✅ 获取成功!");
+ System.out.println("主板 UUID: " + uuid);
+ } else {
+ System.out.println("❌ 获取失败!");
+ System.out.println("可能原因:");
+ System.out.println("1. 不是 Windows 系统");
+ System.out.println("2. wmic 命令未找到(Win11 可能被禁用)");
+ System.out.println("3. 权限不足");
+ System.out.println("4. 虚拟机或某些品牌机返回空");
+ }
+ }
+}
\ No newline at end of file
diff --git a/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/wx/CreateOrderReq.java b/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/wx/CreateOrderReq.java
new file mode 100644
index 0000000000..0a0e357477
--- /dev/null
+++ b/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/wx/CreateOrderReq.java
@@ -0,0 +1,31 @@
+package cn.iocoder.yudao.server.controller.wx;
+
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+
+/**
+ * @author caozhen
+ * @ClassName CreateOrderReq
+ * @description: TODO
+ * @date 2024年01月03日
+ * @version: 1.0
+ */
+@Data
+public class CreateOrderReq {
+
+ @ApiModelProperty(name = "description", value = "商品描述")
+ private String description;
+
+ @ApiModelProperty(name = "wxOpenId", value = "用户小程序openid")
+ private String wxOpenId;
+
+// @ApiModelProperty(name = "outTradeNo", value = "商户订单号")
+// private String outTradeNo;
+
+ @ApiModelProperty(name = "totalFee", value = "支付金额,单位:分")
+ private BigDecimal totalFee;
+}
\ No newline at end of file
diff --git a/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/wx/CreateRefundController.java b/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/wx/CreateRefundController.java
new file mode 100644
index 0000000000..09d5c09ed2
--- /dev/null
+++ b/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/wx/CreateRefundController.java
@@ -0,0 +1,45 @@
+package cn.iocoder.yudao.server.controller.wx;//package cn.iocoder.yudao.server.controller.wx;
+//
+//import io.swagger.annotations.ApiOperation;
+//import org.springframework.beans.factory.annotation.Autowired;
+//import org.springframework.http.ResponseEntity;
+//import org.springframework.web.bind.annotation.*;
+//
+//import javax.annotation.security.PermitAll;
+//import javax.servlet.http.HttpServletRequest;
+//
+//@RestController
+//@RequestMapping("/createRefund")
+//public class CreateRefundController {
+//
+// @Autowired
+// private WxPayService wxPayService;
+//
+//
+//
+//
+// @PostMapping("/wxPayment")
+// @ApiOperation(value = "微信支付-微信支付")
+// @PermitAll
+// public R wxPayment(@RequestBody CreateOrderReq req) {
+// return wxPayService.createOrder(req);
+// }
+//
+// @PostMapping("/wxPaymentNotify")
+// @ApiOperation(value = "微信支付-微信支付回调通知")
+// public void wxPaymentNotify(HttpServletRequest request) {
+// String s = wxPayService.payNotify(request);
+//
+// }
+//
+// @RequestMapping(value = "/xcx/createRefund", method = RequestMethod.POST)
+// @ApiOperation(value = "微信支付-微信申请退款")
+// public ResponseEntity> createRefund(String outTradeNo, Long totalAmount, String outRefundNo) {
+// return ResponseEntity.ok(wxPayService.createRefund(outTradeNo, totalAmount, outRefundNo));
+// }
+// @RequestMapping(value = "/wx/refundNotify", method = RequestMethod.POST)
+// @ApiOperation(value = "微信支付-微信退款回调通知")
+// public void refundNotify(HttpServletRequest request) throws Exception {
+// wxPayService.refundNotify(request);
+// }
+//}
diff --git a/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/wx/QueryOrderReq.java b/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/wx/QueryOrderReq.java
new file mode 100644
index 0000000000..ebf6b9ed55
--- /dev/null
+++ b/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/wx/QueryOrderReq.java
@@ -0,0 +1,20 @@
+package cn.iocoder.yudao.server.controller.wx;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * @author caozhen
+ * @ClassName QueryOrderReq
+ * @description: 支付查询
+ * @date 2024年01月04日
+ * @version: 1.0
+ */
+@Data
+public class QueryOrderReq {
+ @ApiModelProperty(name = "paymentNo", value = "微信支付订单号,同:transaction_id")
+ private String paymentNo;
+
+ @ApiModelProperty(name = "orderNo", value = "商户订单号,同:out_trade_no")
+ private String orderNo;
+}
\ No newline at end of file
diff --git a/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/wx/R.java b/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/wx/R.java
new file mode 100644
index 0000000000..314c70b37e
--- /dev/null
+++ b/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/wx/R.java
@@ -0,0 +1,97 @@
+package cn.iocoder.yudao.server.controller.wx;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ *
+ * @author 曹震
+ * @date 2024-1-03
+ */
+public class R extends HashMap {
+
+ private static final long serialVersionUID = 1L;
+
+ public R() {
+ put("code", 0);
+ }
+
+ public R(Integer code) {
+ put("code", code);
+ put("data", new HashMap());
+ }
+
+ public R(Integer code, String msg) {
+ put("code", code);
+ put("msg", msg);
+ put("data", new HashMap());
+ }
+
+ public static R error() {
+ return error(500, "未知异常,请联系管理员");
+ }
+
+ public static R errorDebug(String message) {
+ return error(500, "未知异常 " + message + ",请联系管理员");
+ }
+
+ public static R error(String msg) {
+ return error(500, msg);
+ }
+
+
+ public static R error(int code, String msg) {
+ R r = new R();
+ r.put("code", code);
+ r.put("msg", msg);
+ return r;
+ }
+
+ public R errorInfo(String msg) {
+ this.put("errorMsg", msg);
+ return this;
+ }
+
+ public static R ok(String msg) {
+ R r = new R();
+ r.put("msg", msg);
+ r.put("data", new HashMap());
+ return r;
+ }
+
+ public static R ok(Map map) {
+ R r = new R();
+ r.putAll(map);
+ r.put("data", new HashMap());
+ return r;
+ }
+
+ public static R ok() {
+ return new R().put("msg", "success").put("data", new HashMap());
+ }
+
+ public static R ok(Integer size) {
+ return new R().put("data", new HashMap((int)Math.round(size / 0.75)));
+ }
+
+ @Override
+ public R put(String key, Object value) {
+ super.put(key, value);
+ return this;
+ }
+
+ /**
+ * 添加返回结果数据
+ *
+ * @param key
+ * @param value
+ * @return
+ */
+ public R putData(String key, Object value) {
+ Map map = (HashMap)this.get("data");
+ map.put(key, value);
+ return this;
+ }
+
+
+}
\ No newline at end of file
diff --git a/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/wx/SortablePageParam.java b/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/wx/SortablePageParam.java
new file mode 100644
index 0000000000..6b996b23af
--- /dev/null
+++ b/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/wx/SortablePageParam.java
@@ -0,0 +1,20 @@
+package cn.iocoder.yudao.server.controller.wx;//package cn.iocoder.yudao.server.controller.wx;
+//
+//import cn.iocoder.yudao.framework.common.pojo.PageParam;
+//import io.swagger.v3.oas.annotations.media.Schema;
+//import lombok.Data;
+//import lombok.EqualsAndHashCode;
+//import lombok.ToString;
+//
+//import java.util.List;
+//
+//@Schema(description = "可排序的分页参数")
+//@Data
+//@EqualsAndHashCode(callSuper = true)
+//@ToString(callSuper = true)
+//public class SortablePageParam extends PageParam {
+//
+// @Schema(description = "排序字段")
+// private List sortingFields;
+//
+//}
\ No newline at end of file
diff --git a/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/wx/SortingField.java b/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/wx/SortingField.java
new file mode 100644
index 0000000000..7b9b43a769
--- /dev/null
+++ b/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/wx/SortingField.java
@@ -0,0 +1,37 @@
+package cn.iocoder.yudao.server.controller.wx;//package cn.iocoder.yudao.server.controller.wx;
+//
+//import lombok.AllArgsConstructor;
+//import lombok.Data;
+//import lombok.NoArgsConstructor;
+//
+//import java.io.Serializable;
+//
+///**
+// * 排序字段 DTO
+// *
+// * 类名加了 ing 的原因是,避免和 ES SortField 重名。
+// */
+//@Data
+//@NoArgsConstructor
+//@AllArgsConstructor
+//public class SortingField implements Serializable {
+//
+// /**
+// * 顺序 - 升序
+// */
+// public static final String ORDER_ASC = "asc";
+// /**
+// * 顺序 - 降序
+// */
+// public static final String ORDER_DESC = "desc";
+//
+// /**
+// * 字段
+// */
+// private String field;
+// /**
+// * 顺序
+// */
+// private String order;
+//
+//}
diff --git a/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/wx/WxOrderDataService.java b/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/wx/WxOrderDataService.java
new file mode 100644
index 0000000000..c9679b0065
--- /dev/null
+++ b/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/wx/WxOrderDataService.java
@@ -0,0 +1,11 @@
+package cn.iocoder.yudao.server.controller.wx;
+
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.server.controller.Entity.WxOrderEntity;
+
+/**
+ * 微信订单数据服务接口
+ */
+public interface WxOrderDataService extends BaseMapperX {
+
+}
diff --git a/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/wx/WxPayAutoCertificateConfig.java b/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/wx/WxPayAutoCertificateConfig.java
new file mode 100644
index 0000000000..beb50d526f
--- /dev/null
+++ b/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/wx/WxPayAutoCertificateConfig.java
@@ -0,0 +1,35 @@
+package cn.iocoder.yudao.server.controller.wx;//package cn.iocoder.yudao.server.controller.wx;
+//
+//import com.wechat.pay.java.core.RSAAutoCertificateConfig;
+//import org.springframework.context.annotation.Bean;
+//import org.springframework.context.annotation.Configuration;
+//
+//import javax.annotation.Resource;
+//
+///**
+// * @author caozhen
+// * @ClassName WxPayAutoCertificateConfig
+// * @description: 微信支付证书自动更新配置
+// * @date 2024年01月03日
+// * @version: 1.0
+// */
+//@Configuration
+//public class WxPayAutoCertificateConfig {
+// @Resource
+// private WxPayConfig wxPayConfig;
+//
+// /**
+// * 初始化商户配置
+// * @return
+// */
+// @Bean
+// public RSAAutoCertificateConfig rsaAutoCertificateConfig() {
+// RSAAutoCertificateConfig config = new RSAAutoCertificateConfig.Builder()
+// .merchantId(wxPayConfig.getMerchantId())
+// .privateKey(wxPayConfig.getPrivateKey())
+// .merchantSerialNumber(wxPayConfig.getMerchantSerialNumber())
+// .apiV3Key(wxPayConfig.getApiV3Key())
+// .build();
+// return config;
+// }
+//}
\ No newline at end of file
diff --git a/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/wx/WxPayConfig.java b/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/wx/WxPayConfig.java
new file mode 100644
index 0000000000..1ba1c4b333
--- /dev/null
+++ b/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/wx/WxPayConfig.java
@@ -0,0 +1,31 @@
+package cn.iocoder.yudao.server.controller.wx;//package cn.iocoder.yudao.server.controller.wx;
+//
+//import lombok.Data;
+//import org.springframework.stereotype.Component;
+//
+///**
+// * @author caozhen
+// * @ClassName WxPayConfig
+// * @description: 微信支付配置类
+// * @date 2024年01月03日
+// * @version: 1.0
+// */
+//@Data
+//@Component
+////@ConfigurationProperties(prefix = "wx.pay")
+//public class WxPayConfig {
+// //APPID
+// private String appId;
+// //商户号id
+// private String merchantId;
+// //商户API私钥
+// private String privateKey;
+// //商户证书序列号
+// private String merchantSerialNumber;
+// //商户APIv3密钥
+// private String apiV3Key;
+// //支付通知地址
+// private String payNotifyUrl;
+// //退款通知地址
+// private String refundNotifyUrl;
+//}
\ No newline at end of file
diff --git a/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/wx/WxPayLogDataService.java b/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/wx/WxPayLogDataService.java
new file mode 100644
index 0000000000..c6c7b01faa
--- /dev/null
+++ b/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/wx/WxPayLogDataService.java
@@ -0,0 +1,7 @@
+package cn.iocoder.yudao.server.controller.wx;//package cn.iocoder.yudao.server.controller.wx;
+//
+//import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+//import cn.iocoder.yudao.server.controller.Entity.WxPayLogEntity;
+//
+//public interface WxPayLogDataService extends BaseMapperX {
+//}
diff --git a/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/wx/WxPayService.java b/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/wx/WxPayService.java
new file mode 100644
index 0000000000..f26ae28877
--- /dev/null
+++ b/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/wx/WxPayService.java
@@ -0,0 +1,790 @@
+package cn.iocoder.yudao.server.controller.wx;//package cn.iocoder.yudao.server.controller.wx;
+//
+//import cn.iocoder.yudao.server.controller.Entity.WxOrderEntity;
+//import cn.iocoder.yudao.server.controller.Entity.WxPayLogEntity;
+//import cn.iocoder.yudao.server.controller.Util.DateUtils;
+//import cn.iocoder.yudao.server.controller.Util.HttpServletUtils;
+//import cn.iocoder.yudao.server.controller.Util.Util;
+//import com.alibaba.fastjson.JSONObject;
+//import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+//import com.wechat.pay.java.core.RSAAutoCertificateConfig;
+//import com.wechat.pay.java.core.exception.HttpException;
+//import com.wechat.pay.java.core.exception.MalformedMessageException;
+//import com.wechat.pay.java.core.exception.ServiceException;
+//import com.wechat.pay.java.core.notification.NotificationParser;
+//import com.wechat.pay.java.core.notification.RequestParam;
+//import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
+//import com.wechat.pay.java.service.payments.jsapi.model.*;
+//import com.wechat.pay.java.service.payments.jsapi.model.Amount;
+//import com.wechat.pay.java.service.payments.model.Transaction;
+//import com.wechat.pay.java.service.refund.RefundService;
+//import com.wechat.pay.java.service.refund.model.*;
+//import lombok.extern.slf4j.Slf4j;
+//import org.apache.commons.lang3.StringUtils;
+//import org.redisson.api.RLock;
+//import org.redisson.api.RedissonClient;
+//import org.springframework.beans.factory.annotation.Autowired;
+//import org.springframework.stereotype.Service;
+//import org.springframework.transaction.annotation.Transactional;
+//
+//import javax.annotation.Resource;
+//import javax.servlet.http.HttpServletRequest;
+//import java.io.IOException;
+//import java.math.BigDecimal;
+//import java.util.Date;
+//import java.util.HashMap;
+//import java.util.LinkedHashMap;
+//import java.util.Map;
+//import java.util.concurrent.TimeUnit;
+//
+///**
+// * @author caozhen
+// * @ClassName WxPayService
+// * @description: 微信支付
+// * @date 2024年01月03日
+// * @version: 1.0
+// */
+//@Slf4j
+//@Service
+//public class WxPayService {
+//
+// @Resource
+// private WxPayConfig wxPayConfig;
+// @Autowired
+// private RSAAutoCertificateConfig rsaAutoCertificateConfig;
+// @Autowired
+// private WxOrderDataService wxOrderDataService;
+// @Autowired
+// private WxPayLogDataService wxPayLogDataService;
+// // 注入RedissonClient
+// @Autowired
+// private RedissonClient redissonClient;
+//
+//
+// /***
+// * 预支付订单
+// * @param req
+// * @return
+// */
+// public R createOrder(CreateOrderReq req) {
+// if (req == null) {
+// return R.error("创建订单失败,缺少参数!");
+// }
+// //先解密
+//
+// // String orderNo = req.getOutTradeNo();
+// //Integer totalFee = Math.toIntExact(req.getTotalFee());
+// //通过工具生成订单号
+// String orderNo = Util.getMerOrderId("WX");
+// //将元转为分
+// Integer totalFee = req.getTotalFee().multiply(new BigDecimal("100")).intValue();
+// String description = req.getDescription();
+// //创建初始化订单
+// //todo,创建订单这边你们自己来(后面我会放出表结构)
+// //请求微信支付相关配置
+// JsapiServiceExtension service =
+// new JsapiServiceExtension.Builder()
+// .config(rsaAutoCertificateConfig)
+// .signType("RSA") // 不填默认为RSA
+// .build();
+// PrepayWithRequestPaymentResponse response = new PrepayWithRequestPaymentResponse();
+// try {
+// PrepayRequest request = new PrepayRequest();
+// //appid
+// request.setAppid(wxPayConfig.getAppId());
+// //商户号id
+// request.setMchid(wxPayConfig.getMerchantId());
+// //商品描述
+// request.setDescription(description + "充值");
+// //订单号
+// request.setOutTradeNo(orderNo);
+// //支付回调
+// request.setNotifyUrl(wxPayConfig.getPayNotifyUrl());
+// //amount.setTotal(totalFee.multiply(new BigDecimal("100")).intValue());
+// //微信支付API金额对象
+// Amount amount = new Amount();
+// //将元转分的金额设置到金额对象中
+// amount.setTotal(totalFee);
+// //将封装后的金额 添加微信支付预下单中
+// request.setAmount(amount);
+// //创建付款人对象
+// Payer payer = new Payer();
+// //设置付款人OpenId (OpenId是微信用户特定下的唯一标识)
+// payer.setOpenid(req.getWxOpenId());
+// //将付款人对象设置到预下单中
+// request.setPayer(payer);
+// log.info("请求预支付下单,请求参数:{}", JSONObject.toJSONString(request));
+// // 调用预下单接口
+// response = service.prepayWithRequestPayment(request);
+// log.info("订单【{}】发起预支付成功,返回信息:{}", orderNo, response);
+//
+// } catch (HttpException e) { // 发送HTTP请求失败
+// log.error("微信下单发送HTTP请求失败,错误信息:{}", e.getHttpRequest());
+// return R.error("下单失败");
+// } catch (ServiceException e) { // 服务返回状态小于200或大于等于300,例如500
+// log.error("微信下单服务状态错误,错误信息:{}", e.getErrorMessage());
+// return R.error("下单失败");
+// } catch (MalformedMessageException e) { // 服务返回成功,返回体类型不合法,或者解析返回体失败
+// log.error("服务返回成功,返回体类型不合法,或者解析返回体失败,错误信息:{}", e.getMessage());
+// return R.error("下单失败");
+// }
+// return R.ok().put("data", response);
+// }
+//
+// /***
+// * 微信支付回调通知
+// * @param request
+// * @return
+// * @throws IOException
+// */
+// @Transactional
+// public synchronized String payNotify(HttpServletRequest request) {
+// log.info("------收到支付通知------");
+// // 请求头Wechatpay-Signature
+// String signature = request.getHeader("Wechatpay-Signature");
+// // 请求头Wechatpay-nonce
+// String nonce = request.getHeader("Wechatpay-Nonce");
+// // 请求头Wechatpay-Timestamp
+// String timestamp = request.getHeader("Wechatpay-Timestamp");
+// // 微信支付证书序列号
+// String serial = request.getHeader("Wechatpay-Serial");
+// // 签名方式
+// String signType = request.getHeader("Wechatpay-Signature-Type");
+// // 构造 RequestParam
+// RequestParam requestParam;
+// try {
+// requestParam = new RequestParam.Builder()
+// .serialNumber(serial)
+// .nonce(nonce)
+// .signature(signature)
+// .timestamp(timestamp)
+// .signType(signType)
+// .body(HttpServletUtils.getRequestBody(request))
+// .build();
+// } catch (Exception e) {
+// throw new RuntimeException(e);
+// }
+//
+// // 初始化 NotificationParser
+// NotificationParser parser = new NotificationParser(rsaAutoCertificateConfig);
+// // 以支付通知回调为例,验签、解密并转换成 Transaction
+// log.info("验签参数:{}", requestParam);
+// Transaction transaction = parser.parse(requestParam, Transaction.class);
+// log.info("验签成功!-支付回调结果:{}", transaction.toString());
+//
+//
+// Map returnMap = new HashMap<>(2);
+// returnMap.put("code", "FAIL");
+// returnMap.put("message", "失败");
+// //修改订单前,建议主动请求微信查询订单是否支付成功,防止恶意post
+// QueryWrapper wrapper = new QueryWrapper();
+// wrapper.eq("out_trade_no", transaction.getOutTradeNo());
+// //wrapper.eq("transaction_id", transaction.getTransactionId());
+// WxOrderEntity wxOrderEntity = wxOrderDataService.selectOne(wrapper);
+// if (wxOrderEntity != null) {
+// if (wxOrderEntity.getPayStatus() == 1) {
+// //此时已经是支付成功,不在处理订单信息
+// returnMap.put("code", "SUCCESS");
+// returnMap.put("message", "成功");
+// return JSONObject.toJSONString(returnMap);
+// }
+// }
+// if (Transaction.TradeStateEnum.SUCCESS != transaction.getTradeState()) {
+// log.info("内部订单号【{}】,微信支付订单号【{}】支付未成功", transaction.getOutTradeNo(), transaction.getTransactionId());
+// if (wxOrderEntity != null) {
+// wxOrderEntity.setUpdateTime(new Date());
+// wxOrderEntity.setPayStatus(2);
+// wxOrderEntity.setPayNonce(nonce);
+// wxOrderEntity.setTransactionId(transaction.getTransactionId());
+// //修改订单信息
+// wxOrderDataService.updateById(wxOrderEntity);
+// }
+// return JSONObject.toJSONString(returnMap);
+// }
+// if (wxOrderEntity != null) {
+// wxOrderEntity.setUpdateTime(new Date());
+// wxOrderEntity.setPayTime(DateUtils.stringToDateTime(transaction.getSuccessTime()));
+// wxOrderEntity.setPayDate(DateUtils.stringToDateTime(transaction.getSuccessTime()));
+// wxOrderEntity.setPayStatus(1);
+// wxOrderEntity.setPayNonce(nonce);
+// wxOrderEntity.setTransactionId(transaction.getTransactionId());
+// //修改订单信息
+// wxOrderDataService.updateById(wxOrderEntity);
+// //同时处理支付记录
+// QueryWrapper payWrapper = new QueryWrapper();
+// wrapper.eq("out_trade_no", transaction.getOutTradeNo());
+// wrapper.eq("pay_status", 1);//支付
+// WxPayLogEntity wxPayLogEntity = wxPayLogDataService.selectOne(payWrapper);
+// if (wxPayLogEntity == null) {
+// wxPayLogEntity = new WxPayLogEntity();
+// wxPayLogEntity.setCreateTime(new Date());
+// wxPayLogEntity.setOutTradeNo(wxOrderEntity.getOutTradeNo());
+// wxPayLogEntity.setPayStatus(1);
+// wxPayLogEntity.setTotalFee(wxOrderEntity.getTotalFee());
+// wxPayLogEntity.setTransactionId(wxOrderEntity.getTransactionId());
+// wxPayLogEntity.setWxOpenId(wxOrderEntity.getWxOpenId());
+// wxPayLogDataService.insert(wxPayLogEntity);
+// }
+// }
+//
+// returnMap.put("code", "SUCCESS");
+// returnMap.put("message", "成功");
+// return JSONObject.toJSONString(returnMap);
+// }
+//
+// @Transactional
+// public synchronized String payNotif(HttpServletRequest request) {
+// log.info("------收到支付通知------");
+// // 请求头Wechatpay-Signature 微信支付签名
+// String signature = request.getHeader("Wechatpay-Signature");
+// // 请求头Wechatpay-nonce 随机字符串
+// String nonce = request.getHeader("Wechatpay-Nonce");
+// // 请求头Wechatpay-Timestamp 时间戳
+// String timestamp = request.getHeader("Wechatpay-Timestamp");
+// // 微信支付证书序列号
+// String serial = request.getHeader("Wechatpay-Serial");
+// // 签名方式 签名类型
+// String signType = request.getHeader("Wechatpay-Signature-Type");
+// // 构造请求参数对象 RequestParam
+// RequestParam requestParam;
+// try {
+// requestParam = new RequestParam.Builder()
+// // 微信支付签名
+// .signature(signature)
+// // 随机字符串
+// .nonce(nonce)
+// // 时间戳
+// .timestamp(timestamp)
+// // 微信支付证书序列号
+// .serialNumber(serial)
+// // 签名类型
+// .signType(signType)
+// // 请求体
+// .body(HttpServletUtils.getRequestBody(request))
+// //构建
+// .build();
+// } catch (Exception e) {
+// throw new RuntimeException(e);
+// }
+//
+// // 初始化 NotificationParser (通知解析器微信支付 Java SDK回调通知类 (解析通知进行签名验证) 创建一个带 RSA 安全验证的通知解析器 )
+// NotificationParser parser = new NotificationParser(rsaAutoCertificateConfig);
+// // 以支付通知回调为例,验签、解密并转换成 Transaction
+// log.info("验签参数:{}", requestParam);
+// // 解析原始通知数据,转换成 Transaction 对象(自动校验签名)
+// Transaction transaction = parser.parse(requestParam, Transaction.class);
+// log.info("验签成功!-支付回调结果:{}", transaction.toString());
+//
+// // 获取订单号作为锁key
+// String orderNo = transaction.getOutTradeNo();
+// String lockKey = "pay_notify_lock:" + orderNo;
+//
+// // 获取Redisson锁
+// RLock lock = redissonClient.getLock(lockKey);
+// boolean locked = false;
+//
+// try {
+// // 尝试获取锁,等待30秒,锁过期时间30秒
+// locked = lock.tryLock(30, 30, TimeUnit.SECONDS);
+// if (!locked) {
+// log.info("订单[{}]已被处理,放弃重复处理", orderNo);
+// return buildSuccessResponse(); // 返回成功,避免微信重复回调
+// }
+//
+// // 原有业务逻辑开始
+// Map returnMap = new HashMap<>(2);
+// returnMap.put("code", "FAIL");
+// returnMap.put("message", "失败");
+//
+// //修改订单前,建议主动请求微信查询订单是否支付成功,防止恶意post
+// QueryWrapper wrapper = new QueryWrapper();
+// wrapper.eq("out_trade_no", transaction.getOutTradeNo());
+// wrapper.eq("transaction_id", transaction.getTransactionId());
+// WxOrderEntity wxOrderEntity = wxOrderDataService.selectOne(wrapper);
+// if (wxOrderEntity != null) {
+// if (wxOrderEntity.getPayStatus() == 1) {
+// //此时已经是支付成功,不在处理订单信息
+// returnMap.put("code", "SUCCESS");
+// returnMap.put("message", "成功");
+// return JSONObject.toJSONString(returnMap);
+// }
+// }
+// if (Transaction.TradeStateEnum.SUCCESS != transaction.getTradeState()) {
+// log.info("内部订单号【{}】,微信支付订单号【{}】支付未成功", transaction.getOutTradeNo(), transaction.getTransactionId());
+// if (wxOrderEntity != null) {
+// wxOrderEntity.setUpdateTime(new Date());
+// wxOrderEntity.setPayStatus(2);
+// wxOrderEntity.setPayNonce(nonce);
+// wxOrderEntity.setTransactionId(transaction.getTransactionId());
+// //修改订单信息
+// wxOrderDataService.updateById(wxOrderEntity);
+// }
+// return JSONObject.toJSONString(returnMap);
+// }
+// if (wxOrderEntity != null) {
+// wxOrderEntity.setUpdateTime(new Date());
+// wxOrderEntity.setPayTime(DateUtils.stringToDateTime(transaction.getSuccessTime()));
+// wxOrderEntity.setPayDate(DateUtils.stringToDateTime(transaction.getSuccessTime()));
+// wxOrderEntity.setPayStatus(1);
+// wxOrderEntity.setPayNonce(nonce);
+// wxOrderEntity.setTransactionId(transaction.getTransactionId());
+// //修改订单信息
+// wxOrderDataService.updateById(wxOrderEntity);
+// //同时处理支付记录
+// QueryWrapper payWrapper = new QueryWrapper();
+// payWrapper.eq("out_trade_no", transaction.getOutTradeNo());
+// //支付
+// payWrapper.eq("pay_status", 1);
+// //更新记录
+// WxPayLogEntity wxPayLogEntity = wxPayLogDataService.selectOne(payWrapper);
+// if (wxPayLogEntity == null) {
+// wxPayLogEntity = new WxPayLogEntity();
+// wxPayLogEntity.setCreateTime(new Date());
+// wxPayLogEntity.setOutTradeNo(wxOrderEntity.getOutTradeNo());
+// wxPayLogEntity.setPayStatus(1);
+// wxPayLogEntity.setTotalFee(wxOrderEntity.getTotalFee());
+// wxPayLogEntity.setTransactionId(wxOrderEntity.getTransactionId());
+// wxPayLogEntity.setWxOpenId(wxOrderEntity.getWxOpenId());
+// wxPayLogDataService.insert(wxPayLogEntity);
+// }
+// }
+// returnMap.put("code", "SUCCESS");
+// returnMap.put("message", "成功");
+// return JSONObject.toJSONString(returnMap);
+// // 原有业务逻辑结束
+// } catch (InterruptedException e) {
+// Thread.currentThread().interrupt();
+// log.error("获取锁中断异常: {}", e.getMessage(), e);
+// return buildFailResponse("处理中断");
+// } finally {
+// // 释放锁
+// if (locked && lock.isLocked() && lock.isHeldByCurrentThread()) {
+// lock.unlock();
+// }
+// }
+// }
+//
+// // 辅助方法:构建成功响应
+// private String buildSuccessResponse() {
+// Map returnMap = new HashMap<>(2);
+// returnMap.put("code", "SUCCESS");
+// returnMap.put("message", "成功");
+// return JSONObject.toJSONString(returnMap);
+// }
+//
+// // 辅助方法:构建失败响应
+// private String buildFailResponse(String message) {
+// Map returnMap = new HashMap<>(2);
+// returnMap.put("code", "FAIL");
+// returnMap.put("message", message);
+// return JSONObject.toJSONString(returnMap);
+// }
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+// /***
+// * 根据商户订单号查询订单 outTradeNo
+// * @param req
+// * @return
+// */
+// @Transactional
+// public R queryOrderByOrderNo(QueryOrderReq req) {
+// QueryOrderByOutTradeNoRequest queryRequest = new QueryOrderByOutTradeNoRequest();
+// queryRequest.setMchid(wxPayConfig.getMerchantId());
+// queryRequest.setOutTradeNo(req.getOrderNo());
+// try {
+// JsapiServiceExtension service =
+// new JsapiServiceExtension.Builder()
+// .config(rsaAutoCertificateConfig)
+// .signType("RSA") // 不填默认为RSA
+// .build();
+// Transaction result = service.queryOrderByOutTradeNo(queryRequest);
+// LinkedHashMap retmap = new LinkedHashMap();
+// //支付成功
+// if (Transaction.TradeStateEnum.SUCCESS == result.getTradeState()) {
+// log.info("内部订单号【{}】,微信支付订单号【{}】支付成功", result.getOutTradeNo(), result.getTransactionId());
+// retmap.put("out_trade_no", result.getOutTradeNo());
+// retmap.put("transaction_id", result.getTransactionId());
+// retmap.put("success", true);
+// retmap.put("msg", "支付成功!");
+// retmap.put("success_time", DateUtils.getDateTimeString(DateUtils.stringToDateTime(result.getSuccessTime())));
+// //主动查询
+// QueryWrapper wrapper = new QueryWrapper();
+// wrapper.eq("out_trade_no", req.getOrderNo());
+// WxOrderEntity wxOrderEntity = wxOrderDataService.selectOne(wrapper);
+// if (wxOrderEntity != null) {
+// if (wxOrderEntity.getPayStatus() != 1) {
+// wxOrderEntity.setPayStatus(1);
+// wxOrderEntity.setTransactionId(result.getTransactionId());
+// wxOrderEntity.setPayDate(DateUtils.stringToDateTime(result.getSuccessTime()));
+// wxOrderEntity.setPayTime(DateUtils.stringToDateTime(result.getSuccessTime()));
+// wxOrderEntity.setUpdateTime(new Date());
+// wxOrderDataService.updateById(wxOrderEntity);
+// //同时处理支付记录
+// QueryWrapper payWrapper = new QueryWrapper();
+// wrapper.eq("out_trade_no", req.getOrderNo());
+// WxPayLogEntity wxPayLogEntity = wxPayLogDataService.selectOne(payWrapper);
+// if (wxPayLogEntity == null) {
+// wxPayLogEntity = new WxPayLogEntity();
+// wxPayLogEntity.setCreateTime(new Date());
+// wxPayLogEntity.setOutTradeNo(wxOrderEntity.getOutTradeNo());
+// wxPayLogEntity.setPayStatus(1);
+// wxPayLogEntity.setTotalFee(wxOrderEntity.getTotalFee());
+// wxPayLogEntity.setTransactionId(result.getTransactionId());
+// wxPayLogEntity.setWxOpenId(wxOrderEntity.getWxOpenId());
+// wxPayLogDataService.insert(wxPayLogEntity);
+// }
+// }
+// }
+// } else {
+// log.info("内部订单号【{}】,微信支付订单号【{}】支付未成功", result.getOutTradeNo(), result.getTransactionId());
+// retmap.put("out_trade_no", result.getOutTradeNo());
+// retmap.put("transaction_id", result.getTransactionId());
+// retmap.put("success", false);
+// retmap.put("msg", "支付失败!");
+// retmap.put("success_time", null);
+// }
+// return R.ok().put("data", retmap);
+// } catch (ServiceException e) {
+// log.error("订单查询失败,返回码:{},返回信息:{}", e.getErrorCode(), e.getErrorMessage());
+// return R.error("订单查询失败!");
+// }
+// }
+//
+// /***
+// * 根据支付订单号查询订单 paymentNo
+// * @param req
+// * @return
+// */
+// @Transactional
+// public R queryOrderByPaymentNo(QueryOrderReq req) {
+// QueryOrderByIdRequest queryRequest = new QueryOrderByIdRequest();
+// queryRequest.setMchid(wxPayConfig.getMerchantId());
+// queryRequest.setTransactionId(req.getPaymentNo());
+// try {
+// JsapiServiceExtension service =
+// new JsapiServiceExtension.Builder()
+// .config(rsaAutoCertificateConfig)
+// .signType("RSA") // 不填默认为RSA
+// .build();
+// Transaction result = service.queryOrderById(queryRequest);
+// LinkedHashMap map = new LinkedHashMap();
+// //支付成功
+// if (Transaction.TradeStateEnum.SUCCESS == result.getTradeState()) {
+// log.info("内部订单号【{}】,微信支付订单号【{}】支付成功", result.getOutTradeNo(), result.getTransactionId());
+// map.put("out_trade_no", result.getOutTradeNo());
+// map.put("transaction_id", result.getTransactionId());
+// map.put("success", true);
+// map.put("msg", "支付成功!");
+// map.put("success_time", DateUtils.getDateTimeString(DateUtils.stringToDateTime(result.getSuccessTime())));
+// //主动查询
+// QueryWrapper wrapper = new QueryWrapper();
+// wrapper.eq("transaction_id", req.getPaymentNo());
+// WxOrderEntity wxOrderEntity = wxOrderDataService.selectOne(wrapper);
+// if (wxOrderEntity != null) {
+// if (wxOrderEntity.getPayStatus() != 1) {
+// wxOrderEntity.setPayStatus(1);
+// wxOrderEntity.setPayDate(DateUtils.stringToDateTime(result.getSuccessTime()));
+// wxOrderEntity.setPayTime(DateUtils.stringToDateTime(result.getSuccessTime()));
+// wxOrderEntity.setUpdateTime(new Date());
+// wxOrderDataService.updateById(wxOrderEntity);
+// //同时处理支付记录
+// QueryWrapper payWrapper = new QueryWrapper();
+// wrapper.eq("transaction_id", req.getPaymentNo());
+// WxPayLogEntity wxPayLogEntity = wxPayLogDataService.selectOne(payWrapper);
+// if (wxPayLogEntity == null) {
+// wxPayLogEntity = new WxPayLogEntity();
+// wxPayLogEntity.setCreateTime(new Date());
+// wxPayLogEntity.setOutTradeNo(wxOrderEntity.getOutTradeNo());
+// wxPayLogEntity.setPayStatus(1);
+// wxPayLogEntity.setTotalFee(wxOrderEntity.getTotalFee());
+// wxPayLogEntity.setTransactionId(result.getTransactionId());
+// wxPayLogEntity.setWxOpenId(wxOrderEntity.getWxOpenId());
+// wxPayLogDataService.insert(wxPayLogEntity);
+// }
+// }
+// }
+// } else {
+// log.info("内部订单号【{}】,微信支付订单号【{}】支付未成功", result.getOutTradeNo(), result.getTransactionId());
+// map.put("out_trade_no", result.getOutTradeNo());
+// map.put("transaction_id", result.getTransactionId());
+// map.put("success", false);
+// map.put("msg", "支付失败!");
+// map.put("success_time", null);
+// }
+// return R.ok().put("data", map);
+// } catch (ServiceException e) {
+// log.error("订单查询失败,返回码:{},返回信息:{}", e.getErrorCode(), e.getErrorMessage());
+// return R.error("订单查询失败!");
+// }
+// }
+//
+// /***
+// * 微信申请退款
+// * @param outTradeNo 商户订单号
+// * @param totalAmount
+// * @return
+// */
+// public R createRefund(String outTradeNo, Long totalAmount) {
+// //返回参数
+// LinkedHashMap map = new LinkedHashMap();
+// map.put("out_trade_no", outTradeNo);
+// map.put("success", false);
+// map.put("msg", "正在申请退款中!");
+// String outRefundNo = "REFUND_" + outTradeNo;
+// map.put("out_refund_no", outRefundNo);
+// //申请退款订单,需要变更订单记录
+// QueryWrapper wrapper = new QueryWrapper();
+// wrapper.eq("out_trade_no", outTradeNo);
+// WxOrderEntity wxOrderEntity = wxOrderDataService.selectOne(wrapper);
+// if (wxOrderEntity == null) {
+// return R.error("订单不存在,申请退款不存在!");
+// }
+// wxOrderEntity.setPayStatus(4);//退款中
+// wxOrderEntity.setUpdateTime(new Date());
+// wxOrderDataService.updateById(wxOrderEntity);
+// try {
+// // 构建退款service
+// RefundService service = new RefundService.Builder()
+// .config(rsaAutoCertificateConfig)
+// .build();
+// CreateRequest request = new CreateRequest();
+// // 调用request.setXxx(val)设置所需参数,具体参数可见Request定义
+// request.setOutTradeNo(outTradeNo);
+// request.setOutRefundNo(outRefundNo);
+//
+// AmountReq amount = new AmountReq();
+// amount.setTotal(totalAmount);
+// amount.setRefund(totalAmount);
+// amount.setCurrency("CNY");
+//
+// request.setAmount(amount);
+// request.setNotifyUrl(wxPayConfig.getRefundNotifyUrl());
+//
+// //接收退款返回参数
+// Refund refund = service.create(request);
+// log.info("退款返回信息:{}", refund);
+// if (refund.getStatus().equals(Status.SUCCESS)) {
+// map.put("success", true);
+// map.put("msg", "退款成功!");
+// //说明退款成功,开始接下来的业务操作
+// //主动查询
+// QueryWrapper againWrapper = new QueryWrapper();
+// againWrapper.eq("out_trade_no", outTradeNo);
+// WxOrderEntity orderEntity = wxOrderDataService.selectOne(againWrapper);
+// if (orderEntity != null) {
+// orderEntity.setPayStatus(3);//退款成功
+// orderEntity.setUpdateTime(new Date());
+// wxOrderDataService.updateById(orderEntity);
+// //同时处理退款记录
+// QueryWrapper payWrapper = new QueryWrapper();
+// payWrapper.eq("out_trade_no", outTradeNo);
+// payWrapper.eq("pay_status", 2);//退款
+// WxPayLogEntity wxPayLogEntity = wxPayLogDataService.selectOne(payWrapper);
+// if (wxPayLogEntity == null) {
+// wxPayLogEntity = new WxPayLogEntity();
+// wxPayLogEntity.setCreateTime(new Date());
+// wxPayLogEntity.setOutTradeNo(outTradeNo);
+// wxPayLogEntity.setPayStatus(2);
+// wxPayLogEntity.setTotalFee(totalAmount.intValue());
+// wxPayLogEntity.setTransactionId(wxOrderEntity.getTransactionId());
+// wxPayLogEntity.setOutRefundNo(outRefundNo);
+// wxPayLogEntity.setWxOpenId(wxOrderEntity.getWxOpenId());
+// wxPayLogDataService.insert(wxPayLogEntity);
+// }
+// }
+// }
+// } catch (ServiceException e) {
+// log.error("退款失败!,错误信息:{}", e.getMessage());
+// return R.error("退款失败!");
+// } catch (Exception e) {
+// log.error("服务返回成功,返回体类型不合法,或者解析返回体失败,错误信息:{}", e.getMessage());
+// return R.error("退款失败!");
+// }
+// return R.ok().put("data", map);
+// }
+//
+// /***
+// * 微信申请退款
+// * @param outTradeNo 商户订单号
+// * @param totalAmount 退款金额,单位分
+// * @return
+// */
+// public R createRefund(String outTradeNo, Long totalAmount, String outRefundNo) {
+// log.info("申请退款参数,outTradeNo:{},totalAmount:{},outRefundNo:{}", outTradeNo, totalAmount, outRefundNo);
+// //返回参数
+// LinkedHashMap map = new LinkedHashMap();
+// map.put("out_trade_no", outTradeNo);
+// map.put("success", false);
+// map.put("msg", "退款失败!");
+// if (StringUtils.isEmpty(outRefundNo)) {
+// outRefundNo = "REFUND_" + outTradeNo;
+// }
+// map.put("out_refund_no", outRefundNo);
+// //申请退款订单,需要变更订单记录
+// QueryWrapper wrapper = new QueryWrapper();
+// wrapper.eq("out_trade_no", outTradeNo);
+// WxOrderEntity wxOrderEntity = wxOrderDataService.selectOne(wrapper);
+// if (wxOrderEntity == null) {
+// return R.error("订单不存在,申请退款不存在!");
+// }
+// wxOrderEntity.setPayStatus(4);//退款中
+// wxOrderEntity.setUpdateTime(new Date());
+// wxOrderDataService.updateById(wxOrderEntity);
+// try {
+// // 构建退款service
+// RefundService service = new RefundService.Builder()
+// .config(rsaAutoCertificateConfig)
+// .build();
+// CreateRequest request = new CreateRequest();
+// // 调用request.setXxx(val)设置所需参数,具体参数可见Request定义
+// request.setOutTradeNo(outTradeNo);
+// request.setOutRefundNo(outRefundNo);
+//
+// AmountReq amount = new AmountReq();
+// amount.setTotal(wxOrderEntity.getTotalFee().longValue());
+// amount.setRefund(totalAmount);
+// amount.setCurrency("CNY");
+//
+// request.setAmount(amount);
+// request.setNotifyUrl(wxPayConfig.getRefundNotifyUrl());
+//
+// //接收退款返回参数
+// Refund refund = service.create(request);
+// log.info("退款返回信息:{}", refund);
+// //SUCCESS:退款成功,PROCESSING:正在处理中
+// if (refund.getStatus().equals(Status.SUCCESS)) {
+// map.put("success", true);
+// map.put("msg", "退款成功!");
+// map.put("transaction_id", refund.getTransactionId());
+// //说明退款成功,开始接下来的业务操作
+// //主动查询
+// QueryWrapper againWrapper = new QueryWrapper();
+// againWrapper.eq("out_trade_no", outTradeNo);
+// WxOrderEntity orderEntity = wxOrderDataService.selectOne(againWrapper);
+// if (orderEntity != null) {
+// orderEntity.setPayStatus(3);//退款成功
+// orderEntity.setUpdateTime(new Date());
+// wxOrderDataService.updateById(orderEntity);
+// //同时处理退款记录
+// QueryWrapper payWrapper = new QueryWrapper();
+// payWrapper.eq("out_trade_no", outTradeNo);
+// payWrapper.eq("pay_status", 2);//退款
+// WxPayLogEntity wxPayLogEntity = wxPayLogDataService.selectOne(payWrapper);
+// if (wxPayLogEntity == null) {
+// wxPayLogEntity = new WxPayLogEntity();
+// wxPayLogEntity.setCreateTime(new Date());
+// wxPayLogEntity.setOutTradeNo(outTradeNo);
+// wxPayLogEntity.setPayStatus(2);
+// wxPayLogEntity.setTotalFee(totalAmount.intValue());
+// wxPayLogEntity.setTransactionId(refund.getTransactionId());
+// wxPayLogEntity.setOutRefundNo(outRefundNo);
+// wxPayLogEntity.setWxOpenId(wxOrderEntity.getWxOpenId());
+// wxPayLogDataService.insert(wxPayLogEntity);
+// }
+// }
+// } else if (refund.getStatus().equals(Status.ABNORMAL)) {
+// map.put("success", false);
+// map.put("msg", "退款失败,账户异常!");
+// map.put("transaction_id", refund.getTransactionId());
+// } else if (refund.getStatus().equals(Status.PROCESSING)) {
+// map.put("success", true);
+// map.put("msg", "正在退款中!");
+// map.put("transaction_id", refund.getTransactionId());
+// } else if (refund.getStatus().equals(Status.CLOSED)) {
+// map.put("success", false);
+// map.put("msg", "用户余额不足或者订单超过退款期限!");
+// map.put("transaction_id", refund.getTransactionId());
+// }
+// } catch (ServiceException e) {
+// log.error("退款失败!,错误信息:{}", e.getErrorMessage());
+// return R.error("退款失败!错误信息:" + e.getErrorMessage());
+// } catch (Exception e) {
+// log.error("服务返回成功,返回体类型不合法,或者解析返回体失败,错误信息:{}", e.getMessage());
+// return R.error("退款失败!错误信息:" + e.getMessage());
+// }
+// log.info("微信退款响应参数:{}", map);
+// return R.ok().put("data", map);
+// }
+//
+// /***
+// * 微信退款回调
+// * @param request
+// * @throws Exception
+// */
+// public void refundNotify(HttpServletRequest request) throws Exception {
+// try {
+// log.info("------收到退款通知------");
+// // 请求头Wechatpay-Signature
+// String signature = request.getHeader("Wechatpay-Signature");
+// // 请求头Wechatpay-nonce
+// String nonce = request.getHeader("Wechatpay-Nonce");
+// // 请求头Wechatpay-Timestamp
+// String timestamp = request.getHeader("Wechatpay-Timestamp");
+// // 微信支付证书序列号
+// String serial = request.getHeader("Wechatpay-Serial");
+// // 签名方式
+// String signType = request.getHeader("Wechatpay-Signature-Type");
+// // 构造 RequestParam
+// RequestParam requestParam = new RequestParam.Builder()
+// .serialNumber(serial)
+// .nonce(nonce)
+// .signature(signature)
+// .timestamp(timestamp)
+// .signType(signType)
+// .body(HttpServletUtils.getRequestBody(request))
+// .build();
+//
+// // 初始化 NotificationParser
+// NotificationParser parser = new NotificationParser(rsaAutoCertificateConfig);
+// // 以支付通知回调为例,验签、解密并转换成 Transaction
+// log.info("验签参数:{}", requestParam);
+// RefundNotification parse = parser.parse(requestParam, RefundNotification.class);
+// log.info("验签成功!-退款回调结果:{}", parse.toString());
+// //parse.getRefundStatus().equals("SUCCESS");说明退款成功
+// String refundStatus = parse.getRefundStatus().toString();
+// log.info("getRefundStatus状态:{}", refundStatus);
+//
+// if (refundStatus.equals("SUCCESS")) {
+// log.info("成功进入退款回调,状态:{}", parse.getRefundStatus());
+// //你的业务代码
+// QueryWrapper wrapper = new QueryWrapper();
+// wrapper.eq("out_trade_no", parse.getOutTradeNo());
+// WxOrderEntity wxOrderEntity = wxOrderDataService.selectOne(wrapper);
+// log.info("订单数据:{}", wxOrderEntity);
+// if (wxOrderEntity != null) {
+// wxOrderEntity.setUpdateTime(new Date());
+// wxOrderEntity.setPayStatus(3);//退款成功
+// wxOrderEntity.setPayNonce(nonce);
+// wxOrderDataService.updateById(wxOrderEntity);
+// //同时处理退款记录
+// QueryWrapper payWrapper = new QueryWrapper();
+// payWrapper.eq("out_trade_no", parse.getOutTradeNo());
+// payWrapper.eq("pay_status", 2);//退款
+// payWrapper.eq("out_refund_no", parse.getOutRefundNo());//退款
+// WxPayLogEntity wxPayLogEntity = wxPayLogDataService.selectOne(payWrapper);
+// if (wxPayLogEntity == null) {
+// wxPayLogEntity = new WxPayLogEntity();
+// wxPayLogEntity.setCreateTime(new Date());
+// wxPayLogEntity.setOutTradeNo(parse.getOutTradeNo());
+// wxPayLogEntity.setPayStatus(2);
+// wxPayLogEntity.setTotalFee(parse.getAmount().getRefund().intValue());
+// wxPayLogEntity.setTransactionId(parse.getTransactionId());
+// wxPayLogEntity.setOutRefundNo(parse.getOutRefundNo());
+// wxPayLogEntity.setWxOpenId(wxOrderEntity.getWxOpenId());
+// wxPayLogDataService.insert(wxPayLogEntity);
+// }
+// }
+// }
+// } catch (Exception e) {
+// log.info("退款回调失败!错误信息:{}", e.getMessage());
+// }
+// }
+//}
\ No newline at end of file
--
Gitee
From 5f6691a335c15438c3bc89716278181de7a73dc8 Mon Sep 17 00:00:00 2001
From: JMY <1960978976qq.com>
Date: Mon, 18 Aug 2025 09:44:40 +0800
Subject: [PATCH 4/5] =?UTF-8?q?util:=20=E6=B7=BB=E5=8A=A0=20HttpServletUti?=
=?UTF-8?q?ls=20=E5=B7=A5=E5=85=B7=E7=B1=BB?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 新增 HttpServletUtils 类,用于处理 HTTP 请求相关操作- 添加 getRequestBody 方法,用于获取请求体内容
- 该工具类可帮助简化请求处理逻辑,提高代码复用性
---
.../controller/Util/HttpServletUtils.java | 42 +++++++++++++++++++
1 file changed, 42 insertions(+)
create mode 100644 yudao-server/src/main/java/cn/iocoder/yudao/server/controller/Util/HttpServletUtils.java
diff --git a/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/Util/HttpServletUtils.java b/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/Util/HttpServletUtils.java
new file mode 100644
index 0000000000..032fb5f6bd
--- /dev/null
+++ b/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/Util/HttpServletUtils.java
@@ -0,0 +1,42 @@
+package cn.iocoder.yudao.server.controller.Util;
+
+import javax.servlet.ServletInputStream;
+import javax.servlet.http.HttpServletRequest;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+/**
+ * @author caozhen
+ * @ClassName HttpServletUtils
+ * @description: TODO
+ * @date 2024年01月04日
+ * @version: 1.0
+ */
+public class HttpServletUtils {
+ /**
+ * 获取请求体
+ *
+ * @param request
+ * @return
+ * @throws IOException
+ */
+ public static String getRequestBody(HttpServletRequest request) throws IOException {
+ ServletInputStream stream = null;
+ BufferedReader reader = null;
+ StringBuffer sb = new StringBuffer();
+ try {
+ stream = request.getInputStream();
+ // 获取响应
+ reader = new BufferedReader(new InputStreamReader(stream,"UTF-8"));
+ String line;
+ while ((line = reader.readLine()) != null) {
+ sb.append(line);
+ }
+ } catch (IOException e) {
+ throw new IOException("读取返回支付接口数据流出现异常!");
+ } finally {
+ reader.close();
+ }
+ return sb.toString();
+ }
+}
\ No newline at end of file
--
Gitee
From dca935202d753b0df00e95adac9585b5d1019484 Mon Sep 17 00:00:00 2001
From: JMY <1960978976qq.com>
Date: Mon, 18 Aug 2025 09:45:11 +0800
Subject: [PATCH 5/5] =?UTF-8?q?feat(server):=20=E6=B7=BB=E5=8A=A0=E6=97=A5?=
=?UTF-8?q?=E6=9C=9F=E5=B7=A5=E5=85=B7=E7=B1=BB=E5=92=8C=20IP=20=E5=9C=B0?=
=?UTF-8?q?=E5=9D=80=E8=8E=B7=E5=8F=96=E7=B1=BB?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 新增 DateUtils 类,提供日期时间转换相关方法
- 添加 GetAllIPs 类,用于获取系统中的所有 IP 地址
- 实现 GetLocalIP 类,用于获取本机非回环 IPv4地址
---
.../server/controller/Util/DateUtils.java | 63 +++++++++++++++++
.../yudao/server/controller/ip/GetAllIPs.java | 50 +++++++++++++
.../server/controller/ip/GetLocalIP.java | 70 +++++++++++++++++++
3 files changed, 183 insertions(+)
create mode 100644 yudao-server/src/main/java/cn/iocoder/yudao/server/controller/Util/DateUtils.java
create mode 100644 yudao-server/src/main/java/cn/iocoder/yudao/server/controller/ip/GetAllIPs.java
create mode 100644 yudao-server/src/main/java/cn/iocoder/yudao/server/controller/ip/GetLocalIP.java
diff --git a/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/Util/DateUtils.java b/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/Util/DateUtils.java
new file mode 100644
index 0000000000..623b90d0ee
--- /dev/null
+++ b/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/Util/DateUtils.java
@@ -0,0 +1,63 @@
+package cn.iocoder.yudao.server.controller.Util;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+public class DateUtils {
+ // 定义日期时间格式
+ private static final String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
+ private static final SimpleDateFormat DATE_TIME_FORMAT = new SimpleDateFormat(DATE_TIME_PATTERN);
+
+ /**
+ * 将字符串转换为日期时间
+ * @param dateTimeStr 日期时间字符串,格式应为 "yyyy-MM-dd HH:mm:ss"
+ * @return 转换后的日期时间对象
+ * @throws IllegalArgumentException 如果字符串格式不正确
+ */
+ public static Date stringToDateTime(String dateTimeStr) {
+ try {
+ return DATE_TIME_FORMAT.parse(dateTimeStr);
+ } catch (ParseException e) {
+ throw new IllegalArgumentException("Invalid date time format. Expected format: " + DATE_TIME_PATTERN, e);
+ }
+ }
+
+ /**
+ * 将日期时间转换为字符串
+ * @param date 日期时间对象
+ * @return 格式化后的日期时间字符串,格式为 "yyyy-MM-dd HH:mm:ss"
+ */
+ public static String getDateTimeString(Date date) {
+ return DATE_TIME_FORMAT.format(date);
+ }
+
+ // 你可以添加其他常用的日期时间格式方法
+ public static Date stringToDate(String dateStr) {
+ try {
+ SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
+ return dateFormat.parse(dateStr);
+ } catch (ParseException e) {
+ throw new IllegalArgumentException("Invalid date format. Expected format: yyyy-MM-dd", e);
+ }
+ }
+
+ public static String getDateString(Date date) {
+ SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
+ return dateFormat.format(date);
+ }
+
+ public static Date stringToTime(String timeStr) {
+ try {
+ SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm:ss");
+ return timeFormat.parse(timeStr);
+ } catch (ParseException e) {
+ throw new IllegalArgumentException("Invalid time format. Expected format: HH:mm:ss", e);
+ }
+ }
+
+ public static String getTimeString(Date date) {
+ SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm:ss");
+ return timeFormat.format(date);
+ }
+}
\ No newline at end of file
diff --git a/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/ip/GetAllIPs.java b/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/ip/GetAllIPs.java
new file mode 100644
index 0000000000..97ad16e9ff
--- /dev/null
+++ b/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/ip/GetAllIPs.java
@@ -0,0 +1,50 @@
+package cn.iocoder.yudao.server.controller.ip;
+
+import java.net.*;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+
+public class GetAllIPs {
+ public static void main(String[] args) {
+ try {
+ Enumeration networkInterfaces = NetworkInterface.getNetworkInterfaces();
+
+ List ipv4Addresses = new ArrayList<>();
+ List ipv6Addresses = new ArrayList<>();
+
+ while (networkInterfaces.hasMoreElements()) {
+ NetworkInterface networkInterface = networkInterfaces.nextElement();
+
+ // 可以选择性地过滤,例如排除回环和虚拟接口
+ if (networkInterface.isLoopback() || networkInterface.isVirtual()) {
+ continue;
+ }
+
+ System.out.println("网络接口: " + networkInterface.getName() + " (" + networkInterface.getDisplayName() + ")");
+
+ Enumeration inetAddresses = networkInterface.getInetAddresses();
+ while (inetAddresses.hasMoreElements()) {
+ InetAddress inetAddress = inetAddresses.nextElement();
+ String hostAddress = inetAddress.getHostAddress();
+
+ if (inetAddress instanceof Inet4Address) {
+ System.out.println(" IPv4 地址: " + hostAddress);
+ ipv4Addresses.add(hostAddress);
+ } else if (inetAddress instanceof Inet6Address) {
+ System.out.println(" IPv6 地址: " + hostAddress);
+ ipv6Addresses.add(hostAddress);
+ }
+ }
+ System.out.println("---");
+ }
+
+ System.out.println("所有找到的 IPv4 地址: " + ipv4Addresses);
+ System.out.println("所有找到的 IPv6 地址: " + ipv6Addresses);
+
+ } catch (SocketException e) {
+ System.err.println("获取网络接口时发生错误: " + e.getMessage());
+ e.printStackTrace();
+ }
+ }
+}
\ No newline at end of file
diff --git a/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/ip/GetLocalIP.java b/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/ip/GetLocalIP.java
new file mode 100644
index 0000000000..582810ac4e
--- /dev/null
+++ b/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/ip/GetLocalIP.java
@@ -0,0 +1,70 @@
+package cn.iocoder.yudao.server.controller.ip;
+
+import java.net.*;
+import java.util.Enumeration;
+
+public class GetLocalIP {
+ public static void main(String[] args) {
+ try {
+ // 1. 获取本机 InetAddress 对象
+ InetAddress localHost = InetAddress.getLocalHost();
+ String hostAddress = localHost.getHostAddress();
+
+ // 2. 检查是否是回环地址 (127.0.0.1) 或 IPv6 地址
+ if (localHost.isLoopbackAddress() || hostAddress.contains(":")) {
+ // 如果是回环地址或 IPv6, 则遍历网络接口查找合适的 IPv4 地址
+ InetAddress ipv4Address = getFirstNonLoopbackIPv4Address();
+ if (ipv4Address != null) {
+ System.out.println("本机IP地址: " + ipv4Address.getHostAddress());
+ } else {
+ System.out.println("未找到有效的非回环IPv4地址。");
+ }
+ } else {
+ // 直接使用获取到的地址 (通常是有效的)
+ System.out.println("本机IP地址: " + hostAddress);
+ }
+
+ } catch (UnknownHostException e) {
+ System.err.println("无法获取本机主机信息: " + e.getMessage());
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * 遍历所有网络接口,查找第一个非回环、非虚拟、启用的IPv4地址
+ * @return 找到的 InetAddress, 未找到则返回 null
+ */
+ private static InetAddress getFirstNonLoopbackIPv4Address() {
+ try {
+ // 获取所有网络接口
+ Enumeration networkInterfaces = NetworkInterface.getNetworkInterfaces();
+ while (networkInterfaces.hasMoreElements()) {
+ NetworkInterface networkInterface = networkInterfaces.nextElement();
+
+ // 跳过回环接口 (lo) 和 虚拟接口 (如 docker, vmware)
+ if (networkInterface.isLoopback() || networkInterface.isVirtual() || !networkInterface.isUp()) {
+ continue;
+ }
+
+ // 获取该接口绑定的所有 IP 地址
+ Enumeration inetAddresses = networkInterface.getInetAddresses();
+ while (inetAddresses.hasMoreElements()) {
+ InetAddress inetAddress = inetAddresses.nextElement();
+
+ // 只关心 IPv4 地址 (排除 IPv6)
+ if (inetAddress instanceof Inet4Address) {
+ String hostAddress = inetAddress.getHostAddress();
+
+ // 排除回环地址 (127.x.x.x) 和 0.0.0.0
+ if (!hostAddress.startsWith("127.") && !hostAddress.equals("0.0.0.0")) {
+ return inetAddress;
+ }
+ }
+ }
+ }
+ } catch (SocketException e) {
+ System.err.println("获取网络接口时发生错误: " + e.getMessage());
+ }
+ return null;
+ }
+}
\ No newline at end of file
--
Gitee