在 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;
}
}
您好,我需要动态忽略 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;
}
}