如何使用 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
- 添加
build.gradle.kts
:
implementation("com.fasterxml.jackson.datatype:jackson-datatype-hibernate5:$jacksonHibernate")
- 创建
@Bean
@Bean
fun hibernate5Module(): Module = Hibernate5Module()
注意Module
是com.fasterxml.jackson.databind.Module
,不是java.util.Module
另外一个好的做法是将 @JsonBackReference
& @JsonManagedReference
添加到 @OneToMany
& @ManyToOne
关系。
我有一个使用 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
- 添加
build.gradle.kts
:
implementation("com.fasterxml.jackson.datatype:jackson-datatype-hibernate5:$jacksonHibernate")
- 创建
@Bean
@Bean
fun hibernate5Module(): Module = Hibernate5Module()
注意
Module
是com.fasterxml.jackson.databind.Module
,不是java.util.Module
另外一个好的做法是将
@JsonBackReference
&@JsonManagedReference
添加到@OneToMany
&@ManyToOne
关系。