不灭的焱

革命尚未成功,同志仍须努力 下载Java

作者:AlbertWen  添加时间:2026-03-10 11:48:48  修改时间:2026-03-10 17:58:27  分类:01.AI编程  编辑

AI学习 Java后端编码规范

更新时间:2026-03-10

结论:这个仓库的 Java 后端开发已经形成了比较明确的固定套路。下次继续写后端代码时,默认按“模块化目录 + DTO 入出参 + R<T> 统一返回 + Service 承载业务 + MyBatis-Flex 承载单表 ORM + XML 承载复杂 SQL + BusinessException 承载业务异常”的方式执行。

1. 当前项目的总规则

1.1 根包名

  • 根包名统一为:com.fuyo.dic

1.2 模块化组织

系统按模块拆分,当前典型模块有:

  • fuyo-common
  • fuyo-framework
  • fuyo-ccc-bos
  • fuyo-launch

业务代码主要集中在 fuyo-common

1.3 每个业务模块的标准目录

由代码生成器和当前工程实践共同决定,标准目录基本如下:

com.fuyo.dic.{module}/
├── controller/
├── entity/
│   └── table/
├── mapper/
├── service/
│   └── impl/
├── dto/
│   ├── req/
│   └── resp/
└── enums/

结论:

  • 新模块优先沿用这套目录,不要随意发明新层次
  • dto/reqdto/resp 是项目当前明确在用的结构,不要省略

2. 资源文件规范

  • Mapper.xml 统一放在 resources/mapper/
  • 命名规则统一是:XxxMapper.xml

当前例子:

  • fuyo-common/src/main/resources/mapper/SysUserMapper.xml
  • fuyo-common/src/main/resources/mapper/SysRoleMapper.xml

结论:

  • Mapper 接口在 java/.../mapper
  • SQL 文件在 resources/mapper
  • 不要把 XML 混进 java 目录

3. Controller 规范

3.1 基本形态

当前项目里的标准 Controller 写法大致如下:

@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping(UrlConfig.API_SYSTEM_MENU)
public class MenuController {

    private final SysMenuService sysMenuService;

    @SaCheckLogin
    @GetMapping
    public R<List<MenuPageResp.MenuItem>> list(MenuPageReq req) {
        log.info("获取菜单搜索列表:req={}", req);
        return R.ok(sysMenuService.list(req));
    }
}

3.2 必备注解

默认优先使用:

  • @Slf4j
  • @RestController
  • @RequiredArgsConstructor
  • @RequestMapping
  • @GetMapping / @PostMapping / @PutMapping / @DeleteMapping

3.3 登录校验

项目规范是:

  • 受保护接口默认加 @SaCheckLogin
  • 认证类开放接口例外,例如验证码、登录接口

真实例子:

  • AuthController.getCaptcha() 没有 @SaCheckLogin
  • AuthController.login() 没有 @SaCheckLogin
  • 其他受保护接口普遍有 @SaCheckLogin

结论:

  • 不要机械地给所有接口都加 @SaCheckLogin
  • 规则应该写成:默认需要登录校验,认证入口例外

3.4 控制器返回值

控制器层统一返回 R<T>

当前项目实际用法:

  • 返回数据:R.ok(data)
  • 返回消息:R.ok("操作成功")
  • 返回消息 + 数据:R.ok("登录成功", data)
  • 返回失败:R.error("操作失败")

示例:

public R<Object> add(@Valid @RequestBody AddMenuReq req) {
    sysMenuService.add(req);
    return R.ok("操作成功");
}

结论:

  • Controller 不直接返回裸对象
  • 删除、新增、修改这类无数据返回场景,统一用 R<Object>R<String>
  • 如果不确定泛型,按项目约定可以使用 Object

3.5 路由定义方式

项目明确要求类级主路由写在 UrlConfig 中。

真实做法:

  • @RequestMapping(UrlConfig.API_SYSTEM_MENU)
  • @GetMapping(UrlConfig.auth_captcha) 这类认证接口也直接复用常量

结论:

  • 不要在 Controller 里硬编码 /api/system/xxx
  • 先去 UrlConfig.java 增加或复用路由常量

4. DTO 规范

4.1 请求 DTO

请求对象统一放 dto/req

典型命名:

  • AddMenuReq
  • UpdateMenuReq
  • MenuPageReq
  • LoginReq

4.2 响应 DTO

响应对象统一放 dto/resp

