在软件开发中,Controller(控制器)、Mapper(数据访问层/持久层) 和 Service(服务层) 是常见的分层架构组件,它们各自承担不同的职责,共同协作完成业务逻辑。以下是它们的详细说明及协作关系:
1. Controller(控制器)
职责:
- 接收请求:处理来自客户端(如浏览器、移动应用)的 HTTP 请求(如 GET、POST、PUT、DELETE)。
- 协调调用:调用 Service 层处理业务逻辑,不直接操作数据。
- 返回响应:将 Service 层返回的数据格式化后返回给客户端(如 JSON、HTML)。
特点:
- 属于 表现层,专注于请求和响应的处理。
- 遵循 单一职责原则,不包含业务逻辑。
- 示例(Spring Boot):
java
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/{id}")
public User getUser(@PathVariable Long id) {
return userService.getUserById(id); // 调用 Service 层
}
}
2. Service(服务层)
职责:
- 业务逻辑处理:封装核心业务规则(如用户注册验证、订单计算)。
- 协调 Mapper:调用 Mapper 层进行数据操作(如增删改查)。
- 事务管理:确保数据一致性(如转账操作需原子性)。
特点:
- 属于 业务逻辑层,是系统的核心。
- 可能依赖多个 Mapper 或其他 Service。
- 示例:
java
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public User getUserById(Long id) {
// 业务逻辑(如权限校验)
return userMapper.selectById(id); // 调用 Mapper 层
}
}
3. Mapper(数据访问层/持久层)
职责:
- 数据操作:直接与数据库交互(如 SQL 查询、ORM 映射)。
- 抽象数据源:隐藏数据库细节(如 MySQL、Redis),提供统一接口。
特点:
- 属于 持久层,通常使用 MyBatis、JPA 等框架。
- 示例(MyBatis Mapper 接口):
java
@Mapper
public interface UserMapper {
@Select("SELECT * FROM users WHERE id = #{id}")
User selectById(Long id);
}
4. 三者协作关系
- 请求流程:
- 客户端请求 → Controller 接收 → 调用 Service → Service 调用 Mapper → Mapper 操作数据库 → 逐层返回结果。
- 分层示例:
- Controller:
UserController
接收/api/users/{id}
请求。 - Service:
UserService
验证权限后调用UserMapper
。 - Mapper:
UserMapper
执行 SQL 查询并返回数据。
- Controller:
- 依赖关系:
- Controller 依赖 Service,Service 依赖 Mapper,形成单向依赖链。
5. 常见问题与解决方案
问题 | 解决方案 |
---|---|
Controller 臃肿 | 提取业务逻辑到 Service 层,Controller 仅负责请求和响应。 |
Service 层事务失效 | 确保 Service 方法被 Spring 管理(如添加 @Transactional 注解)。 |
Mapper 层 SQL 硬编码 | 使用 MyBatis 的 XML 或注解动态生成 SQL,或使用 JPA 的 JPQL。 |
跨层调用(如 Controller 直接调用 Mapper) | 严格遵循分层架构,禁止跨层调用。 |
6. 最佳实践
- 单一职责:每层只做自己该做的事,避免职责混乱。
- 依赖注入:通过 Spring 的
@Autowired
或构造函数注入实现层间解耦。 - 异常处理:在 Controller 层统一捕获异常并返回友好提示。
- 日志记录:在关键层(如 Service)记录操作日志,便于排查问题。
总结
- Controller:负责请求入口和响应出口,是系统的“门面”。
- Service:封装业务逻辑,是系统的“大脑”。
- Mapper:负责数据持久化,是系统的“手脚”。
通过合理的分层设计,可以降低代码耦合度,提高可维护性和可测试性。