DukeDuke
主页
关于我们
主页
关于我们
  • 技术文档

    • 网络原理

      • 交换机
      • 路由器
      • TCP/IP协议
      • HTTP 与 HTTPS
    • 软件架构

      • 什么是软件架构
      • 分层架构
      • 微服务架构
      • 事件驱动架构
      • 领域驱动设计(DDD)
      • 架构图
      • 高并发系统
    • Vue3

      • Vue3简介
      • Vue3响应式系统
      • Vue3组合式API
      • Vue3生命周期
      • Vue3模板语法
      • Vue3组件系统
      • Vue3 路由系统
      • Vue3 状态管理
      • Vue3 性能优化
      • Vue3 TypeScript 支持
      • Vue3 项目实战
      • VUE 面试题大全
      • Node.js 安装
    • Python

      • Python简介
      • Python安装
      • Python hello world
      • Python基础语法
      • Python数据类型
      • Python数字
      • Python字符串
      • Python列表
      • Python元组
      • Python字典
      • Python日期时间
      • Python文件操作
      • Python异常处理
      • Python函数
      • Python类
      • Python模块
      • Python包
      • Python多线程
      • Python面向对象
      • Python爬虫
      • Django web框架
      • Python 面试题

        • Python 面试题导航
        • Python 基础概念
        • Python 面向对象编程
        • Python 数据结构
        • Python 高级特性
        • Python 框架
        • Python 性能优化
        • Python 项目经验
    • Spring

      • Spring
      • Springboot
      • Spring Security 安全框架
      • SpringBoot 中的事件详解
      • SpringBoot 中的定时任务详解
      • SpringBoot 自动装配原理与源码解释
    • Mybatis

      • Mybatis
      • Mybatis-Plus
    • 数据库

      • Redis

        • Redis简介
        • Redis(单机)安装
        • Redis配置
        • Redis数据结构
        • RDB、AOF 和混合持久化机制
        • Redis内存管理
        • Redis缓存一致性
        • Redis缓存穿透
        • Redis缓存击穿
        • Redis缓存雪崩
        • Redis Lua脚本
        • Redis主从复制
        • Redis哨兵模式
        • Redis集群
        • Redis数据分片
        • Redis CPU使用率过高
        • Redis面试题
      • MySQL

        • MySQL简介
        • MySQL安装
        • MySQL配置
        • MYSQL日常维护
        • MYSQL优化-慢查询
        • MYSQL优化-索引
        • MYSQL数据库设计规范
    • 消息队列

      • RocketMQ
      • Kafka
      • RabbitMQ
      • 消息队列面试题
    • 微服务

      • SpringCloud 微服务
      • Eureka 注册中心
      • Nacos 注册中心
      • Gateway 网关
      • Feign 服务调用
      • Sentinel 限流 与 熔断
      • Seata 分布式事务
      • CAP 理论
      • Redis 分布式锁
      • 高并发系统设计
    • ELK日志分析系统

      • Elasticsearch 搜索引擎
      • Logstash 数据处理
      • Kibana 可视化
      • ELK 实战
    • 开放API

      • 开放API设计
      • 开放API示例项目
    • 人工智能

      • 人工智能简介
      • 机器学习

      • 深度学习

      • 自然语言处理

      • 计算机视觉

        • CUDA与cuDNN详细安装
        • Conda 安装
        • Pytorch 深度学习框架
        • yolo 目标检测
        • TensorRT 深度学习推理优化引擎
        • TensorFlow 机器学习
        • CVAT 图像标注
        • Windows 下安装 CUDA、cuDNN、TensorRT、TensorRT-YOLO 环境
        • Windows10+CUDA+cuDNN+TensorRT+TensorRT-YOLO 部署高性能YOLO11推理
    • 大数据

      • 大数据简介
      • Hadoop 数据存储
      • Flume 数据采集
      • Sqoop 数据导入导出
      • Hive 数据仓库
      • Spark 数据处理
      • Flink 数据处理
      • Kafka 数据采集
      • HBase 数据存储
      • Elasticsearch 搜索引擎
    • 图像处理

      • 图像处理简介
      • 医学图像web呈现
      • 医学图像处理
      • 切片细胞分离问题
    • 服务器&运维

      • Linux 系统

        • Linux 系统管理
        • Linux 网络管理
        • Linux 文件管理
        • Linux 命令大全
      • Nginx Web 服务器

        • Nginx 安装 与 配置
        • Nginx 负载均衡
        • Nginx SSL证书配置
        • Nginx Keepalived 高可用
      • Docker 容器

        • Docker 简介
        • Docker 安装与配置
        • Docker 命令
        • Docker 部署 Nginx
        • Docker 部署 MySQL
        • Docker 部署 Redis
      • 服务器

        • 塔式服务器
        • 机架式服务器
        • 刀片服务器
      • Git 版本控制
      • Jenkins 持续集成
      • Jmeter 性能测试
      • Let's Encrypt 免费SSL证书
    • 简历

      • 项目经理简历
      • 开发工程师简历

