Java 后端代码规范

本文档定义 Java 后端项目的通用代码规范,基于阿里巴巴开发规约和业界最佳实践。

代码风格

  • 使用 4 空格缩进
  • 左花括号前留一个空格
  • 每行最多 120 字符
  • 字段、方法、类访问修饰符顺序:private​ > protected​ > public
  • 不要使用尾行注释(行末的 // comment
  • 工具类优先使用 Hutool
  • 缩进使用空格,禁止使用 Tab

命名规范

常用命名

类型规范示例
项目名小写字母,多个单词用 - 分隔my-project
包名全小写com.example.project
类名UpperCamelCaseUserController
方法名lowerCamelCasegetById​, page
变量名lowerCamelCaseuserId​, isDeleted
常量名全大写,下划线分隔MAX_PAGE_SIZE​, DEFAULT_STATUS
枚举UpperCamelCase,枚举值全大写下划线分隔Status.ENABLED​, USER_TYPE_VIP

类命名

类型规范示例
Controller{Entity}Controller​ / {Entity}AdminControllerUserController
Service接口{Entity}ServiceUserService
Service实现{Entity}ServiceImplUserServiceImpl
Mapper{Entity}MapperUserMapper
Entity驼峰命名User
DTO{Entity}QueryDTO​, {Entity}DTOUserQueryDTO
VO{Entity}VOUserVO
工具类XxxUtil​ 或 XxxToolStringUtil​, DateUtil

字段命名

  • 数据库字段:下划线命名 user_id​, created_at
  • Java 字段:驼峰命名 userId
  • 布尔字段:避免 is​ 前缀,如 deleted​ 而非 isDeleted(与数据库映射时注意)
  • 集合:List​ 后缀 userList​,Map​ 后缀 userMap

注解使用

Controller 注解

@Tag(name = "用户管理", description = "用户相关接口")  // API 文档分类
@Slf4j
@RestController
@RequestMapping("/api/user")
@RequiredArgsConstructor
public class UserController {

    @Operation(summary = "获取用户列表", description = "分页获取用户列表")  // API 操作描述
    @GetMapping("/list")
    public Result<List<User>> list() {
        // ...
    }

    @Operation(summary = "分页查询用户")
    @PostMapping("/page")
    public Result<PageResult<User>> page(@RequestBody UserQueryDTO queryDTO) {
        // ...
    }

    @Operation(summary = "根据ID获取用户")
    @Parameter(description = "用户ID")  // 路径参数描述
    @GetMapping("/{id}")
    public Result<User> getById(@PathVariable Long id) {
        // ...
    }

    @Operation(summary = "新增用户")
    @PostMapping
    public Result<Void> add(@Valid @RequestBody UserDTO dto) {
        // ...
    }

    @Operation(summary = "更新用户")
    @PutMapping
    public Result<Void> update(@Valid @RequestBody UserDTO dto) {
        // ...
    }

    @Operation(summary = "删除用户")
    @Parameter(description = "用户ID")
    @DeleteMapping("/{id}")
    public Result<Void> delete(@PathVariable Long id) {
        // ...
    }
}

Entity/DTO 注解

@Data
@Schema(description = "用户实体")  // 实体描述
public class User {

    @Schema(description = "用户ID")  // 字段描述
    @TableId(type = IdType.ASSIGN_ID)
    private Long id;

    @Schema(description = "用户名", example = "张三")  // example 指定示例值
    @NotBlank(message = "用户名不能为空")
    @Size(max = 50, message = "用户名长度不能超过50")
    private String username;

    @Schema(description = "邮箱", example = "user@example.com")
    @Email(message = "邮箱格式不正确")
    private String email;

    @Schema(description = "手机号", example = "13800138000")
    private String phone;

    @Schema(description = "状态", allowableValues = {"0", "1"})  // 可选值
    private Integer status;

    @Schema(description = "创建时间", accessMode = Schema.AccessMode.READ_ONLY)  // 只读字段
    private LocalDateTime createdAt;
}

注解说明

类型注解说明
Controller类@TagAPI 分类标签,用于分组
Controller方法@OperationAPI 操作描述,summary 为简短描述,description 为详细描述
Controller方法@Parameter参数描述,用于 PathVariable 和 Query 参数
Entity/DTO类@Schema实体/DTO 描述
Entity/DTO字段@Schema字段描述、示例值、取值范围
参数校验@Valid启用参数校验
Service实现@Service服务层标记
日志@Slf4j日志标记

@Schema 常用属性

@Schema(
    description = "描述",                           // 字段描述
    example = "示例值",                            // 示例值
    requiredMode = RequiredMode.REQUIRED,          // 是否必填
    allowableValues = {"0", "1", "2"},            // 可选值列表
    minLength = 1,                                 // 最小长度
    maxLength = 50,                                // 最大长度
    minimum = "0",                                 // 最小值
    maximum = "100",                               // 最大值
    accessMode = Schema.AccessMode.READ_ONLY       // 访问模式(READ_ONLY 只读)
)

SpringDoc 依赖

<dependency>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
    <version>2.3.0</version>
</dependency>

接口文档访问

  • Swagger UI: http://host:port/swagger-ui.html
  • OpenAPI Docs: http://host:port/v3/api-docs

参数校验

使用 @Valid 和校验注解对输入参数进行验证:

@PostMapping
public Result<Void> add(@Valid @RequestBody UserDTO dto) {
    // ...
}
@Data
@Schema(description = "用户DTO")
public class UserDTO {
    @NotBlank(message = "名称不能为空")
    @Size(max = 50, message = "名称长度不能超过50")
    private String name;

    @NotNull(message = "ID不能为空")
    private Long id;

    @Min(value = 0, message = "值不能为负数")
    @Max(value = 1000, message = "值不能超过1000")
    private Integer value;
}

常用校验注解:

  • @NotNull:不能为 null
  • @NotBlank:不能为空白字符串
  • @NotEmpty:不能为 null 或空集合
  • @Size:字符串/集合长度范围
  • @Min​/@Max:数值范围
  • @Email:邮箱格式
  • @Pattern:正则表达式

事务管理

增删改操作必须添加 @Transactional,并指定异常回滚:

@Transactional(rollbackFor = Exception.class)
public void update(User user) {
    userService.updateById(user);
}

异常处理

原则

  1. 不要 catch Throwable​ 或 Exception
  2. 记录完整异常堆栈:log.error("错误信息", e)
  3. 不要只记录异常消息:log.error(e.getMessage()) 会丢失堆栈
  4. 敏感信息脱敏后再记录

推荐模式

try {
    userService.save(user);
    log.info("【模块名】操作成功: id={}", user.getId());
} catch (Exception e) {
    log.error("【模块名】操作异常: ", e);
    return Result.error("操作失败");
}

自定义业务异常

public class BusinessException extends RuntimeException {
    private final Integer code;

    public BusinessException(String message) {
        super(message);
        this.code = 500;
    }

    public BusinessException(Integer code, String message) {
        super(message);
        this.code = code;
    }
}

日志规范

格式

使用 Slf4j 日志,格式为 【模块名】操作描述

log.info("【用户管理】获取用户列表请求");
log.info("【用户管理】获取用户列表成功, 数量: {}", list.size());
log.warn("【用户管理】参数验证失败: {}", errorMessage);
log.error("【用户管理】查询异常: ", e);

占位符

日志参数使用占位符 {},禁止字符串拼接:

// 禁止
log.debug("用户" + userId + "登录成功");

// 推荐
log.debug("用户 {} 登录成功", userId);

敏感信息脱敏

String maskedPhone = phone.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2");
log.info("用户 {} 手机号更新为 {}", userId, maskedPhone);

分页查询模式

@Operation(summary = "分页查询用户")
@PostMapping("/page")
public Result<PageResult<User>> page(@RequestBody UserQueryDTO queryDTO) {
    Page<User> page = new Page<>(queryDTO.getCurrent(), queryDTO.getSize());
    LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
    if (queryDTO.getName() != null) {
        wrapper.like(User::getName, queryDTO.getName());
    }
    wrapper.orderByDesc(User::getCreatedAt);
    Page<User> result = userService.page(page, wrapper);
    return Result.success(PageResult.of(result));
}

常量定义

使用枚举

public enum Status {
    DRAFT(1, "草稿"),
    ENABLED(2, "启用"),
    DISABLED(3, "禁用");

    private final int code;
    private final String desc;

    Status(int code, String desc) {
        this.code = code;
        this.desc = desc;
    }

    public int getCode() {
        return code;
    }

    public String getDesc() {
        return desc;
    }

    public static Status fromCode(int code) {
        for (Status status : values()) {
            if (status.code == code) {
                return status;
            }
        }
        return null;
    }
}

避免魔法值

// 禁止
if (status == 1) {
    // ...
}

// 推荐
if (Status.ENABLED.getCode() == status) {
    // ...
}

方法设计

原则

  • 单一职责:每个方法只做一件事
  • 方法长度:单个方法不超过 50 行
  • 参数数量:不超过 5 个参数,超过时使用对象封装

卫语句提前返回

public void process(User user) {
    if (user == null) {
        return;
    }
    // 正常业务逻辑
}

集合处理

遍历

// 推荐:for-each
for (User user : userList) {
    // ...
}

// 推荐:Stream API
List<Long> ids = userList.stream()
    .map(User::getId)
    .collect(Collectors.toList());

判空

// Hutool 判空
if (CollUtil.isEmpty(userList)) {
    return;
}

// 或
if (userList == null || userList.isEmpty()) {
    return;
}

字符串处理

避免字符串拼接

// 禁止:循环内字符串拼接
String s = "";
for (String item : list) {
    s += item;
}

// 推荐:StringBuilder
StringBuilder sb = new StringBuilder();
for (String item : list) {
    sb.append(item);
}
String s = sb.toString();

// 推荐:Hutool
String s = StrUtil.join(list, ",");

判空去空

// Hutool 字符串工具
StrUtil.isBlank(str);       // 是否空白
StrUtil.isNotBlank(str);    // 是否非空白
StrUtil.trim(str);          // 去首尾空白
StrUtil.blankToDefault(str, "默认");  // 空白时默认值

Optional 使用

// 避免
String name = null;
if (user != null) {
    name = user.getName();
}

// 推荐
String name = Optional.ofNullable(user)
    .map(User::getName)
    .orElse("匿名");

Lombok 使用

@Data

适用于 Entity、DTO、VO:

@Data
@Schema(description = "用户DTO")
public class UserDTO {
    private Long id;
    private String name;
}

@Builder

复杂对象构造时使用:

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class UserDTO {
    private Long id;
    private String name;
}

// 使用
UserDTO dto = UserDTO.builder()
    .id(1L)
    .name("测试")
    .build();

数据库规范

字段命名

  • 使用下划线命名:user_id​, created_at​, is_deleted
  • 主键:id
  • 时间字段:created_at​, updated_at​, deleted_at
  • 软删除:is_deleted

基础实体

项目中的基础实体类应包含:

@Data
public class BaseEntity {
    @TableId(type = IdType.ASSIGN_ID)
    private Long id;

    @TableField("created_by")
    private String createdBy;

    @TableField("created_at")
    private LocalDateTime createdAt;

    @TableField("updated_by")
    private String updatedBy;

    @TableField("updated_at")
    private LocalDateTime updatedAt;

    @TableField("is_deleted")
    private Boolean isDeleted;

    @TableField("deleted_at")
    private LocalDateTime deletedAt;
}

数据库迁移

  • 迁移文件放在指定目录
  • 命名: V{version}__{description}.sql
  • 版本号递增,不要修改已执行的迁移文件

禁止项

  1. 禁止使用 System.out.println() 输出日志
  2. 禁止在循环体内声明大对象
  3. 禁止使用 new Date()​,使用 LocalDateTime.now()
  4. 禁止使用 select *,明确指定查询字段
  5. 禁止在 Service 层直接操作 Map/List 等集合做业务处理
  6. 禁止使用可变参数作为方法重载
  7. 禁止使用 Thread.sleep() 替代等待逻辑
  8. 禁止在生产环境使用日志级别 debug