配置体系
配置体系
业务用途
本篇梳理后端的全部配置来源:三个 profile 文件(application.yml 主配置、application-h2.yml 开发库、application-mysql.yml 生产库)、本地缓存 CacheConfig、Jackson 序列化 JacksonConfig,以及启动时自动播种基础数据的 DataInitializer。理解这些配置后,你就能在开发(H2 免安装)与生产(MySQL)之间自如切换,并清楚默认租户/管理员/菜单从何而来。
涉及文件
| 文件 | 作用 |
|---|---|
backend/src/main/resources/application.yml | 主配置,默认激活 mysql profile |
backend/src/main/resources/application-h2.yml | H2 内存库 profile(开发体验) |
backend/src/main/resources/application-mysql.yml | MySQL profile(生产/类生产) |
backend/src/main/java/com/lowcode/config/CacheConfig.java | 本地缓存(ConcurrentHashMap + TTL) |
backend/src/main/java/com/lowcode/config/JacksonConfig.java | Jackson 日期格式化 |
backend/src/main/java/com/lowcode/config/DataInitializer.java | 启动种数据(CommandLineRunner) |
后端实现
application.yml(主配置)
# backend/src/main/resources/application.yml
spring:
profiles:
active: mysql # 默认 mysql profile
data:
redis: # Redis(限流/防抖/缓存可选依赖)
host: ${REDIS_HOST:124.71.29.50}
port: ${REDIS_PORT:6379}
password: ${REDIS_PASSWORD:MFrG]q7m@6n2}
database: ${REDIS_DATABASE:0}
timeout: ${REDIS_TIMEOUT:3s}
lettuce:
pool: { max-active: 16, max-idle: 8, min-idle: 0, max-wait: 3s }
servlet:
multipart:
max-file-size: 20MB # 单文件上限
max-request-size: 50MB # 单请求上限
server:
address: 0.0.0.0
port: 52856 # 后端端口
servlet:
context-path: /
tomcat:
uri-encoding: UTF-8
logs:
slow-query-log-enabled: true
slow-query-threshold-ms: 1000 # Tomcat 层慢查询阈值
mybatis-plus:
mapper-locations: classpath*:/mapper/**/*.xml
type-aliases-package: com.lowcode.entity
configuration:
map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 打印 SQL
global-config:
db-config:
id-type: auto
logic-delete-field: deleted
logic-delete-value: 1
logic-not-delete-value: 0
jwt:
secret: lowcode-platform-secret-key-2024-abcdefghijklmnopqrstuvwxyz
expiration: 86400000 # 24 小时(毫秒)
header: Authorization
generator: # 代码生成默认值
author: lowcode
package-name: com.lowcode
module-name: system
table-prefix: sys_
logging:
level:
com.lowcode: debug
api: # 接口防抖
debounce:
enabled: ${API_DEBOUNCE_ENABLED:true}
ttl-ms: ${API_DEBOUNCE_TTL_MS:1000} # 默认 1000ms
key-prefix: ${API_DEBOUNCE_KEY_PREFIX:lowcode:api:debounce}
fail-open: ${API_DEBOUNCE_FAIL_OPEN:true}
file:
upload:
path: ./uploads/
url-prefix: /uploads/要点:
- 默认 profile 是
mysql,所以直接mvn spring-boot:run会连 MySQL。开发免安装体验用mvn spring-boot:run -Dspring-boot.run.profiles=h2。 - 端口 52856,监听所有网卡(
0.0.0.0)。 - Redis 配置全部支持环境变量覆盖(
REDIS_HOST等),Lettuce 连接池。 - 文件上传:单文件 20MB、整请求 50MB(H2 profile 下单文件改为 10MB)。
- JWT:密钥硬编码在 yml(生产应改为环境变量注入),过期 24 小时。
- 防抖:默认 1000ms,环境变量
API_DEBOUNCE_TTL_MS可调。
application-h2.yml(H2 开发库)
# backend/src/main/resources/application-h2.yml
spring:
application:
name: lowcode-platform
sql:
init:
schema-locations: classpath:schema-h2.sql # 启动自动建表
data-locations: classpath:data-h2.sql # 启动自动导数据
mode: always # 每次启动都执行
datasource:
driver-class-name: org.h2.Driver
url: jdbc:h2:mem:lowcode;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE;MODE=MySQL
username: sa
password: # H2 空密码
h2:
console:
enabled: true
path: /h2-console # 访问 /h2-console 可查内存库
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
freemarker:
enabled: true # 工程导出用 FreeMarker 模板
template-loader-path: classpath:/templates/
suffix: .ftl
servlet:
multipart:
max-file-size: 10MB # H2 下单文件 10MB
max-request-size: 50MB
tenant: # 多租户开启(注:此配置当前未被 TenantInterceptor 读取,见下)
enabled: true
ignore-tables:
- sys_tenant
- sys_user
- sys_role
- sys_menu
- sys_user_role
- sys_role_menu- 内存库
jdbc:h2:mem:lowcode,MODE=MySQL兼容 MySQL 语法,重启数据丢失。 - 自动建表+导数据:
mode: always每次启动跑schema-h2.sql+data-h2.sql(schema-h2.sql是最完整的建表脚本)。 - H2 控制台:
http://localhost:52856/h2-console,JDBC URL 填jdbc:h2:mem:lowcode,用户sa无密码。 - Jackson 日期:
yyyy-MM-dd HH:mm:ss,时区GMT+8(与JacksonConfig一致)。 - FreeMarker:工程导出模板(
templates/export/)用 FreeMarker 渲染。
tenant.ignore-tables 当前未生效
application-h2.yml 里的 tenant.ignore-tables 列表并未被 TenantInterceptor 读取(拦截器白名单是硬编码常量,见 )。此段配置目前只是「文档性」存在。如需配置化,需改造拦截器用 @ConfigurationProperties 绑定。
application-mysql.yml(MySQL 生产库)
# backend/src/main/resources/application-mysql.yml
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/lowcode?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
username: root
password: Admin123.
hikari: # HikariCP 连接池
minimum-idle: 5
maximum-pool-size: 20
connection-timeout: 30000
idle-timeout: 600000
max-lifetime: 1800000
connection-test-query: SELECT 1
pool-name: LowcodeHikariPool
sql:
init:
mode: never # 不自动建表,需手动导入
schema-locations: classpath*:sql/mysql/*.sql
slow-query:
enabled: true
threshold-ms: 1000 # 自定义慢查询阈值(非 Spring 标准属性)
server:
port: 52856- 默认连
localhost:3306/lowcode,账号root/ 密码Admin123.(按实际环境改)。 - 不自动建表(
mode: never),生产初始化用docs/SQL_INIT.sql+SQL_EXTENSION.sql等组合,详见 。 - HikariCP 连接池:最小空闲 5、最大 20、连接超时 30s、空闲超时 10min、最大生命周期 30min。
Profile 对照
| Profile | 数据源 | 自动建表/导数据 | 用途 |
|---|---|---|---|
mysql(默认) | MySQL localhost:3306/lowcode | 否(mode: never) | 生产 / 类生产 |
h2 | H2 内存库 jdbc:h2:mem:lowcode | 是(mode: always,跑 schema-h2.sql + data-h2.sql) | 快速体验、调试 |
切换:mvn spring-boot:run -Dspring-boot.run.profiles=h2。
CacheConfig:本地缓存
是 ConcurrentHashMap,不是 Caffeine/Redis
CacheConfig 实际使用 ConcurrentHashMap 实现的本地 TTL 缓存,不是 Caffeine 也非 Redis(类注释写「可替换为Redis」)。
// backend/src/main/java/com/lowcode/config/CacheConfig.java
@Configuration
public class CacheConfig {
public static final Cache<String, Object> DICT_CACHE = new Cache<>(3600); // 字典 1 小时
public static final Cache<String, Object> TABLE_META_CACHE = new Cache<>(600); // 表元数据 10 分钟
public static final Cache<String, Object> USER_PERMISSION_CACHE = new Cache<>(1800); // 用户权限 30 分钟
public static final Cache<String, Object> TENANT_CONFIG_CACHE = new Cache<>(600); // 租户配置 10 分钟
public static class Cache<K, V> {
private final ConcurrentHashMap<K, CacheEntry<V>> map = new ConcurrentHashMap<>();
private final long ttlSeconds;
// get / put / evict / clear / getOrCompute(带 TTL 过期判断)
}
// 静态便捷方法:getDictData/putDictData/evictDictData、getTableMeta/...、getUserPermission/...
}| 缓存实例 | TTL | 用途 |
|---|---|---|
DICT_CACHE | 3600s(1h) | 字典数据 |
TABLE_META_CACHE | 600s(10min) | 表元数据 |
USER_PERMISSION_CACHE | 1800s(30min) | 用户权限 |
TENANT_CONFIG_CACHE | 600s(10min) | 租户配置 |
- 单机内存缓存,多实例部署时各实例独立、可能不一致;如需分布式缓存可替换为 Redis 实现。
getOrCompute(key, supplier)封装了「先查缓存、未命中则加载并回填」模式。
JacksonConfig:日期序列化
// backend/src/main/java/com/lowcode/config/JacksonConfig.java
@Configuration
public class JacksonConfig {
private static final DateTimeFormatter DATE_TIME_FORMATTER =
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
@Bean
public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
return builder -> {
JavaTimeModule module = new JavaTimeModule();
module.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DATE_TIME_FORMATTER));
module.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DATE_TIME_FORMATTER));
builder.modules(module);
};
}
}- 统一
LocalDateTime序列化/反序列化格式为yyyy-MM-dd HH:mm:ss。 - 时区由
application-h2.yml的spring.jackson.time-zone: GMT+8设定(东八区)。
启动种数据 DataInitializer
DataInitializer 实现 CommandLineRunner,启动后按顺序执行一系列「建表/补列/播种」操作:
// backend/src/main/java/com/lowcode/config/DataInitializer.java
@Component
public class DataInitializer implements CommandLineRunner {
@Override
public void run(String... args) {
ensureTenantColumns(); // 给全库缺失 tenant_id 的表补列
ensureUserTenantUniqueIndex(); // sys_user 改为租户内用户名唯一(uk_tenant_username)
ensureDictTenantUniqueIndex(); // 字典表租户化索引
fixBpmTableColumns(); // BPM 表补字段
fixLowCodeTableColumns(); // 低代码核心表补字段(含 sys_tenant 配额字段)
initPermissionTables(); // 建 sys_role_data/field/button_permission
initNotificationTables(); // 建 sys_notification
initSsoTables(); // 建 sys_sso_provider / sys_sso_user_binding
initAiModelConfigTables(); // 建 sys_ai_model_config
initAuditAndConfigTables(); // 建 sys_config / sys_audit_log / sys_tenant_menu
initOpenTableApiConfigTable(); // 建 lc_open_table_api_config
initUserAppTable(); // 建 sys_user_app
initAuditDefaultConfigs(); // 写入 audit.* 默认配置
initTenant(); // 默认租户(id=1, 默认租户/default)
initRoles(); // 角色 admin / user
initAdminUser(); // 管理员 admin / admin123
ensureApprovalUsersAndRoles(); // 15 个审批角色 + 20 个审批用户 + 6 个用户组
initMenus(); // 完整菜单树
ensureSsoMenu(); // 补 SSO 菜单
ensureSystemSettingsMenus(); // 补系统设置菜单
ensureSystemButtonMenus(); // 补按钮权限菜单
ensureAdminSystemPermissions(); // 给 admin 角色补系统权限
initDepts(); // 默认部门
initPosts(); // 默认岗位
initDictData(); // 默认字典(sys_user_sex 等)
initBpmCategories(); // BPM 分类
ensureTenantBaseData(); // 为每个启用租户补菜单范围/角色/管理员
System.out.println("=== 数据初始化完成 ===");
}
}默认播种的关键数据:
| 类别 | 内容 |
|---|---|
| 租户 | id=1,名称「默认租户」,编码 default,状态启用 |
| 管理员 | 用户名 admin,密码 admin123(BCrypt),租户 1,角色 admin;可用系统属性 -Dapp.admin.password=xxx 覆盖密码 |
| 角色 | admin(超级管理员)、user(普通用户) |
| 审批用户 | 20 个示例用户(如 zhangsan/lisi/...),密码统一 123456,分属 15 个审批角色(部门经理、HR 经理、采购经理、总经理 等) |
| BPM 用户组 | 6 个审批组(常规/人事/财务/采购/合同/库存审批组) |
| 菜单 | 完整菜单树(系统管理、应用管理、数据管理、页面设计、流程中心、代码生成、AI 助手、行业模板、ERP 示例、人事管理 等) |
| 部门 | 总公司 / 技术部 / 产品部 / 运营部 / 人事部 / 财务部 |
| 岗位 | 总经理 / 技术总监 / 人力资源 / 普通员工 / 实习生 |
| 字典 | sys_user_sex、sys_common_status、sys_yes_no |
| 审计配置 | audit.login.enabled=true、audit.logout.enabled=true、audit.operation.enabled=false(默认关)、各分项开关、脱敏开关 |
新建租户的默认管理员密码
DataInitializer.initTenantAdmin 为新租户创建的 admin 账号密码是 123456(与默认租户的 admin123 不同)。新租户的菜单范围按 plan_type(free/pro/enterprise)分配。
DataInitializer 会改库结构?
是的。它会在启动时用 JdbcTemplate 执行大量 ALTER TABLE ADD COLUMN、CREATE TABLE IF NOT EXISTS、CREATE/ DROP INDEX,用于把旧库结构升级到当前版本(如给 sys_tenant 补配额字段、给全库表补 tenant_id、调整唯一索引为租户内唯一)。这些操作都是幂等的(先查 information_schema 再执行),可安全重复执行。
操作步骤
- 开发联调:用 H2 profile 启动(
-Dspring-boot.run.profiles=h2),开箱即用,无需装 MySQL。 - 生产部署:用默认 mysql profile;先建库
lowcode并导入SQL_INIT.sql等脚本;改application-mysql.yml里的数据源账号密码;启动后DataInitializer会自动补结构 + 种基础数据。 - 改 Redis:用环境变量
REDIS_HOST/REDIS_PORT/REDIS_PASSWORD覆盖,或直接改application.yml。 - 改 JWT 密钥/有效期:改
jwt.secret/jwt.expiration(生产建议环境变量注入,勿用默认密钥)。 - 调防抖窗口:环境变量
API_DEBOUNCE_TTL_MS,或临时关API_DEBOUNCE_ENABLED=false。 - 查 H2 控制台:H2 profile 下访问
http://localhost:52856/h2-console,JDBC URLjdbc:h2:mem:lowcode,用户sa。
常见问题
默认 mysql profile 启动失败?
默认连 localhost:3306/lowcode,需先建库并保证账号密码正确(默认 root / Admin123.)。若本地无 MySQL,改用 h2 profile 体验。
缓存数据不更新?
CacheConfig 是带 TTL 的本地缓存,字典/表元数据/权限改动后最长需等 TTL 到期才刷新,或手动调用 evictDictData/evictTableMeta/evictUserPermission 失效。多实例部署时各实例缓存独立,可能短期不一致。
审计/操作日志默认不记录?
DataInitializer 把 audit.operation.enabled 默认设为 false。需到 sys_config 改为 true(并按需开分项开关),AuditLogAspect 才记录操作日志(详见 )。登录/登出日志默认开。
想改默认管理员密码?
默认租户 admin 密码 admin123,可用启动参数 -Dapp.admin.password=新密码 覆盖(initAdminUser 读取该系统属性)。已有 admin 记录则不会改密,需在库里更新或走「忘记密码」流程。新租户 admin 密码固定 123456。
DataInitializer 每次启动都跑,会影响性能吗?
它做了大量 IF NOT EXISTS / COUNT 判定后才执行变更,正常情况下(结构已是最新)仅做检查不写数据,开销可控。种子数据也都是「存在则跳过」。首次启动或升级版本时会执行较多 DDL。
