如何使用 Spring Data JPA + Spring Web MVC 在 JSON 序列化中避免延迟获取?

How to avoid lazy fetch in JSON serialization using Spring Data JPA + Spring Web MVC?

我有一个使用 Spring Data JPA 和 Spring Web MVC 中的 REST 控制器的解决方案。持久性提供程序是 Hibernate。

持久层是使用 Spring 存储库构建的,在 de REST 控制器和存储库之间存在一个服务层:

Entity <--> Repository <--> Service <--> Controller

在实体级别,我有带 FetchType = LAZY 的 @OneToMany 字段。

当 REST 控制器进行序列化时,进行提取,但在某些情况下这是不希望的。

我已经尝试使用@JSONInclude Jackson 注释,但序列化仍然存在。

有人可以帮助我提供经过验证的解决方案吗?

我们可以通过将 Hibernate4Module(支持惰性对象)添加到 Spring 已经提供的默认 MappingJackson2HttpMessageConverter 并将其添加到 HttpMessageConverters 来实现。

所以我们需要从 WebMvcConfigurerAdapter 扩展我们的 spring 配置 class 并覆盖方法 configureMessageConverters 并添加 MappingJackson2HttpMessageConverter其中注册了Hibernate4Module。

@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    //Here we add our custom-configured HttpMessageConverter
    converters.add(jacksonMessageConverter());
    super.configureMessageConverters(converters);
}

// Here we register the Hibernate4Module into an ObjectMapper, 
// then use this custom ObjectMapper
// to the MessageConverter
public MappingJackson2HttpMessageConverter jacksonMessageConverter(){
    MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();

    ObjectMapper mapper = new ObjectMapper();
    //Registering Hibernate4Module to support lazy objects
    mapper.registerModule(new Hibernate4Module());

    messageConverter.setObjectMapper(mapper);
    return messageConverter;

}

如果我没理解错的话,您只想在获取延迟加载集合时进行序列化,但不希望序列化触发获取。

如果是这种情况,您应该使用 jackson-datatype-hibernate,并添加为他们的文档已经解释

public class HibernateAwareObjectMapper extends ObjectMapper {

    public HibernateAwareObjectMapper() {
        registerModule(new Hibernate4Module());
    }
}

比注册

 <mvc:annotation-driven>
        <mvc:message-converters>
            <!-- Use the HibernateAware mapper instead of the default -->
            <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
                <property name="objectMapper">
                    <bean class="path.to.your.HibernateAwareObjectMapper" />
                </property>
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>

该模块有一个Feature.FORCE_LAZY_LOADING设置,告诉是否应该强制加载对象然后序列化,默认设置为false 我相信这是你需要的行为

简单的架构解决方案是不使用模型实体作为数据传输对象。将简单的 POJO 作为数据传输对象。在转换逻辑中,您可以轻松地为 LazyInitializationException 放置 try 和 catch 块。因此你的 POJO 总是可序列化的,你可以在你的控制器上使用它。

如果您总是想跳过这个特定字段,请使用@JsonIgnore 注释。如果要动态确定要跳过的字段,请使用 @JsonView。请注意,@JsonView 是 Jackson 特定的注释,但由于您已经在使用 Jackson,所以应该没问题。

你可以通过 jackson-datatype-hibernate:

两步解决这个问题

kotlin example

  1. 添加 build.gradle.kts:
implementation("com.fasterxml.jackson.datatype:jackson-datatype-hibernate5:$jacksonHibernate")
  1. 创建@Bean
   @Bean
   fun hibernate5Module(): Module = Hibernate5Module()

  • 注意Modulecom.fasterxml.jackson.databind.Module,不是java.util.Module

  • 另外一个好的做法是将 @JsonBackReference & @JsonManagedReference 添加到 @OneToMany & @ManyToOne 关系。