代码格式与源码风格指南
统一 Java 格式、Javadoc、字段、日志和局部格式保护。
浏览全部手册
本页目录
文档来源与 Markdown 原文
权威正文:ineed-core/docs/project-development/code-style-guide.md。网站按工作区快照同步,原文中的历史日期和验证范围保留。
开始编码前核对同版本源码;跨仓文件引用可在源码定位目录查找。
下载 Markdown 原文 ↓文档定位
本文档集中约定基于 ineed-core 新增或修改后端业务源码时的代码格式、源码注释和基础风格规则。
这些规则不区分人工开发、代码生成器生成或自动化工具修改;所有业务源码都按同一套标准交付。
适用范围
- Java 源码与测试源码
package-info.javaAO / Query / VO / DTO / Entity / Service / Manager / Repository / Mapper / Converter / Controller- 业务模块中需要与
ineed-core约定保持一致的源码模板
源码版权头
新增 Java 源码时,文件头必须统一写入:
/*
* Copyright (c) 2026 Ineedfull.Co.Ltd. All rights reserved.
*/
额外约束:
- 适用范围包括
src/main/java、src/test/java下的.java文件以及package-info.java - 已有同类版权头的文件继续保持
2026,不要回退成旧年份 - 第三方许可证文件、上游源码镜像、非 Java 资源文件不要机械套用这条规则
类级 Javadoc
类级 Javadoc 是正式交付内容,不能删除、压缩或空置。
统一要求:
AO / Query / VO / DTO / Entity / Service / Manager / Repository / Mapper / Converter / Controller都要补齐类级 Javadoc- 类级 Javadoc 必须先说明职责边界,再按业务需要补充关键业务规则
- 类级 Javadoc 必须包含
@author标签 @author的值按项目模板或既有模块约定填写- 不要额外机械添加生成时间等易过期的生成信息
- 类级 Javadoc 除
@author外,正文只描述职责边界和关键业务规则 - 不要只写“某某管理器”“某某服务类”“某某对象”这类空泛说明
默认职责口径:
| 类型 | 类级 Javadoc 应表达的职责 |
|---|---|
AO |
承载新增、修改等入参数据和接口层输入校验,不承载持久化逻辑或跨对象业务规则 |
Query |
只表达查询条件和过滤参数,查询组合、默认条件、权限范围由 Manager 统一拼装 |
VO / Detail |
面向接口返回和前端展示,写入操作仍使用对应 AO |
Entity |
只描述表结构和持久化映射,业务校验、状态流转和跨聚合规则落到 Manager 或领域支持类 |
Repository / EntityManager |
只提供底层数据访问能力,不承接业务流程判断或事务编排 |
Mapper |
只提供当前数据栈的持久化访问能力;对象转换实现不放在 mapper 包 |
Converter |
只负责实体、入参对象和返回对象之间的结构转换 |
Manager |
承载单实体规则、持久化编排、查询拼装、数据状态操作和必要领域校验 |
Service |
作为事务与业务用例编排边界,只组织流程,不直接访问 Repository,也不与其它 Service 互调 |
Controller / API |
只暴露访问契约、路由入口、参数校验和统一返回,不直接编排多表业务 |
如果需求中已经明确唯一性、状态流转、删除保护、级联清理、外部同步、审计或权限边界,必须把这些具体规则补充到对应源码的 Javadoc 或必要注释中,不能保留空泛模板原文作为最终交付。
类级 Javadoc 示例:
/**
* 个人会员管理器
*
* <p>负责个人会员单实体的创建、编辑、查询、数据状态切换和删除规则,不承接企业与会员关系的跨表编排。
*
* @author "PangZhiGang, xiaopanghhh@163.com"
*/
public class MemberManager {
}
字段级 Javadoc 与字段声明
字段级 Javadoc 不是可选装饰。
统一要求:
Entity所有成员变量都必须保留字段级 Javadoc,字段语义要和 SQL 及需求文档一致core下contract/*中的AO / VO / Query / DTO以及其它普通契约对象,所有成员变量都必须保留字段级 JavadocEntity与contract/*对象的成员变量统一使用protected- 不要在同一模块内混用
protected字段和private裸字段风格 @Schema(title = ...)、Javadoc、message.multiproperties中的对象名和字段名应保持一致- 不要写空洞注释,例如“客户名称字段”“设置名称”
- 字段注释应直接表达业务语义,例如“客户名称国际化 JSON 内容”“互动下次跟进时间”
- 注解与字段声明分行书写,
@Schema(...)独占一行,下一行再写字段声明
正确格式示例:
/**
* 经营场所
*/
@Schema(title = "经营场所", requiredMode = RequiredMode.NOT_REQUIRED)
protected String branchKey;
错误格式示例:
/** 经营场所。 */
@Schema(title = "经营场所", requiredMode = RequiredMode.NOT_REQUIRED) protected String branchKey;
实体数据状态与租户范围方法
继承 AbstractTenantBase*Entity 且需要声明数据状态能力或覆盖租户范围的实体,统一保持固定的类体布局和注解格式。
统一要求:
@EnableDataStatus必须使用多行格式,每个DataStatusFeature独占一行@EnableDataStatus必须使用//@formatter:off///@formatter:on做局部保护@EnableDataStatus的 formatter 标记只包住该注解,不要把@Table、@Entity、Lombok 注解或类声明包进去//@formatter:on后必须换行再写下一个注解,不能出现//@formatter:on@Table(...)这类粘连- 类体内先声明
serialVersionUID,再放tenantScopeMode(),再放业务成员变量 tenantScopeMode()只表达租户范围策略,不要夹在字段声明之间,也不要放到类尾tenantScopeMode()内部保持标准 2 空格缩进,方法体内语句再缩进 2 空格
正确格式示例:
//@formatter:off
@EnableDataStatus({
DataStatusFeature.FIXED,
DataStatusFeature.ENABLED,
DataStatusFeature.LOCKED
})
//@formatter:on
@Table("icfg_category_definition")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class CategoryDefinition extends AbstractTenantBaseEntity {
@Serial
private static final long serialVersionUID = 1L;
@Override
public TenantScopeMode tenantScopeMode() {
return TenantScopeMode.GLOBAL_ONLY;
}
/**
* 应用标识
*/
@Column("application_key")
protected String applicationKey;
}
错误格式示例:
@EnableDataStatus({ DataStatusFeature.FIXED, DataStatusFeature.ENABLED, DataStatusFeature.LOCKED })
@Table("icfg_category_definition")
public class CategoryDefinition extends AbstractTenantBaseEntity {
/**
* 应用标识
*/
@Column("application_key")
protected String applicationKey;
@Override
public TenantScopeMode tenantScopeMode() {
return TenantScopeMode.GLOBAL_ONLY;
}
}
方法 Javadoc
统一要求:
- 方法 Javadoc 必须使用标准多行格式
- 摘要与
@param、@return、@throws等标签之间必须保留一个空*行 - Javadoc 文本不要机械追加中文句号
。 - 如果需求原文已经带标点,避免重复标点
正确格式示例:
/**
* 追加应用指标
*
* @param ao 应用指标提交对象
* @return 应用指标视图对象
*/
Javadoc 格式
统一要求:
- 类级、字段级和方法级 Javadoc 必须保留
/**必须独占一行,摘要从下一行*开始- 不要生成
/** 摘要 */、/** 摘要。 */或/** 摘要这类压缩格式 package-info.java也必须保留包级 Javadoc 和@author
Java 类声明格式
编写 Manager、Service、Controller、Repository、Mapper、Converter 以及其他长继承或长接口组合类声明时,统一遵守:
- 当
extends/implements后存在两个及以上父类型、fragment、能力接口,或单行声明明显过长时,继承 / 接口列表统一换行 - 使用
//@formatter:off///@formatter:on只包住继承 / 接口列表 extends/implements关键字放在类声明首行末尾,行尾不要留空格- 每个父类型独占一行,使用 2 空格缩进,除最后一个父类型外保留逗号
//@formatter:on放在类体第一行之后,不能包住字段、构造器、方法或整个类- 类体开始后,首个字段或成员声明前保留一个空行
- 单一父类型且声明较短时,可以保持单行,不要为了形式化强行加 formatter 标记
示例:
public interface IXxxManager extends
//@formatter:off
ICreateManager<XxxAO, XxxVO>,
IFindByIdManager<XxxVO>,
ISearchManager<XxxQuery, XxxVO> {
//@formatter:on
}
public class XxxManager extends AbstractJdbcManager implements
//@formatter:off
IXxxManager,
CreateManager<XxxEntity, XxxAO, XxxVO>,
SearchManager<XxxEntity, XxxQuery, XxxVO> {
//@formatter:on
private final XxxRepository xxxRepository;
}
局部 formatter 保护
自动格式化是默认规则,但有些代码块的换行、缩进和对齐本身承载了阅读结构。遇到这类块时,应使用 //@formatter:off / //@formatter:on 进行局部保护,避免 IDE 或批量格式化把结构压扁。
必须保护的典型场景:
- 长
extends/implements接口列表 - 多行
@EnableDataStatus数据状态能力声明 - 多行 fluent chain,例如 Reactor 链、Stream 链、QueryDSL / MyBatis-Flex
QueryWrapper链 - 多行 builder,尤其是安全用户、权限树、数据范围快照、字典项等含多个业务字段的构造
- 多行 SQL / R2DBC / JDBC 查询绑定链
- 多行
List.of(...)、字典构造、Comparator 链 - Manager 中
getKeySearchPath()/getKeySearchColumns()返回的查询键数组,包括空数组 - 人工排版过、格式变化会明显降低可读性的业务规则块
统一要求:
- formatter 标记只包住需要保护的最小代码块,不包整个方法、整个类或无关字段
//@formatter:off与//@formatter:on必须成对出现- 使用项目既有写法
//@formatter:off,不要写成// @formatter:off - 普通短链、单行 builder、简单 getter / setter、短 Repository 调用不需要机械保护
- 测试代码中只有确实依赖多行结构表达场景意图时才加保护,不要把所有测试 builder 都包起来
- 新增或批量修改后,至少检查 formatter 标记数量是否平衡
批量调整流程:
- 改动前先确认当前工作区是否已有无关修改;有无关修改时不要运行会覆盖大范围文件的格式化命令。
- 对本次修改范围内的文件执行项目默认 formatter,优先使用 IDE 或项目既有格式化配置,不手写一套新的缩进规则。
- 对需要人工排版的结构化代码块补
//@formatter:off///@formatter:on,再重新格式化确认保护有效。 - 格式化后用 diff 复核,只保留本次任务需要的排版变化。无关文件被 formatter 改动时,应从本次提交中排除。
- 提交前运行 formatter 标记平衡检查,并用
git diff --check检查尾随空白、冲突标记和空白错误。
示例:
//@formatter:off
return roleManager.findById(roleId)
.switchIfEmpty(Mono.error(StatefulException.of(
AccessControlConstant.ErrorCode.ROLE_NOT_FOUND,
"角色不存在")))
.flatMap(role -> Boolean.TRUE.equals(role.getDeleted())
? Mono.error(StatefulException.of(
AccessControlConstant.ErrorCode.ROLE_NOT_FOUND,
"角色不存在"))
: Mono.just(role));
//@formatter:on
//@formatter:off
return Comparator
.comparing(Permission::getOrderWeight, Comparator.nullsLast(Comparator.reverseOrder()))
.thenComparing(Permission::getCreatedTimestamp, Comparator.nullsLast(Comparator.naturalOrder()))
.thenComparing(Permission::getId, Comparator.nullsLast(Comparator.naturalOrder()));
//@formatter:on
@Override
public StringPath[] getKeySearchPath() {
//@formatter:off
return new StringPath[] {
QMember.member.memberNo,
QMember.member.memberName,
QMember.member.mobile
};
//@formatter:on
}
@Override
public String[] getKeySearchColumns() {
//@formatter:off
return new String[] {
};
//@formatter:on
}
批量修改后可用以下命令做平衡检查:
awk '/formatter:off/{off++} /formatter:on/{on++} END{print "off=" off " on=" on}' $(find -L java -path '*/target/*' -prune -o -name '*.java' -print)
import 与注解格式
统一要求:
import按 IDE / formatter 默认规则整理- 同一组 import 之间不要每个 import 都插入空行
- 注解独占一行,不要和类声明、字段声明挤在同一行
@Schema(...)、验证注解、Excel 注解和字段声明分行书写
第三方 API 使用
新增或修改代码时,不允许继续使用 JDK 或第三方依赖中已经标记为 @Deprecated 的 API。
统一要求:
- 编写或修改代码前,应处理 IDE / 编译器提示的 deprecation warning,不要用
@SuppressWarnings("deprecation")掩盖问题 - 修改遗留代码时,如果当前方法或当前改动路径中存在过期 API,应顺手迁移到推荐替代 API
- Apache Commons Lang 3 中已过期的字符串比较和查找方法不要继续使用,例如
StringUtils.equals(...)、StringUtils.equalsIgnoreCase(...)、StringUtils.contains(...)、StringUtils.containsIgnoreCase(...) - 大小写敏感比较和查找统一使用
org.apache.commons.lang3.Strings.CS.equals(...)、Strings.CS.contains(...) - 大小写不敏感比较和查找统一使用
org.apache.commons.lang3.Strings.CI.equals(...)、Strings.CI.contains(...) StringUtils.isBlank(...)、StringUtils.isNotBlank(...)、StringUtils.defaultIfBlank(...)等未过期的空白判断和默认值方法可以继续使用
示例:
// 错误:StringUtils.equals(...) 已过期
StringUtils.equals(user.getTenantKey(), tenantKey);
// 正确:大小写敏感比较
Strings.CS.equals(user.getTenantKey(), tenantKey);
// 正确:大小写不敏感查找
Strings.CI.contains(message, keyword);
通用实体可用性判断
涉及关系绑定、授权对象筛选、候选数据过滤等场景时,不要在各业务模块重复手写“未删除、租户匹配、数据状态可用”判断。
统一要求:
- 基础必要检查是逻辑删除和租户归属:实体必须未删除,且
tenantKey必须匹配 - 数据状态检查是可选条件:按业务场景传入
DataStatusFilter,为空或不包含任何字段时不检查数据状态 - 关系绑定这类只做通用可用性过滤的场景,优先直接调用
EntityAvailabilitySupport,不要额外抽取无业务增量的私有判断函数 - 数据状态过滤对象统一使用
DataStatusFilter
示例:
if (!EntityAvailabilitySupport.isAvailableInTenant(user, tenantKey)) {
continue;
}
日志注解
新增具体业务类统一使用 Lombok 的 @Slf4j,不要继续手写 LoggerFactory.getLogger(...)。
标准支持接口已有默认日志时,空壳实现不要再包一层重复日志;自定义方法按 delete-hook-and-logging-guide.md 补入口日志和异常日志。
生成与修改检查清单
提交或交付前至少检查:
- Java 源码和
package-info.java是否具备统一版权头 - 类级 Javadoc 是否描述职责边界和关键业务规则
- 类级 Javadoc 是否包含
@author - 是否没有机械添加生成时间等易过期信息
- 字段级 Javadoc 是否完整,且语义与 SQL、需求和
@Schema一致 Entity与contract/*对象的成员变量是否统一使用protected- 实体
tenantScopeMode()是否位于serialVersionUID后、业务成员变量前 @EnableDataStatus是否使用 formatter 保护,且每个DataStatusFeature独占一行- 是否没有单行压缩 Javadoc
- 方法 Javadoc 的摘要与标签之间是否保留空行
- 注解、字段声明和类声明是否分行书写
- 长
extends/implements是否只用局部 formatter 标记包住接口列表,且父类型列表使用 2 空格缩进 import是否按 formatter 默认规则整理- 新写具体类是否统一使用
@Slf4j - 是否没有继续使用 JDK 或第三方依赖中已标记为过期的 API
- 手写排版的链式调用、builder、SQL、字典、Comparator 等结构化代码块是否已用局部 formatter 标记保护,且
off/on数量平衡 - 批量格式化是否只影响本次任务相关文件,且无关 formatter diff 没有进入提交
- 是否已执行
git diff --check,确认没有空白错误
最后更新:2026-06-01
仍有疑问?按反馈清单整理复现信息 →