stack-be-java — Java 微服务技术栈规范
以 10 年经验 Java 架构师的标准生成、重构、解释所有 Java 后端代码。所有规范的可执行载体是 assets/project-template/:一个可直接编译的脚手架工程,含一套 Project CRUD 参考实现。写代码前先想清楚对应模板中的哪一层、哪个类,与其保持一致。
一、技术栈基准
| 类别 | 选型 | 版本 | 关键约束 |
|---|---|---|---|
| 语言 | Java | JDK 17 | 编译参数 -parameters;禁用 JDK 8/11 |
| 构建 | Gradle | 8.10.x(wrapper) | 多模块:根工程 + <service>-service 可执行模块 |
| 框架 | Spring Boot | 3.3.5 | Jakarta 命名空间;排除 DataSource 自动装配 |
| 持久层 | Ebean | 13.18.0-jakarta | QueryBean + 字节码增强;实体不继承 io.ebean.Model |
| 数据库 | MySQL | 8.0 | 表名下划线;连接池 HikariCP |
| SQL 监控 | p6spy | 3.9.1 | 慢查询日志 |
| 接口文档 | knife4j | 4.5.0 | OpenAPI3 / Jakarta |
| 缓存 | Redis | Jedis(排除 Lettuce) | commons-pool2 连接池 |
| 网关票据 | Nimbus JOSE+JWT | 9.37.3 | 解密 x-tai-identity |
| 腾讯特色 | CRM starter / Rainbow 七彩石 / Polaris / adhome 脚本 | 见模板 | 统一响应、配置中心、服务发现、部署 |
版本集中于根 gradle.properties 管理。按需引入:GraalJS 脚本沙箱(24.1.2)。
统一响应(违反视为严重错误):
- 所有对外响应用 starter 的 ServiceResponse<T>;分页用 PageResultResponse<T>
- 业务异常用 ServiceException + 错误码枚举;参数校验用 VerifyUtil
- 严禁自造响应信封、自造分页结构、自造错误码体系
二、新建项目:使用模板脚手架
新建任何 Java 微服务时,必须从模板初始化,禁止从零手写工程文件:
- 复制
assets/project-template/到目标位置,根目录改名<service>-be-java - (SkillHub 版必做)还原构建文件:平台白名单不含
.gradle/.properties/.jar/无扩展名文件,按 references/template-build-files.md 将build.gradle/settings.gradle/gradle.properties/template-service/build.gradle/Dockerfile/clear_file.conf/.gitignore还原到对应路径,并在模板根目录执行gradle wrapper --gradle-version 8.10.2 --distribution-type bin生成 wrapper 四件套 - 全局批量替换(先长后短):
template-service→<service>-service;template→<service>(包名、配置、Dockerfile);Template→<Service>(类名TemplateErrorCode等,同步重命名文件) settings.gradle确认rootProject.name与include;template-service/build.gradle确认archivesBaseName、bootJar.mainClass- 替换
application.yml中appName/calleeName、七彩石appid(环境变量注入密钥,勿硬编码)、Dockerfile 的MAINTAINER - 保留
ProjectXxx一组文件作为分层参考实现,编写真实领域代码后删除 - 构建验证:
JAVA_HOME=<jdk17> ./gradlew build -x test;本地运行:./gradlew :<service>-service:bootRun
模板已含:adhome 部署脚本(dockerfile/bin)、tencent_checkstyle、Ebean 手动装配全套配置、鉴权三件套(AuthInterceptor/TaiIdentityDecoder/UserContext)、p6spy 慢查询、Rainbow/Polaris 接入、统一异常处理。
三、分层架构铁律(风格 A)
controller → service → manager(可选) → repository → database
- controller 只编排:参数接收、校验触发、调 service、包装响应;不写业务
- service 接口+实现分离(
service/impl/);返回实体或 PageVO,不返回 VO - manager 仅当多个 service 复用同一段跨领域逻辑时抽取(
@Component,命名XxxManager);YAGNI,非必须层 - repository 命名
XxxDao(@Repository),注入@Resource(name = "<service>Database") Database;查询默认过滤软删 - 严禁 controller 直调 repository;严禁下层反向依赖上层;严禁 manager 反向依赖 service
- 包根
com.<company>.<service>,顶层包固定为:controller/ service/ manager/ repository/ model/ convert/ config/ common/ aop/ utils/,不得新增
各层详细职责、注解清单与对象规范(Entity/DTO/VO/Query)见 references/layer-rules.md。
四、API 设计铁律
- URL 固定不含资源 id:动作语义路径,如
/projects/create、/projects/detail;严禁 RESTful/{pid}路径参数 - id 类参数一律放
@RequestBody;对外 id 一律String(IdCodec.encode/decode),内部Long - 响应包装:
ResponseHelper.ok(vo)/ResponseHelper.page(pageVO, EntityVO::from) - 类注解:
@Tag+@RestController+@RequestMapping("/资源复数")+@RequiredArgsConstructor;端点加@Operation(summary=...);写操作加@ResponseStatus(HttpStatus.CREATED) - 异常即状态:资源不存在
NotFoundException(404);唯一冲突ConflictException.of(field,msg)(409);参数非法ValidationException(422);严禁返回 null 或 200+错误码 - 写操作方法必须
@Transactional(rollbackFor = Exception.class) - 错误码枚举按模块分段(业务 20000 / 通用 30000 / 鉴权 40000),追加不 scattered
五、常见场景速查
| 需求 | 应该做 | 不应该做 |
|---|---|---|
| 返回数据 | ResponseHelper.ok(vo) |
裸返回实体 / 自造信封 |
| 分页列表 | ResponseHelper.page(...) |
手拼分页 JSON |
| 传 id 操作 | id 放 body,URL 用 /detail /update |
/{pid} 路径参数 |
| 查询数据库 | new QXxx(database)...findOne() + 软删过滤 |
手写 SQL 字符串 |
| 复杂查询条件 | 抽 private QXxx buildQuery(query) |
堆砌在查询方法里 |
| 实体映射 VO | XxxVO.from(entity) 静态工厂 |
controller 里逐字段 set |
| 转换逻辑复杂 | 抽 convert/XxxConvert |
散落各层 |
| 跨 service 通用逻辑 | 抽 manager/XxxManager |
复制到多个 service |
| JSON 列扩展 | @DbJson 加字段,向后兼容 |
频繁 DDL 加列 |
| 类型分发逻辑 | 策略模式 + Map 注入 | if/else 分支堆砌 |
| 切换环境 | -Denv=prod |
改 yml 提交 |
| 构建 | JAVA_HOME=<jdk17> ./gradlew build -x test |
用 JDK 8 构建 |
| 本地运行 | ./gradlew :<service>-service:bootRun |
直接跑 main |
| 可选 SDK | @ConditionalOnClass 条件装配 |
强依赖致启动失败 |
六、编码硬约束(阿里嵩山版)
- 命名:类 UpperCamelCase / 方法 lowerCamelCase / 常量全大写下划线 / 包名全小写单数;禁止拼音缩写;抽象类
Abstract/Base前缀,异常类Exception后缀 - 格式:K&R 行尾大括号;
if/else/for/while/do必加括号;4 空格缩进;魔法值抽命名常量 - 方法 ≤80 行(硬上限),if 嵌套 ≤3 层(guard clause 拆解);类内方法顺序 public > protected > private
- 每个 public 方法写 Javadoc;注释用中文;只对非直觉逻辑加行内注释
- 关键逻辑必须用
// 1. xxx编号步骤注释标明每一步(双斜线+空格+数字+半角句号+空格+≤30字动宾,步骤间不留空行) - 新增三方依赖前必须先向用户确认必要性与用途,获批后版本统一落
gradle.properties - 写新工具方法前先查
utils/、CommonUtils、commons-lang3/collections4 等已有实现,能复用不新造
设计原则(SOLID/DRY/YAGNI)、设计模式速查、依赖冲突处理见 references/coding-style.md。
七、提交前自检清单
生成或修改代码后逐条自检,违反立即修正:
- [ ] controller 无业务逻辑?service 未直接拼 SQL?repository 未反向依赖?
- [ ] 所有 URL 固定不含 id?id 在 body 且对外 String?
- [ ] 响应统一
ServiceResponse/PageResultResponse?未自造信封? - [ ] 方法 ≤80 行?if 嵌套 ≤3 层?魔法值已抽常量?关键逻辑已加
// 1. xxx编号步骤注释? - [ ] 无拼音缩写?命名符合规范?
- [ ] 写操作加
@Transactional(rollbackFor = Exception.class)? - [ ] 查询显式判空抛领域异常(NotFound/Conflict)而非返回 null?
- [ ] VO 用
@JsonInclude(NON_NULL)+from()工厂?时间格式化字符串? - [ ] 重复逻辑已抽取(DRY)?未引入用不上的抽象(YAGNI)?
- [ ] 新增依赖已获用户确认且版本落
gradle.properties?新工具方法已确认无现有可复用实现? - [ ] 实体带齐 tenantId/createdAt/updatedAt/createdBy/updatedBy/deletedAt?