如何在 Spring Data JPA 中的控制器和服务方法之间传递实体?
How to pass entity between controller and service methods in Spring Data JPA?
让我们考虑一个 Spring 引导(Spring 数据 JPA)应用程序,它带有一个控制器和一个服务,如下例所示:
processEntity()
从数据库中获取一个对象并 processes/updates 它。
publishEntity()
是一个单独的方法,再次从数据库中获取对象,并将其发布到另一个系统。它需要数据库中实体的“最新”状态。
我发现有几篇博文和文章建议不要与控制器中的实体一起操作,即在事务范围之外。所以我的 类 看起来像这样:
@Service
public SomeService {
@Transactional
public void processEntity(long id) {
final SomeEntity someEntity = entityRepository.findById(id);
// process entity...
entityRepository.save(someEntity);
}
@Transactional(readOnly = true)
public void publishEntity(long id) {
final SomeEntity someEntity = entityRepository.findById(id);
// publish entity to another system...
}
}
@RestController
public SomeController {
@GetMapping(path = "/api/entity")
public ResponseEntity<Void> getEntity() {
someService.processEntity(1);
someService.publishEntity(1);
}
}
这种做法合理吗?或者对于这样的用例是否有更好的模式?如果 processEntity
将实体本身返回给传递给 publishEntity
的控制器,是否会被视为“不良做法”?
在你的控制器中返回实体和接收实体通常是一种不好的做法,也是问题的常见来源(不要误会我的意思,它确实有效,但除非你的用例非常简单,否则你很可能会遇到一些问题这样做时的约束)。您应该改用 DTOs,这与您的实体类似 class,但它可以代表您的域模型(您的实体在您的案例中)的多个视图。
使用 DTO 有多种原因:
- 它允许您的域模型和“public”模型之间的关注点分离,允许您更改一个而无需更改另一个。
- 它允许您轻松拥有实体的多个视图,而无需包含 Jackson 魔术注释来包含或排除实体中的某些属性 classes。
您可以在以下在线资源中阅读更多相关信息:https://www.baeldung.com/java-dto-pattern。
如果您决定使用 DTO,请考虑使用如下映射器:
我不太喜欢使用它们(我更喜欢自己做映射),但您可能会发现它们很有用。映射可以在服务层本身或控制器层中完成。每种方法都各有利弊,但我会说这真的取决于您的喜好。
建议在控制器和服务之间使用DTO对象。如果您稍后决定删除数据库并使用一些外部系统,那么控制器层将不会受到影响。
让我们考虑一个 Spring 引导(Spring 数据 JPA)应用程序,它带有一个控制器和一个服务,如下例所示:
processEntity()
从数据库中获取一个对象并 processes/updates 它。publishEntity()
是一个单独的方法,再次从数据库中获取对象,并将其发布到另一个系统。它需要数据库中实体的“最新”状态。
我发现有几篇博文和文章建议不要与控制器中的实体一起操作,即在事务范围之外。所以我的 类 看起来像这样:
@Service
public SomeService {
@Transactional
public void processEntity(long id) {
final SomeEntity someEntity = entityRepository.findById(id);
// process entity...
entityRepository.save(someEntity);
}
@Transactional(readOnly = true)
public void publishEntity(long id) {
final SomeEntity someEntity = entityRepository.findById(id);
// publish entity to another system...
}
}
@RestController
public SomeController {
@GetMapping(path = "/api/entity")
public ResponseEntity<Void> getEntity() {
someService.processEntity(1);
someService.publishEntity(1);
}
}
这种做法合理吗?或者对于这样的用例是否有更好的模式?如果 processEntity
将实体本身返回给传递给 publishEntity
的控制器,是否会被视为“不良做法”?
在你的控制器中返回实体和接收实体通常是一种不好的做法,也是问题的常见来源(不要误会我的意思,它确实有效,但除非你的用例非常简单,否则你很可能会遇到一些问题这样做时的约束)。您应该改用 DTOs,这与您的实体类似 class,但它可以代表您的域模型(您的实体在您的案例中)的多个视图。
使用 DTO 有多种原因:
- 它允许您的域模型和“public”模型之间的关注点分离,允许您更改一个而无需更改另一个。
- 它允许您轻松拥有实体的多个视图,而无需包含 Jackson 魔术注释来包含或排除实体中的某些属性 classes。
您可以在以下在线资源中阅读更多相关信息:https://www.baeldung.com/java-dto-pattern。
如果您决定使用 DTO,请考虑使用如下映射器:
我不太喜欢使用它们(我更喜欢自己做映射),但您可能会发现它们很有用。映射可以在服务层本身或控制器层中完成。每种方法都各有利弊,但我会说这真的取决于您的喜好。
建议在控制器和服务之间使用DTO对象。如果您稍后决定删除数据库并使用一些外部系统,那么控制器层将不会受到影响。