更新完成:优化微信支付证书读取机制等等
This commit is contained in:
111
docs/SERVER_URL_REFACTOR_SUMMARY.md
Normal file
111
docs/SERVER_URL_REFACTOR_SUMMARY.md
Normal file
@@ -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被引入
|
||||||
79
docs/start_frp.sh
Executable file
79
docs/start_frp.sh
Executable file
@@ -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"
|
||||||
@@ -37,7 +37,7 @@ public class SwaggerConfig {
|
|||||||
.name("科技小王子")
|
.name("科技小王子")
|
||||||
.url("https://www.gxwebsoft.com")
|
.url("https://www.gxwebsoft.com")
|
||||||
.email("170083662@qq.com"))
|
.email("170083662@qq.com"))
|
||||||
.termsOfService("https://server.gxwebsoft.com/api/system"))
|
.termsOfService(config.getServerUrl() + "/system"))
|
||||||
.components(new Components()
|
.components(new Components()
|
||||||
.addSecuritySchemes("Authorization",
|
.addSecuritySchemes("Authorization",
|
||||||
new SecurityScheme()
|
new SecurityScheme()
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
|||||||
map.put("username", jwtSubject.getUsername());
|
map.put("username", jwtSubject.getUsername());
|
||||||
map.put("tenantId", jwtSubject.getTenantId());
|
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("Authorization", access_token)
|
||||||
.header("Tenantid", jwtSubject.getTenantId().toString())
|
.header("Tenantid", jwtSubject.getTenantId().toString())
|
||||||
.body(JSONUtil.toJSONString(map))//表单内容
|
.body(JSONUtil.toJSONString(map))//表单内容
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ public class PaymentCacheService {
|
|||||||
|
|
||||||
if (ObjectUtil.isNotEmpty(payment)) {
|
if (ObjectUtil.isNotEmpty(payment)) {
|
||||||
log.debug("从缓存获取支付配置成功: {}", primaryKey);
|
log.debug("从缓存获取支付配置成功: {}", primaryKey);
|
||||||
// return payment;
|
return payment;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 如果 Payment:1* 格式不存在,尝试原有格式
|
// 2. 如果 Payment:1* 格式不存在,尝试原有格式
|
||||||
@@ -55,7 +55,7 @@ public class PaymentCacheService {
|
|||||||
log.debug("从兜底缓存获取支付配置成功: {}", fallbackKey);
|
log.debug("从兜底缓存获取支付配置成功: {}", fallbackKey);
|
||||||
// 将查询结果缓存到 Payment:1* 格式
|
// 将查询结果缓存到 Payment:1* 格式
|
||||||
redisUtil.set(primaryKey, payment);
|
redisUtil.set(primaryKey, payment);
|
||||||
// return payment;
|
return payment;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. 最后从数据库查询
|
// 3. 最后从数据库查询
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.gxwebsoft.common.core.utils;
|
|||||||
|
|
||||||
import cn.hutool.http.HttpRequest;
|
import cn.hutool.http.HttpRequest;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.gxwebsoft.common.core.config.ConfigProperties;
|
||||||
import com.gxwebsoft.common.core.web.ApiResult;
|
import com.gxwebsoft.common.core.web.ApiResult;
|
||||||
import com.gxwebsoft.common.system.entity.Payment;
|
import com.gxwebsoft.common.system.entity.Payment;
|
||||||
import com.gxwebsoft.common.system.entity.User;
|
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.ShopOrder;
|
||||||
import com.gxwebsoft.shop.entity.ShopMerchantAccount;
|
import com.gxwebsoft.shop.entity.ShopMerchantAccount;
|
||||||
import com.wechat.pay.java.service.partnerpayments.jsapi.model.Transaction;
|
import com.wechat.pay.java.service.partnerpayments.jsapi.model.Transaction;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -16,7 +18,10 @@ import java.util.HashMap;
|
|||||||
|
|
||||||
@Component
|
@Component
|
||||||
public class RequestUtil {
|
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 ACCESS_TOKEN;
|
||||||
private static String TENANT_ID;
|
private static String TENANT_ID;
|
||||||
|
|
||||||
@@ -28,6 +33,10 @@ public class RequestUtil {
|
|||||||
ACCESS_TOKEN = token;
|
ACCESS_TOKEN = token;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getServerUrl() {
|
||||||
|
return configProperties.getServerUrl();
|
||||||
|
}
|
||||||
|
|
||||||
// 预付请求付款(余额支付)
|
// 预付请求付款(余额支付)
|
||||||
public Object balancePay(ShopOrder order) {
|
public Object balancePay(ShopOrder order) {
|
||||||
// 设置租户ID
|
// 设置租户ID
|
||||||
@@ -38,7 +47,7 @@ public class RequestUtil {
|
|||||||
String path = "/system/payment/balancePay";
|
String path = "/system/payment/balancePay";
|
||||||
try {
|
try {
|
||||||
// 链式构建请求
|
// 链式构建请求
|
||||||
final String body = HttpRequest.post(host.concat(path))
|
final String body = HttpRequest.post(getServerUrl().concat(path))
|
||||||
.header("Tenantid", TENANT_ID)
|
.header("Tenantid", TENANT_ID)
|
||||||
.header("Authorization", ACCESS_TOKEN)
|
.header("Authorization", ACCESS_TOKEN)
|
||||||
.body(JSONUtil.toJSONString(order))//表单内容
|
.body(JSONUtil.toJSONString(order))//表单内容
|
||||||
@@ -77,7 +86,7 @@ public class RequestUtil {
|
|||||||
String path = "/system/user/getByPhone/" + phone;
|
String path = "/system/user/getByPhone/" + phone;
|
||||||
try {
|
try {
|
||||||
// 链式构建请求
|
// 链式构建请求
|
||||||
String result = HttpRequest.get(host.concat(path))
|
String result = HttpRequest.get(getServerUrl().concat(path))
|
||||||
.header("Authorization", ACCESS_TOKEN)
|
.header("Authorization", ACCESS_TOKEN)
|
||||||
.header("Tenantid", TENANT_ID)
|
.header("Tenantid", TENANT_ID)
|
||||||
.timeout(20000)//超时,毫秒
|
.timeout(20000)//超时,毫秒
|
||||||
@@ -96,7 +105,7 @@ public class RequestUtil {
|
|||||||
String path = "/system/user/" + userId;
|
String path = "/system/user/" + userId;
|
||||||
try {
|
try {
|
||||||
// 链式构建请求
|
// 链式构建请求
|
||||||
String result = HttpRequest.get(host.concat(path))
|
String result = HttpRequest.get(getServerUrl().concat(path))
|
||||||
.header("Authorization", ACCESS_TOKEN)
|
.header("Authorization", ACCESS_TOKEN)
|
||||||
.header("Tenantid", TENANT_ID)
|
.header("Tenantid", TENANT_ID)
|
||||||
.timeout(20000)//超时,毫秒
|
.timeout(20000)//超时,毫秒
|
||||||
@@ -131,7 +140,7 @@ public class RequestUtil {
|
|||||||
map.put("roles", roles);
|
map.put("roles", roles);
|
||||||
map.put("tenantId", TENANT_ID);
|
map.put("tenantId", TENANT_ID);
|
||||||
// 链式构建请求
|
// 链式构建请求
|
||||||
String result = HttpRequest.post(host.concat(path))
|
String result = HttpRequest.post(getServerUrl().concat(path))
|
||||||
.header("Authorization", ACCESS_TOKEN)
|
.header("Authorization", ACCESS_TOKEN)
|
||||||
.header("Tenantid", TENANT_ID)
|
.header("Tenantid", TENANT_ID)
|
||||||
.body(JSONUtil.toJSONString(map))//表单内容
|
.body(JSONUtil.toJSONString(map))//表单内容
|
||||||
@@ -147,7 +156,7 @@ public class RequestUtil {
|
|||||||
public ApiResult<?> updateUserBalance(String path, User user) {
|
public ApiResult<?> updateUserBalance(String path, User user) {
|
||||||
try {
|
try {
|
||||||
// 链式构建请求
|
// 链式构建请求
|
||||||
final String body = HttpRequest.put(host.concat(path))
|
final String body = HttpRequest.put(getServerUrl().concat(path))
|
||||||
.header("Authorization", ACCESS_TOKEN)
|
.header("Authorization", ACCESS_TOKEN)
|
||||||
.header("Tenantid", TENANT_ID)
|
.header("Tenantid", TENANT_ID)
|
||||||
.body(JSONUtil.toJSONString(user))
|
.body(JSONUtil.toJSONString(user))
|
||||||
@@ -163,7 +172,7 @@ public class RequestUtil {
|
|||||||
public User getParent(Integer userId) {
|
public User getParent(Integer userId) {
|
||||||
try {
|
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("Authorization", ACCESS_TOKEN)
|
||||||
.header("Tenantid", TENANT_ID)
|
.header("Tenantid", TENANT_ID)
|
||||||
.timeout(20000)
|
.timeout(20000)
|
||||||
@@ -182,7 +191,7 @@ public class RequestUtil {
|
|||||||
String path = "/system/user/";
|
String path = "/system/user/";
|
||||||
try {
|
try {
|
||||||
// 链式构建请求
|
// 链式构建请求
|
||||||
final String body = HttpRequest.put(host.concat(path))
|
final String body = HttpRequest.put(getServerUrl().concat(path))
|
||||||
.header("Authorization", ACCESS_TOKEN)
|
.header("Authorization", ACCESS_TOKEN)
|
||||||
.header("Tenantid", TENANT_ID)
|
.header("Tenantid", TENANT_ID)
|
||||||
.body(JSONUtil.toJSONString(user))
|
.body(JSONUtil.toJSONString(user))
|
||||||
@@ -197,7 +206,7 @@ public class RequestUtil {
|
|||||||
String path = "/wx-login/getOrderQRCode/";
|
String path = "/wx-login/getOrderQRCode/";
|
||||||
try {
|
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("Authorization", ACCESS_TOKEN)
|
||||||
.header("tenantId", TENANT_ID)
|
.header("tenantId", TENANT_ID)
|
||||||
.timeout(20000)
|
.timeout(20000)
|
||||||
@@ -215,7 +224,7 @@ public class RequestUtil {
|
|||||||
String path = "/wx-login/getOrderQRCodeUnlimited/";
|
String path = "/wx-login/getOrderQRCodeUnlimited/";
|
||||||
try {
|
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("Authorization", ACCESS_TOKEN)
|
||||||
.header("tenantId", TENANT_ID)
|
.header("tenantId", TENANT_ID)
|
||||||
.timeout(20000)
|
.timeout(20000)
|
||||||
@@ -235,7 +244,7 @@ public class RequestUtil {
|
|||||||
String path = "/system/user/updateUserMerchantId";
|
String path = "/system/user/updateUserMerchantId";
|
||||||
try {
|
try {
|
||||||
// 链式构建请求
|
// 链式构建请求
|
||||||
final String body = HttpRequest.put(host.concat(path))
|
final String body = HttpRequest.put(getServerUrl().concat(path))
|
||||||
.header("Authorization", ACCESS_TOKEN)
|
.header("Authorization", ACCESS_TOKEN)
|
||||||
.header("tenantId", TENANT_ID)
|
.header("tenantId", TENANT_ID)
|
||||||
.body(JSONUtil.toJSONString(user))
|
.body(JSONUtil.toJSONString(user))
|
||||||
@@ -250,7 +259,7 @@ public class RequestUtil {
|
|||||||
String path = "/system/setting?settingKey=mp-weixin";
|
String path = "/system/setting?settingKey=mp-weixin";
|
||||||
try {
|
try {
|
||||||
// 链式构建请求
|
// 链式构建请求
|
||||||
final String body = HttpRequest.get(host.concat(path))
|
final String body = HttpRequest.get(getServerUrl().concat(path))
|
||||||
.header("Authorization", ACCESS_TOKEN)
|
.header("Authorization", ACCESS_TOKEN)
|
||||||
.header("tenantId", TENANT_ID)
|
.header("tenantId", TENANT_ID)
|
||||||
.timeout(20000)
|
.timeout(20000)
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ public class WxOfficialUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String getCodeUrl() throws UnsupportedEncodingException {
|
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";
|
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";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import cn.hutool.http.HttpRequest;
|
|||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import com.alibaba.fastjson.TypeReference;
|
import com.alibaba.fastjson.TypeReference;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
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.security.JwtUtil;
|
||||||
import com.gxwebsoft.common.core.utils.CommonUtil;
|
import com.gxwebsoft.common.core.utils.CommonUtil;
|
||||||
import com.gxwebsoft.common.core.utils.RedisUtil;
|
import com.gxwebsoft.common.core.utils.RedisUtil;
|
||||||
@@ -59,6 +60,8 @@ public class OaAppController extends BaseController {
|
|||||||
private OaAppUserService oaAppUserService;
|
private OaAppUserService oaAppUserService;
|
||||||
@Resource
|
@Resource
|
||||||
private RedisUtil redisUtil;
|
private RedisUtil redisUtil;
|
||||||
|
@Resource
|
||||||
|
private ConfigProperties configProperties;
|
||||||
|
|
||||||
@PreAuthorize("hasAuthority('oa:app:list')")
|
@PreAuthorize("hasAuthority('oa:app:list')")
|
||||||
@Operation(summary = "分页查询应用")
|
@Operation(summary = "分页查询应用")
|
||||||
@@ -249,7 +252,7 @@ public class OaAppController extends BaseController {
|
|||||||
// 读取项目附件(链式构建GET请求)
|
// 读取项目附件(链式构建GET请求)
|
||||||
HashMap<String, Object> map = new HashMap<>();
|
HashMap<String, Object> map = new HashMap<>();
|
||||||
map.put("appId", d.getAppId());
|
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)
|
String response = HttpRequest.get(build)
|
||||||
.header("Authorization", param.getToken())
|
.header("Authorization", param.getToken())
|
||||||
.header("Tenantid", d.getTenantId().toString())
|
.header("Tenantid", d.getTenantId().toString())
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import com.gxwebsoft.common.core.config.ConfigProperties;
|
|||||||
import com.gxwebsoft.common.core.config.CertificateProperties;
|
import com.gxwebsoft.common.core.config.CertificateProperties;
|
||||||
import com.gxwebsoft.common.core.utils.RedisUtil;
|
import com.gxwebsoft.common.core.utils.RedisUtil;
|
||||||
import com.gxwebsoft.common.core.utils.CertificateLoader;
|
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.core.web.BaseController;
|
||||||
import com.gxwebsoft.common.system.entity.Payment;
|
import com.gxwebsoft.common.system.entity.Payment;
|
||||||
import com.gxwebsoft.shop.service.ShopOrderGoodsService;
|
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.gxwebsoft.common.system.entity.User;
|
||||||
import com.wechat.pay.java.core.notification.NotificationConfig;
|
import com.wechat.pay.java.core.notification.NotificationConfig;
|
||||||
import com.wechat.pay.java.core.notification.NotificationParser;
|
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.notification.RequestParam;
|
||||||
|
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
|
||||||
import com.wechat.pay.java.service.partnerpayments.jsapi.model.Transaction;
|
import com.wechat.pay.java.service.partnerpayments.jsapi.model.Transaction;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
@@ -67,6 +68,8 @@ public class ShopOrderController extends BaseController {
|
|||||||
private CertificateProperties certConfig;
|
private CertificateProperties certConfig;
|
||||||
@Resource
|
@Resource
|
||||||
private CertificateLoader certificateLoader;
|
private CertificateLoader certificateLoader;
|
||||||
|
@Resource
|
||||||
|
private WechatCertAutoConfig wechatCertAutoConfig;
|
||||||
@Value("${spring.profiles.active}")
|
@Value("${spring.profiles.active}")
|
||||||
String active;
|
String active;
|
||||||
|
|
||||||
@@ -210,26 +213,14 @@ public class ShopOrderController extends BaseController {
|
|||||||
String key = "Payment:1:".concat(tenantId.toString());
|
String key = "Payment:1:".concat(tenantId.toString());
|
||||||
Payment payment = redisUtil.get(key, Payment.class);
|
Payment payment = redisUtil.get(key, Payment.class);
|
||||||
|
|
||||||
// 证书配置
|
// 检查支付配置
|
||||||
String apiV3Key;
|
if (ObjectUtil.isEmpty(payment)) {
|
||||||
String apiclientCert;
|
throw new RuntimeException("未找到租户支付配置信息,租户ID: " + tenantId);
|
||||||
|
|
||||||
// 开发环境 - 使用证书加载器
|
|
||||||
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("生产环境未找到支付配置信息");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.info("开始处理微信支付异步通知 - 租户ID: {}", tenantId);
|
||||||
|
logger.info("支付配置信息 - 商户号: {}, 应用ID: {}", payment.getMchId(), payment.getAppId());
|
||||||
|
|
||||||
RequestParam requestParam = new RequestParam.Builder()
|
RequestParam requestParam = new RequestParam.Builder()
|
||||||
.serialNumber(header.get("wechatpay-serial"))
|
.serialNumber(header.get("wechatpay-serial"))
|
||||||
.nonce(header.get("wechatpay-nonce"))
|
.nonce(header.get("wechatpay-nonce"))
|
||||||
@@ -238,12 +229,51 @@ public class ShopOrderController extends BaseController {
|
|||||||
.body(body)
|
.body(body)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
// 如果已经初始化了 RSAAutoCertificateConfig,可直接使用
|
// 创建通知配置 - 使用与下单方法相同的证书配置逻辑
|
||||||
// 没有的话,则构造一个
|
NotificationConfig config;
|
||||||
NotificationConfig config = new RSANotificationConfig.Builder()
|
try {
|
||||||
.apiV3Key(apiV3Key)
|
if (active.equals("dev")) {
|
||||||
.certificatesFromPath(apiclientCert)
|
// 开发环境 - 构建包含租户号的私钥路径
|
||||||
.build();
|
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
|
||||||
NotificationParser parser = new NotificationParser(config);
|
NotificationParser parser = new NotificationParser(config);
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ import com.gxwebsoft.common.core.service.PaymentCacheService;
|
|||||||
final Payer payer = new Payer();
|
final Payer payer = new Payer();
|
||||||
payer.setOpenid(order.getOpenid());
|
payer.setOpenid(order.getOpenid());
|
||||||
request.setPayer(payer);
|
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")) {
|
if (active.equals("dev")) {
|
||||||
amount.setTotal(1);
|
amount.setTotal(1);
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ mqtt:
|
|||||||
# 框架配置
|
# 框架配置
|
||||||
config:
|
config:
|
||||||
# 生产环境接口
|
# 生产环境接口
|
||||||
server-url: https://server.gxwebsoft.com/api
|
server-url: https://server.s209.websoft.top/api
|
||||||
upload-path: /www/wwwroot/file.ws/
|
upload-path: /www/wwwroot/file.ws/
|
||||||
|
|
||||||
# 阿里云OSS云存储
|
# 阿里云OSS云存储
|
||||||
|
|||||||
@@ -106,9 +106,9 @@ config:
|
|||||||
swagger-version: 2.0
|
swagger-version: 2.0
|
||||||
token-key: WLgNsWJ8rPjRtnjzX/Gx2RGS80Kwnm/ZeLbvIL+NrBs=
|
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/
|
upload-path: /Users/gxwebsoft/Documents/uploads/
|
||||||
local-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"
|
app-cert-public-key-file: "appCertPublicKey.crt"
|
||||||
alipay-cert-public-key-file: "alipayCertPublicKey.crt"
|
alipay-cert-public-key-file: "alipayCertPublicKey.crt"
|
||||||
alipay-root-cert-file: "alipayRootCert.crt"
|
alipay-root-cert-file: "alipayRootCert.crt"
|
||||||
|
|
||||||
|
|||||||
51
src/test/java/com/gxwebsoft/config/ServerUrlConfigTest.java
Normal file
51
src/test/java/com/gxwebsoft/config/ServerUrlConfigTest.java
Normal file
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user