分层架构(Layered Architecture)

什么是分层架构

分层架构(Layered Architecture)是一种将软件系统按照职责划分为多个层次的设计模式。每一层都有明确的职责和边界,上层只能依赖下层,不能反向依赖。这种架构模式通过将系统分解为不同的抽象层次,使得系统更容易理解、开发和维护。

核心思想

分层架构的核心思想是关注点分离(Separation of Concerns)。通过将不同职责的代码分离到不同的层次中,每一层只需要关注自己的职责,不需要了解其他层的实现细节。

主要特点

  1. 层次分明:每一层都有明确的职责和边界,职责单一
  2. 单向依赖:上层只能依赖下层,不能反向依赖,形成清晰的依赖关系
  3. 封装性:每一层都对其上层隐藏实现细节,只暴露必要的接口
  4. 可替换性:每一层都可以被相同接口的其他实现替换,提高系统的灵活性
  5. 可测试性:每一层都可以独立测试,便于单元测试和集成测试

典型分层结构

分层架构通常包含以下三个核心层次:

1. 表现层(Presentation Layer / Controller Layer)

职责:

  • 接收用户请求(HTTP 请求、RPC 调用等)
  • 参数校验和格式化
  • 调用业务逻辑层处理请求
  • 将业务结果转换为响应格式返回给用户
  • 处理异常并返回友好的错误信息

特点:

  • 不包含业务逻辑,只负责请求的接收和响应的返回
  • 可以支持多种表现方式(Web、移动端 API、RPC 接口等)
  • 通常使用 DTO(Data Transfer Object)与业务层交互

常见组件:

  • Controller:处理 HTTP 请求
  • DTO:数据传输对象,用于层间数据传递
  • Validator:参数校验器
  • Exception Handler:异常处理器

2. 业务逻辑层(Business Logic Layer / Service Layer)

职责:

  • 实现核心业务规则和业务逻辑
  • 协调多个数据访问层的操作
  • 处理业务异常和业务校验
  • 事务管理
  • 调用外部服务(如第三方 API、消息队列等)

特点:

  • 不依赖具体的数据库实现,只依赖数据访问层的接口
  • 包含系统的核心业务逻辑,是最重要的一层
  • 可以调用多个 Repository 完成复杂的业务操作
  • 通常使用领域模型(Entity/Domain Model)进行业务处理

常见组件:

  • Service Interface:服务接口定义
  • Service Implementation:服务实现类
  • Domain Model:领域模型(业务实体)
  • Business Exception:业务异常

3. 数据访问层(Data Access Layer / Repository Layer)

职责:

  • 封装数据库操作(增删改查)
  • 管理数据库连接和事务
  • 提供数据持久化接口
  • 处理数据访问异常

特点:

  • 隐藏数据库的具体实现细节(SQL、ORM 框架等)
  • 为业务层提供统一的数据访问接口
  • 可以切换不同的数据库或 ORM 框架而不影响业务层
  • 通常使用 Entity 或 DO(Data Object)表示数据库实体

常见组件:

  • Repository Interface:数据访问接口
  • Repository Implementation:数据访问实现(通常由 ORM 框架自动生成)
  • Entity/DO:数据库实体对象
  • Mapper:MyBatis 的 Mapper 接口

