后端Java编码规范

复制代码
---
trigger: always_on
---
# 后端Java编码规范

## 命名规则
- 类名:大驼峰 UpperCamelCase,名词或名词短语,如 `UserService`, `OrderController`
- 方法名:小驼峰 lowerCamelCase,动词或动词短语,如 `findUserById()`, `createOrder()`
- 查询列表方法:`query` 开头,如 `queryFactoryElectricianMasterRecord()`,禁止用 `get` 开头
- 查询单个方法:`find` 开头,如 `findFactoryElectricianMasterEntityByDataKey()`,禁止用 `get` 开头
- 事务方法:`trans`/`tx` 后缀,如 `saveTemplateTrans()`, `enableTemplateTrans()`, `deleteTemplateTrans()`
- 构建实体方法:`build` 开头,如 `buildXxxEntity()`, `buildXxxVO()`
- 常量名:全大写+下划线,如 `MAX_THREAD_COUNT`, `CACHE_EXPIRE_TIME`
- 局部/成员变量:小驼峰,禁止 `m_`/`_` 前缀
- 布尔变量:以 `is`/`has`/`can` 开头,如 `isDeleted`, `hasPermission`
- 数组/集合:复数形式,List用集合词,Map用map,如 `List<User> userList`, `String[] fileNames`
- DTO/VO/POJO:意义明确的名称,在包结构中区分,如 `UserQueryDTO`, `OrderVO`
- 聚合根命名:以 `Agg` 结尾,如 `AiOutboundCallAgg`, `FactoryElectricianOrderAgg`
- Service接口命名:无前缀I,如 `AiOutboundCallService`(老模块有IFactory前缀)
- Store接口命名:以 `Store` 结尾,如 `CollectionLetterTemplateStore`

## 代码格式
- 使用4个空格缩进,禁止使用Tab键
- 单行字符数不超过120个,超出必须换行

## OOP规则
- 覆写父类方法必须加 `@Override` 注解
- 使用 equals() 比较对象时,必须用常量或确定非空的对象调用,如 `"test".equals(variable)`

## 控制语句
- `if/else/for/while/do` 必须使用大括号,即使只有一行代码
- 采用卫语句形式避免 if-else 过深,代码难以维护
- 禁止在条件判断中执行复杂语句,应赋值给有明确意义的布尔变量
- 循环嵌套不要超过三层

## 注释规范
- 类、类属性、类方法的注释必须使用 Javadoc 规范 `/** ... */`
- 所有抽象方法(含接口方法)必须用 Javadoc 注释
- 代码修改时,注释也要同步修改

## 异常处理
- 项目使用两种自定义异常:
  - `FebsException`(checked exception):用于业务校验失败、资源不存在等可预期场景
  - `BizException`(unchecked, RuntimeException):用于不可恢复的系统级业务异常
- 禁止捕获异常后什么都不做(空catch块是魔鬼)
- 捕获异常是为了处理它,不想处理就抛给调用者
- finally块必须关闭资源对象、流对象,有异常也要 try-catch
- 异常抛出应尽量考虑周全,宁愿多写代码也不要少写
- Store层不存在时抛异常:`throw new FebsException("当前记录不存在!")`
- **Controller层异常处理策略**:声明 `throws FebsException` 由全局异常处理器统一捕获并返回 `RestResponse.error()`,Controller禁止手动 catch 业务异常

## 消除魔数
- 禁止直接使用魔法数字表示状态等类型,必须使用枚举或常量替代
- 错误:`if (status == 1) { ... }`
- 正确:`if (status == OrderStatus.COMPLETED) { ... }`

## 枚举类规范
- 使用 `@Getter` + 全参构造方法(不用 `@Data`)
- 状态枚举统一 `code` + `name` 字段模式
```java
@Getter
public enum OutboundStatusEnum {
    PUSHING(1, "推送中"),
    REPEAT(2, "重复");

    private Integer code;
    private String name;

    OutboundStatusEnum(Integer code, String name) {
        this.code = code;
        this.name = name;
    }

    public static OutboundStatusEnum toEnum(Integer code) {...}
}
```
- 权限枚举使用 String 类型 code:`private String code; private String name;`

## 类职责单一
- Controller层:禁止添加业务查询和过多业务处理,仅负责API映射
- Service层:专注业务处理和参数校验,业务代码和查询代码不混在一起,查询代码放在Store层
- Store层:数据储存层,负责数据查询
- Mapper层:数据库操作
- 通用:类应保持单一职责,避免过于臃肿(如不同业务混在同一个类中应拆分)

## Entity编码规范
```java
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("factory_xxx")
@ApiModel(value = "XxxEntity对象")
public class XxxEntity implements Serializable {
    private static final long serialVersionUID = 1L;

    @ApiModelProperty(value = "ID")
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;

    @ApiModelProperty(value = "业务字段")
    @TableField("business_field")                    // 每个字段必须显式指定列名
    private String businessField;

    @ApiModelProperty(value = "创建时间")
    @TableField("create_time")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime createTime;

    @ApiModelProperty(value = "删除标记")
    @TableField("deleted")
    private Integer deleted;

    public XxxEntity() { super(); }

    public XxxEntity(String businessField, ...) {  // 全参构造(不含id、createBy等基础字段)
        this();
        this.businessField = businessField;
        ...
    }
}
```

