Java 后端分层架构详解:从项目结构到 DTO/VO 设计

5 分钟阅读10 次浏览

Java 后端分层架构详解:从项目结构到 DTO/VO 设计

在 Spring Boot 项目中,合理的包结构和分层设计是保证代码可维护性、可扩展性的基础。本文详细介绍一个常见的 Java 后端项目结构,并逐一说明各层的职责与调用规则,同时解释 DTO 和 VO 存在的必要性。

1. 项目初始化结构

一个典型的 Spring Boot 项目包结构如下:

com.公司名.项目名/
├── UserApplication.java        # 启动类(放最外层)
├── config/            # 配置类:MyBatis、Redis、跨域、线程池等
├── controller/        # 控制器 → 接收前端请求
├── service/           # 业务逻辑
│   └── impl/          # 业务实现类
├── mapper/            # 数据库操作接口(MyBatis-Plus Mapper)
├── entity/            # 实体类 
├── dto/               # 前端传过来的数据封装
├── vo/                # 返回给前端的数据封装
├── common/            # 公共工具
│   ├── result/        # 统一返回结果
│   └── exception/     # 全局异常
└── util/              # 工具类

按功能可将它们归纳为:

  • common → 公共工具、全局对象
  • config → 项目配置
  • controller → 接口入口
  • entity → 数据库实体
  • exception → 异常处理
  • service → 业务逻辑
  • mapper → 数据库操作

2. 各层详细说明

2.1 common(公共核心层)

用途:存放项目通用工具类、统一返回结构、分页对象、请求包装类等。

示例类

  • BaseResponse — 统一返回结果
  • DeleteRequest — 删除请求包装
  • PageRequest — 分页参数
  • ResultUtils — 统一返回工具

为什么放这里?
这些类属于整个项目全局共享的工具或包装对象,不属于 controller、service、mapper 的任何一层,是项目的“公共组件”。

2.2 config(配置层)

用途:所有配置类统一放置,Spring Boot 启动时会扫描 @Configuration 注解并加载。

示例类

  • CorsConfig — 跨域配置
  • MyBatisPlusConfig — 分页插件
  • RedisConfig — Redis 序列化
  • SecurityConfig — 安全认证
  • ThreadPoolConfig — 线程池配置

将配置单独分包,结构清晰,便于团队维护。

2.3 exception(异常层)

用途:统一异常处理、定义业务异常与错误码,并提供异常抛出工具。

示例类

  • BusinessException — 业务异常
  • ErrorCode — 错误码枚举
  • GlobalExceptionHandler — 全局异常处理器
  • ThrowUtils — 异常抛出工具

典型调用流程

  1. 业务逻辑中抛出自定义 BusinessException
  2. GlobalExceptionHandler 捕获
  3. 返回统一格式 BaseResponse(code, msg) 给前端

前三层(common、config、exception)基本属于一次编写、永久复用的基础设施。

2.4 controller(控制层)

用途:接收 HTTP 请求,调用 service 层,将结果返回给前端。

示例类

  • MainController
  • TestController

典型功能

  • 映射请求路径:@GetMapping("/user/list")
  • 接收 DTO 参数:UserDTO
  • 返回 VO 封装:BaseResponse<UserVO>

作为第一层入口,controller 必须存在,且只负责协调,不包含业务逻辑。

2.5 entity(实体层)

用途:对应数据库表的 Java 对象,用作 ORM 映射(MyBatis-Plus),字段与表列一一对应。

示例类

  • User.java
  • Order.java
  • Product.java

实体类只用作数据载体,不参与业务逻辑。

2.6 dto(数据传输对象,前端→后端)

用途:仅接收前端传递的少数几个字段,封装成对象传递给后端。

结构示例

com.kxy.aicontextgenerater
    ├── dto
    │   ├── UserLoginDTO.java
    │   ├── UserRegisterDTO.java
public class UserLoginDTO {
    private String username;
    private String password;
}
// 只接收前端必要的两个字段

为什么需要 DTO?
假设 User 实体包含 idusernamepasswordphonecreateTimeupdateTime 等字段,但用户登录时前端只需传 usernamepassword。直接用实体接收会有以下问题:

  • 字段过多,容易暴露数据库结构
  • 增加安全隐患
  • 不符合单一职责原则

DTO 完美解决了这些痛点,只定义接口真正需要的字段。

2.7 vo(视图对象,后端→前端)

用途:专门封装要返回给前端展示的数据,过滤敏感字段,定制数据结构。

结构示例

  • vo/UserLoginVO.java — 登录成功后返回的用户信息

特点

  • 由后端处理完数据后构建
  • 仅包含前端需要展示的字段
  • 绝不含密码等敏感信息
  • 不对应数据库表,只用于接口响应

2.8 service(业务逻辑层)

用途:实现核心业务逻辑,定义接口与实现类。

结构

  • service/UserService.java — 接口
  • service/impl/UserServiceImpl.java — 实现

负责

  • 用户注册逻辑
  • 登录校验
  • 权限判断
  • 数据计算
  • 调用 mapper 完成数据读写

2.9 mapper(数据访问层)

用途:直接与数据库交互,执行增删改查 SQL 操作。

结构

  • mapper/UserMapper.java — 接口,继承 MyBatis-Plus 基类

特点

  • 继承框架父接口,自带通用 CRUD 方法
  • 自定义 SQL 方法只写数据读写
  • 绝不包含业务逻辑
  • 只被 Service 层调用,不直接对接 Controller

3. 调用红线规则

为保证架构清晰,必须严格遵守以下调用约束:

  1. Controller 只能调用 Service
    绝不允许 Controller 直接调用 Mapper 或操作数据库。

  2. Service 只能调用 Mapper
    业务层只负责逻辑编排,数据操作全委托给 Mapper。

  3. Mapper 只与数据库、Entity 交互
    不编写业务逻辑,不被 Controller 直接使用。

  4. Entity 只是数据载体
    不主动调用其他任何层,仅在各层间传递。

  5. common / config / exception 是全局基础设施
    所有层都可以随时使用,属于项目底层地基,不在主业务调用链路中。

4. 实体类设计(第二步)

在搭建好项目结构后,接下来进入具体的实体类编写……

(后续内容待补充)

评论

加载评论中...