java spring使用Jackson过滤
一、问题的提出。
项目使用Spring MVC框架,并用jackson库处理JSON和POJO的转换。在POJO转化成JSON时,希望动态的过滤掉对象的某些属性。所谓动态,是指的运行时,不同的controler方法可以针对同一POJO过滤掉不同的属性。
以下是一个Controler方法的定义,使用@ResponseBody把获得的对象列表写入响应的输出流(当然,必须配置jackson的MappingJacksonHttpMessageConverter,来完成对象的序列化)
|
1
2
3
4
5
6
7
8
|
@RequestMapping(params = "method=getAllBmForList")@ResponseBodypublic List<DepartGenInfo> getAllBmForList(HttpServletRequest request, HttpServletResponse response) throws Exception { BmDto dto = bmglService.getAllBm(); return dto.getBmList();} |
POJO定义
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
public class DepartGenInfo implements java.io.Serializable { private String depid; private String name; private Company company; //getter... //setter...} public class Company { private String comid; private String name;<pre name="code" class="java"> //getter... //setter...} |
我希望在getAllBmForList返回时,过滤掉DepartGenInfo的name属性,以及company的comid属性。
jackson支持@JsonIgnore和@JsonIgnoreProperties注解,但是无法实现动态过滤。jackson给出了几种动态过滤的办法,我选择使用annotation mixin
•JSON View
•JSON Filter
•Annotation Mixin
二、使用annotation mixin动态过滤
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
@RequestMapping(params = "method=getAllBmForList")public void getAllBmForList(HttpServletRequest request, HttpServletResponse response) throws Exception { BmDto dto = bmglService.getAllBm(); ObjectMapper mapper = new ObjectMapper(); SerializationConfig serializationConfig = mapper.getSerializationConfig(); serializationConfig.addMixInAnnotations(DepartGenInfo.class, DepartGenInfoFilter.class); serializationConfig.addMixInAnnotations(Company.class, CompanyFilter.class); mapper.writeValue(response.getOutputStream(),dto.getBmList()); return;} |
DepartGenInfoFilter的定义如下:
@JsonIgnoreProperties(value={"name"}) //希望动态过滤掉的属性public interface DepartGenInfoFilter {}//CompanyFilter的定义如下: |
这个实现方法看起来非常不简洁,需要在动态过滤的时候写不少代码,而且也改变了@ResponseBody的运行方式,失去了REST风格,因此考虑到使用AOP来进行处理。
二、最终解决方案
先看下我想达到的目标,通过自定义注解的方式来控制动态过滤。
@XunerJsonFilters(value={@XunerJsonFilter(mixin=DepartGenInfoFilter.class, target=DepartGenInfo.class) ,@XunerJsonFilter(mixin=CompanyFilter.class, target=Company.class)}) @RequestMapping(params = "method=getAllBmForList") @ResponseBody public List getAllBmForList(HttpServletRequest request, HttpServletResponse response) throws Exception { BmDto dto = bmglService.getAllBm();return dto.getBmList(); } |
@XunerJsonFilters和@XunerJsonFilter是我定义的注解。@XunerJsonFilters是@XunerJsonFilter的集合,@XunerJsonFilter定义了混合的模板以及目标类。
|
1
2
3
4
5
6
7
8
9
|
@Retention(RetentionPolicy.RUNTIME)public @interface XunerJsonFilters { XunerJsonFilter[] value();}@Retention(RetentionPolicy.RUNTIME)public @interface XunerJsonFilter { Class<?> mixin() default Object.class; Class<?> target() default Object.class;} |
当然,只是定义注解并没有什么意义。重要的是如何根据自定义的注解进行处理。我定义了一个AOP Advice如下:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
public class XunerJsonFilterAdvice { public Object doAround(ProceedingJoinPoint pjp) throws Throwable { MethodSignature msig = (MethodSignature) pjp.getSignature(); XunerJsonFilter annotation = msig.getMethod().getAnnotation( XunerJsonFilter.class); XunerJsonFilters annotations = msig.getMethod().getAnnotation( XunerJsonFilters.class); if (annotation == null && annotations == null) { return pjp.proceed(); } ObjectMapper mapper = new ObjectMapper(); if (annotation != null) { Class<?> mixin = annotation.mixin(); Class<?> target = annotation.target(); if (target != null) { mapper.getSerializationConfig().addMixInAnnotations(target, mixin); } else { mapper.getSerializationConfig().addMixInAnnotations( msig.getMethod().getReturnType(), mixin); } } if (annotations != null) { XunerJsonFilter[] filters= annotations.value(); for(XunerJsonFilter filter :filters){ Class<?> mixin = filter.mixin(); Class<?> target = filter.target(); if (target != null) { mapper.getSerializationConfig().addMixInAnnotations(target, mixin); } else { mapper.getSerializationConfig().addMixInAnnotations( msig.getMethod().getReturnType(), mixin); } } } try { mapper.writeValue(WebContext.getInstance().getResponse() .getOutputStream(), pjp.proceed()); } catch (Exception ex) { throw new RuntimeException(ex); } return null; }} |
其中pointcut的expression能够匹配到目标类的方法。
在doAround方法中,需要获得当前引用的HttpResponse对象,因此使用以下方法解决:
创建一个WebContext工具类:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
public class WebContext { private static ThreadLocal<WebContext> tlv = new ThreadLocal<WebContext>(); private HttpServletRequest request; private HttpServletResponse response; private ServletContext servletContext; protected WebContext() { } public HttpServletRequest getRequest() { return request; } public void setRequest(HttpServletRequest request) { this.request = request; } public HttpServletResponse getResponse() { return response; } public void setResponse(HttpServletResponse response) { this.response = response; } public ServletContext getServletContext() { return servletContext; } public void setServletContext(ServletContext servletContext) { this.servletContext = servletContext; } private WebContext(HttpServletRequest request, HttpServletResponse response, ServletContext servletContext) { this.request = request; this.response = response; this.servletContext = servletContext; } public static WebContext getInstance() { return tlv.get(); } public static void create(HttpServletRequest request, HttpServletResponse response, ServletContext servletContext) { WebContext wc = new WebContext(request, response, servletContext); tlv.set(wc); } public static void clear() { tlv.set(null); }} |
别忘了在web.xml中增加这个filter。
OK,It is all。
四、总结
设计的一些要点:
1、要便于程序员使用。程序员根据业务逻辑需要过滤字段时,只需要定义个"Filter“,然后使用注解引入该Filter。
2、引入AOP来保持原来的REST风格。对于项目遗留的代码,不需要进行大幅度的修改,只需要增加注解来增加对过滤字段的支持。
仍需解决的问题:
按照目前的设计,定义的Filter不支持继承,每一种动态字段的业务需求就会产生一个Filter类,当类数量很多时,不便于管理。
五、参考资料
http://www.cowtowncoder.com/blog/archives/cat_json.html
http://www.jroller.com/RickHigh/entry/filtering_json_feeds_from_spring
原文地址:https://www.cnblogs.com/zcw-ios/articles/3343071.html
java spring使用Jackson过滤的更多相关文章
- [Java] Spring + SpringMVC + Maven + JUnit 搭建
示例项目下载: https://github.com/yangyxd/SpringDemo 利用前面 SpringMVC 项目的配置方式,完成初步的项目创建.下面只讲一些不同之处. 传送门: [Jav ...
- Java Spring Boot VS .NetCore (二)实现一个过滤器Filter
Java Spring Boot VS .NetCore (一)来一个简单的 Hello World Java Spring Boot VS .NetCore (二)实现一个过滤器Filter Jav ...
- Java Spring Boot VS .NetCore (十) Java Interceptor vs .NetCore Interceptor
Java Spring Boot VS .NetCore (一)来一个简单的 Hello World Java Spring Boot VS .NetCore (二)实现一个过滤器Filter Jav ...
- Jackson 过滤属性
jackson过滤属性分为静态和动态两种. 静态如下: 定义两个Bean 先,这两个bean 是父子关系. public class User { private String name; priva ...
- Spring Security 多过滤链的使用
Spring Security 多过滤链的使用 一.背景 二.需求 1.给客户端使用的api 2.给网站使用的api 三.实现方案 方案一: 方案二 四.实现 1.app 端 Spring Secur ...
- 从零开始学 Java - Spring 集成 Memcached 缓存配置(二)
Memcached 客户端选择 上一篇文章 从零开始学 Java - Spring 集成 Memcached 缓存配置(一)中我们讲到这篇要谈客户端的选择,在 Java 中一般常用的有三个: Memc ...
- 从零开始学 Java - Spring 集成 ActiveMQ 配置(一)
你家小区下面有没有快递柜 近两年来,我们收取快递的方式好像变了,变得我们其实并不需要见到快递小哥也能拿到自己的快递了.对,我说的就是类似快递柜.菜鸟驿站这类的代收点的出现,把我们原来快递小哥必须拿着快 ...
- 从零开始学 Java - Spring 集成 Memcached 缓存配置(一)
硬盘和内存的作用是什么 硬盘的作用毫无疑问我们大家都清楚,不就是用来存储数据文件的么?如照片.视频.各种文档或等等,肯定也有你喜欢的某位岛国老师的动作片,这个时候无论我们电脑是否关机重启它们永远在那里 ...
- 从零开始学 Java - Spring 集成 ActiveMQ 配置(二)
从上一篇开始说起 上一篇从零开始学 Java - Spring 集成 ActiveMQ 配置(一)文章中讲了我关于消息队列的思考过程,现在这一篇会讲到 ActivMQ 与 Spring 框架的整合配置 ...
随机推荐
- golang中特殊的标识符
你会发现在 Go 代码中的几乎所有东西都有一个名称或标识符.另外,Go 语言也是区分大小写的,这与 C 家族中的其它语言相同.有效的标识符必须以字符(可以使用任何 UTF-8 编码的字符或 _)开头, ...
- bootStrap表单验证插件的使用
bootStrapValidator插件的使用 1.插件的下载和引用 首先要引入bootstrapValidator插件.链接的地址:https://www.bootcdn.cn/jquery.boo ...
- 【JZOJ4935】【NOIP2017GDKOI模拟1.12】b
Boring 构造一棵包含1号结点的连通子集个数刚好为给定的n的树. 这棵树的结点不能多于60. 1<=n<=109 Gai 容易得到,计算给定一棵树的Ans1,其中Ansi表示包含i号结 ...
- Mybatis自查询递归查找子菜单
之前写过 java从数据库读取菜单,递归生成菜单树 今天才发现mybatis也可以递归查询子菜单 先看一下数据库 主键id,名称name,父id,和url 设计菜单类 public class Men ...
- Directx11教程(7) 画一个颜色立方体
原文:Directx11教程(7) 画一个颜色立方体 前面教程我们通过D3D11画了一个三角形,本章我们将画一个颜色立方体,它的立体感更强.主要的变动是ModelClass类,在Model ...
- Jmeter里面的时间单位
1.线程组里面的时间单位为秒(s),如下图:
- python 数据分析领域常用的包
- oracle如何启用审计
通过数据库初始化参数文件中的AUDIT_TRAIL 初始化参数启用和禁用数据库审计. DB 启用数据库审计并引导所有审计记录到数据库的审计跟踪 OS 启用数据库审计并引导所有审计记录到操作系统的审 ...
- C++中delete this
Is it legal (and moral) for a member function to say delete this? As long as you’re careful, it’s ok ...
- pytorch 多GPU训练总结(DataParallel的使用)
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/weixin_40087578/artic ...