开发规范

代码格式与源码风格指南

统一 Java 格式、Javadoc、字段、日志和局部格式保护。

浏览全部手册
本页目录
文档来源与 Markdown 原文

权威正文:ineed-core/docs/project-development/code-style-guide.md。网站按工作区快照同步,原文中的历史日期和验证范围保留。

开始编码前核对同版本源码;跨仓文件引用可在源码定位目录查找。

下载 Markdown 原文 ↓

文档定位

本文档集中约定基于 ineed-core 新增或修改后端业务源码时的代码格式、源码注释和基础风格规则。

这些规则不区分人工开发、代码生成器生成或自动化工具修改;所有业务源码都按同一套标准交付。

适用范围

  • Java 源码与测试源码
  • package-info.java
  • AO / Query / VO / DTO / Entity / Service / Manager / Repository / Mapper / Converter / Controller
  • 业务模块中需要与 ineed-core 约定保持一致的源码模板

源码版权头

新增 Java 源码时,文件头必须统一写入:

/*
 * Copyright (c) 2026 Ineedfull.Co.Ltd. All rights reserved.
 */

额外约束:

  • 适用范围包括 src/main/javasrc/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 及需求文档一致
  • corecontract/* 中的 AO / VO / Query / DTO 以及其它普通契约对象,所有成员变量都必须保留字段级 Javadoc
  • Entitycontract/* 对象的成员变量统一使用 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 类声明格式

编写 ManagerServiceControllerRepositoryMapperConverter 以及其他长继承或长接口组合类声明时,统一遵守:

  • 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 标记数量是否平衡

批量调整流程:

  1. 改动前先确认当前工作区是否已有无关修改;有无关修改时不要运行会覆盖大范围文件的格式化命令。
  2. 对本次修改范围内的文件执行项目默认 formatter,优先使用 IDE 或项目既有格式化配置,不手写一套新的缩进规则。
  3. 对需要人工排版的结构化代码块补 //@formatter:off / //@formatter:on,再重新格式化确认保护有效。
  4. 格式化后用 diff 复核,只保留本次任务需要的排版变化。无关文件被 formatter 改动时,应从本次提交中排除。
  5. 提交前运行 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 补入口日志和异常日志。

生成与修改检查清单

提交或交付前至少检查:

  1. Java 源码和 package-info.java 是否具备统一版权头
  2. 类级 Javadoc 是否描述职责边界和关键业务规则
  3. 类级 Javadoc 是否包含 @author
  4. 是否没有机械添加生成时间等易过期信息
  5. 字段级 Javadoc 是否完整,且语义与 SQL、需求和 @Schema 一致
  6. Entitycontract/* 对象的成员变量是否统一使用 protected
  7. 实体 tenantScopeMode() 是否位于 serialVersionUID 后、业务成员变量前
  8. @EnableDataStatus 是否使用 formatter 保护,且每个 DataStatusFeature 独占一行
  9. 是否没有单行压缩 Javadoc
  10. 方法 Javadoc 的摘要与标签之间是否保留空行
  11. 注解、字段声明和类声明是否分行书写
  12. extends / implements 是否只用局部 formatter 标记包住接口列表,且父类型列表使用 2 空格缩进
  13. import 是否按 formatter 默认规则整理
  14. 新写具体类是否统一使用 @Slf4j
  15. 是否没有继续使用 JDK 或第三方依赖中已标记为过期的 API
  16. 手写排版的链式调用、builder、SQL、字典、Comparator 等结构化代码块是否已用局部 formatter 标记保护,且 off/on 数量平衡
  17. 批量格式化是否只影响本次任务相关文件,且无关 formatter diff 没有进入提交
  18. 是否已执行 git diff --check,确认没有空白错误

最后更新:2026-06-01

仍有疑问?按反馈清单整理复现信息 →