Skip to content

开发规范

本文档定义 youlai-boot 后端项目的开发约定,参考《阿里巴巴 Java 开发手册》及业界最佳实践。

命名规范

包命名

规则示例说明
全部小写com.youlai.boot.system✅ 正确
单词间无分隔com.youlai.boot.systemService❌ 错误

包结构规范

com.youlai.boot
├── auth/                    # 认证模块
├── common/                  # 公共组件
├── config/                  # 配置类
├── core/                    # 核心组件
├── platform/                # 平台模块
├── security/                # 安全模块
└── system/                  # 系统模块
    ├── controller/          # 控制层
    ├── service/             # 业务层
    │   └── impl/            # 业务实现
    ├── mapper/              # 数据访问层
    └── model/               # 数据模型
        ├── entity/          # 实体类
        ├── form/            # 表单对象
        ├── query/           # 查询对象
        ├── vo/              # 视图对象
        ├── dto/             # 数据传输对象
        └── bo/              # 业务对象

类命名

类型规则示例
控制器XxxControllerUserController
业务接口XxxServiceUserService
业务实现XxxServiceImplUserServiceImpl
数据访问XxxMapperUserMapper
实体类XxxUser
表单对象XxxFormUserForm
查询对象XxxQueryUserQuery
视图对象XxxVOUserPageVO
数据传输XxxDTOCurrentUserDTO
业务对象XxxBORolePermsBO
枚举类XxxEnumDataScopeEnum
常量类XxxConstantsSystemConstants
配置类XxxConfig / XxxPropertiesSecurityConfig
异常类XxxExceptionBusinessException

方法命名

查询方法

方法前缀说明示例
get单个对象查询getUserById()getUserFormData()
list列表查询listUsers()listUserOptions()
page / getPage分页查询getUserPage()
count统计数量countUsers()
exists存在性判断existsByUsername()
java
// ✅ 推荐
User getUserById(Long id);
List<User> listUsers(UserQuery query);
IPage<UserPageVO> getUserPage(UserQuery query);
boolean existsByUsername(String username);

// ❌ 不推荐
User selectUser(Long id);      // 应使用 get
List<User> queryUsers();       // 应使用 list

写操作方法

方法前缀说明示例
save新增saveUser()
update修改updateUser()
delete删除deleteUser()
batch批量操作batchInsert()
java
// ✅ 推荐
boolean saveUser(UserForm form);
boolean updateUser(Long id, UserForm form);
boolean deleteUser(Long id);
boolean deleteUsers(String ids);  // 批量删除

// ❌ 不推荐
boolean addUser();        // 应使用 save
boolean modifyUser();     // 应使用 update
boolean removeUser();     // 应使用 delete

方法命名规范示例

java
public interface UserService {

    // 查询方法
    User getUserById(Long id);                    // 单个查询
    UserForm getUserFormData(Long id);            // 获取表单数据
    IPage<UserPageVO> getUserPage(UserQuery q);   // 分页查询
    List<User> listUsers();                       // 列表查询
    List<Option<String>> listUserOptions();       // 下拉选项
    boolean existsByUsername(String username);    // 存在性判断

    // 写操作方法
    boolean saveUser(UserForm form);              // 新增
    boolean updateUser(Long id, UserForm form);   // 修改
    boolean deleteUsers(String ids);              // 删除(批量)
    boolean resetUserPassword(Long id, String pwd); // 特殊操作
}

变量命名

类型规则示例
成员变量lowerCamelCaseprivate UserService userService;
局部变量lowerCamelCaseUser user = userService.getById(id);
常量UPPER_SNAKE_CASEpublic static final String DEFAULT_PASSWORD = "123456";
布尔变量is/has/can 前缀private boolean isRoot;

分层架构规约

调用链路

各层职责

层级职责禁止事项
Controller参数校验、调用 Service、组装返回结果❌ 禁止直接调用 Mapper
Service业务逻辑、事务控制、数据组装❌ 禁止跨业务调用 Mapper
Mapper数据库访问、SQL 编写❌ 禁止包含业务逻辑

