【发布时间】:2020-10-16 13:15:31
【问题描述】:
我们是一个小团队,开始一个新项目,并使用 Spring-Boot 框架开发后端。
后端项目将具有以下 Spring-Boot 应用程序的标准层:
- 控制器(映射端点和句柄)
- 服务(处理业务逻辑)
- 存储库(用于抽象和与数据库交互)
我们还有一个实体包,代表数据库实体的所有类都位于其中。 我们还使用库将实体与 Api 模型进行映射。
这并没有持续多久,我们在团队中进行了第一次辩论。所以我认为在外面寻求建议是个好主意。
我的其他合作伙伴认为控制器应该包含尽可能少的代码行。 理想情况下只包含一行代码,其中调用相应的 Service,其余的在 Service 中处理。
我反对这种做法,因为如果我们这样做,Service 和 Controller 最终将拥有相同的界面,这感觉不对。
但是,我同意控制器应具有尽可能少的代码行的原则。 我认为控制器方法应该只接受和返回 Api 模型,并且控制器中不应该存在实体的概念。
同时,我认为 services 方法应该接受和返回实体,而不是与 ApiModels 一起工作。
我们是否应该在 Controller 和 Service 之间引入一个新层?是否有一些我不知道的标准与该主题相关?
我将用两种方法(我的和我的合作伙伴的)给你一个具体的例子:
第一种方法:
public class UserController implements UsersApi {
@Autowired
private UserService userService;
@Override
public ResponseEntity<UserAPIModel> createUser(@Valid UserAPIModel body) {
User createdUser = userService.save(UserMapper.INSTANCE.toUserEntity(body));
return ResponseEntity.ok(UserMapper.INSTANCE.toUserAPIModel(createdUser));
}
}
还有服务:
public class UserService {
@Autowired
private UserRepository repository;
public User save(User entity) {
return repository.save(entity);
}
}
第二种方法:
public class UserController implements UsersApi {
@Autowired
private UserService userService;
@Override
public ResponseEntity<UserAPIModel> createUser(@Valid UserAPIModel body) {
return ResponseEntity.ok(userService.createUser(body));
}
}
和服务:
public class UserService {
@Autowired
private UserRepository repository;
public UserAPIModel createUser(UserAPIModel body) {
User user = repository.save(UserMapper.INSTANCE.toUserEntity(body));
return UserMapper.INSTANCE.toUserAPIModel(user);
}
}
正如您在第一种方法中看到的那样,从实体到 Api 模型的映射(反之亦然)是在 Controller 中完成的。在第二种方法中,这个映射是在服务中完成的。
你会推荐哪一个?还是您认为在 Controller 和 Service 之间引入一个新层更好?
对这个简单的例子做出决定,可以帮助我们制定更通用的规则,并为未来的类似问题设定标准。
【问题讨论】:
-
我认为对于简单的 CRUD 案例,除非您在持久化之前要运行一些业务逻辑,否则服务类会过度。
-
@code_mechanic 是的,会有业务逻辑,我们需要服务层。为了简单起见,我举了一个简单的例子。
-
我喜欢将编排/映射工作分离到一个单独的层(在域层之上),并使我的控制器尽可能虚拟。看看 DDD 概念“域服务”和“应用程序服务”。
-
当它们不同时使用单独的域实体和 API 模型(否则它会引入一个无用的层来维护)。那么问题就变成了,应该有不同的域实体和 API 模型吗?端点响应是否公开数据库表结构?例如,假设一个表被规范化,它改变了一些域实体。端点的消费者是否需要改变?
标签: java spring-boot object-oriented-analysis