# ⚙️ 配置指南

> 版本: 1.0
> 更新时间: 2026-03-04

## 📋 目录

1. [配置文件结构](#配置文件结构)
2. [环境配置](#环境配置)
3. [数据库配置](#数据库配置)
4. [Redis配置](#redis配置)
5. [安全配置](#安全配置)
6. [性能配置](#性能配置)
7. [日志配置](#日志配置)
8. [环境变量](#环境变量)

## 📁 配置文件结构

```
src/main/resources/
├── application.properties          # 主配置文件
├── application-dev.yml            # 开发环境配置
├── application-test.yml           # 测试环境配置
├── application-prod.yml           # 生产环境配置
├── application-e2e.properties     # E2E测试配置
└── logback-spring.xml             # 日志配置
```

### 配置优先级

1. 命令行参数 (`--spring.datasource.url=...`)
2. 环境变量 (`SPRING_DATASOURCE_URL`)
3. 外部配置文件 (`/opt/mosquito/application-prod.yml`)
4. 内部配置文件 (`classpath:application-prod.yml`)
5. 默认配置 (`application.properties`)

## 🌍 环境配置

### 开发环境 (dev)

`application-dev.yml`:

```yaml
spring:
  datasource:
    url: jdbc:postgresql://localhost:5432/mosquito_dev
    username: mosquito
    password: dev_password
    hikari:
      maximum-pool-size: 10
      minimum-idle: 2

  data:
    redis:
      host: localhost
      port: 6379
      password: dev_redis_password

  flyway:
    enabled: true
    baseline-on-migrate: true

  jpa:
    show-sql: true
    properties:
      hibernate:
        format_sql: true

app:
  api-key:
    encryption-key: dev_32_char_encryption_key_12
  rate-limit:
    per-minute: 1000
  poster:
    cache-enabled: false

logging:
  level:
    root: INFO
    com.mosquito.project: DEBUG
    org.springframework.web: DEBUG
```

### 测试环境 (test)

`application-test.yml`:

```yaml
spring:
  datasource:
    url: jdbc:h2:mem:testdb
    driver-class-name: org.h2.Driver
    username: sa
    password:

  data:
    redis:
      host: localhost
      port: 6379

  flyway:
    enabled: true

  jpa:
    hibernate:
      ddl-auto: validate

app:
  api-key:
    encryption-key: test_32_char_encryption_key_12
  rate-limit:
    per-minute: 10000
  poster:
    cache-enabled: false

logging:
  level:
    root: WARN
    com.mosquito.project: INFO
```

### 生产环境 (prod)

`application-prod.yml`:

```yaml
spring:
  datasource:
    url: ${DB_URL:jdbc:postgresql://localhost:5432/mosquito_prod}
    username: ${DB_USERNAME:mosquito_prod}
    password: ${DB_PASSWORD}
    hikari:
      maximum-pool-size: 20
      minimum-idle: 5
      connection-timeout: 30000
      idle-timeout: 600000
      max-lifetime: 1800000
      leak-detection-threshold: 60000

  data:
    redis:
      host: ${REDIS_HOST:localhost}
      port: ${REDIS_PORT:6379}
      password: ${REDIS_PASSWORD}
      timeout: 3000ms
      lettuce:
        pool:
          max-active: 20
          max-idle: 10
          min-idle: 5
          max-wait: 3000ms

  flyway:
    enabled: true
    baseline-on-migrate: true
    validate-on-migrate: true

  jpa:
    show-sql: false
    properties:
      hibernate:
        jdbc:
          batch_size: 20
        order_inserts: true
        order_updates: true

app:
  api-key:
    encryption-key: ${API_KEY_ENCRYPTION_KEY}
  rate-limit:
    per-minute: ${RATE_LIMIT_PER_MINUTE:100}
  poster:
    cache-enabled: true
    cache-ttl: 3600

logging:
  level:
    root: INFO
    com.mosquito.project: INFO
  file:
    name: /var/log/mosquito/application.log
    max-size: 100MB
    max-history: 30

management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics,prometheus
  endpoint:
    health:
      show-details: when-authorized
```

## 🗄️ 数据库配置

### PostgreSQL连接池

```yaml
spring:
  datasource:
    hikari:
      # 最大连接数（推荐：CPU核心数 * 2 + 磁盘数）
      maximum-pool-size: 20

      # 最小空闲连接数
      minimum-idle: 5

      # 连接超时（毫秒）
      connection-timeout: 30000

      # 空闲超时（毫秒）
      idle-timeout: 600000

      # 连接最大生命周期（毫秒）
      max-lifetime: 1800000

      # 连接泄漏检测阈值（毫秒）
      leak-detection-threshold: 60000

      # 连接测试查询
      connection-test-query: SELECT 1
```

### Flyway迁移配置

```yaml
spring:
  flyway:
    # 启用Flyway
    enabled: true

    # 迁移脚本位置
    locations: classpath:db/migration

    # 基线版本
    baseline-version: 1

    # 在迁移时创建基线
    baseline-on-migrate: true

    # 验证迁移
    validate-on-migrate: true

    # 清理数据库（生产环境禁用）
    clean-disabled: true

    # 占位符
    placeholders:
      schema: public
```

### JPA/Hibernate配置

```yaml
spring:
  jpa:
    # 显示SQL（仅开发环境）
    show-sql: false

    # DDL策略（生产环境使用validate）
    hibernate:
      ddl-auto: validate

    properties:
      hibernate:
        # SQL格式化
        format_sql: true

        # 批量操作
        jdbc:
          batch_size: 20
        order_inserts: true
        order_updates: true

        # 二级缓存
        cache:
          use_second_level_cache: true
          region:
            factory_class: org.hibernate.cache.jcache.JCacheRegionFactory

        # 查询缓存
        cache:
          use_query_cache: true
```

## 🔴 Redis配置

### 基础配置

```yaml
spring:
  data:
    redis:
      # Redis服务器地址
      host: ${REDIS_HOST:localhost}

      # Redis端口
      port: ${REDIS_PORT:6379}

      # Redis密码
      password: ${REDIS_PASSWORD}

      # 数据库索引
      database: 0

      # 连接超时
      timeout: 3000ms

      # Lettuce连接池
      lettuce:
        pool:
          max-active: 20
          max-idle: 10
          min-idle: 5
          max-wait: 3000ms

        # 关闭超时
        shutdown-timeout: 100ms
```

### 缓存配置

```yaml
spring:
  cache:
    type: redis
    redis:
      # 缓存TTL（毫秒）
      time-to-live: 3600000

      # 缓存null值
      cache-null-values: false

      # 键前缀
      key-prefix: "mosquito:"

      # 使用键前缀
      use-key-prefix: true

app:
  cache:
    # 活动缓存TTL（秒）
    activity-ttl: 3600

    # 统计缓存TTL（秒）
    stats-ttl: 300

    # 排行榜缓存TTL（秒）
    leaderboard-ttl: 60
```

### Redis Sentinel配置（高可用）

```yaml
spring:
  data:
    redis:
      sentinel:
        master: mymaster
        nodes:
          - 192.168.1.10:26379
          - 192.168.1.11:26379
          - 192.168.1.12:26379
      password: ${REDIS_PASSWORD}
```

### Redis Cluster配置（集群）

```yaml
spring:
  data:
    redis:
      cluster:
        nodes:
          - 192.168.1.10:6379
          - 192.168.1.11:6379
          - 192.168.1.12:6379
          - 192.168.1.13:6379
          - 192.168.1.14:6379
          - 192.168.1.15:6379
        max-redirects: 3
      password: ${REDIS_PASSWORD}
```

## 🔐 安全配置

### 回调API白名单配置

系统对回调API请求进行IP白名单验证，确保只有受信任的服务器才能调用回调接口。

#### 回调白名单配置项

```yaml
app:
  callback:
    # IP白名单列表，用逗号分隔
    # 生产环境必须配置，否则启动会失败（fail-fast）
    whitelist:
      ips: "203.0.113.1,198.51.100.1,10.0.0.0/8"

    # 宽松模式（仅用于开发/测试环境）
    # 设为true时跳过IP白名单验证
    whitelist:
      permissive: false
```

#### 环境变量配置

```bash
# 方式1：直接配置IP白名单（推荐生产环境使用）
export MOSQUITO_CALLBACK_WHITELIST_IPS="203.0.113.1,198.51.100.1"

# 方式2：启用宽松模式（仅用于开发/测试）
export MOSQUITO_CALLBACK_WHITELIST_PERMISSIVE="true"

# Spring配置方式
export MOSQUITO_CALLBACK_WHITELIST_IPS="203.0.113.1,198.51.100.1"
```

#### 生产环境配置示例

```yaml
# application-prod.yml
app:
  callback:
    whitelist:
      ips: "${MOSQUITO_CALLBACK_WHITELIST_IPS}"
      permissive: false
```

生产环境启动前检查清单：

1. **确认已配置IP白名单**
   ```bash
   # 检查环境变量
   echo $MOSQUITO_CALLBACK_WHITELIST_IPS

   # 如果未配置，启动会失败并报错：
   # "生产环境回调白名单配置缺失！请配置 mosquito.callback.whitelist.ips 或启用 permissive 模式。"
   ```

2. **配置CIDR格式IP段**
   ```bash
   # 支持CIDR格式（但需注意：系统使用简单字符串分割，不支持严格的CIDR解析）
   # 推荐列出所有具体IP或使用云服务商的弹性IP
   export MOSQUITO_CALLBACK_WHITELIST_IPS="203.0.113.1,198.51.100.10,198.51.100.20"
   ```

3. **常见云服务商IP段**
   ```bash
   # 阿里云ECS（需要根据实际配置）
   export MOSQUITO_CALLBACK_WHITELIST_IPS="10.0.0.0/8,172.16.0.0/12"

   # AWS EC2
   export MOSQUITO_CALLBACK_WHITELIST_IPS="3.0.0.0/8,18.0.0.0/8"
   ```

#### 开发/测试环境配置

```yaml
# application-dev.yml
app:
  callback:
    whitelist:
      permissive: true  # 跳过白名单验证
```

或通过环境变量：

```bash
# 开发环境
export MOSQUITO_CALLBACK_WHITELIST_PERMISSIVE="true"

# 测试环境（使用测试配置）
export SPRING_PROFILES_ACTIVE=test
```

#### 故障排查

| 错误信息 | 原因 | 解决方案 |
|---------|------|---------|
| "生产环境回调白名单配置缺失" | 未配置`mosquito.callback.whitelist.ips` | 配置IP白名单或启用permissive模式 |
| "来源IP不在白名单中" | 回调请求IP不在白名单中 | 将该IP添加到白名单 |
| "启动失败" | 生产环境未配置白名单 | 配置`MOSQUITO_CALLBACK_WHITELIST_IPS` |

#### 白名单验证逻辑

- 系统启动时如果`permissive=false`且`ips`为空，会抛出异常阻止启动（fail-fast）
- 每个回调请求都会验证来源IP是否在白名单中
- 不在白名单中的请求会被拒绝并返回`IP_NOT_WHITELISTED`错误

### API密钥加密

```yaml
app:
  api-key:
    # 加密密钥（必须32字符）
    encryption-key: ${API_KEY_ENCRYPTION_KEY}

    # PBKDF2迭代次数
    pbkdf2-iterations: 10000

    # 密钥长度
    key-length: 256
```

生成加密密钥：

```bash
# 生成32字符随机密钥
openssl rand -base64 24 | head -c 32
```

### 速率限制

```yaml
app:
  rate-limit:
    # 每分钟请求限制
    per-minute: ${RATE_LIMIT_PER_MINUTE:100}

    # 限流键前缀
    key-prefix: "rate_limit:"

    # 限流窗口（秒）
    window-seconds: 60
```

### CORS配置

```yaml
app:
  cors:
    # 允许的源
    allowed-origins:
      - https://example.com
      - https://www.example.com

    # 允许的方法
    allowed-methods:
      - GET
      - POST
      - PUT
      - DELETE
      - OPTIONS

    # 允许的头
    allowed-headers:
      - "*"

    # 暴露的头
    exposed-headers:
      - X-API-Version
      - X-RateLimit-Remaining

    # 允许凭证
    allow-credentials: true

    # 预检请求缓存时间（秒）
    max-age: 3600
```

## ⚡ 性能配置

### 线程池配置

```yaml
spring:
  task:
    execution:
      pool:
        # 核心线程数
        core-size: 8

        # 最大线程数
        max-size: 16

        # 队列容量
        queue-capacity: 100

        # 线程名前缀
        thread-name-prefix: "async-"

        # 空闲线程存活时间（秒）
        keep-alive: 60s
```

### HTTP客户端配置

```yaml
app:
  http-client:
    # 连接超时（毫秒）
    connect-timeout: 5000

    # 读取超时（毫秒）
    read-timeout: 10000

    # 最大连接数
    max-connections: 100

    # 每个路由的最大连接数
    max-connections-per-route: 20
```

### 海报生成配置

```yaml
app:
  poster:
    # 启用缓存
    cache-enabled: true

    # 缓存TTL（秒）
    cache-ttl: 3600

    # 图片质量（0.0-1.0）
    image-quality: 0.9

    # 图片格式
    image-format: PNG

    # 最大宽度
    max-width: 1080

    # 最大高度
    max-height: 1920
```

## 📝 日志配置

### Logback配置

`logback-spring.xml`:

```xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <!-- 开发环境 -->
    <springProfile name="dev">
        <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
            <encoder>
                <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
            </encoder>
        </appender>

        <root level="INFO">
            <appender-ref ref="CONSOLE" />
        </root>

        <logger name="com.mosquito.project" level="DEBUG" />
        <logger name="org.springframework.web" level="DEBUG" />
    </springProfile>

    <!-- 生产环境 -->
    <springProfile name="prod">
        <!-- 文件输出 -->
        <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <file>/var/log/mosquito/application.log</file>
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <fileNamePattern>/var/log/mosquito/application.%d{yyyy-MM-dd}.log</fileNamePattern>
                <maxHistory>30</maxHistory>
                <totalSizeCap>10GB</totalSizeCap>
            </rollingPolicy>
            <encoder>
                <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
            </encoder>
        </appender>

        <!-- 错误日志单独输出 -->
        <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <file>/var/log/mosquito/error.log</file>
            <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
                <level>ERROR</level>
            </filter>
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <fileNamePattern>/var/log/mosquito/error.%d{yyyy-MM-dd}.log</fileNamePattern>
                <maxHistory>90</maxHistory>
            </rollingPolicy>
            <encoder>
                <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
            </encoder>
        </appender>

        <root level="INFO">
            <appender-ref ref="FILE" />
            <appender-ref ref="ERROR_FILE" />
        </root>

        <logger name="com.mosquito.project" level="INFO" />
    </springProfile>
</configuration>
```

### 日志级别

```yaml
logging:
  level:
    # 根日志级别
    root: INFO

    # 应用日志
    com.mosquito.project: INFO

    # Spring框架
    org.springframework: INFO
    org.springframework.web: INFO
    org.springframework.security: INFO

    # Hibernate
    org.hibernate: INFO
    org.hibernate.SQL: DEBUG
    org.hibernate.type.descriptor.sql.BasicBinder: TRACE

    # Redis
    org.springframework.data.redis: INFO

    # Flyway
    org.flywaydb: INFO
```

## 🌐 环境变量

### 必需环境变量

```bash
# 数据库配置
export DB_URL="jdbc:postgresql://localhost:5432/mosquito_prod"
export DB_USERNAME="mosquito_prod"
export DB_PASSWORD="your_secure_password"

# Redis配置
export REDIS_HOST="localhost"
export REDIS_PORT="6379"
export REDIS_PASSWORD="your_redis_password"

# 安全配置
export API_KEY_ENCRYPTION_KEY="your_32_char_encryption_key_12"
```

### 可选环境变量

```bash
# 速率限制
export RATE_LIMIT_PER_MINUTE="100"

# 日志配置
export LOG_LEVEL="INFO"
export LOG_FILE="/var/log/mosquito/application.log"

# JVM配置
export JAVA_OPTS="-Xms2g -Xmx4g -XX:+UseG1GC"

# Spring配置
export SPRING_PROFILES_ACTIVE="prod"
export SERVER_PORT="8080"
```

### 环境变量文件

创建 `.env` 文件（不要提交到Git）：

```bash
# .env
DB_PASSWORD=your_secure_password
REDIS_PASSWORD=your_redis_password
API_KEY_ENCRYPTION_KEY=your_32_char_encryption_key_12
RATE_LIMIT_PER_MINUTE=100
```

加载环境变量：

```bash
# 使用source加载
source .env

# 或使用export
export $(cat .env | xargs)
```

## 🔧 配置验证

### 启动时验证

```java
@Configuration
public class ConfigValidation {

    @Value("${app.api-key.encryption-key}")
    private String encryptionKey;

    @PostConstruct
    public void validate() {
        if (encryptionKey.length() != 32) {
            throw new IllegalStateException(
                "API key encryption key must be exactly 32 characters"
            );
        }
    }
}
```

### 配置检查命令

```bash
# 检查配置文件语法
java -jar mosquito-1.0.0.jar --spring.config.location=application-prod.yml --spring.profiles.active=prod --debug

# 查看实际配置
java -jar mosquito-1.0.0.jar --spring.profiles.active=prod \
  --spring.boot.admin.client.enabled=false \
  org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
```

## 📚 相关资源

- [部署指南](./DEPLOYMENT_GUIDE.md) - 部署说明
- [API文档](./api.md) - API接口文档
- [开发指南](./DEVELOPMENT_GUIDE.md) - 开发环境搭建

---

**文档版本**: 1.0
**最后更新**: 2026-03-04
