From 803c6344ab428c954165b32d6d83e8e4aba75fc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=BF=A0=E6=9E=97?= <170083662@qq.com> Date: Sun, 27 Jul 2025 23:02:59 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=AE=8C=E6=88=90=EF=BC=9A?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=BE=AE=E4=BF=A1=E6=94=AF=E4=BB=98=E8=AF=81?= =?UTF-8?q?=E4=B9=A6=E8=AF=BB=E5=8F=96=E6=9C=BA=E5=88=B6=E7=AD=89=E7=AD=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../GENERATOR_FIX_SUMMARY.md | 0 .../JAVA17_UPGRADE_SUMMARY.md | 0 .../PROJECT_STARTUP_REPORT.md | 0 docs/SERVER_URL_REFACTOR_SUMMARY.md | 111 ++++++++++++++++++ .../SPRINGDOC_MIGRATION_REPORT.md | 0 .../SWAGGER_FIX_GUIDE.md | 0 fix_generators.sh => docs/fix_generators.sh | 0 .../migrate_swagger_annotations.sh | 0 docs/start_frp.sh | 79 +++++++++++++ .../common/core/config/SwaggerConfig.java | 2 +- .../security/JwtAuthenticationFilter.java | 2 +- .../core/service/PaymentCacheService.java | 4 +- .../common/core/utils/RequestUtil.java | 33 ++++-- .../common/core/utils/WxOfficialUtil.java | 2 +- .../oa/controller/OaAppController.java | 5 +- .../shop/controller/ShopOrderController.java | 80 +++++++++---- .../service/impl/ShopOrderServiceImpl.java | 2 +- src/main/resources/application-prod.yml | 2 +- src/main/resources/application.yml | 5 +- .../gxwebsoft/config/ServerUrlConfigTest.java | 51 ++++++++ 20 files changed, 330 insertions(+), 48 deletions(-) rename GENERATOR_FIX_SUMMARY.md => docs/GENERATOR_FIX_SUMMARY.md (100%) rename JAVA17_UPGRADE_SUMMARY.md => docs/JAVA17_UPGRADE_SUMMARY.md (100%) rename PROJECT_STARTUP_REPORT.md => docs/PROJECT_STARTUP_REPORT.md (100%) create mode 100644 docs/SERVER_URL_REFACTOR_SUMMARY.md rename SPRINGDOC_MIGRATION_REPORT.md => docs/SPRINGDOC_MIGRATION_REPORT.md (100%) rename SWAGGER_FIX_GUIDE.md => docs/SWAGGER_FIX_GUIDE.md (100%) rename fix_generators.sh => docs/fix_generators.sh (100%) rename migrate_swagger_annotations.sh => docs/migrate_swagger_annotations.sh (100%) create mode 100755 docs/start_frp.sh create mode 100644 src/test/java/com/gxwebsoft/config/ServerUrlConfigTest.java diff --git a/GENERATOR_FIX_SUMMARY.md b/docs/GENERATOR_FIX_SUMMARY.md similarity index 100% rename from GENERATOR_FIX_SUMMARY.md rename to docs/GENERATOR_FIX_SUMMARY.md diff --git a/JAVA17_UPGRADE_SUMMARY.md b/docs/JAVA17_UPGRADE_SUMMARY.md similarity index 100% rename from JAVA17_UPGRADE_SUMMARY.md rename to docs/JAVA17_UPGRADE_SUMMARY.md diff --git a/PROJECT_STARTUP_REPORT.md b/docs/PROJECT_STARTUP_REPORT.md similarity index 100% rename from PROJECT_STARTUP_REPORT.md rename to docs/PROJECT_STARTUP_REPORT.md diff --git a/docs/SERVER_URL_REFACTOR_SUMMARY.md b/docs/SERVER_URL_REFACTOR_SUMMARY.md new file mode 100644 index 0000000..7e49a3d --- /dev/null +++ b/docs/SERVER_URL_REFACTOR_SUMMARY.md @@ -0,0 +1,111 @@ +# 服务器URL配置重构总结 + +## 概述 +将项目中硬编码的服务器地址 `https://server.gxwebsoft.com/api` 改为从配置文件读取,提高了代码的可维护性和灵活性。 + +## 修改的文件 + +### 1. RequestUtil.java +**文件路径**: `src/main/java/com/gxwebsoft/common/core/utils/RequestUtil.java` + +**修改内容**: +- 添加了 `ConfigProperties` 依赖注入 +- 移除了硬编码的 `host` 常量 +- 添加了 `getServerUrl()` 方法 +- 将所有 `host.concat(path)` 替换为 `getServerUrl().concat(path)` + +**影响的方法**: +- `balancePay()` +- `getUserByPhone()` +- `getByUserId()` +- `saveUserByPhone()` +- `updateUserBalance()` +- `getParent()` +- `updateUser()` +- `getMpOrderQrCode()` +- `getOrderQRCodeUnlimited()` +- `updateUserMerchantId()` +- `getWxConfig()` + +### 2. JwtAuthenticationFilter.java +**文件路径**: `src/main/java/com/gxwebsoft/common/core/security/JwtAuthenticationFilter.java` + +**修改内容**: +- 将硬编码的URL `"https://server.gxwebsoft.com/api/auth/user"` +- 改为 `configProperties.getServerUrl() + "/auth/user"` + +### 3. OaAppController.java +**文件路径**: `src/main/java/com/gxwebsoft/oa/controller/OaAppController.java` + +**修改内容**: +- 添加了 `ConfigProperties` 依赖注入 +- 将硬编码的URL `"https://server.gxwebsoft.com/api/file/page"` +- 改为 `configProperties.getServerUrl() + "/file/page"` + +### 4. SwaggerConfig.java +**文件路径**: `src/main/java/com/gxwebsoft/common/core/config/SwaggerConfig.java` + +**修改内容**: +- 将硬编码的URL `"https://server.gxwebsoft.com/api/system"` +- 改为 `config.getServerUrl() + "/system"` + +### 5. WxOfficialUtil.java +**文件路径**: `src/main/java/com/gxwebsoft/common/core/utils/WxOfficialUtil.java` + +**修改内容**: +- 将硬编码的URL `"https://server.gxwebsoft.com/api/open/wx-official/accessToken"` +- 改为 `pathConfig.getServerUrl() + "/open/wx-official/accessToken"` + +### 6. ShopOrderServiceImpl.java +**文件路径**: `src/main/java/com/gxwebsoft/shop/service/impl/ShopOrderServiceImpl.java` + +**修改内容**: +- 将微信支付回调地址中的硬编码URL +- 从 `"https://server.gxwebsoft.com/api/system/wx-pay/notify/"` +- 改为 `config.getServerUrl() + "/system/wx-pay/notify/"` + +## 配置文件设置 + +### 开发环境 (application-dev.yml) +```yaml +config: + server-url: http://127.0.0.1:9091/api +``` + +### 生产环境 (application-prod.yml) +```yaml +config: + server-url: https://server.gxwebsoft.com/api +``` + +### 默认配置 (application.yml) +```yaml +config: + server-url: https://server.gxwebsoft.com/api +``` + +## 优势 + +1. **可维护性**: 服务器地址集中管理,修改时只需要更新配置文件 +2. **环境适配**: 不同环境可以使用不同的服务器地址 +3. **部署灵活**: 部署时可以通过环境变量或外部配置文件覆盖 +4. **代码清洁**: 移除了硬编码,提高了代码质量 + +## 测试验证 + +创建了测试类 `ServerUrlConfigTest` 来验证配置是否正确读取: +- 验证配置属性不为空 +- 验证URL格式正确 +- 验证开发环境使用本地地址 + +## 注意事项 + +1. 确保所有环境的配置文件都正确设置了 `server-url` +2. 部署时需要根据实际环境调整配置 +3. 如果有新的代码需要调用服务器API,应该使用 `ConfigProperties.getServerUrl()` 而不是硬编码 + +## 后续建议 + +1. 可以考虑将其他硬编码的URL也进行类似的重构 +2. 建立代码规范,禁止在代码中硬编码URL +3. 在CI/CD流程中添加检查,确保没有新的硬编码URL被引入 diff --git a/SPRINGDOC_MIGRATION_REPORT.md b/docs/SPRINGDOC_MIGRATION_REPORT.md similarity index 100% rename from SPRINGDOC_MIGRATION_REPORT.md rename to docs/SPRINGDOC_MIGRATION_REPORT.md diff --git a/SWAGGER_FIX_GUIDE.md b/docs/SWAGGER_FIX_GUIDE.md similarity index 100% rename from SWAGGER_FIX_GUIDE.md rename to docs/SWAGGER_FIX_GUIDE.md diff --git a/fix_generators.sh b/docs/fix_generators.sh similarity index 100% rename from fix_generators.sh rename to docs/fix_generators.sh diff --git a/migrate_swagger_annotations.sh b/docs/migrate_swagger_annotations.sh similarity index 100% rename from migrate_swagger_annotations.sh rename to docs/migrate_swagger_annotations.sh diff --git a/docs/start_frp.sh b/docs/start_frp.sh new file mode 100755 index 0000000..ef4a74b --- /dev/null +++ b/docs/start_frp.sh @@ -0,0 +1,79 @@ +#!/bin/bash +cd /Users/gxwebsoft/frp/frp_0.63.0_darwin_arm64 + +echo "=== FRP客户端启动脚本 ===" + +# 检查是否已有frpc进程运行 +if pgrep -f "frpc" > /dev/null; then + echo "⚠️ 检测到frpc进程正在运行:" + ps aux | grep frpc | grep -v grep + echo "" + echo "正在停止现有进程..." + pkill -f frpc + sleep 3 + + # 再次检查是否还有进程 + if pgrep -f "frpc" > /dev/null; then + echo "❌ 无法停止现有进程,强制终止..." + pkill -9 -f frpc + sleep 2 + fi +fi + +# 检查配置文件是否存在(优先使用toml格式) +CONFIG_FILE="" +if [ -f "frpc.toml" ]; then + CONFIG_FILE="frpc.toml" +elif [ -f "frpc.ini" ]; then + CONFIG_FILE="frpc.ini" +else + echo "❌ 错误:配置文件不存在(frpc.toml 或 frpc.ini)" + echo "当前目录: $(pwd)" + echo "目录内容:" + ls -la + exit 1 +fi + +echo "📋 配置文件检查通过,使用: $CONFIG_FILE" + +# 清理旧的日志文件 +if [ -f "frpc.log" ]; then + mv frpc.log frpc.log.old +fi + +# 后台启动frpc客户端 +echo "🚀 正在启动FRP客户端..." +nohup ./frpc -c $CONFIG_FILE > frpc.log 2>&1 & +FRP_PID=$! + +# 等待启动 +sleep 3 + +# 检查是否启动成功 +if pgrep -f "frpc" > /dev/null; then + echo "✅ FRP客户端启动成功!" + echo "📊 进程信息:" + ps aux | grep frpc | grep -v grep + echo "" + echo "📄 日志文件: $(pwd)/frpc.log" + echo "🔍 查看实时日志: tail -f $(pwd)/frpc.log" + echo "" + echo "📋 最新日志内容:" + echo "----------------------------------------" + tail -10 frpc.log + echo "----------------------------------------" +else + echo "❌ FRP客户端启动失败!" + echo "📄 错误日志:" + echo "----------------------------------------" + cat frpc.log + echo "----------------------------------------" + exit 1 +fi + +echo "" +echo "🔧 常用管理命令:" +echo " 查看进程: ps aux | grep frpc" +echo " 停止服务: pkill -f frpc" +echo " 查看日志: tail -f $(pwd)/frpc.log" +echo " 检查端口: lsof -i | grep frp" \ No newline at end of file diff --git a/src/main/java/com/gxwebsoft/common/core/config/SwaggerConfig.java b/src/main/java/com/gxwebsoft/common/core/config/SwaggerConfig.java index 5a92e02..c63c2c7 100644 --- a/src/main/java/com/gxwebsoft/common/core/config/SwaggerConfig.java +++ b/src/main/java/com/gxwebsoft/common/core/config/SwaggerConfig.java @@ -37,7 +37,7 @@ public class SwaggerConfig { .name("科技小王子") .url("https://www.gxwebsoft.com") .email("170083662@qq.com")) - .termsOfService("https://server.gxwebsoft.com/api/system")) + .termsOfService(config.getServerUrl() + "/system")) .components(new Components() .addSecuritySchemes("Authorization", new SecurityScheme() diff --git a/src/main/java/com/gxwebsoft/common/core/security/JwtAuthenticationFilter.java b/src/main/java/com/gxwebsoft/common/core/security/JwtAuthenticationFilter.java index 8a7aa74..e910c6d 100644 --- a/src/main/java/com/gxwebsoft/common/core/security/JwtAuthenticationFilter.java +++ b/src/main/java/com/gxwebsoft/common/core/security/JwtAuthenticationFilter.java @@ -63,7 +63,7 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { map.put("username", jwtSubject.getUsername()); map.put("tenantId", jwtSubject.getTenantId()); // 链式构建请求 - String result = HttpRequest.post("https://server.gxwebsoft.com/api/auth/user") + String result = HttpRequest.post(configProperties.getServerUrl() + "/auth/user") .header("Authorization", access_token) .header("Tenantid", jwtSubject.getTenantId().toString()) .body(JSONUtil.toJSONString(map))//表单内容 diff --git a/src/main/java/com/gxwebsoft/common/core/service/PaymentCacheService.java b/src/main/java/com/gxwebsoft/common/core/service/PaymentCacheService.java index ffaa016..64c44be 100644 --- a/src/main/java/com/gxwebsoft/common/core/service/PaymentCacheService.java +++ b/src/main/java/com/gxwebsoft/common/core/service/PaymentCacheService.java @@ -44,7 +44,7 @@ public class PaymentCacheService { if (ObjectUtil.isNotEmpty(payment)) { log.debug("从缓存获取支付配置成功: {}", primaryKey); -// return payment; + return payment; } // 2. 如果 Payment:1* 格式不存在,尝试原有格式 @@ -55,7 +55,7 @@ public class PaymentCacheService { log.debug("从兜底缓存获取支付配置成功: {}", fallbackKey); // 将查询结果缓存到 Payment:1* 格式 redisUtil.set(primaryKey, payment); -// return payment; + return payment; } // 3. 最后从数据库查询 diff --git a/src/main/java/com/gxwebsoft/common/core/utils/RequestUtil.java b/src/main/java/com/gxwebsoft/common/core/utils/RequestUtil.java index 9bfc2b8..2b1673e 100644 --- a/src/main/java/com/gxwebsoft/common/core/utils/RequestUtil.java +++ b/src/main/java/com/gxwebsoft/common/core/utils/RequestUtil.java @@ -2,6 +2,7 @@ package com.gxwebsoft.common.core.utils; import cn.hutool.http.HttpRequest; import com.alibaba.fastjson.JSONObject; +import com.gxwebsoft.common.core.config.ConfigProperties; import com.gxwebsoft.common.core.web.ApiResult; import com.gxwebsoft.common.system.entity.Payment; import com.gxwebsoft.common.system.entity.User; @@ -9,6 +10,7 @@ import com.gxwebsoft.common.system.entity.UserRole; import com.gxwebsoft.shop.entity.ShopOrder; import com.gxwebsoft.shop.entity.ShopMerchantAccount; import com.wechat.pay.java.service.partnerpayments.jsapi.model.Transaction; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.ArrayList; @@ -16,7 +18,10 @@ import java.util.HashMap; @Component public class RequestUtil { - private static final String host = "https://server.gxwebsoft.com/api"; + + @Autowired + private ConfigProperties configProperties; + private static String ACCESS_TOKEN; private static String TENANT_ID; @@ -28,6 +33,10 @@ public class RequestUtil { ACCESS_TOKEN = token; } + private String getServerUrl() { + return configProperties.getServerUrl(); + } + // 预付请求付款(余额支付) public Object balancePay(ShopOrder order) { // 设置租户ID @@ -38,7 +47,7 @@ public class RequestUtil { String path = "/system/payment/balancePay"; try { // 链式构建请求 - final String body = HttpRequest.post(host.concat(path)) + final String body = HttpRequest.post(getServerUrl().concat(path)) .header("Tenantid", TENANT_ID) .header("Authorization", ACCESS_TOKEN) .body(JSONUtil.toJSONString(order))//表单内容 @@ -77,7 +86,7 @@ public class RequestUtil { String path = "/system/user/getByPhone/" + phone; try { // 链式构建请求 - String result = HttpRequest.get(host.concat(path)) + String result = HttpRequest.get(getServerUrl().concat(path)) .header("Authorization", ACCESS_TOKEN) .header("Tenantid", TENANT_ID) .timeout(20000)//超时,毫秒 @@ -96,7 +105,7 @@ public class RequestUtil { String path = "/system/user/" + userId; try { // 链式构建请求 - String result = HttpRequest.get(host.concat(path)) + String result = HttpRequest.get(getServerUrl().concat(path)) .header("Authorization", ACCESS_TOKEN) .header("Tenantid", TENANT_ID) .timeout(20000)//超时,毫秒 @@ -131,7 +140,7 @@ public class RequestUtil { map.put("roles", roles); map.put("tenantId", TENANT_ID); // 链式构建请求 - String result = HttpRequest.post(host.concat(path)) + String result = HttpRequest.post(getServerUrl().concat(path)) .header("Authorization", ACCESS_TOKEN) .header("Tenantid", TENANT_ID) .body(JSONUtil.toJSONString(map))//表单内容 @@ -147,7 +156,7 @@ public class RequestUtil { public ApiResult updateUserBalance(String path, User user) { try { // 链式构建请求 - final String body = HttpRequest.put(host.concat(path)) + final String body = HttpRequest.put(getServerUrl().concat(path)) .header("Authorization", ACCESS_TOKEN) .header("Tenantid", TENANT_ID) .body(JSONUtil.toJSONString(user)) @@ -163,7 +172,7 @@ public class RequestUtil { public User getParent(Integer userId) { try { // 链式构建请求 - final String result = HttpRequest.get(host.concat("/system/user-referee/getReferee/" + userId)) + final String result = HttpRequest.get(getServerUrl().concat("/system/user-referee/getReferee/" + userId)) .header("Authorization", ACCESS_TOKEN) .header("Tenantid", TENANT_ID) .timeout(20000) @@ -182,7 +191,7 @@ public class RequestUtil { String path = "/system/user/"; try { // 链式构建请求 - final String body = HttpRequest.put(host.concat(path)) + final String body = HttpRequest.put(getServerUrl().concat(path)) .header("Authorization", ACCESS_TOKEN) .header("Tenantid", TENANT_ID) .body(JSONUtil.toJSONString(user)) @@ -197,7 +206,7 @@ public class RequestUtil { String path = "/wx-login/getOrderQRCode/"; try { // 链式构建请求 - final String body = HttpRequest.get(host.concat(path).concat(orderNo)) + final String body = HttpRequest.get(getServerUrl().concat(path).concat(orderNo)) .header("Authorization", ACCESS_TOKEN) .header("tenantId", TENANT_ID) .timeout(20000) @@ -215,7 +224,7 @@ public class RequestUtil { String path = "/wx-login/getOrderQRCodeUnlimited/"; try { // 链式构建请求 - final String body = HttpRequest.get(host.concat(path).concat(orderNo)) + final String body = HttpRequest.get(getServerUrl().concat(path).concat(orderNo)) .header("Authorization", ACCESS_TOKEN) .header("tenantId", TENANT_ID) .timeout(20000) @@ -235,7 +244,7 @@ public class RequestUtil { String path = "/system/user/updateUserMerchantId"; try { // 链式构建请求 - final String body = HttpRequest.put(host.concat(path)) + final String body = HttpRequest.put(getServerUrl().concat(path)) .header("Authorization", ACCESS_TOKEN) .header("tenantId", TENANT_ID) .body(JSONUtil.toJSONString(user)) @@ -250,7 +259,7 @@ public class RequestUtil { String path = "/system/setting?settingKey=mp-weixin"; try { // 链式构建请求 - final String body = HttpRequest.get(host.concat(path)) + final String body = HttpRequest.get(getServerUrl().concat(path)) .header("Authorization", ACCESS_TOKEN) .header("tenantId", TENANT_ID) .timeout(20000) diff --git a/src/main/java/com/gxwebsoft/common/core/utils/WxOfficialUtil.java b/src/main/java/com/gxwebsoft/common/core/utils/WxOfficialUtil.java index 077e615..4f10747 100644 --- a/src/main/java/com/gxwebsoft/common/core/utils/WxOfficialUtil.java +++ b/src/main/java/com/gxwebsoft/common/core/utils/WxOfficialUtil.java @@ -72,7 +72,7 @@ public class WxOfficialUtil { } public String getCodeUrl() throws UnsupportedEncodingException { - String encodedReturnUrl = URLEncoder.encode("https://server.gxwebsoft.com/api/open/wx-official/accessToken","UTF-8"); + String encodedReturnUrl = URLEncoder.encode(pathConfig.getServerUrl() + "/open/wx-official/accessToken","UTF-8"); return "https://open.weixin.qq.com/connect/oauth2/authorize?appid="+ this.appId +"&redirect_uri=" + encodedReturnUrl + "&response_type=code&scope=snsapi_userinfo&state="+ this.tenantId +"#wechat_redirect"; } diff --git a/src/main/java/com/gxwebsoft/oa/controller/OaAppController.java b/src/main/java/com/gxwebsoft/oa/controller/OaAppController.java index 02843b6..f2850c6 100644 --- a/src/main/java/com/gxwebsoft/oa/controller/OaAppController.java +++ b/src/main/java/com/gxwebsoft/oa/controller/OaAppController.java @@ -8,6 +8,7 @@ import cn.hutool.http.HttpRequest; import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.TypeReference; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.gxwebsoft.common.core.config.ConfigProperties; import com.gxwebsoft.common.core.security.JwtUtil; import com.gxwebsoft.common.core.utils.CommonUtil; import com.gxwebsoft.common.core.utils.RedisUtil; @@ -59,6 +60,8 @@ public class OaAppController extends BaseController { private OaAppUserService oaAppUserService; @Resource private RedisUtil redisUtil; + @Resource + private ConfigProperties configProperties; @PreAuthorize("hasAuthority('oa:app:list')") @Operation(summary = "分页查询应用") @@ -249,7 +252,7 @@ public class OaAppController extends BaseController { // 读取项目附件(链式构建GET请求) HashMap map = new HashMap<>(); map.put("appId", d.getAppId()); - final String build = UrlBuilder.of("https://server.gxwebsoft.com/api/file/page").setQuery(new UrlQuery(map)).build(); + final String build = UrlBuilder.of(configProperties.getServerUrl() + "/file/page").setQuery(new UrlQuery(map)).build(); String response = HttpRequest.get(build) .header("Authorization", param.getToken()) .header("Tenantid", d.getTenantId().toString()) diff --git a/src/main/java/com/gxwebsoft/shop/controller/ShopOrderController.java b/src/main/java/com/gxwebsoft/shop/controller/ShopOrderController.java index 000ee2e..48c2fc6 100644 --- a/src/main/java/com/gxwebsoft/shop/controller/ShopOrderController.java +++ b/src/main/java/com/gxwebsoft/shop/controller/ShopOrderController.java @@ -10,6 +10,7 @@ import com.gxwebsoft.common.core.config.ConfigProperties; import com.gxwebsoft.common.core.config.CertificateProperties; import com.gxwebsoft.common.core.utils.RedisUtil; import com.gxwebsoft.common.core.utils.CertificateLoader; +import com.gxwebsoft.common.core.utils.WechatCertAutoConfig; import com.gxwebsoft.common.core.web.BaseController; import com.gxwebsoft.common.system.entity.Payment; import com.gxwebsoft.shop.service.ShopOrderGoodsService; @@ -24,8 +25,8 @@ import com.gxwebsoft.common.core.web.BatchParam; import com.gxwebsoft.common.system.entity.User; import com.wechat.pay.java.core.notification.NotificationConfig; import com.wechat.pay.java.core.notification.NotificationParser; -import com.wechat.pay.java.core.notification.RSANotificationConfig; import com.wechat.pay.java.core.notification.RequestParam; +import com.wechat.pay.java.core.RSAAutoCertificateConfig; import com.wechat.pay.java.service.partnerpayments.jsapi.model.Transaction; import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.media.Schema; @@ -67,6 +68,8 @@ public class ShopOrderController extends BaseController { private CertificateProperties certConfig; @Resource private CertificateLoader certificateLoader; + @Resource + private WechatCertAutoConfig wechatCertAutoConfig; @Value("${spring.profiles.active}") String active; @@ -210,26 +213,14 @@ public class ShopOrderController extends BaseController { String key = "Payment:1:".concat(tenantId.toString()); Payment payment = redisUtil.get(key, Payment.class); - // 证书配置 - String apiV3Key; - String apiclientCert; - - // 开发环境 - 使用证书加载器 - if (active.equals("dev")) { - apiV3Key = certConfig.getWechatPay().getDev().getApiV3Key(); - apiclientCert = certificateLoader.loadCertificatePath( - certConfig.getWechatPayCertPath(certConfig.getWechatPay().getDev().getWechatpayCertFile())); - } else { - // 生产环境 - if (ObjectUtil.isNotEmpty(payment)) { - apiV3Key = payment.getApiKey(); - apiclientCert = certificateLoader.loadCertificatePath( - conf.getUploadPath().concat("/file").concat(payment.getApiclientCert())); - } else { - throw new RuntimeException("生产环境未找到支付配置信息"); - } + // 检查支付配置 + if (ObjectUtil.isEmpty(payment)) { + throw new RuntimeException("未找到租户支付配置信息,租户ID: " + tenantId); } + logger.info("开始处理微信支付异步通知 - 租户ID: {}", tenantId); + logger.info("支付配置信息 - 商户号: {}, 应用ID: {}", payment.getMchId(), payment.getAppId()); + RequestParam requestParam = new RequestParam.Builder() .serialNumber(header.get("wechatpay-serial")) .nonce(header.get("wechatpay-nonce")) @@ -238,12 +229,51 @@ public class ShopOrderController extends BaseController { .body(body) .build(); - // 如果已经初始化了 RSAAutoCertificateConfig,可直接使用 - // 没有的话,则构造一个 - NotificationConfig config = new RSANotificationConfig.Builder() - .apiV3Key(apiV3Key) - .certificatesFromPath(apiclientCert) - .build(); + // 创建通知配置 - 使用与下单方法相同的证书配置逻辑 + NotificationConfig config; + try { + if (active.equals("dev")) { + // 开发环境 - 构建包含租户号的私钥路径 + String tenantCertPath = "dev/wechat/" + tenantId; + String privateKeyPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getPrivateKeyFile(); + String privateKey = certificateLoader.loadCertificatePath(privateKeyPath); + String apiV3Key = certConfig.getWechatPay().getDev().getApiV3Key(); + + // 使用自动证书配置 + config = new RSAAutoCertificateConfig.Builder() + .merchantId(payment.getMchId()) + .privateKeyFromPath(privateKey) + .merchantSerialNumber(payment.getMerchantSerialNumber()) + .apiV3Key(apiV3Key) + .build(); + + logger.info("开发环境使用自动证书配置创建通知解析器"); + } else { + // 生产环境 - 使用自动证书配置 + final String certRootPath = certConfig.getCertRootPath(); + final String certBasePath = certRootPath + "/file"; + + String privateKeyRelativePath = payment.getApiclientKey(); + String privateKeyFullPath = privateKeyRelativePath.startsWith("/") + ? certBasePath + privateKeyRelativePath + : certBasePath + "/" + privateKeyRelativePath; + String privateKey = certificateLoader.loadCertificatePath(privateKeyFullPath); + String apiV3Key = payment.getApiKey(); + + // 使用自动证书配置 + config = new RSAAutoCertificateConfig.Builder() + .merchantId(payment.getMchId()) + .privateKeyFromPath(privateKey) + .merchantSerialNumber(payment.getMerchantSerialNumber()) + .apiV3Key(apiV3Key) + .build(); + + logger.info("生产环境使用自动证书配置创建通知解析器"); + } + } catch (Exception e) { + logger.error("创建通知配置失败", e); + throw new RuntimeException("微信支付通知配置失败: " + e.getMessage(), e); + } // 初始化 NotificationParser NotificationParser parser = new NotificationParser(config); diff --git a/src/main/java/com/gxwebsoft/shop/service/impl/ShopOrderServiceImpl.java b/src/main/java/com/gxwebsoft/shop/service/impl/ShopOrderServiceImpl.java index b597a48..e104f52 100644 --- a/src/main/java/com/gxwebsoft/shop/service/impl/ShopOrderServiceImpl.java +++ b/src/main/java/com/gxwebsoft/shop/service/impl/ShopOrderServiceImpl.java @@ -143,7 +143,7 @@ import com.gxwebsoft.common.core.service.PaymentCacheService; final Payer payer = new Payer(); payer.setOpenid(order.getOpenid()); request.setPayer(payer); - request.setNotifyUrl("https://server.gxwebsoft.com/api/system/wx-pay/notify/" + order.getTenantId()); // 默认回调地址 + request.setNotifyUrl(config.getServerUrl() + "/system/wx-pay/notify/" + order.getTenantId()); // 默认回调地址 // 测试环境 if (active.equals("dev")) { amount.setTotal(1); diff --git a/src/main/resources/application-prod.yml b/src/main/resources/application-prod.yml index 54009d7..ce27de5 100644 --- a/src/main/resources/application-prod.yml +++ b/src/main/resources/application-prod.yml @@ -44,7 +44,7 @@ mqtt: # 框架配置 config: # 生产环境接口 - server-url: https://server.gxwebsoft.com/api + server-url: https://server.s209.websoft.top/api upload-path: /www/wwwroot/file.ws/ # 阿里云OSS云存储 diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index f434b56..8ecca01 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -106,9 +106,9 @@ config: swagger-version: 2.0 token-key: WLgNsWJ8rPjRtnjzX/Gx2RGS80Kwnm/ZeLbvIL+NrBs= # 主服务器 - server-url: https://server.gxwebsoft.com/api + server-url: https://server.s209.websoft.top/api # 文件服务器 - file-server: https://file.websoft.top + file-server: https://file.wsdns.cn upload-path: /Users/gxwebsoft/Documents/uploads/ local-upload-path: /Users/gxwebsoft/Documents/uploads/ @@ -170,4 +170,3 @@ certificate: app-cert-public-key-file: "appCertPublicKey.crt" alipay-cert-public-key-file: "alipayCertPublicKey.crt" alipay-root-cert-file: "alipayRootCert.crt" - diff --git a/src/test/java/com/gxwebsoft/config/ServerUrlConfigTest.java b/src/test/java/com/gxwebsoft/config/ServerUrlConfigTest.java new file mode 100644 index 0000000..a85bbb9 --- /dev/null +++ b/src/test/java/com/gxwebsoft/config/ServerUrlConfigTest.java @@ -0,0 +1,51 @@ +package com.gxwebsoft.config; + +import com.gxwebsoft.common.core.config.ConfigProperties; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * 服务器URL配置测试 + * 验证server-url配置是否正确从配置文件读取 + */ +@SpringBootTest +@ActiveProfiles("dev") +public class ServerUrlConfigTest { + + @Autowired + private ConfigProperties configProperties; + + @Test + public void testServerUrlConfiguration() { + // 验证配置属性不为空 + assertNotNull(configProperties, "ConfigProperties should not be null"); + + // 验证server-url配置正确读取 + String serverUrl = configProperties.getServerUrl(); + assertNotNull(serverUrl, "Server URL should not be null"); + assertFalse(serverUrl.isEmpty(), "Server URL should not be empty"); + + // 在开发环境下,应该是本地地址 + assertTrue(serverUrl.contains("127.0.0.1") || serverUrl.contains("localhost"), + "In dev environment, server URL should contain localhost or 127.0.0.1"); + + System.out.println("当前配置的服务器URL: " + serverUrl); + } + + @Test + public void testServerUrlFormat() { + String serverUrl = configProperties.getServerUrl(); + + // 验证URL格式 + assertTrue(serverUrl.startsWith("http://") || serverUrl.startsWith("https://"), + "Server URL should start with http:// or https://"); + assertTrue(serverUrl.endsWith("/api"), + "Server URL should end with /api"); + + System.out.println("服务器URL格式验证通过: " + serverUrl); + } +}