在 Spring Data rest json Response 中动态过滤实体字段

Posted

技术标签:

【中文标题】在 Spring Data rest json Response 中动态过滤实体字段【英文标题】:Filtering entity fields dynamically in Spring Data rest json Response 【发布时间】:2015-10-15 00:22:28 【问题描述】:

嗨,我需要动态忽略 spring 数据休息响应中的实体字段 [我知道它们可以通过使用 @JsonIgnore 注释以静态方式完成] 理想情况下基于 spring 安全角色。角色部分仍然是可管理的,但如何动态忽略 json 响应中的字段是一个挑战。 经过一些分析和文档,我认为 jackson 是要走的路,因为 spring data rest 确实通过 jackson 模块和 mixins http://docs.spring.io/spring-data/rest/docs/current/reference/html/#customizing-sdr.custom-jackson-deserialization 提供了 jackson 定制。

所以我认为在 jackson api 中可以通过 @jsonFilter 完成,然后在 ObjectMapper 写入对象时提供相同的内容 [更多详细信息在这里 http://www.cowtowncoder.com/blog/archives/2011/09/entry_461.html] 。

但我不确定这如何与 Spring data rest 连接(基本上是我可以将 filterprovider 注入 spring data rest objectmapper 的部分)。让我知道是否有人尝试过这个或 Spring 数据团队的某人有见解。

如果我能达到同样的效果,我会自己发布答案。

更新

所以我发现实现自定义过滤的方法是通过 jackson BeanSerializerModifier。得到了 Twitter 上 @cowtowncoder 的大力帮助。还有有用的参考或使用 jackson 过滤的圣杯http://www.cowtowncoder.com/blog/archives/2011/02/entry_443.html

【问题讨论】:

ok 终于可以实现了,很快就会给出答案 【参考方案1】:

所以是的,最后我能够解决这个问题。这里的诀窍是使用自定义 BeanSerializerModifier 并通过自定义模块注册它[这是可用于自定义 spring data rest jackson 序列化的自定义钩子],类似于

 setSerializerModifier( new CustomSerializerModifier()).build()));

现在您可以通过覆盖方法 changeProperties 来自定义我们的 BeanSerializerModifier 以应用您的自定义过滤器,该过滤器基本上包括和排除 BeanPropertyWriter 根据您的逻辑。示例如下

List<BeanPropertyWriter> included = Lists.newArrayList();
    for (BeanPropertyWriter property : beanProperties)
        if (!filter.contains(property.getName()))
            included.add(property);

通过这种方式,您可以在每个类中包含任何逻辑或以其他方式包含任何逻辑,并以自定义方式过滤属性表单响应。希望对您有所帮助

还更新了我在 github 上的代码,请查看https://github.com/gauravbrills/SpringPlayground

【讨论】:

【参考方案2】:

这个例子展示了如何在 Spring Boot REST 控制器中实现动态 JSON 转换(过滤)。它使用 AOP 控制器建议在运行时更改控制器方法输出。 github上的代码:https://github.com/andreygrigoriev/jsonfilter

AOP 建议

@ControllerAdvice
@SuppressWarnings("unused")
public class FilterAdvice implements ResponseBodyAdvice<Object> 

   @Override
   public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) 
      String fields = ((ServletServerHttpRequest) request).getServletRequest().getParameter("fields");
      return new FilterMappingJacksonValue<>(body, StringUtils.isEmpty(fields) ? new String[]  : fields.split(","));
   

   @Override
   public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) 
      return true;
   

FilterMappingJacksonValue

public class FilterMappingJacksonValue<T> extends MappingJacksonValue 

   public FilterMappingJacksonValue(final T value, final String... filters) 
      super(value);
      setFilters(new SimpleFilterProvider().addFilter("dynamicFilter",
            filters.length > 0 ? SimpleBeanPropertyFilter.filterOutAllExcept(filters) : SimpleBeanPropertyFilter.serializeAll()));
   

简单的 DTO

@Data
@AllArgsConstructor
@JsonFilter("dynamicFilter")
public class Book 
   String name;
   String author;

图书控制器

@RestController
@SuppressWarnings("unused")
public class BookController 

   @GetMapping("/books")
   public List<Book> books() 
      List<Book> books = new ArrayList<>();
      books.add(new Book("Don Quixote", "Miguel de Cervantes"));
      books.add(new Book("One Hundred Years of Solitude", "Gabriel Garcia Marquez"));
      return books;
   

【讨论】:

以上是关于在 Spring Data rest json Response 中动态过滤实体字段的主要内容,如果未能解决你的问题,请参考以下文章

spring-data-rest 集成测试因简单的 json 请求而失败

在 Spring Data rest json Response 中动态过滤实体字段

纯 JSON(非 HAL 格式)的 Spring Data REST

Spring data rest @ManyToOne 字段不在 json 中

从 Spring Data REST 返回 JSON 响应中的 ID

Jason中的Spring Data Rest -Disable自我链接(HAL)