知识模块
☕ Java 知识模块
十一、设计模式
MVC 分层架构

MVC 分层架构

MVC 是一种软件架构模式,将应用程序分为三个核心部分,实现关注点分离。

一、MVC 基本概念

1. 三层结构

┌─────────────────────────────────────────────────────────┐
│                      View (视图层)                       │
│                    负责展示数据和用户交互                  │
└─────────────────────────┬───────────────────────────────┘


┌─────────────────────────────────────────────────────────┐
│                   Controller (控制层)                    │
│                  接收请求,调用业务逻辑,返回响应           │
└─────────────────────────┬───────────────────────────────┘


┌─────────────────────────────────────────────────────────┐
│                     Model (模型层)                       │
│                    业务逻辑和数据存取                     │
└─────────────────────────────────────────────────────────┘

2. 各层职责

层次职责示例
View展示数据、用户交互JSP、Thymeleaf、Vue
Controller请求分发、参数校验Spring MVC Controller
Model业务逻辑、数据访问Service、Repository

二、Java Web 分层架构

1. 经典四层架构

┌─────────────────────────────────────────────────────────┐
│                    表现层 (Web)                         │
│              Controller、DTO、VO                        │
└─────────────────────────┬───────────────────────────────┘


┌─────────────────────────────────────────────────────────┐
│                    业务层 (Service)                      │
│              Service、BO、业务逻辑                       │
└─────────────────────────┬───────────────────────────────┘


┌─────────────────────────────────────────────────────────┐
│                    数据访问层 (DAO)                      │
│              Repository/Mapper、DO                      │
└─────────────────────────┬───────────────────────────────┘


┌─────────────────────────────────────────────────────────┐
│                      数据库 (DB)                         │
│                    MySQL、PostgreSQL                     │
└─────────────────────────────────────────────────────────┘

2. 各层实现

Controller 层

@RestController
@RequestMapping("/api/users")
public class UserController {
    
    @Autowired
    private UserService userService;
    
    @PostMapping
    public Result<UserVO> create(@RequestBody @Valid UserDTO dto) {
        UserVO user = userService.create(dto);
        return Result.success(user);
    }
    
    @GetMapping("/{id}")
    public Result<UserVO> getById(@PathVariable Long id) {
        UserVO user = userService.getById(id);
        return Result.success(user);
    }
    
    @PutMapping("/{id}")
    public Result<UserVO> update(@PathVariable Long id, @RequestBody @Valid UserDTO dto) {
        UserVO user = userService.update(id, dto);
        return Result.success(user);
    }
    
    @DeleteMapping("/{id}")
    public Result<Void> delete(@PathVariable Long id) {
        userService.delete(id);
        return Result.success();
    }
}

Service 层

@Service
@Transactional
public class UserServiceImpl implements UserService {
    
    @Autowired
    private UserRepository userRepository;
    
    @Autowired
    private PasswordEncoder passwordEncoder;
    
    @Override
    public UserVO create(UserDTO dto) {
        // 检查用户名是否存在
        if (userRepository.existsByUsername(dto.getUsername())) {
            throw new BusinessException("用户名已存在");
        }
        
        // 创建用户
        User user = new User();
        user.setUsername(dto.getUsername());
        user.setPassword(passwordEncoder.encode(dto.getPassword()));
        user.setEmail(dto.getEmail());
        
        userRepository.save(user);
        
        return toVO(user);
    }
    
    @Override
    @Transactional(readOnly = true)
    public UserVO getById(Long id) {
        User user = userRepository.findById(id)
            .orElseThrow(() -> new NotFoundException("用户不存在"));
        return toVO(user);
    }
    
    private UserVO toVO(User user) {
        UserVO vo = new UserVO();
        vo.setId(user.getId());
        vo.setUsername(user.getUsername());
        vo.setEmail(user.getEmail());
        return vo;
    }
}

Repository 层

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    
    boolean existsByUsername(String username);
    
    Optional<User> findByUsername(String username);
    
    @Query("SELECT u FROM User u WHERE u.email = :email")
    Optional<User> findByEmail(@Param("email") String email);
}

三、数据对象分类

1. 各类对象职责

对象全称位置职责
DTOData Transfer ObjectController 层接收请求参数
VOView ObjectController 层返回响应数据
BOBusiness ObjectService 层业务逻辑对象
DOData ObjectDAO 层数据库映射
POPersistent ObjectDAO 层持久化对象

2. 对象转换

// DTO → BO
public UserBO toBO(UserDTO dto) {
    UserBO bo = new UserBO();
    bo.setUsername(dto.getUsername());
    bo.setEmail(dto.getEmail());
    return bo;
}
 
// BO → DO
public UserDO toDO(UserBO bo) {
    UserDO user = new UserDO();
    user.setUsername(bo.getUsername());
    user.setEmail(bo.getEmail());
    return user;
}
 