Service 调用规范

核心原则:Service 只能调用自己业务域的 Mapper,禁止跨业务调用。

java
// ✅ 正确:UserService 调用 UserMapper
@Service
public class UserServiceImpl implements UserService {
    private final UserMapper userMapper;        // 自己业务域
    private final UserRoleService userRoleService;  // 通过 Service 交互

    public User getUserById(Long id) {
        return userMapper.selectById(id);
    }
}

// ❌ 错误:UserService 直接调用 RoleMapper
@Service
public class UserServiceImpl implements UserService {
    private final UserMapper userMapper;
    private final RoleMapper roleMapper;  // ❌ 禁止跨业务调用 Mapper

    public User getUserWithRoles(Long id) {
        User user = userMapper.selectById(id);
        List<Role> roles = roleMapper.listByUserId(id);  // ❌ 错误
        return user;
    }
}

// ✅ 正确:通过 RoleService 获取角色
@Service
public class UserServiceImpl implements UserService {
    private final UserMapper userMapper;
    private final RoleService roleService;  // ✅ 通过 Service 交互

    public User getUserWithRoles(Long id) {
        User user = userMapper.selectById(id);
        List<Role> roles = roleService.listRolesByUserId(id);  // ✅ 正确
        return user;
    }
}

跨业务数据交互

场景正确做法
UserService 需要角色数据调用 RoleService.listRolesByUserId()
OrderService 需要用户数据调用 UserService.getUserById()
需要多个业务数据组装在 Service 层调用多个 Service 组装

RESTful API 规范

URL 设计

规则示例说明
使用名词复数/api/v1/users✅ 正确
避免动词/api/v1/getUsers❌ 错误
层级不超过 3 层/api/v1/users/{id}/roles✅ 正确
使用连字符分隔/api/v1/user-profiles✅ 正确

HTTP 方法映射

HTTP 方法操作URL 示例权限标识
GET列表查询GET /api/v1/userssys:user:list
GET单个查询GET /api/v1/users/{id}sys:user:list
POST新增POST /api/v1/userssys:user:create
PUT全量修改PUT /api/v1/users/{id}sys:user:update
PATCH部分修改PATCH /api/v1/users/{id}/statussys:user:update
DELETE删除DELETE /api/v1/users/{id}sys:user:delete

接口示例

java
@RestController
@RequestMapping("/api/v1/users")
public class UserController {

    // 列表查询
    @GetMapping
    public PageResult<UserPageVO> getUserList(UserQuery queryParams) { }

    // 单个查询
    @GetMapping("/{id}")
    public Result<User> getUser(@PathVariable Long id) { }

    // 新增
    @PostMapping
    @PreAuthorize("@ss.hasPerm('sys:user:create')")
    public Result<Void> saveUser(@RequestBody @Valid UserForm form) { }

    // 修改
    @PutMapping("/{id}")
    @PreAuthorize("@ss.hasPerm('sys:user:update')")
    public Result<Void> updateUser(@PathVariable Long id, @RequestBody @Valid UserForm form) { }

    // 删除
    @DeleteMapping("/{id}")
    @PreAuthorize("@ss.hasPerm('sys:user:delete')")
    public Result<Void> deleteUser(@PathVariable Long id) { }

    // 部分修改
    @PatchMapping("/{id}/status")
    @PreAuthorize("@ss.hasPerm('sys:user:update')")
    public Result<Void> updateUserStatus(@PathVariable Long id, @RequestParam Integer status) { }

    // 子资源
    @GetMapping("/{id}/roles")
    public Result<List<Role>> getUserRoles(@PathVariable Long id) { }

    // 特殊操作(动词转名词)
    @PostMapping("/{id}/password/reset")
    @PreAuthorize("@ss.hasPerm('sys:user:reset-password')")
    public Result<Void> resetPassword(@PathVariable Long id) { }
}

URL 命名规范

java
// ✅ 推荐
GET  /api/v1/users              // 用户列表
GET  /api/v1/users/{id}         // 用户详情
GET  /api/v1/users/{id}/form    // 用户表单数据
GET  /api/v1/users/me           // 当前用户信息
POST /api/v1/users/{id}/password/reset  // 重置密码

