如何在 Spring Data JPA 中的控制器和服务方法之间传递实体?

How to pass entity between controller and service methods in Spring Data JPA?

让我们考虑一个 Spring 引导(Spring 数据 JPA)应用程序,它带有一个控制器和一个服务,如下例所示:

我发现有几篇博文和文章建议不要与控制器中的实体一起操作,即在事务范围之外。所以我的 类 看起来像这样:

@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对象。如果您稍后决定删除数据库并使用一些外部系统,那么控制器层将不会受到影响。