关于 best-java-structure
best-java-structure 是面向 Java 团队的 Spring Boot 与 MyBatis-Plus 分层架构设计指南,适用于新建、重构和评审项目。它以五层结构说明职责边界、依赖方向和数据传递规范。
主要功能
- 01说明经典五层架构职责
- 02规定单向依赖与接口抽象
- 03指导 DTO、VO 与 Entity 传递
- 04涵盖异常处理与事务边界
- 05列出跨层调用常见问题
适用场景
- 01规划新的 Java Web 项目结构
- 02重构多模块 Java 系统
- 03在代码评审中检查架构规范
- 04制定团队分层开发标准
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ chasepassion/ skills --skill best-java-structure安装后在 Claude Code 中输入/best-java-structure确认已加载。
详细介绍
Java 分层架构设计模式(Spring Boot + MyBatis-Plus)
使用 Spring Boot 和 MyBatis-Plus 实现经典五层架构的实用指南。
适用场景
在以下场景中使用此技能:
- 创建新的 Java Web 项目
- 重构现有项目架构
- 设计多模块 Java 系统
- 在代码审查期间检查架构合规性
- 为团队开发制定架构标准
- 数据库迁移或技术栈迁移
假设
- Spring Boot 3.x
- 使用 MyBatis-Plus 进行数据访问
- 在 API 边界进行 DTO/VO 分离
快速参考
| 优先级 | 类别 | 影响范围 | 前缀 |
|---|---|---|---|
| 1 | 关注点分离 | 架构清晰度 | -principle- |
| 2 | 单向依赖 | 依赖管理 | -dependency- |
| 3 | 接口抽象 | 可替换性 | -abstraction- |
| 4 | 数据传输 | API 一致性 | -data- |
| 5 | 异常处理 | 错误处理 | -exception- |
| 6 | 跨层调用 | 架构合规性 | -crosslayer- |
| 7 | 反向依赖 | 架构合规性 | -reverse- |
| 8 | 实体暴露 | 安全性 | -entity-exposure- |
核心原则
1. 关注点分离(SoC)
每一层都应解决一类问题,且不得承担属于其他层的职责。
// Correct: clear responsibilities per layer
// Presentation layer: HTTP handling only
@RestController
public class ProjectController {
private final ProjectService projectService;
public ProjectController(ProjectService projectService) {
this.projectService = projectService;
}
@GetMapping("/{id}")
public ApiReturn<ProjectVo> getProject(@PathVariable Long id) {
Project project = projectService.getProject(id);
ProjectVo vo = new ProjectVo();
BeanUtils.copyProperties(project, vo);
return ApiReturn.of(vo);
}
}
// Business logic layer: business rules only
@Service
public class ProjectService {
private final ProjectMapper projectMapper;
public ProjectService(ProjectMapper projectMapper) {
this.projectMapper = projectMapper;
}
public Project getProject(Long id) {
Project project = projectMapper.selectById(id);
if (project == null) {
throw new BusinessException(404, "Project does not exist");
}
return project;
}
}
// Data access layer: data interfaces only
public interface ProjectMapper extends BaseMapper<Project> {
}
2. 单向依赖
上层可以调用下层,但下层不得依赖上层。
// Correct: depend on a lower layer abstraction
@Service
public class ProjectService {
private final ProjectMapper projectMapper;
public ProjectService(ProjectMapper projectMapper) {
this.projectMapper = projectMapper;
}
}
// Incorrect: cross-layer invocation
@RestController
public class ProjectController {
private final ProjectMapper projectMapper;
public ProjectController(ProjectMapper projectMapper) {
this.projectMapper = projectMapper;
}
}
3. 接口抽象
各层应通过接口交互,而非具体实现。
// Correct: mapper interface managed by MyBatis-Plus
public interface ProjectMapper extends BaseMapper<Project> {
}
// Incorrect: depending on a non-existent implementation class
public class ProjectService {
private ProjectMapperImpl projectMapperImpl;
}
架构分层
经典五层架构
Presentation Layer → Business Logic Layer → Data Access Layer → Persistence Layer → Database Layer
| 层 | Spring 技术栈 | 常用名称 | 核心职责 |
|---|---|---|---|
| 表示层 | @Controller | Controller、API | 处理 HTTP 请求和响应 |
| 业务逻辑层 | @Service | Service | 实现业务规则和工作流 |
| 数据访问层 | @Mapper | Mapper、DAO | 定义数据库访问接口 |
| 持久化层 | MyBatis XML、Entity | Mapper XML、Entity | SQL 映射和实体定义 |
| 数据库层 | MySQL | 数据库 | 存储和检索数据 |
各层定义
表示层
职责:
- 处理 HTTP 请求和响应
- 接收并校验参数
- 路由和分发
- 数据格式转换(DTO ↔ Entity ↔ VO)
- 异常处理和 HTTP 状态映射 模板:
@RestController
@RequestMapping("/api/projects")
public class ProjectController {
private final ProjectService projectService;
public ProjectController(ProjectService projectService) {
this.projectService = projectService;
}
@GetMapping("/{id}")
public ApiReturn<ProjectVo> getProject(@PathVariable Long id) {
Project project = projectService.getProject(id);
ProjectVo vo = new ProjectVo();
BeanUtils.copyProperties(project, vo);
return ApiReturn.of(vo);
}
@PostMapping
public ApiReturn<ProjectVo> createProject(@Valid @RequestBody ProjectCreateRequest request) {
Project project = new Project();
BeanUtils.copyProperties(request, project);
Project created = projectService.createProject(project);
ProjectVo vo = new ProjectVo();
BeanUtils.copyProperties(created, vo);
return ApiReturn.of(vo);
}
}
设计说明:
- 保持精简:仅处理与 HTTP 相关的逻辑
- 使用 DTO/VO 传输数据
- 通过 Bean Validation 和全局异常处理集中进行校验
- 不包含业务逻辑
- 不直接访问数据库
业务逻辑层
职责:
- 实现业务规则和工作流
- 数据校验和业务检查
- 授权和访问控制
- 事务管理(事务边界位于此层)
- 协调多个服务和 Mapper
- 调用数据访问层 模板:
@Service
public class ProjectService {
private final ProjectMapper projectMapper;
public ProjectService(ProjectMapper projectMapper) {
this.projectMapper = projectMapper;
}
public Project getProject(Long id) {
if (id == null || id <= 0) {
throw new BusinessException(400, "Invalid project ID");
}
Project project = projectMapper.selectById(id);
if (project == null) {
throw new BusinessException(404, "Project does not exist");
}
return project;
}
@Transactional
public Project createProject(Project project) {
if (project.getCustomerId() == null) {
throw new BusinessException(400, "Customer ID must not be null");
}
project.setCreatedTime(LocalDateTime.now());
project.setStatus(ProjectStatus.CREATED);
projectMapper.insert(project);
return project;
}
}
设计说明:
- 包含核心业务逻辑
- 使用
@Transactional管理事务 - 执行业务校验
- 编排多个服务和 Mapper
- 不处理 HTTP 相关问题
- 不直接处理数据库连接
- Service 不应返回 DTO(DTO 是输入模型)。应统一返回 Entity/Domain 或 VO。
数据访问层(MyBatis-Plus)
职责:
- 定义数据库访问接口
- 提供 CRUD 抽象
- 封装持久化细节
- 在需要时提供聚合查询接口 模板:
public interface ProjectMapper extends BaseMapper<Project> {
}
设计说明:
- 仅定义接口,不提供具体实现
- 方法名称清晰表达意图
- 此处不编写 SQL 语句(复杂 SQL 使用 XML)
- 不包含业务逻辑
- 不管理事务
- 不得依赖 Service 层
持久化层
职责:
- SQL 映射和结果映射
- 实体定义
- 数据库专用 SQL 片段(需要时) 模板(MyBatis-Plus XML):
<mapper namespace="com.example.mapper.ProjectMapper">
<select id="selectActive" resultType="com.example.entity.Project">
SELECT * FROM project WHERE status = 'CREATED'
</select>
</mapper>
设计说明:
- 专注于 SQL 编写和优化
- 结果映射和类型转换
- 使用 SQL 片段提高复用性
- 不包含业务逻辑
- 不包含业务校验
- 连接管理和事务边界由 Spring 和 DataSource 处理
数据库层
职责:
- 持久化存储
- 数据完整性约束
- 索引和性能优化
- 事务支持 模板(MySQL):
CREATE TABLE project (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
created_time DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
customer_id BIGINT NOT NULL,
status VARCHAR(50) DEFAULT 'CREATED'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
数据传输模式
使用 DTO、VO 和 Entity
Frontend → Controller → Service → Mapper → Database
DTO Entity Entity
VO Entity
转换示例
@PostMapping("/projects")
public ApiReturn<ProjectVo> createProject(@Valid @RequestBody ProjectCreateRequest request) {
Project project = new Project();
BeanUtils.copyProperties(request, project);
Project created = projectService.createProject(project);
ProjectVo vo = new ProjectVo();
BeanUtils.copyProperties(created, vo);
return ApiReturn.of(vo);
}
异常处理
集中式异常处理
public class BusinessException extends RuntimeException {
private final int code;
public BusinessException(int code, String message) {
super(message);
this.code = code;
}
public int getCode() {
return code;
}
}
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(BusinessException.class)
public ApiReturn<Void> handleBusinessException(BusinessException e) {
return ApiReturn.error(e.getCode(), e.getMessage());
}
@ExceptionHandler(Exception.class)
public ApiReturn<Void> handleException(Exception e) {
return ApiReturn.error(500, "Internal server error");
}
}
事务指南
- 事务边界应属于 Service 方法。
- 对只读查询使用
@Transactional(readOnly = true)。 - 默认在 RuntimeException 时回滚;如需对受检异常回滚,应记录说明。
- 避免在 Controller、Mapper 或 XML 中使用事务。
常见陷阱
陷阱 1:跨层调用
// Incorrect: Controller directly calls Mapper
@RestController
public class ProjectController {
private final ProjectMapper projectMapper;
public ProjectController(ProjectMapper projectMapper) {
this.projectMapper = projectMapper;
}
public List<Project> getProjects() {
return projectMapper.selectList(null);
}
}
陷阱 2:反向依赖
// Incorrect: Service depends on Controller
@Service
public class ProjectService {
private ProjectController projectController;
}
陷阱 3:在 SQL 中编写业务逻辑
<select id="getById" resultMap="BaseResultMap">
SELECT * FROM project
WHERE id = #{id}
AND is_deleted = 0
AND has_permission(#{currentUserId}, id) = 1
</select>
陷阱 4:Controller 直接返回 Entity
// Incorrect: Controller returns Entity directly
@GetMapping("/projects/{id}")
public Project getProject(@PathVariable Long id) {
return projectService.getProject(id);
}
项目结构模板(推荐)
src/main/java/com/xdyai/backend/
controller/
internal/
request/
service/
common/
context/
integration/
mapper/
entity/
enumeration/
src/main/resources/
application.yml
application-dev.yml
mapper/
db/
validation/
integration/
最佳实践摘要
表现层
- 保持精简:仅处理 HTTP 逻辑
- 使用 DTO/VO 传输数据
- 集中式异常处理
- 不包含业务逻辑
- 不直接访问 Mapper
业务逻辑层
- 包含核心业务逻辑
- 使用
@Transactional管理事务 - 编排多个服务
- 不涉及 HTTP
- 不直接处理数据库连接
数据访问层
- 仅定义接口
- 方法命名清晰
- 通过 MyBatis-Plus 执行 CRUD
- 此处不编写 SQL 语句
- 不包含业务逻辑
持久化层
- 专注于 SQL 编写
- 使用 SQL 片段
- 对复杂查询使用动态 SQL
- 不包含业务逻辑
- 不包含业务校验
跨层通信
- Controller ← DTO
- Service ← Entity
- Mapper ← Entity
- Controller ← VO
- 避免跨层调用
- 避免反向依赖
评论
支持 Markdown