Yin 单体多模块改造记录
原创2026/7/24大约 3 分钟
Yin 单体多模块改造记录
改造目标
将原来的单模块 Spring Boot 项目调整为单体多模块结构,保持一个应用进程启动,同时把公共能力、系统业务、启动 API 层和代码生成器拆开,降低后续业务扩展时的耦合。
模块结构
yin
├── pom.xml # 父工程,统一版本和插件管理
├── yin-common # 公共基础能力
├── yin-system # system 业务模块
├── yin-admin # Spring Boot 启动模块和 Web/API 层
└── yin-generator # 代码生成器和模板模块依赖方向:
yin-admin -> yin-system -> yin-common
yin-generator 独立迁移内容
- 根
pom.xml改为packaging=pom,声明yin-common、yin-system、yin-admin、yin-generator四个子模块,并集中管理 MapStruct、MyBatis Plus、JWT、Apache POI、SpringDoc、Velocity 等版本。 yin-common保留公共树工具、时间工具、统一响应对象、基础实体和基础分页/转换器。yin-system承载系统业务的实体、DTO、Query、Mapper、Service、MapStruct Converter,并把 MyBatis XML 统一迁移到src/main/resources/mapper/system。yin-admin承载启动类、Controller、安全认证、全局异常/响应处理、MyBatis Plus 配置、Swagger 配置、Excel 帮助类、应用配置和测试。yin-generator承载CodeGenerator和 Velocity 模板,避免生成器依赖进入主应用启动模块。
业务和代码优化
- 启动类删除固定密码 BCrypt 生成和
System.out输出,只保留应用启动逻辑。 @MapperScan从扫描整个com.yinyang.yin收窄到com.yinyang.yin.mapper。- 数据库地址、账号、密码和 JWT 配置改为环境变量读取,默认使用本地开发配置:
YIN_DATASOURCE_URLYIN_DATASOURCE_USERNAMEYIN_DATASOURCE_PASSWORDYIN_JWT_SECRETYIN_JWT_EXPIRATION
mybatis-plus.mapper-locations显式配置为classpath*:mapper/**/*.xml,保证模块内 XML Mapper 能被加载。UserService改为注入PasswordEncoder,修复导入用户时调用encode但未写回哈希值的问题。- 用户更新时如果未传新密码,会保留数据库中已有密码哈希,避免空密码覆盖。
- 全局异常处理改为日志记录,不再
printStackTrace,并统一返回Result。 - 登录失败不再向前端透出异常细节,统一返回
Invalid username or password。 - 代码生成器去掉硬编码远程数据库连接和密码,改用环境变量:
YIN_GENERATOR_DATASOURCE_URLYIN_GENERATOR_DATASOURCE_USERNAMEYIN_GENERATOR_DATASOURCE_PASSWORDYIN_GENERATOR_OUTPUT_DIR
- 业务模块中的
io.jsonwebtoken.lang.Assert改为org.springframework.util.Assert,避免非安全业务代码依赖 JWT 包。 - 补充
spring-boot-starter-validation,让 Controller 上的@Validated有实际校验提供者。 - 登录请求补充
username和password非空校验,用户不存在时使用 Spring Security 的UsernameNotFoundException。
构建和验证
已执行:
./mvnw.cmd -q test
./mvnw.cmd -q package结果:测试和完整打包均通过。
运行方式
主应用入口在 yin-admin 模块:
./mvnw.cmd -pl yin-admin -am spring-boot:run使用非本地数据库时,先设置环境变量,例如:
set YIN_DATASOURCE_URL=jdbc:mysql://host:3306/db?allowPublicKeyRetrieval=true^&useSSL=false^&serverTimezone=Asia/Shanghai^&characterEncoding=utf8
set YIN_DATASOURCE_USERNAME=root
set YIN_DATASOURCE_PASSWORD=your_password
set YIN_JWT_SECRET=replace-with-at-least-32-bytes-secret