【问题标题】:Best way to convert a JPA entity to REST representations using JAX-RS and Jackson使用 JAX-RS 和 Jackson 将 JPA 实体转换为 REST 表示的最佳方法
【发布时间】:2016-11-09 01:12:02
【问题描述】:

我正在寻找一种将一些 JPA 实体导出到 REST API 的方法,但不是每次我想根据入口点共享一些特定字段时都发送整个实体。这是一个小例子:

假设我们有一个带有少量字段的 Author 类:

@Entity
public class Author implements Serializable{

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = SEQUENCE)
    private Long id;

    @NotNull
    @Size(min = 1, message = "{required.field}")
    private String name;

    @NotNull
    @Size(min = 1, message = "{required.field}")
    private String country;

    private LocalDate birthDate;

    // getters and setters
}

假设我们有这个 REST 服务(只有两种方法):

@Path("authors")
public class AuthorREST {

    @Inject
    private AuthorBC bc;

    @GET
    @Produces("application/json")
    public List<Author> find(@QueryParam("q") String query) throws Exception {

        List<Author> result;

        if (Strings.isEmpty(query)) {
            result = bc.findAll();
        } else {
            result =  bc.find(query);
        }
        return result;
    }

    @GET
    @Path("{id}")
    @Produces("application/json")
    public Author load(@PathParam("id") Long id) throws Exception {

        Author result = bc.load(id);

        if (result == null) {
            throw new NotFoundException();
        }

        return result;
    }
}

现在,这样一来,当我的 API 被调用时,我将始终拥有 4 个字段。

我了解,如果我使用 Jackson,我可以将 @JsonIgnore 设置为我想忽略的字段,并且它们将始终被忽略。

但是如果我想要这样的话,在某些情况下,我的整个实体由一个服务返回,而在其他服务(或同一服务中的其他方法)中,只返回 2 或 3 个字段?

有办法吗?

【问题讨论】:

    标签: java rest jpa jackson jax-rs


    【解决方案1】:

    @JsonView 和混入

    您已经知道可以使用 @JsonIgnore 和 @JsonIgnoreProperties 等注解让 Jackson 忽略某些属性。

    您也可以检查@JsonView 注释。有关如何将 @JsonView 与 JAX-RS 一起使用的一些详细信息,请查看 here。

    如果修改 JPA 实体不是一个选项,请考虑按照answer 中所述的混合注释。

    数据传输对象

    Data Transfer Object (DTO) 是一种具有明确目的的模式:将数据传输到远程接口,就像 webservices。这种模式非常适合 REST API,从长远来看,使用 DTO 您将拥有更多灵活性。一旦 REST 资源表示不需要具有与持久性对象相同的属性,您就可以根据需要定制类。

    为避免使用样板代码,您可以使用映射框架(例如 MapStruct)将您的 REST API DTO 从/到您的持久性对象映射。

    有关使用 DTO 的好处的详细信息,请查看以下答案:

    要为您的 DTO 提供更好的名称,请检查以下答案:

    【讨论】:

      【解决方案2】:

      如果你想从你的 JPA 实体中解耦解析并只返回某些属性,你总是可以使用 Mixins 来达到这个目的。 http://www.cowtowncoder.com/blog/archives/2009/08/entry_305.html https://github.com/FasterXML/jackson-docs/wiki/JacksonMixInAnnotations

      还有一件事。如果您希望某项服务中的事物是动态的,则在另一个服务中返回一种表示以返回另一种表示。您的选择是编写自定义 JSON 序列化程序! 查看这篇文章以了解如何创建客户序列化程序: How do I use a custom Serializer with Jackson?

      【讨论】:

      • 我会试试看它是否是我正在寻找的。谢谢
      • 谢谢,我已经使用混音进行了测试,比起使用 DTO,我更喜欢它。此外,@JsonViews 似乎是一个不错的选择,但目前我会坚持使用 Mixin。
      • 我认为你不应该序列化你的实体类,将值复制到 DTO 以获得更好的序列化控制。使用 Mixins 处理实体的不同视图听起来像是一种解耦,下一个查看代码的开发人员很容易忽略它。
      【解决方案3】:

      就我自己而言,我发现使用@JsonView 注解非常合适。因此,您可以定义要在特定视图中呈现的字段。你可以在这里找到更多信息http://wiki.fasterxml.com/JacksonJsonViews

      【讨论】:

      • 我喜欢 @JsonView 可以做的事情,但我可以使用 mixins。我还不知道使用一种或另一种是否有任何优势/劣势,但目前我会坚持使用 Mixin。还是谢谢你。
      【解决方案4】:

      我认为您可以使用 Jersey 框架编写自定义 MessageBodyWriter,并且可以按照您想要的方式控制响应负载。在这里,您必须编写几行代码才能管理响应负载。欲了解更多信息,请访问https://jersey.java.net/documentation/latest/message-body-workers.html#d0e6826

      【讨论】:

        【解决方案5】:

        我会使用 Spring Data REST,然后使用 ApiModel 注释来隐藏您不想暴露的属性。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-08-23
          • 2012-11-30
          相关资源
          最近更新 更多