This commit is contained in:
2026-07-31 12:03:24 +08:00
27 changed files with 294 additions and 11 deletions
@@ -0,0 +1,6 @@
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: ${AUDIT_DB_URL:jdbc:mysql://127.0.0.1:3306/baiyue_audit?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true}
username: ${AUDIT_DB_USERNAME:root}
password: ${AUDIT_DB_PASSWORD:123456}
@@ -0,0 +1,6 @@
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: ${AUDIT_TEST_DB_URL:jdbc:mysql://${TEST_DB_HOST:8.163.30.128}:${TEST_DB_PORT:3306}/baiyue_audit?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true&rewriteBatchedStatements=true}
username: ${AUDIT_TEST_DB_USERNAME:${TEST_DB_USERNAME:root}}
password: ${AUDIT_TEST_DB_PASSWORD:${TEST_DB_PASSWORD}}
@@ -0,0 +1,6 @@
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: ${AUTH_DB_URL:jdbc:mysql://127.0.0.1:3306/baiyue_auth?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true}
username: ${AUTH_DB_USERNAME:root}
password: ${AUTH_DB_PASSWORD:123456}
@@ -0,0 +1,6 @@
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: ${AUTH_TEST_DB_URL:jdbc:mysql://${TEST_DB_HOST:8.163.30.128}:${TEST_DB_PORT:3306}/baiyue_auth?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true&rewriteBatchedStatements=true}
username: ${AUTH_TEST_DB_USERNAME:${TEST_DB_USERNAME:root}}
password: ${AUTH_TEST_DB_PASSWORD:${TEST_DB_PASSWORD}}
+9
View File
@@ -4,5 +4,14 @@ baiyue:
enabled: ${BAIDU_OCR_ENABLED:false} enabled: ${BAIDU_OCR_ENABLED:false}
api-key: ${BAIDU_OCR_API_KEY:} api-key: ${BAIDU_OCR_API_KEY:}
secret-key: ${BAIDU_OCR_SECRET_KEY:} secret-key: ${BAIDU_OCR_SECRET_KEY:}
input-root: ${WEIGHT_OCR_INPUT_ROOT:/data/baiyue/weight-ocr/input}
output-root: ${WEIGHT_OCR_OUTPUT_ROOT:/data/baiyue/weight-ocr/output}
max-image-size: ${WEIGHT_OCR_MAX_IMAGE_SIZE:3MB}
max-image-pixels: ${WEIGHT_OCR_MAX_IMAGE_PIXELS:40000000}
max-batch-size: ${WEIGHT_OCR_MAX_BATCH_SIZE:50}
connect-timeout: ${BAIDU_OCR_CONNECT_TIMEOUT:10s}
request-timeout: ${BAIDU_OCR_REQUEST_TIMEOUT:60s}
min-request-interval: ${BAIDU_OCR_MIN_REQUEST_INTERVAL:600ms}
max-qps-retries: ${BAIDU_OCR_MAX_QPS_RETRIES:3}
amazon-sp-api: amazon-sp-api:
enabled: ${AMAZON_SP_API_ENABLED:false} enabled: ${AMAZON_SP_API_ENABLED:false}
+11 -3
View File
@@ -1,3 +1,11 @@
baiyue.integration: baiyue:
baidu-ocr.enabled: ${BAIDU_OCR_ENABLED:false} integration:
amazon-sp-api.enabled: ${AMAZON_SP_API_ENABLED:false} baidu-ocr:
enabled: ${BAIDU_OCR_ENABLED:false}
input-root: ${WEIGHT_OCR_INPUT_ROOT:${java.io.tmpdir}/baiyue-weight-ocr/input}
output-root: ${WEIGHT_OCR_OUTPUT_ROOT:${java.io.tmpdir}/baiyue-weight-ocr/output}
max-image-size: ${WEIGHT_OCR_MAX_IMAGE_SIZE:3MB}
max-image-pixels: ${WEIGHT_OCR_MAX_IMAGE_PIXELS:40000000}
max-batch-size: ${WEIGHT_OCR_MAX_BATCH_SIZE:50}
amazon-sp-api:
enabled: ${AMAZON_SP_API_ENABLED:false}
+67
View File
@@ -0,0 +1,67 @@
# 数据库环境切换说明
## 环境定义
- `dev`:本地开发环境,连接 `127.0.0.1:3306`,默认账号为 `root/123456`。
- `test`:联调测试环境,连接 `8.163.30.128:3306`,各微服务仍使用独立数据库。
所有服务默认使用 `dev`:
```yaml
spring:
profiles:
active: ${SPRING_PROFILES_ACTIVE:dev}
```
建议不要直接修改配置文件。通过 IDEA 的启动配置设置 `Active profiles` 即可切换:
- 本地数据库:`dev`
- 测试数据库:`test`
也可以使用启动参数:
```text
--spring.profiles.active=test
```
## 测试数据库密码
测试数据库密码不写入 Git。启动 `test` 环境前,在 IDEA 启动配置的环境变量中设置:
```text
TEST_DB_PASSWORD=测试数据库密码
```
公共测试连接参数支持覆盖:
```text
TEST_DB_HOST=8.163.30.128
TEST_DB_PORT=3306
TEST_DB_USERNAME=root
TEST_DB_PASSWORD=测试数据库密码
```
每个服务还支持使用自己的 `*_TEST_DB_URL`、`*_TEST_DB_USERNAME` 和 `*_TEST_DB_PASSWORD` 覆盖公共参数。
## 分库映射
| 服务 | 测试数据库 |
| --- | --- |
| 认证服务 | `baiyue_auth` |
| 权限服务 | `baiyue_iam` |
| 订单服务 | `baiyue_order` |
| 仓库服务 | `baiyue_warehouse` |
| 头程履约服务 | `baiyue_firstleg` |
| 文件服务 | `baiyue_file` |
| 打印服务 | `baiyue_print` |
| 审计服务 | `baiyue_audit` |
| 事件桥接服务 | `baiyue_event_bridge` |
网关和集成服务没有业务数据库,但同样支持 `dev/test` Profile。网关在两种环境下都会自动加载 `cn` 路由配置。
## 注意事项
- `test` 只切换数据库,Nacos 和 Redis 默认仍连接本机。
- 环境变量优先级高于配置文件,可用于临时覆盖单个服务。
- 修改 IDEA 环境变量后需要重启对应服务。
- 不要把测试数据库密码提交到配置文件、启动脚本或 Git。
@@ -0,0 +1,6 @@
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: ${EVENT_BRIDGE_DB_URL:jdbc:mysql://127.0.0.1:3306/baiyue_event_bridge?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true}
username: ${EVENT_BRIDGE_DB_USERNAME:root}
password: ${EVENT_BRIDGE_DB_PASSWORD:123456}
@@ -0,0 +1,6 @@
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: ${EVENT_BRIDGE_TEST_DB_URL:jdbc:mysql://${TEST_DB_HOST:8.163.30.128}:${TEST_DB_PORT:3306}/baiyue_event_bridge?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true&rewriteBatchedStatements=true}
username: ${EVENT_BRIDGE_TEST_DB_USERNAME:${TEST_DB_USERNAME:root}}
password: ${EVENT_BRIDGE_TEST_DB_PASSWORD:${TEST_DB_PASSWORD}}
@@ -0,0 +1,6 @@
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: ${FILE_DB_URL:jdbc:mysql://127.0.0.1:3306/baiyue_file?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true}
username: ${FILE_DB_USERNAME:root}
password: ${FILE_DB_PASSWORD:123456}
@@ -0,0 +1,6 @@
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: ${FILE_TEST_DB_URL:jdbc:mysql://${TEST_DB_HOST:8.163.30.128}:${TEST_DB_PORT:3306}/baiyue_file?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true&rewriteBatchedStatements=true}
username: ${FILE_TEST_DB_USERNAME:${TEST_DB_USERNAME:root}}
password: ${FILE_TEST_DB_PASSWORD:${TEST_DB_PASSWORD}}
@@ -0,0 +1,6 @@
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: ${FIRSTLEG_DB_URL:jdbc:mysql://127.0.0.1:3306/baiyue_firstleg?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true}
username: ${FIRSTLEG_DB_USERNAME:root}
password: ${FIRSTLEG_DB_PASSWORD:123456}
@@ -0,0 +1,6 @@
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: ${FIRSTLEG_TEST_DB_URL:jdbc:mysql://${TEST_DB_HOST:8.163.30.128}:${TEST_DB_PORT:3306}/baiyue_firstleg?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true&rewriteBatchedStatements=true}
username: ${FIRSTLEG_TEST_DB_USERNAME:${TEST_DB_USERNAME:root}}
password: ${FIRSTLEG_TEST_DB_PASSWORD:${TEST_DB_PASSWORD}}
@@ -0,0 +1,6 @@
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: ${IAM_DB_URL:jdbc:mysql://127.0.0.1:3306/baiyue_iam?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true}
username: ${IAM_DB_USERNAME:root}
password: ${IAM_DB_PASSWORD:123456}
@@ -0,0 +1,6 @@
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: ${IAM_TEST_DB_URL:jdbc:mysql://${TEST_DB_HOST:8.163.30.128}:${TEST_DB_PORT:3306}/baiyue_iam?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true&rewriteBatchedStatements=true}
username: ${IAM_TEST_DB_USERNAME:${TEST_DB_USERNAME:root}}
password: ${IAM_TEST_DB_PASSWORD:${TEST_DB_PASSWORD}}
+10
View File
@@ -13,11 +13,21 @@
<name>integration-service</name> <name>integration-service</name>
<dependencies> <dependencies>
<dependency>
<groupId>com.baiyue.shared</groupId>
<artifactId>baiyue-common-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency> <dependency>
<groupId>com.baiyue.shared</groupId> <groupId>com.baiyue.shared</groupId>
<artifactId>baiyue-common-web</artifactId> <artifactId>baiyue-common-web</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency>
<groupId>com.baiyue.shared</groupId>
<artifactId>baiyue-common-openapi</artifactId>
<version>${project.version}</version>
</dependency>
<dependency> <dependency>
<groupId>com.alibaba.cloud</groupId> <groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
@@ -4,7 +4,7 @@ import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan; import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
@SpringBootApplication @SpringBootApplication(scanBasePackages = {"com.baiyue.integration", "com.baiyue.common.web"})
@ConfigurationPropertiesScan @ConfigurationPropertiesScan
public class IntegrationServiceApplication { public class IntegrationServiceApplication {
public static void main(String[] args) { public static void main(String[] args) {
@@ -1,12 +1,68 @@
package com.baiyue.integration.config; package com.baiyue.integration.config;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.util.unit.DataSize;
import java.net.URI;
import java.nio.file.Path;
import java.time.Duration;
@ConfigurationProperties(prefix = "baiyue.integration") @ConfigurationProperties(prefix = "baiyue.integration")
public record IntegrationProperties(BaiduOcr baiduOcr, AmazonSpApi amazonSpApi) { public record IntegrationProperties(BaiduOcr baiduOcr, AmazonSpApi amazonSpApi) {
public record BaiduOcr(boolean enabled, String apiKey, String secretKey) { public record BaiduOcr(boolean enabled,
String apiKey,
String secretKey,
URI tokenUrl,
URI meterUrl,
Duration connectTimeout,
Duration requestTimeout,
Path inputRoot,
Path outputRoot,
DataSize maxImageSize,
long maxImagePixels,
int maxBatchSize,
Duration minRequestInterval,
int maxQpsRetries) {
public boolean configured() { public boolean configured() {
return enabled && hasText(apiKey) && hasText(secretKey); return enabled
&& hasText(apiKey)
&& hasText(secretKey)
&& tokenUrl != null
&& meterUrl != null;
}
public Duration effectiveConnectTimeout() {
return positive(connectTimeout) ? connectTimeout : Duration.ofSeconds(10);
}
public Duration effectiveRequestTimeout() {
return positive(requestTimeout) ? requestTimeout : Duration.ofSeconds(60);
}
public DataSize effectiveMaxImageSize() {
return maxImageSize != null && maxImageSize.toBytes() > 0
? maxImageSize : DataSize.ofMegabytes(3);
}
public long effectiveMaxImagePixels() {
return maxImagePixels > 0 ? maxImagePixels : 40_000_000L;
}
public int effectiveMaxBatchSize() {
return maxBatchSize > 0 ? maxBatchSize : 50;
}
public Duration effectiveMinRequestInterval() {
return minRequestInterval != null && !minRequestInterval.isNegative()
? minRequestInterval : Duration.ofMillis(600);
}
public int effectiveMaxQpsRetries() {
return Math.min(10, Math.max(0, maxQpsRetries));
}
private boolean positive(Duration value) {
return value != null && !value.isNegative() && !value.isZero();
} }
} }
@@ -1,9 +1,9 @@
package com.baiyue.integration.security; package com.baiyue.integration.security;
import com.baiyue.common.core.api.ResultCode;
import com.baiyue.common.core.exception.BizException;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.web.server.ResponseStatusException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.security.MessageDigest; import java.security.MessageDigest;
@@ -22,7 +22,7 @@ public class InternalServiceTokenGuard {
public void verify(String actualToken) { public void verify(String actualToken) {
byte[] actual = actualToken == null ? new byte[0] : actualToken.getBytes(StandardCharsets.UTF_8); byte[] actual = actualToken == null ? new byte[0] : actualToken.getBytes(StandardCharsets.UTF_8);
if (!MessageDigest.isEqual(expectedToken, actual)) { if (!MessageDigest.isEqual(expectedToken, actual)) {
throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, "内部服务令牌无效"); throw new BizException(ResultCode.UNAUTHORIZED, "内部服务令牌无效");
} }
} }
} }
@@ -35,6 +35,17 @@ baiyue:
enabled: ${BAIDU_OCR_ENABLED:false} enabled: ${BAIDU_OCR_ENABLED:false}
api-key: ${BAIDU_OCR_API_KEY:} api-key: ${BAIDU_OCR_API_KEY:}
secret-key: ${BAIDU_OCR_SECRET_KEY:} secret-key: ${BAIDU_OCR_SECRET_KEY:}
token-url: ${BAIDU_OCR_TOKEN_URL:https://aip.baidubce.com/oauth/2.0/token}
meter-url: ${BAIDU_OCR_METER_URL:https://aip.baidubce.com/rest/2.0/ocr/v1/meter}
connect-timeout: ${BAIDU_OCR_CONNECT_TIMEOUT:10s}
request-timeout: ${BAIDU_OCR_REQUEST_TIMEOUT:60s}
input-root: ${WEIGHT_OCR_INPUT_ROOT:${java.io.tmpdir}/baiyue-weight-ocr/input}
output-root: ${WEIGHT_OCR_OUTPUT_ROOT:${java.io.tmpdir}/baiyue-weight-ocr/output}
max-image-size: ${WEIGHT_OCR_MAX_IMAGE_SIZE:3MB}
max-image-pixels: ${WEIGHT_OCR_MAX_IMAGE_PIXELS:40000000}
max-batch-size: ${WEIGHT_OCR_MAX_BATCH_SIZE:50}
min-request-interval: ${BAIDU_OCR_MIN_REQUEST_INTERVAL:600ms}
max-qps-retries: ${BAIDU_OCR_MAX_QPS_RETRIES:3}
amazon-sp-api: amazon-sp-api:
enabled: ${AMAZON_SP_API_ENABLED:false} enabled: ${AMAZON_SP_API_ENABLED:false}
client-id: ${AMAZON_SP_API_CLIENT_ID:} client-id: ${AMAZON_SP_API_CLIENT_ID:}
@@ -2,19 +2,33 @@ package com.baiyue.integration.config;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.net.URI;
import java.nio.file.Path;
import java.time.Duration;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
class IntegrationPropertiesTest { class IntegrationPropertiesTest {
@Test @Test
void providerIsConfiguredOnlyWhenEnabledAndAllSecretsExist() { void providerIsConfiguredOnlyWhenEnabledAndAllSecretsExist() {
var baidu = new IntegrationProperties.BaiduOcr(true, "key", "secret"); var baidu = baidu(true, "key", "secret");
var amazon = new IntegrationProperties.AmazonSpApi( var amazon = new IntegrationProperties.AmazonSpApi(
true, "client", "secret", "refresh", "access", "aws-secret", "us-east-1"); true, "client", "secret", "refresh", "access", "aws-secret", "us-east-1");
assertThat(baidu.configured()).isTrue(); assertThat(baidu.configured()).isTrue();
assertThat(amazon.configured()).isTrue(); assertThat(amazon.configured()).isTrue();
assertThat(new IntegrationProperties.BaiduOcr(false, "key", "secret").configured()).isFalse(); assertThat(baidu(false, "key", "secret").configured()).isFalse();
assertThat(new IntegrationProperties.AmazonSpApi( assertThat(new IntegrationProperties.AmazonSpApi(
true, "client", "secret", "", "access", "aws-secret", "us-east-1").configured()).isFalse(); true, "client", "secret", "", "access", "aws-secret", "us-east-1").configured()).isFalse();
} }
private IntegrationProperties.BaiduOcr baidu(boolean enabled, String apiKey, String secretKey) {
return new IntegrationProperties.BaiduOcr(
enabled, apiKey, secretKey,
URI.create("https://example.com/token"), URI.create("https://example.com/meter"),
Duration.ofSeconds(10), Duration.ofSeconds(60),
Path.of("input"), Path.of("output"), null,
40_000_000L, 50, Duration.ofMillis(600), 3
);
}
} }
@@ -0,0 +1,6 @@
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: ${ORDER_DB_URL:jdbc:mysql://127.0.0.1:3306/baiyue_order?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true}
username: ${ORDER_DB_USERNAME:root}
password: ${ORDER_DB_PASSWORD:123456}
@@ -0,0 +1,6 @@
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: ${ORDER_TEST_DB_URL:jdbc:mysql://${TEST_DB_HOST:8.163.30.128}:${TEST_DB_PORT:3306}/baiyue_order?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true&rewriteBatchedStatements=true}
username: ${ORDER_TEST_DB_USERNAME:${TEST_DB_USERNAME:root}}
password: ${ORDER_TEST_DB_PASSWORD:${TEST_DB_PASSWORD}}
@@ -0,0 +1,6 @@
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: ${PRINT_DB_URL:jdbc:mysql://127.0.0.1:3306/baiyue_print?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true}
username: ${PRINT_DB_USERNAME:root}
password: ${PRINT_DB_PASSWORD:123456}
@@ -0,0 +1,6 @@
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: ${PRINT_TEST_DB_URL:jdbc:mysql://${TEST_DB_HOST:8.163.30.128}:${TEST_DB_PORT:3306}/baiyue_print?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true&rewriteBatchedStatements=true}
username: ${PRINT_TEST_DB_USERNAME:${TEST_DB_USERNAME:root}}
password: ${PRINT_TEST_DB_PASSWORD:${TEST_DB_PASSWORD}}
@@ -0,0 +1,6 @@
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: ${WAREHOUSE_DB_URL:jdbc:mysql://127.0.0.1:3306/baiyue_warehouse?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true}
username: ${WAREHOUSE_DB_USERNAME:root}
password: ${WAREHOUSE_DB_PASSWORD:123456}
@@ -0,0 +1,6 @@
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: ${WAREHOUSE_TEST_DB_URL:jdbc:mysql://${TEST_DB_HOST:8.163.30.128}:${TEST_DB_PORT:3306}/baiyue_warehouse?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true&rewriteBatchedStatements=true}
username: ${WAREHOUSE_TEST_DB_USERNAME:${TEST_DB_USERNAME:root}}
password: ${WAREHOUSE_TEST_DB_PASSWORD:${TEST_DB_PASSWORD}}