典型命名:

  • MenuPageResp
  • UserPageResp
  • RolePageResp
  • LoginResp

4.3 DTO 命名约定

默认使用:

  • 新增:AddXxxReq
  • 修改:UpdateXxxReq
  • 分页/查询:XxxPageReq
  • 列表/分页返回:XxxPageResp
  • 特殊业务返回:XxxResp

4.4 嵌套 DTO

当前项目已大量使用内部静态类承载子项:

  • MenuPageResp.MenuItem
  • UserPageResp.UserItem
  • UserPageResp.RoleInfo

结论:

  • 如果响应结构天然是“列表主体 + 子项”,优先用内部静态类
  • 不要随意把一个页面返回拆成过多零散类

5. 参数校验规范

5.1 控制器入参

Controller 层统一优先使用 @Valid

例如:

public R<Object> add(@Valid @RequestBody AddMenuReq req)

5.2 DTO 字段校验

当前项目已实际使用:

  • @NotBlank
  • @NotNull

例如:

@NotBlank(message = "用户名不能为空")
private String username;

5.3 全局校验异常处理

项目已经有统一异常处理:

  • MethodArgumentNotValidException
  • BindException

位置:

  • fuyo-framework/src/main/java/com/fuyo/dic/framework/exception/GlobalExceptionHandler.java

结论:

  • 参数校验失败会自动转成统一 R.error(400, message)
  • Controller 不要自己手写重复的参数错误处理

5.4 实际落地提醒

虽然规范要求明确,但当前代码里个别字段校验还不完整,比如有些 @NotNull 被注释掉了。

结论:

  • 下次新写代码时按规范补齐校验
  • 如果改旧代码,优先保持兼容,不要盲目一次性收紧所有老接口校验

6. Service 规范

6.1 Service 接口职责

Service 接口层只定义业务方法,不放实现。

当前典型形态:

public interface SysUserService extends IService<SysUser> {
    UserPageResp page(UserPageReq req);
    void add(AddUserReq req);
    void update(UpdateUserReq req);
}

结论:

  • 接口负责暴露业务能力
  • 具体实现放到 service/impl

6.2 Service 实现层职责

ServiceImpl 承担:

  • 业务规则校验
  • 数据库操作
  • 多表数据组装
  • 事务控制
  • 日志记录

当前典型注解组合:

  • @Slf4j
  • @Service
  • @RequiredArgsConstructor

6.3 事务规范

凡是数据库写操作,默认加:

@Transactional(rollbackFor = Exception.class)

适用场景:

  • 新增
  • 修改
  • 删除
  • 重置密码
  • 多表关系维护

结论:

  • 纯查询一般不加事务
  • 只要跨多步写操作,默认上事务

6.4 ServiceImpl 内部的编码习惯

从当前代码看,默认模式是:

  1. log.info 打入口日志
  2. 做业务校验
  3. 调 ORM / Mapper
  4. 失败抛 BusinessException
  5. 成功打结果日志

例如:

  • SysUserServiceImpl
  • SysRoleServiceImpl
  • SysMenuServiceImpl

7. 数据访问规范

7.1 优先使用 MyBatis-Flex Service API

项目明确约定:

  • 优先使用 MyBatis-Flex 提供的 ServiceImpl / IService 能力
  • 常规 CRUD、条件查询、分页查询,优先不要直接手写 Mapper 调用

本项目常用 API:

  • save
  • saveBatch
  • getById
  • getOne
  • list
  • count
  • updateById
  • remove
  • page

7.2 QueryWrapper 的使用边界

适用场景:

  • 单表查询
  • 动态条件拼装
  • 唯一性校验
  • 逻辑删除过滤

7.3 XML SQL 的使用边界

复杂多表 Join 查询时,优先使用 Mapper XML。

真实例子:

  • SysUserMapper + SysUserMapper.xml

这类场景通常包括:

  • 连表分页
  • DTO 投影
  • 批量附加关联信息
  • 复杂字段格式化

结论:

  • 不要为了追求“全用 Flex”而把复杂 SQL 写得很难维护
  • 单表 Flex,复杂查询 XML,这就是本项目的真实规范

8. Mapper 规范

8.1 基本形式

@Mapper
public interface XxxMapper extends BaseMapper<XxxEntity> {
}

8.2 自定义方法

如果有复杂 SQL,可以在 Mapper 中声明方法,并在 XML 中实现。

例如:

  • selectUserPageList
  • selectUserCount
  • selectUserRolesList