**关键规则**:
- 每个字段必须用 `@TableField("xxx_yyy")` 显式指定列名
- 主键使用 `@TableId(value = "id", type = IdType.AUTO)`
- 时间字段统一 `LocalDateTime` + `@JsonFormat` + `@DateTimeFormat`
- 逻辑删除字段 `Integer deleted`(0/1)
- `@Accessors(chain = true)` 支持链式调用
- 实现 `Serializable`,声明 `serialVersionUID`

## VO/DTO编码规范
```java
// VO
@Data
@ToString
public class XxxVO implements Serializable {
    private static final long serialVersionUID = 1L;

    @ApiModelProperty(value = "主键ID")
    private Long id;

    @ApiModelProperty(value = "状态文本回显")
    private String statusName;                    // 关联回显字段

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime createTime;

    public XxxVO() { super(); }
    public XxxVO(Long id, ...) { this.id=id; ... }  // 全参构造
}

// QueryDTO
@Data
@ToString
public class XxxQueryDTO extends PageBaseDTO implements Serializable {
    @ApiModelProperty(value = "客户ID")
    private Long customerId;
    private Boolean hasExport = false;             // 导出标识
}

// DTO
@Data
@ToString
public class XxxDTO implements Serializable {
    @ApiModelProperty(value = "业务字段")
    private String businessField;
}
```

**关键规则**:
- VO/DTO 使用 `@Data` + `@ToString`,实现 `Serializable`
- QueryDTO 继承 `PageBaseDTO`(含 pageNum=1, pageSize=10)
- VO 可包含关联回显字段(如 `statusName`, `customerName`)
- 时间字段同样加 `@JsonFormat` + `@DateTimeFormat`

## 聚合根(Agg)编码规范
```java
@Getter
@ToString
@ApiModel(value = "Xxx对象")
public class XxxAgg implements Serializable {
    private static final long serialVersionUID = 1L;
    private Long id;
    private String businessField;
    // ... 其他业务字段

    public XxxAgg create(String businessField, String userKey) {
        this.fillingMainData(businessField);
        return this;
    }

    public XxxAgg modify(String businessField, String userKey) {
        this.fillingMainData(businessField);
        return this;
    }

    private XxxAgg fillingMainData(String businessField) {
        this.businessField = businessField;
        return this;
    }

    public XxxAgg fillingDbId(Long id) {
        this.id = id;
        return this;
    }

    public XxxAgg() { super(); }

    public XxxAgg(Long id, String businessField, ...) {  // 全参构造
        this(); this.id = id; this.businessField = businessField; ...
    }
}
```

**关键规则**:
- 使用 `@Getter`(**不用 `@Data`、`@Setter`**),通过方法封装属性设置
- `create()` / `modify()` 共用私有 `fillingMainData()` 方法
- `fillingDbId()` 用于 Store 层回填主键
- 返回 `this` 支持链式调用
- 全参构造函数用于 Entity→Agg 的转换

## 复用性原则
- 代码块只用一次可以不关注
- 第二次使用需要注意
- 第三次使用必须抽取为独立方法

## 依赖注入
- 统一使用 `@Autowired` 进行依赖注入
- 特殊场景(hologres模块等)可使用 `@Resource`

## 工具库选择
- 优先使用 Hutool 工具类:`ObjectUtil.isEmpty()`, `CollUtil.isEmpty()`, `StrUtil.isBlank()` 等
- 集合工具:`CollUtil` 优先于 `CollectionUtils`
- 对象工具:`ObjectUtil` 优先于手动判空

## 事务处理
- 含事务操作的方法必须含 `trans`/`tx`,如 `createOrderTrans()`
- 传播行为:默认用 REQUIRED,嵌套事务用 REQUIRES_NEW
- 事务边界:仅在Store层使用 `@DSTransactional`
- 禁止在Controller层和private方法使用事务注解

## 日志规范
- 错误日志必须包含关键参数
- 敏感信息必须脱敏处理
相关推荐
阿里嘎多学长2 小时前
2026-08-24 GitHub 热点项目精选
开发语言·程序员·github·代码托管
weixin_399380692 小时前
TongWeb7.0.4.9M11一键安装脚本(by sy)
java·spring
CallFay云起未来2 小时前
AI客服能不能减少人工回复?从重复咨询到人机协同的落地分析
java·大数据·人工智能·文心一言
我命由我123452 小时前
Android 开发 - 获取当前设备屏幕的旋转角度
android·java·java-ee·android studio·android jetpack·android-studio·android runtime
SLD_Allen2 小时前
Go语言runtime全景
开发语言·javascript·golang
Elastic 中国社区官方博客2 小时前
OpenTelemetry Java 扩展:无需分叉 agent 即可自定义追踪
java·大数据·运维·开发语言·数据库·人工智能·elasticsearch
不灭的黄金瞳1233 小时前
C语言手写顺序表
c语言·开发语言·数据结构
京东云开发者3 小时前
上游给空、下游拿到 -1,我把故障一直追到了 commons-beanutils 的构造函数
java·ai编程