分层架构的包结构

标准包结构图

com.example.project
│
├── controller                    # 表现层
│   ├── UserController           # 用户控制器
│   ├── OrderController          # 订单控制器
│   └── ...
│
├── service                       # 业务逻辑层
│   ├── UserService              # 用户服务接口
│   ├── impl                     # 服务实现
│   │   ├── UserServiceImpl
│   │   └── OrderServiceImpl
│   └── ...
│
├── repository                    # 数据访问层
│   ├── UserRepository           # 用户数据访问接口
│   ├── OrderRepository          # 订单数据访问接口
│   └── ...
│
├── model                         # 数据模型
│   ├── entity                   # 实体类(对应数据库表)
│   │   ├── User
│   │   └── Order
│   ├── dto                       # 数据传输对象
│   │   ├── UserDTO
│   │   └── OrderDTO
│   └── vo                        # 视图对象
│       └── UserVO
│
├── config                        # 配置类
│   ├── DatabaseConfig
│   ├── RedisConfig
│   └── ...
│
├── exception                     # 异常处理
│   ├── BusinessException
│   ├── GlobalExceptionHandler
│   └── ...
│
└── util                          # 工具类
    ├── DateUtil
    └── ...

详细包结构说明

1. Controller 层(表现层)

controller/
├── UserController.java          # 用户相关接口
├── OrderController.java         # 订单相关接口
├── ProductController.java       # 商品相关接口
└── dto/                         # 请求/响应 DTO
    ├── request/
    │   ├── CreateUserRequest.java
    │   └── UpdateUserRequest.java
    └── response/
        ├── UserResponse.java
        └── ApiResponse.java

职责说明:

  • Controller 类负责接收 HTTP 请求,调用 Service 层处理业务
  • 使用 DTO 对象进行数据传输,不直接使用 Entity
  • 处理参数校验、异常捕获和响应格式化

2. Service 层(业务逻辑层)

service/
├── UserService.java             # 用户服务接口
├── OrderService.java            # 订单服务接口
├── impl/                        # 服务实现
│   ├── UserServiceImpl.java
│   └── OrderServiceImpl.java
└── converter/                   # 对象转换器
    ├── UserConverter.java       # Entity 与 DTO 转换
    └── OrderConverter.java

职责说明:

  • Service 接口定义业务方法
  • ServiceImpl 实现具体的业务逻辑
  • 可以调用多个 Repository 完成复杂业务
  • 使用 Converter 进行 Entity 和 DTO 之间的转换

3. Repository 层(数据访问层)

repository/
├── UserRepository.java          # 用户数据访问接口
├── OrderRepository.java         # 订单数据访问接口
└── mapper/                      # MyBatis Mapper(如果使用)
    ├── UserMapper.java
    └── UserMapper.xml

职责说明:

  • Repository 接口定义数据访问方法
  • 如果使用 JPA,实现由框架自动生成
  • 如果使用 MyBatis,需要编写 Mapper 接口和 XML

4. Model 层(数据模型)

model/
├── entity/                      # 实体类(对应数据库表)
│   ├── User.java
│   ├── Order.java
│   └── BaseEntity.java          # 基础实体(包含公共字段)
│
├── dto/                         # 数据传输对象
│   ├── UserDTO.java
│   ├── OrderDTO.java
│   └── PageDTO.java             # 分页对象
│
└── vo/                          # 视图对象(用于展示)
    ├── UserVO.java
    └── OrderDetailVO.java

职责说明:

  • Entity:对应数据库表,包含 JPA 注解
  • DTO:用于层间数据传输,不包含业务逻辑
  • VO:用于前端展示,可能包含多个 Entity 的数据

完整项目包结构示例

以下是一个完整的 Spring Boot 项目的包结构:

com.example.ecommerce
│
├── controller/                          # 表现层
│   ├── UserController.java
│   ├── OrderController.java
│   ├── ProductController.java
│   └── dto/
│       ├── request/
│       │   ├── CreateUserRequest.java
│       │   ├── UpdateUserRequest.java
│       │   └── QueryUserRequest.java
│       └── response/
│           ├── UserResponse.java
│           ├── ApiResponse.java
│           └── PageResponse.java
│
├── service/                             # 业务逻辑层
│   ├── UserService.java
│   ├── OrderService.java
│   ├── ProductService.java
│   ├── impl/
│   │   ├── UserServiceImpl.java
│   │   ├── OrderServiceImpl.java
│   │   └── ProductServiceImpl.java
│   └── converter/
│       ├── UserConverter.java
│       ├── OrderConverter.java
│       └── ProductConverter.java
│
├── repository/                          # 数据访问层
│   ├── UserRepository.java
│   ├── OrderRepository.java
│   ├── ProductRepository.java
│   └── mapper/                         # MyBatis Mapper
│       ├── UserMapper.java
│       ├── UserMapper.xml
│       └── ...
│
├── model/                               # 数据模型
│   ├── entity/
│   │   ├── User.java
│   │   ├── Order.java
│   │   ├── Product.java
│   │   └── BaseEntity.java
│   ├── dto/
│   │   ├── UserDTO.java
│   │   ├── OrderDTO.java
│   │   └── ProductDTO.java
│   └── vo/
│       ├── UserVO.java
│       └── OrderDetailVO.java
│
├── config/                              # 配置类
│   ├── DatabaseConfig.java
│   ├── RedisConfig.java
│   ├── SwaggerConfig.java
│   └── WebMvcConfig.java
│
├── exception/                           # 异常处理
│   ├── BusinessException.java
│   ├── GlobalExceptionHandler.java
│   └── ErrorCode.java
│
├── util/                                # 工具类
│   ├── DateUtil.java
│   ├── StringUtil.java
│   └── JsonUtil.java
│
└── constant/                            # 常量类
    ├── UserConstant.java
    └── OrderConstant.java

层间交互流程

请求处理流程

用户请求
    ↓
Controller 层(接收请求、参数校验)
    ↓
Service 层(业务逻辑处理)
    ↓
Repository 层(数据访问)
    ↓
数据库
    ↓
Repository 层(返回 Entity)
    ↓
Service 层(转换为 DTO、处理业务逻辑)
    ↓
Controller 层(转换为 Response、返回给用户)
    ↓
用户响应

数据流转

  1. 请求阶段:

    • Request DTO → Controller → Service → Repository → Entity → 数据库
  2. 响应阶段:

    • 数据库 → Entity → Repository → Service(转换为 DTO)→ Controller(转换为 Response)→ 用户

依赖关系

Controller 层
    ↓ 依赖
Service 层
    ↓ 依赖
Repository 层
    ↓ 依赖
数据库/ORM 框架

重要原则:

  • Controller 只能依赖 Service,不能直接依赖 Repository
  • Service 只能依赖 Repository,不能直接访问数据库
  • Repository 只负责数据访问,不包含业务逻辑

详细实现示例

完整代码示例

下面通过一个用户管理的完整示例,展示分层架构的实现:

1. Entity(实体类)

// model/entity/User.java
@Entity
@Table(name = "users")
public class User extends BaseEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false, length = 50)
    private String username;

    @Column(nullable = false, unique = true)
    private String email;

    @Column(nullable = false)
    private String password;

    @Enumerated(EnumType.STRING)
    private UserStatus status;

    // getters, setters, constructors
}

2. DTO(数据传输对象)

// model/dto/UserDTO.java
public class UserDTO {
    private Long id;
    private String username;
    private String email;
    private UserStatus status;
    
    // getters, setters
}

// controller/dto/request/CreateUserRequest.java
public class CreateUserRequest {
    @NotBlank(message = "用户名不能为空")
    @Size(min = 3, max = 50, message = "用户名长度必须在3-50之间")
    private String username;

    @NotBlank(message = "邮箱不能为空")
    @Email(message = "邮箱格式不正确")
    private String email;

    @NotBlank(message = "密码不能为空")
    @Size(min = 6, message = "密码长度不能少于6位")
    private String password;
    
    // getters, setters
}

// controller/dto/response/UserResponse.java
public class UserResponse {
    private Long id;
    private String username;
    private String email;
    private UserStatus status;
    private LocalDateTime createTime;
    