8.3 参数传递

多参数或复杂参数时,使用 @Param

结论:

  • 简单 CRUD 靠 BaseMapper
  • 复杂查询通过 Mapper 自定义方法 + XML

9. 异常处理规范

9.1 业务异常

业务异常统一抛:

  • BusinessException

不要在 Service 里随便返回 "失败"false 来表达业务错误。

典型写法:

if (existUser != null) {
    throw new BusinessException("用户名已存在");
}

9.2 全局异常处理

项目已统一处理:

  • BusinessException
  • NotLoginException
  • NotPermissionException
  • NotRoleException
  • 参数校验异常
  • 其他系统异常

结论:

  • Controller 和 Service 不要重复 try-catch 这些常规业务异常
  • 非特殊情况,抛出去交给全局异常处理器

10. 日志规范

当前项目主风格:

  • Controller 和 ServiceImpl 普遍使用 @Slf4j
  • 方法入口打印关键参数
  • 成功后打印关键结果
  • 异常不在业务层重复吞掉

推荐写法:

log.info("添加用户:req={}", req);
log.info("添加用户成功:userId={}, username={}", user.getId(), user.getUsername());

结论:

  • 日志重点放业务动作和关键主键
  • 注意不要打印敏感信息,如明文密码

11. 实体类规范

当前实体的主流风格是:

  • @Data
  • @Builder
  • @NoArgsConstructor
  • @AllArgsConstructor
  • @Table("table_name")
  • @Id(keyType = KeyType.Auto)
  • @Serial

字段要求:

  • 每个字段写中文注释
  • 表字段与 Java 字段按当前项目约定映射

结论:

  • 新实体优先沿用代码生成产物风格
  • 不要随意切换成另一套实体编码风格

12. 命名规范

当前项目推荐命名:

  • Controller:XxxController
  • Service:XxxService
  • ServiceImpl:XxxServiceImpl
  • Mapper:XxxMapper
  • Entity:Xxx
  • Req DTO:AddXxxReq / UpdateXxxReq / XxxPageReq
  • Resp DTO:XxxResp / XxxPageResp

结论:

  • 命名尽量贴业务语义
  • 不要出现 TestControllerTempService 这类临时命名进入正式代码

13. 一个标准后端接口的开发顺序

下次新增一个业务接口,默认按这个顺序:

  1. UrlConfig 增加路由常量
  2. 新建或补充 dto/reqdto/resp
  3. 在 Controller 中定义接口,返回 R<T>
  4. Controller 上加 @SaCheckLogin,认证开放接口除外
  5. 入参加 @Valid
  6. 在 Service 接口定义方法
  7. 在 ServiceImpl 实现业务逻辑
  8. 常规查询优先 MyBatis-Flex Service API
  9. 复杂 Join 查询补 Mapper XML
  10. 写操作方法加 @Transactional
  11. 业务错误抛 BusinessException

14. 当前仓库下次直接复用的默认动作

如果下次让我继续写 Java 后端代码,我默认遵守这些动作:

  • 路由先看 UrlConfig
  • 入参先建 dto/req
  • 出参先建 dto/resp
  • Controller 统一返回 R<T>
  • 默认加 @SaCheckLogin,登录/验证码等开放接口除外
  • 默认加 @Valid
  • 业务逻辑写进 ServiceImpl
  • 写操作默认加 @Transactional
  • ORM 优先走 MyBatis-Flex
  • 多表复杂查询优先 XML
  • 业务错误统一抛 BusinessException

15. 容易踩坑的地方

  • 在 Controller 里直接写业务逻辑
  • 路由写死字符串,不走 UrlConfig
  • 直接返回裸对象,不包 R<T>
  • 忘记给写操作加事务
  • 忘记给受保护接口加 @SaCheckLogin
  • 登录/验证码接口误加 @SaCheckLogin
  • DTO 不分 req/resp,导致接口层混乱
  • 能用 Service API 的地方反而直接乱调 Mapper
  • 复杂 Join 还硬写在 QueryWrapper 里
  • 业务异常不用 BusinessException

16. 一句话心智模型

这个项目的 Java 后端编码规范,本质上是在强调“分层清晰、边界明确、风格统一”:Controller 负责接入和返回,ServiceImpl 负责业务,MyBatis-Flex 负责常规 ORM,XML 负责复杂 SQL,R<T> 负责统一响应,BusinessException 负责统一业务失败。