在 Spring 数据 rest json 响应中动态过滤实体字段

Filtering entity fields dynamically in Spring Data rest json Response

您好,我需要动态忽略 spring 数据剩余响应中的实体字段 [我知道它们可以通过使用 @JsonIgnore 注释以静态方式完成] 理想情况下基于 spring security Role 。角色部分仍然是可管理的,但是如何动态地忽略 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 数据剩余连接起来(基本上是我可以将 filterprovider 注入 spring 数据剩余 objectmapper 的部分)。如果有人告诉我已经尝试过这个或者 Spring 数据团队的某个人有见解。

post 我自己能回答吗 如果我能达到同样的效果。

更新

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

所以是的,我终于能够解决这个问题。这里的技巧是使用自定义 BeanSerializerModifier 并通过自定义模块注册它 [这是可用于自定义 spring 数据 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);

通过这种方式,您可以根据 class 或其他方式包含任何逻辑,并在自定义 manner.Hope 中形成响应的过滤器属性 manner.Hope 它有帮助

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

此示例展示了如何在 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;
   }
}