    // getters, setters
}

3. Repository(数据访问层)

// repository/UserRepository.java
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    /**
     * 根据邮箱查询用户
     */
    Optional<User> findByEmail(String email);

    /**
     * 根据状态查询用户列表
     */
    List<User> findByStatus(UserStatus status);

    /**
     * 检查邮箱是否存在
     */
    boolean existsByEmail(String email);

    /**
     * 根据用户名和状态查询
     */
    Optional<User> findByUsernameAndStatus(String username, UserStatus status);
}

4. Service(业务逻辑层)

// service/UserService.java(接口)
public interface UserService {
    /**
     * 根据ID查询用户
     */
    UserDTO getUserById(Long id);

    /**
     * 创建用户
     */
    UserDTO createUser(CreateUserRequest request);

    /**
     * 更新用户
     */
    UserDTO updateUser(Long id, UpdateUserRequest request);

    /**
     * 删除用户
     */
    void deleteUser(Long id);

    /**
     * 分页查询用户
     */
    PageDTO<UserDTO> getUserList(QueryUserRequest request);
}

// service/impl/UserServiceImpl.java(实现)
@Service
@Transactional
public class UserServiceImpl implements UserService {
    
    @Autowired
    private UserRepository userRepository;

    @Override
    @Transactional(readOnly = true)
    public UserDTO getUserById(Long id) {
        User user = userRepository.findById(id)
            .orElseThrow(() -> new BusinessException("用户不存在"));
        return UserConverter.toDTO(user);
    }

    @Override
    public UserDTO createUser(CreateUserRequest request) {
        // 1. 业务校验:检查邮箱是否已存在
        if (userRepository.existsByEmail(request.getEmail())) {
            throw new BusinessException("邮箱已被注册");
        }

        // 2. 创建用户实体
        User user = new User();
        user.setUsername(request.getUsername());
        user.setEmail(request.getEmail());
        user.setPassword(encodePassword(request.getPassword())); // 密码加密
        user.setStatus(UserStatus.ACTIVE);

        // 3. 保存到数据库
        User savedUser = userRepository.save(user);

        // 4. 转换为 DTO 返回
        return UserConverter.toDTO(savedUser);
    }

    @Override
    public UserDTO updateUser(Long id, UpdateUserRequest request) {
        // 1. 查询用户
        User user = userRepository.findById(id)
            .orElseThrow(() -> new BusinessException("用户不存在"));

        // 2. 更新用户信息
        if (request.getUsername() != null) {
            user.setUsername(request.getUsername());
        }
        if (request.getEmail() != null && !user.getEmail().equals(request.getEmail())) {
            // 如果邮箱改变,需要检查新邮箱是否已被使用
            if (userRepository.existsByEmail(request.getEmail())) {
                throw new BusinessException("邮箱已被使用");
            }
            user.setEmail(request.getEmail());
        }

        // 3. 保存更新
        User updatedUser = userRepository.save(user);
        return UserConverter.toDTO(updatedUser);
    }

    @Override
    public void deleteUser(Long id) {
        User user = userRepository.findById(id)
            .orElseThrow(() -> new BusinessException("用户不存在"));
        userRepository.delete(user);
    }

    @Override
    @Transactional(readOnly = true)
    public PageDTO<UserDTO> getUserList(QueryUserRequest request) {
        // 构建查询条件
        Pageable pageable = PageRequest.of(
            request.getPageNum() - 1, 
            request.getPageSize()
        );
        
        // 查询数据
        Page<User> userPage = userRepository.findAll(pageable);
        
        // 转换为 DTO
        List<UserDTO> userDTOList = userPage.getContent().stream()
            .map(UserConverter::toDTO)
            .collect(Collectors.toList());
        
        return new PageDTO<>(
            userDTOList,
            userPage.getTotalElements(),
            userPage.getTotalPages()
        );
    }

    private String encodePassword(String password) {
        // 密码加密逻辑
        return BCrypt.hashpw(password, BCrypt.gensalt());
    }
}

// service/converter/UserConverter.java(对象转换器)
@Component
public class UserConverter {
    
