mcpField
B
best-java-structure

best-java-structure

github.com/chasepassion开发139 次安装1 周前更新
代码仓库

关于 best-java-structure

best-java-structure 是面向 Java 团队的 Spring Boot 与 MyBatis-Plus 分层架构设计指南,适用于新建、重构和评审项目。它以五层结构说明职责边界、依赖方向和数据传递规范。

主要功能

  1. 01说明经典五层架构职责
  2. 02规定单向依赖与接口抽象
  3. 03指导 DTO、VO 与 Entity 传递
  4. 04涵盖异常处理与事务边界
  5. 05列出跨层调用常见问题

适用场景

  1. 01规划新的 Java Web 项目结构
  2. 02重构多模块 Java 系统
  3. 03在代码评审中检查架构规范
  4. 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 技术栈常用名称核心职责
表示层@ControllerController、API处理 HTTP 请求和响应
业务逻辑层@ServiceService实现业务规则和工作流
数据访问层@MapperMapper、DAO定义数据库访问接口
持久化层MyBatis XML、EntityMapper XML、EntitySQL 映射和实体定义
数据库层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