// DO → VO
public UserVO toVO(UserDO user) {
    UserVO vo = new UserVO();
    vo.setId(user.getId());
    vo.setUsername(user.getUsername());
    vo.setEmail(user.getEmail());
    return vo;
}

3. 使用 MapStruct

@Mapper(componentModel = "spring")
public interface UserMapper {
    
    UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);
    
    @Mapping(target = "id", ignore = true)
    User toEntity(UserDTO dto);
    
    UserVO toVO(User user);
    
    @Mapping(target = "password", ignore = true)
    UserVO toVOWithoutPassword(User user);
}

四、分层架构的优势

1. 关注点分离

每层只关注自己的职责:
- Controller:参数校验、异常处理、响应封装
- Service:业务逻辑、事务管理
- Repository:数据访问、SQL 优化

2. 易于测试

// Service 层单元测试
@SpringBootTest
class UserServiceTest {
    
    @MockBean
    private UserRepository userRepository;
    
    @Autowired
    private UserService userService;
    
    @Test
    void testCreate() {
        // Given
        UserDTO dto = new UserDTO();
        dto.setUsername("test");
        
        when(userRepository.existsByUsername("test")).thenReturn(false);
        when(userRepository.save(any())).thenAnswer(inv -> inv.getArgument(0));
        
        // When
        UserVO result = userService.create(dto);
        
        // Then
        assertNotNull(result);
        assertEquals("test", result.getUsername());
    }
}

3. 易于维护

修改数据库 → 只改 Repository 层
修改业务逻辑 → 只改 Service 层
修改 API 格式 → 只改 Controller 层

五、分层架构演进

1. 传统三层

Controller → Service → DAO → Database

2. DDD 分层

┌─────────────────────────────────────┐
│            Interface Layer          │
│        (Controller/DTO)             │
└─────────────────┬───────────────────┘


┌─────────────────────────────────────┐
│           Application Layer         │
│      (Application Service)          │
└─────────────────┬───────────────────┘


┌─────────────────────────────────────┐
│              Domain Layer           │
│     (Entity/Value Object/Repository)│
└─────────────────┬───────────────────┘


┌─────────────────────────────────────┐
│          Infrastructure Layer       │
│       (Persistence/External API)    │
└─────────────────────────────────────┘

3. 微服务架构

每个微服务内部保持分层:
API Gateway → Service A (分层) → Database A
            → Service B (分层) → Database B

六、常见问题

1. 贫血模型 vs 充血模型

贫血模型

// 只有 getter/setter,无业务逻辑
public class User {
    private String username;
    // getter/setter
}
 
// 业务逻辑在 Service 层
public class UserService {
    public void changePassword(User user, String newPassword) {
        user.setPassword(newPassword);
    }
}

充血模型

// 包含业务逻辑
public class User {
    private String username;
    private String password;
    
    public void changePassword(String oldPassword, String newPassword) {
        if (!this.password.equals(oldPassword)) {
            throw new BusinessException("原密码错误");
        }
        this.password = newPassword;
    }
}

2. 跨层调用

❌ 错误:Controller 直接调用 Repository
✅ 正确:Controller → Service → Repository

3. 循环依赖

❌ Service A 依赖 Service B,Service B 依赖 Service A
✅ 提取公共逻辑到 Service C

七、面试高频问题

Q1: 为什么要分层?

  • 关注点分离
  • 降低耦合
  • 易于测试和维护
  • 便于团队协作

Q2: 各层之间的依赖如何处理?

  • 使用依赖注入
  • 面向接口编程
  • Spring 自动装配

Q3: DTO 和 VO 有什么区别?

DTOVO
接收请求参数返回响应数据
可包含校验注解可脱敏处理
入参出参

Q4: Service 层为什么要定义接口?

  • 便于 Mock 测试
  • 支持多实现
  • 符合依赖倒置原则
  • 但并非必须(简单项目可省略)

Q5: 事务应该放在哪一层?

  • 放在 Service 层
  • Controller 层不应该有事务
  • 使用 @Transactional 注解

八、最佳实践

1. 分层规范

- 上层依赖下层,下层不依赖上层
- 同层之间避免相互调用
- 跨层调用通过接口

2. 异常处理

@RestControllerAdvice
public class GlobalExceptionHandler {
    
    @ExceptionHandler(BusinessException.class)
    public Result<Void> handleBusinessException(BusinessException e) {
        return Result.fail(e.getMessage());
    }
    
    @ExceptionHandler(Exception.class)
    public Result<Void> handleException(Exception e) {
        log.error("系统异常", e);
        return Result.fail("系统异常");
    }
}

3. 统一响应格式

@Data
public class Result<T> {
    private int code;
    private String message;
    private T data;
    
    public static <T> Result<T> success(T data) {
        Result<T> result = new Result<>();
        result.setCode(200);
        result.setMessage("success");
        result.setData(data);
        return result;
    }
    
    public static <T> Result<T> fail(String message) {
        Result<T> result = new Result<>();
        result.setCode(500);
        result.setMessage(message);
        return result;
    }
}

更新时间:2026年3月16日