// ❌ 不推荐
GET  /api/v1/getUserList        // URL 包含动词
GET  /api/v1/user               // 应使用复数
POST /api/v1/users/resetPassword/{id}  // 路径参数应在最后

权限标识规范

命名格式

模块:资源:操作

操作命名对照表

操作标识HTTP 方法说明
列表查询listGET分页/列表查询
新增createPOST创建资源
修改updatePUT/PATCH更新资源
删除deleteDELETE删除资源
导入importPOST批量导入
导出exportGET数据导出
发布publishPOST发布操作
撤销revokePOST撤销操作
刷新refreshPOST/GET缓存刷新
分配assignPOST权限分配

权限标识示例

java
// 用户管理
sys:user:list           // 列表
sys:user:create         // 新增
sys:user:update         // 修改
sys:user:delete         // 删除
sys:user:import         // 导入
sys:user:export         // 导出
sys:user:reset-password // 重置密码

// 角色管理
sys:role:create
sys:role:update
sys:role:delete
sys:role:assign         // 分配权限

// 公告管理
sys:notice:list
sys:notice:create
sys:notice:update
sys:notice:delete
sys:notice:publish      // 发布
sys:notice:revoke       // 撤销

通配符使用

java
// 资源级别通配
sys:user:*              // 用户模块所有权限

// 模块级别通配
sys:*:*                 // 系统模块所有权限

// 超级管理员
*:*:*                   // 所有权限

错误码规范

设计原则

参考《阿里巴巴 Java 开发手册》错误码规范:

  1. 快速溯源:通过错误码快速定位错误来源
  2. 简单易记:5 位字符串,易于记忆和比对
  3. 沟通标准化:脱离文档也能准确沟通

错误码结构

错误来源(1位)+ 数字编号(4位)
来源前缀说明
用户端错误A参数错误、认证失败、权限不足等
系统错误B系统超时、内部异常等
第三方服务C数据库、中间件、外部 API 等

号段划分

号段分类示例
A0001一级宏观用户端错误
A0100二级宏观用户注册错误
A01xx三级细分A0101 用户未同意协议
A0200二级宏观用户登录异常
A02xx三级细分A0230 Token 无效

常用错误码

错误码说明场景
00000成功正常执行
A0001用户端错误一级宏观
A0200用户登录异常登录失败
A0230Token 无效或过期认证失败
A0301访问未授权权限不足
A0400请求参数错误参数校验失败
A0506请勿重复提交防重复提交
B0001系统执行出错一级宏观
C0001第三方服务出错一级宏观

使用示例

java
// 定义业务异常
public class BusinessException extends RuntimeException {
    private final IResultCode resultCode;

    public BusinessException(ResultCode resultCode) {
        super(resultCode.getMsg());
        this.resultCode = resultCode;
    }
}

// 使用示例
public void saveUser(UserForm form) {
    if (userRepository.existsByUsername(form.getUsername())) {
        throw new BusinessException(ResultCode.USER_REQUEST_PARAMETER_ERROR);
    }
    // ...
}

// 响应格式
{
    "code": "A0400",
    "msg": "用户请求参数错误",
    "data": null
}

排序字段规范

字段命名

字段名类型说明
sortint排序号(升序,值越小越靠前)
create_timedatetime创建时间(降序)
update_timedatetime更新时间(降序)

排序规则

java
// ✅ 推荐:先按 sort 升序,再按创建时间降序
lambdaQuery()
    .orderByAsc(Entity::getSort)
    .orderByDesc(Entity::getCreateTime)
    .list();

// 示例:角色列表排序
lambdaQuery()
    .orderByAsc(Role::getSort)
    .orderByDesc(Role::getCreateTime)
    .orderByDesc(Role::getUpdateTime)
    .list();

// 示例:菜单列表排序
lambdaQuery()
    .orderByAsc(Menu::getSort)
    .list();

默认排序