    public static UserDTO toDTO(User user) {
        if (user == null) {
            return null;
        }
        UserDTO dto = new UserDTO();
        dto.setId(user.getId());
        dto.setUsername(user.getUsername());
        dto.setEmail(user.getEmail());
        dto.setStatus(user.getStatus());
        return dto;
    }

    public static User toEntity(UserDTO dto) {
        if (dto == null) {
            return null;
        }
        User user = new User();
        user.setId(dto.getId());
        user.setUsername(dto.getUsername());
        user.setEmail(dto.getEmail());
        user.setStatus(dto.getStatus());
        return user;
    }

    public static UserResponse toResponse(UserDTO dto) {
        if (dto == null) {
            return null;
        }
        UserResponse response = new UserResponse();
        response.setId(dto.getId());
        response.setUsername(dto.getUsername());
        response.setEmail(dto.getEmail());
        response.setStatus(dto.getStatus());
        return response;
    }
}

5. Controller(表现层)

// controller/UserController.java
@RestController
@RequestMapping("/api/users")
@Validated
public class UserController {
    
    @Autowired
    private UserService userService;

    /**
     * 根据ID查询用户
     */
    @GetMapping("/{id}")
    public ApiResponse<UserResponse> getUser(@PathVariable Long id) {
        UserDTO userDTO = userService.getUserById(id);
        UserResponse response = UserConverter.toResponse(userDTO);
        return ApiResponse.success(response);
    }

    /**
     * 创建用户
     */
    @PostMapping
    public ApiResponse<UserResponse> createUser(
            @Valid @RequestBody CreateUserRequest request) {
        UserDTO userDTO = userService.createUser(request);
        UserResponse response = UserConverter.toResponse(userDTO);
        return ApiResponse.success(response);
    }

    /**
     * 更新用户
     */
    @PutMapping("/{id}")
    public ApiResponse<UserResponse> updateUser(
            @PathVariable Long id,
            @Valid @RequestBody UpdateUserRequest request) {
        UserDTO userDTO = userService.updateUser(id, request);
        UserResponse response = UserConverter.toResponse(userDTO);
        return ApiResponse.success(response);
    }

    /**
     * 删除用户
     */
    @DeleteMapping("/{id}")
    public ApiResponse<Void> deleteUser(@PathVariable Long id) {
        userService.deleteUser(id);
        return ApiResponse.success(null);
    }

    /**
     * 分页查询用户列表
     */
    @GetMapping
    public ApiResponse<PageResponse<UserResponse>> getUserList(
            @Valid QueryUserRequest request) {
        PageDTO<UserDTO> pageDTO = userService.getUserList(request);
        List<UserResponse> responseList = pageDTO.getList().stream()
            .map(UserConverter::toResponse)
            .collect(Collectors.toList());
        
        PageResponse<UserResponse> pageResponse = new PageResponse<>(
            responseList,
            pageDTO.getTotal(),
            pageDTO.getTotalPages()
        );
        return ApiResponse.success(pageResponse);
    }
}

// controller/dto/response/ApiResponse.java(统一响应格式)
public class ApiResponse<T> {
    private boolean success;
    private T data;
    private String message;
    private Long timestamp;

    public static <T> ApiResponse<T> success(T data) {
        ApiResponse<T> response = new ApiResponse<>();
        response.setSuccess(true);
        response.setData(data);
        response.setMessage("操作成功");
        response.setTimestamp(System.currentTimeMillis());
        return response;
    }

    public static <T> ApiResponse<T> error(String message) {
        ApiResponse<T> response = new ApiResponse<>();
        response.setSuccess(false);
        response.setMessage(message);
        response.setTimestamp(System.currentTimeMillis());
        return response;
    }
    
    // getters, setters
}

6. 异常处理

// exception/BusinessException.java
public class BusinessException extends RuntimeException {
    private String code;
    private String message;

    public BusinessException(String message) {
        super(message);
        this.message = message;
        this.code = "BUSINESS_ERROR";
    }
}

// exception/GlobalExceptionHandler.java
@ControllerAdvice
public class GlobalExceptionHandler {
    
