使用Spring MVC和JPA实现一个返回Json对象的restful-controller的正确方法是什么?
聚焦:
第一个天真的设计是:
@RequestMapping(value = "/{userId}", method = RequestMethod.GET)
@ResponseBody
public JsonUser doSomethingOnUser(@PathVariable("userId") Long userId) {
// 1. load entities by ids
User user = mUserRepository.findOne(userId);
// 2. eventually validate
// 3. perform changes on entities (create, update, delete)
mUserService.DoSomething(user);
// 4. convert back to json
return mUserPresenter.convertToJsonUser(user);
}
动机是:
id
到entity
的转换但是我遇到了几个与事务边界相结合的问题,加上了延迟加载和实体关系,所以它似乎是一个糟糕的设计。
您的最佳做法是什么?
答案 0 :(得分:1)
尝试像这样构建它,这是一个非常频繁的解决方案,它是blue book中描述的域驱动开发方法,这里是同一作者批准的free short version:
控制器不是事务性的,并且没有业务逻辑,因此它不会尝试导航可能导致LazyInitializationExceptions
的用户对象图。
如果需要除业务逻辑以外的任何原因,则控制器调用返回急切获取的对象图的服务,或者首先将对象合并到会话中。
这是例外,而不是规则,通常控制器的作用是验证输入参数以查看它们是否具有正确的类型/强制参数,调用业务逻辑并为其准备DTO。如果需要则回复。
@RequestMapping(value = "/{userId}", method = RequestMethod.GET)
@ResponseBody
public JsonUser doSomethingOnUser(@PathVariable("userId") Long userId) {
// all the business logic is in the service layer
User user = mUserService.doSomething(userId);
// conversion to DTO is handled in the controller layer,
// the domain does not know about DTOs
return mUserPresenter.convertToJsonUser(user);
}
该服务包含使用域模型编写的业务逻辑,并定义事务范围。
@Service
public class MyUserService {
@Autowired
private MyRepository repository;
@Transactional
public User doSomething(String userId) {
//this object is attached due to @Transactional, no exceptions will be thrown
User user = mUserRepository.findOne(userId);
// do something with the attached object
....
}
存储库通常不是事务性的,因为它无法知道它所处的事务的范围。它负责从数据库中检索数据并将其转换为域对象,以及将域对象存储在数据库中:
@Repository
public class MyRepository {
@PersistenceContext
private EntityManager em;
public void someDataRelatedMethod(...) {
... use entity manager ...
}
}