业务场景默认排序
列表查询sort ASC, create_time DESC
树形结构sort ASC
日志记录create_time DESC

代码注释规范

类注释

java
/**
 * 用户业务实现类
 *
 * @author Ray.Hao
 * @since 2022/1/14
 */
@Service
public class UserServiceImpl implements UserService {
    // ...
}

方法注释

java
/**
 * 获取用户分页列表
 *
 * @param queryParams 查询参数
 * @return {@link IPage<UserPageVO>} 用户分页列表
 */
@Override
public IPage<UserPageVO> getUserPage(UserQuery queryParams) {
    // ...
}

/**
 * 新增用户
 *
 * @param userForm 用户表单对象
 * @return {@link Boolean} 是否新增成功
 */
@Override
public boolean saveUser(UserForm userForm) {
    // ...
}

字段注释

java
public class User {
    /** 用户ID */
    private Long id;

    /** 用户名 */
    private String username;

    /** 用户状态:1-启用,0-禁用 */
    private Integer status;
}

参数校验规范

Bean Validation

java
@Data
public class UserForm {
    @NotBlank(message = "用户名不能为空")
    @Size(min = 2, max = 20, message = "用户名长度为2-20个字符")
    private String username;

    @NotBlank(message = "密码不能为空")
    @Size(min = 6, max = 20, message = "密码长度为6-20个字符")
    private String password;

    @Email(message = "邮箱格式不正确")
    private String email;

    @Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确")
    private String mobile;
}

Controller 校验

java
@PostMapping
public Result<Void> saveUser(@RequestBody @Valid UserForm form) {
    // 参数校验通过后执行业务逻辑
    return Result.judge(userService.saveUser(form));
}

Service 校验

java
public boolean saveUser(UserForm form) {
    // 业务校验
    if (userRepository.existsByUsername(form.getUsername())) {
        throw new BusinessException("用户名已存在");
    }

    // 执行保存
    User user = userConverter.toEntity(form);
    return this.save(user);
}

日志规范

日志级别

级别场景
ERROR错误信息,需要立即处理
WARN警告信息,可能存在问题
INFO关键流程信息
DEBUG调试信息

日志格式

java
// ✅ 推荐:使用占位符
log.info("用户登录成功:userId={}, username={}", userId, username);
log.error("用户登录失败:username={}, reason={}", username, e.getMessage(), e);

// ❌ 不推荐:字符串拼接
log.info("用户登录成功:userId=" + userId);

敏感信息脱敏

java
// ✅ 推荐:敏感信息脱敏
log.info("用户登录:mobile={}", maskMobile(mobile));

// ❌ 不推荐:打印敏感信息
log.info("用户登录:password={}", password);

最佳实践

避免魔法值

java
// ❌ 不推荐
if (user.getStatus() == 1) { }

// ✅ 推荐:使用枚举
if (Objects.equals(user.getStatus(), UserStatusEnum.ENABLED.getValue())) { }

// ✅ 推荐:使用常量
public class UserConstants {
    public static final int STATUS_ENABLED = 1;
    public static final int STATUS_DISABLED = 0;
}

集合判空

java
// ❌ 不推荐
if (list.size() > 0) { }

// ✅ 推荐
if (CollectionUtil.isNotEmpty(list)) { }

字符串判空

java
// ❌ 不推荐
if (str != null && str.length() > 0) { }

// ✅ 推荐
if (StrUtil.isNotBlank(str)) { }

避免 NPE

java
// ❌ 不推荐
return user.getUsername().equals("admin");

// ✅ 推荐
return Objects.equals(user.getUsername(), "admin");

// ✅ 推荐:使用 Optional
return Optional.ofNullable(user)
        .map(User::getUsername)
        .map("admin"::equals)
        .orElse(false);

相关文件

文件说明
core/web/ResultCode.java错误码枚举定义
core/exception/GlobalExceptionHandler.java全局异常处理
common/base/BaseQuery.java查询基类
common/annotation/Log.java操作日志注解
common/annotation/RepeatSubmit.java防重复提交注解

参考文档

基于 MIT 许可发布