    /**
     * 处理业务异常
     */
    @ExceptionHandler(BusinessException.class)
    public ResponseEntity<ApiResponse<Void>> handleBusinessException(
            BusinessException ex) {
        ApiResponse<Void> response = ApiResponse.error(ex.getMessage());
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response);
    }

    /**
     * 处理参数校验异常
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<ApiResponse<Void>> handleValidationException(
            MethodArgumentNotValidException ex) {
        String message = ex.getBindingResult().getFieldErrors().stream()
            .map(DefaultMessageSourceResolvable::getDefaultMessage)
            .collect(Collectors.joining(", "));
        ApiResponse<Void> response = ApiResponse.error(message);
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response);
    }

    /**
     * 处理其他异常
     */
    @ExceptionHandler(Exception.class)
    public ResponseEntity<ApiResponse<Void>> handleException(Exception ex) {
        ApiResponse<Void> response = ApiResponse.error("系统异常,请稍后重试");
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
    }
}

分层架构的优缺点

优点

  1. 职责清晰:每一层都有明确的职责,代码组织清晰
  2. 易于理解:新成员可以快速理解代码结构
  3. 易于维护:修改某一层不会影响其他层
  4. 易于测试:每一层都可以独立测试
  5. 可扩展性好:可以轻松添加新的功能模块
  6. 技术栈解耦:可以替换某一层的技术实现而不影响其他层

缺点

  1. 性能开销:层间调用可能带来一定的性能开销
  2. 代码冗余:需要在不同层之间进行对象转换,可能产生冗余代码
  3. 过度设计:对于简单项目,可能显得过于复杂
  4. 层间耦合:如果设计不当,可能出现层间耦合问题

适用场景

适合使用分层架构的场景:

  • 企业级应用开发
  • 需要长期维护的项目
  • 团队协作开发
  • 需要支持多种前端(Web、移动端、API)
  • 业务逻辑复杂,需要清晰的代码组织

不适合使用分层架构的场景:

  • 简单的 CRUD 应用(可能过度设计)
  • 高性能要求的系统(层间调用有开销)
  • 微服务架构中的小服务(可能过于复杂)

包结构可视化图

Mermaid 包结构图

依赖关系图

数据流转图

最佳实践

1. 使用接口定义服务层

原因:便于测试和替换实现

// ✅ 好的做法:使用接口
public interface UserService {
    UserDTO getUserById(Long id);
}

@Service
public class UserServiceImpl implements UserService {
    // 实现
}

// ❌ 不好的做法:直接使用实现类
@Service
public class UserService {
    // 实现
}

2. 使用 DTO 进行层间数据传输

原因:避免暴露 Entity 的内部结构,提高灵活性

// ✅ 好的做法:使用 DTO
public UserDTO getUserById(Long id) {
    User user = repository.findById(id);
    return UserConverter.toDTO(user); // Entity 转 DTO
}

// ❌ 不好的做法:直接返回 Entity
public User getUserById(Long id) {
    return repository.findById(id); // 暴露了 Entity 结构
}

3. 在 Service 层管理事务

原因:业务逻辑的完整性需要事务保证

// ✅ 好的做法:在 Service 层使用 @Transactional
@Service
public class OrderServiceImpl implements OrderService {
    @Transactional
    public OrderDTO createOrder(CreateOrderRequest request) {
        // 多个数据库操作,需要事务保证
        orderRepository.save(order);
        inventoryRepository.updateStock(productId, quantity);
        return OrderConverter.toDTO(order);
    }
}

4. 统一异常处理

原因:提供统一的错误响应格式

// ✅ 好的做法:使用全局异常处理器
@ControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(BusinessException.class)
    public ResponseEntity<ApiResponse<Void>> handleBusinessException(
            BusinessException ex) {
        return ResponseEntity.badRequest()
            .body(ApiResponse.error(ex.getMessage()));
    }
}

5. 使用 Converter 进行对象转换

原因:集中管理转换逻辑,便于维护

// ✅ 好的做法:使用 Converter
@Component
public class UserConverter {
    public static UserDTO toDTO(User user) {
        // 转换逻辑
    }
}

