Java 后端分层架构详解:从项目结构到 DTO/VO 设计
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— 异常抛出工具
典型调用流程:
- 业务逻辑中抛出自定义
BusinessException GlobalExceptionHandler捕获- 返回统一格式
BaseResponse(code, msg)给前端
前三层(common、config、exception)基本属于一次编写、永久复用的基础设施。
2.4 controller(控制层)
用途:接收 HTTP 请求,调用 service 层,将结果返回给前端。
示例类:
MainControllerTestController
典型功能:
- 映射请求路径:
@GetMapping("/user/list") - 接收 DTO 参数:
UserDTO - 返回 VO 封装:
BaseResponse<UserVO>
作为第一层入口,controller 必须存在,且只负责协调,不包含业务逻辑。
2.5 entity(实体层)
用途:对应数据库表的 Java 对象,用作 ORM 映射(MyBatis-Plus),字段与表列一一对应。
示例类:
User.javaOrder.javaProduct.java
实体类只用作数据载体,不参与业务逻辑。
2.6 dto(数据传输对象,前端→后端)
用途:仅接收前端传递的少数几个字段,封装成对象传递给后端。
结构示例:
com.kxy.aicontextgenerater
├── dto
│ ├── UserLoginDTO.java
│ ├── UserRegisterDTO.java
public class UserLoginDTO {
private String username;
private String password;
}
// 只接收前端必要的两个字段
为什么需要 DTO?
假设 User 实体包含 id、username、password、phone、createTime、updateTime 等字段,但用户登录时前端只需传 username 和 password。直接用实体接收会有以下问题:
- 字段过多,容易暴露数据库结构
- 增加安全隐患
- 不符合单一职责原则
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. 调用红线规则
为保证架构清晰,必须严格遵守以下调用约束:
-
Controller 只能调用 Service
绝不允许 Controller 直接调用 Mapper 或操作数据库。 -
Service 只能调用 Mapper
业务层只负责逻辑编排,数据操作全委托给 Mapper。 -
Mapper 只与数据库、Entity 交互
不编写业务逻辑,不被 Controller 直接使用。 -
Entity 只是数据载体
不主动调用其他任何层,仅在各层间传递。 -
common / config / exception 是全局基础设施
所有层都可以随时使用,属于项目底层地基,不在主业务调用链路中。
4. 实体类设计(第二步)
在搭建好项目结构后,接下来进入具体的实体类编写……
(后续内容待补充)
评论
加载评论中...