// ❌ 不好的做法:在 Service 中直接转换
@Service
public class UserServiceImpl {
    public UserDTO getUserById(Long id) {
        User user = repository.findById(id);
        // 直接在这里转换,逻辑分散
        UserDTO dto = new UserDTO();
        dto.setId(user.getId());
        // ...
    }
}

6. 参数校验放在 Controller 层

原因:尽早发现参数错误,减少无效请求

// ✅ 好的做法:在 Controller 层使用 @Valid
@PostMapping
public ApiResponse<UserResponse> createUser(
        @Valid @RequestBody CreateUserRequest request) {
    // 参数校验通过后才会执行
    return userService.createUser(request);
}

// CreateUserRequest.java
public class CreateUserRequest {
    @NotBlank(message = "用户名不能为空")
    private String username;
    
    @Email(message = "邮箱格式不正确")
    private String email;
}

7. 避免在 Controller 中写业务逻辑

原因:保持 Controller 层的简洁,业务逻辑应该在 Service 层

// ✅ 好的做法:Controller 只负责接收和返回
@PostMapping
public ApiResponse<UserResponse> createUser(
        @Valid @RequestBody CreateUserRequest request) {
    UserDTO userDTO = userService.createUser(request);
    return ApiResponse.success(UserConverter.toResponse(userDTO));
}

// ❌ 不好的做法:在 Controller 中写业务逻辑
@PostMapping
public ApiResponse<UserResponse> createUser(
        @Valid @RequestBody CreateUserRequest request) {
    // 业务逻辑不应该在这里
    if (userRepository.existsByEmail(request.getEmail())) {
        throw new BusinessException("邮箱已存在");
    }
    // ...
}

常见问题和解决方案

问题1:层间循环依赖

问题:Service A 依赖 Service B,Service B 又依赖 Service A

解决方案:

  • 提取公共逻辑到新的 Service
  • 使用事件驱动模式解耦
  • 重新设计业务边界

问题2:DTO 转换代码冗余

问题:每个 Service 方法都需要写转换代码

解决方案:

  • 使用 MapStruct 等工具自动生成转换代码
  • 使用 Converter 类集中管理转换逻辑
  • 使用 Builder 模式简化对象创建

问题3:Service 层过于臃肿

问题:一个 Service 类包含太多方法,职责不清

解决方案:

  • 按业务领域拆分 Service
  • 使用领域服务(Domain Service)处理复杂业务逻辑
  • 提取公共逻辑到工具类或 Helper 类

问题4:跨层调用

问题:Controller 直接调用 Repository

解决方案:

  • 严格遵循分层原则,上层只能调用下层
  • 使用代码审查和静态分析工具检查
  • 在 Service 层提供必要的接口

总结

分层架构是一种经典且实用的软件架构模式,它通过清晰的层次划分和职责分配,帮助开发团队更好地组织和管理代码。

核心要点

  1. 职责分离:每一层只负责自己的职责
  2. 单向依赖:上层依赖下层,不能反向依赖
  3. 接口抽象:使用接口定义服务,提高灵活性
  4. 数据转换:使用 DTO 进行层间数据传输
  5. 统一规范:统一的异常处理、响应格式等

适用场景

虽然分层架构可能不是所有场景的最佳选择,但在以下场景中,它仍然是一个可靠的选择:

  • 企业级应用开发:需要长期维护和扩展
  • 团队协作开发:需要清晰的代码组织规范
  • 多端支持:需要支持 Web、移动端、API 等多种前端
  • 复杂业务逻辑:需要清晰的业务逻辑组织

学习建议

  1. 从简单开始:先实现基本的 CRUD 功能,理解各层职责
  2. 逐步完善:添加异常处理、参数校验、对象转换等
  3. 实践优化:在实际项目中应用,不断优化和改进
  4. 学习其他架构:了解六边形架构、洋葱架构等,对比学习

通过掌握分层架构,你可以更好地组织代码,提高代码质量和可维护性,为后续学习更复杂的架构模式打下基础。

最近更新:: 2025/12/25 10:46
Contributors: Duke
Prev
什么是软件架构
Next
微服务架构