`
zcw_java
  • 浏览: 297156 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Spring使用Jackson过滤!JSON

 
阅读更多
原文http://www.cnblogs.com/zcw-ios/articles/3343071.html

一、问题的提出。

项目使用Spring MVC框架,并用jackson库处理JSON和POJO的转换。在POJO转化成JSON时,希望动态的过滤掉对象的某些属性。所谓动态,是指的运行时,不同的controler方法可以针对同一POJO过滤掉不同的属性。

以下是一个Controler方法的定义,使用@ResponseBody把获得的对象列表写入响应的输出流(当然,必须配置jackson的MappingJacksonHttpMessageConverter,来完成对象的序列化)
    @RequestMapping(params = "method=getAllBmForList")
    @ResponseBody
    public List<DepartGenInfo> getAllBmForList(HttpServletRequest request,
            HttpServletResponse response) throws Exception {
        
        BmDto dto = bmglService.getAllBm();
        return dto.getBmList();
    }

POJO定义如下
public class DepartGenInfo implements java.io.Serializable {

     private String depid;
     private String name;
     private Company company;

     //getter...
     //setter...
} 

public class Company&nbsp; {

&nbsp;&nbsp;&nbsp;&nbsp; private String comid;
&nbsp;&nbsp;&nbsp;&nbsp; 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动态过滤
    @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的定义如下:
 serializationConfig.addMixInAnnotations();

这个实现方法看起来非常不简洁,需要在动态过滤的时候写不少代码,而且也改变了@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定义了混合的模板以及目标类。
@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如下:
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;
	}

}

在Spring  MVC中进行AOP的配置
<bean id="xunerJsonFilterAdvice" class="com.xunersoft.common.json.XunerJsonFilterAdvice"/>
    
    <aop:config>
        <aop:aspect id="jsonFilterAspect" ref="xunerJsonFilterAdvice">
            <aop:pointcut id="jsonFilterPointcut" expression="execution(* com.xunersoft.webapp.rsgl.controller.*.*(..))"/>
            <aop:around pointcut-ref="jsonFilterPointcut" method="doAround"/>
        </aop:aspect>
    </aop:config>

其中pointcut的expression能够匹配到目标类的方法。

在doAround方法中,需要获得当前引用的HttpResponse对象,因此使用以下方法解决:

创建一个WebContext工具类:
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);
	}
}

定义一个Servlet Filter:
@Component("webContextFilter")
public class WebContextFilter implements Filter {

	public void init(FilterConfig filterConfig) throws ServletException {    
		
	}
	
	public void doFilter(ServletRequest req, ServletResponse resp,
			FilterChain chain) throws IOException, ServletException {
		HttpServletRequest request = (HttpServletRequest) req;
		HttpServletResponse response = (HttpServletResponse) resp;
		ServletContext servletContext = request.getSession().getServletContext();
		WebContext.create(request, response, servletContext);
		chain.doFilter(request, response);
		WebContext.clear();
	}

	@Override
	public void destroy() {
		// TODO Auto-generated method stub
		
	}

}

别忘了在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
分享到:
评论
1 楼 zhyuan2008 2012-07-10  
请你把示例代码打个包,提供个下载,可以吗?
我按照你的方式做了,但是定义在filter注解上的属性都没有被忽略。

谢谢你了。

相关推荐

    springMVC4-rest-jackson-jsonview-annotation.zip

    分享一个使用SpringMVC4 Rest 和Jackson的@JsonView...Spring提供了MappingJacksonValue 包装POJO和序列化视图设置,在发送到web服务器短的时候,我们可以使用RestTemplate来过滤JSON。现在一步一步呈现完整的示例。

    spring-mvc-JsonIgnoreDynamically:渲染前按名称从 jackson json 序列化中排除某些字段

    spring-mvc-Json动态忽略目的 : 有时,过滤序列化到 HTTP 响应主体的上下文对象会很有用。在某些情况下,返回的部分数据可能对使用 API 的设备没有用,或者应该对公众保持不可见,因此不应该t 通过 JSON 序列化和...

    Spring Boot中文文档.rar

    使用Spring Boot 13.构建系统 13.1.依赖管理 13.2.Maven 13.2.1.继承Starter Parent 13.2.2.在没有父POM的情况下使用Spring Boot 13.2.3.使用Spring Boot Maven插件 13.3.Gradle 13.4.Ant ...

    spring security 参考手册中文版

    使用Spring 4.0.x和Gradle 24 2.4.3项目模块 25 核心 - spring-security-core.jar 25 远程处理 - spring-security-remoting.jar 25 Web - spring-security-web.jar 25 配置 - spring-security-config.jar 26 LDAP - ...

    jfilter:用于过滤REST Spring Web Service类型的应用程序响应的JFilter库

    当您使用Jackson @JsonView接口并且需要更强大和灵活的时候,该库可能会很有用。 有关信息,请点击以下链接。刊物样品您可以在GitHub 查看所有指数库流程图图安装要使用此库,您需要导入依赖项&lt; dependency&gt; ...

    一个简洁的java http框架.rar

    支持JSON转换框架: Fastjson, Jackson, Gson 支持JAXB形式的XML转换 可以通过OnSuccess和OnError接口参数实现请求结果的回调 配置简单,一般只需要@Request一个注解就能完成绝大多数请求的定义 支持异步请求调用

    java8集合源码-tips:尖端

    使用Spring WebSockets聊天应用程序 Spring Cache spring boot Spring Boot启动过程及回调接口汇总 后台运行配置  - 调度示例 spring cloud 文档 工具类集合 分布式ID 学习资料 规范? 中文分词等 网页聊天 通信 ...

    java8集合源码-tips:小贴士

    使用Spring WebSockets聊天应用程序 Spring Cache spring boot Spring Boot启动过程及回调接口汇总 后台运行配置  - 调度示例  - 配置加密 spring cloud 文档 工具类集合 分布式ID 学习资料 规范? 中文分词等 网页...

    eclair:Java Spring库用于声明式日志记录

    JSON (Jackson撰写) XML (通过JAXB) 基于范围的声明式定义(使用SpEL )和擦除映射的诊断上下文(MDC) 多个记录器定义 应用程序上下文启动期间的注释验证 使用元注释(应用于其他注释)和注释方法覆盖的...

    ItCast-HeiMa-Travel

    Jackson:json 序列化工具,前后端数据通用传输格式 2. service层 JavaMail:Java 邮件工具 Redis:nosql 内存数据库 Jedis:Java 的 Jedis 客户端 3. dao层 mysql:关系数据库 druid:数据库连接池 Spring Jdbc ...

    java开源包8

    Jackson 是一个 Java 用来处理 JSON 格式数据的类库,性能非常好。 哈希计算工具 java-hash 用来计算 MD5、SHA 哈希算法的 Java 类库,支持 "MD5", "SHA", "SHA-1", "SHA-256", "SHA-384", "SHA-512". 高性能RPC...

    java开源包1

    Jackson 是一个 Java 用来处理 JSON 格式数据的类库,性能非常好。 哈希计算工具 java-hash 用来计算 MD5、SHA 哈希算法的 Java 类库,支持 "MD5", "SHA", "SHA-1", "SHA-256", "SHA-384", "SHA-512". 高性能RPC...

    java开源包11

    Jackson 是一个 Java 用来处理 JSON 格式数据的类库,性能非常好。 哈希计算工具 java-hash 用来计算 MD5、SHA 哈希算法的 Java 类库,支持 "MD5", "SHA", "SHA-1", "SHA-256", "SHA-384", "SHA-512". 高性能RPC...

    java开源包2

    Jackson 是一个 Java 用来处理 JSON 格式数据的类库,性能非常好。 哈希计算工具 java-hash 用来计算 MD5、SHA 哈希算法的 Java 类库,支持 "MD5", "SHA", "SHA-1", "SHA-256", "SHA-384", "SHA-512". 高性能RPC...

    java开源包3

    Jackson 是一个 Java 用来处理 JSON 格式数据的类库,性能非常好。 哈希计算工具 java-hash 用来计算 MD5、SHA 哈希算法的 Java 类库,支持 "MD5", "SHA", "SHA-1", "SHA-256", "SHA-384", "SHA-512". 高性能RPC...

    java开源包6

    Jackson 是一个 Java 用来处理 JSON 格式数据的类库,性能非常好。 哈希计算工具 java-hash 用来计算 MD5、SHA 哈希算法的 Java 类库,支持 "MD5", "SHA", "SHA-1", "SHA-256", "SHA-384", "SHA-512". 高性能RPC...

    java开源包5

    Jackson 是一个 Java 用来处理 JSON 格式数据的类库,性能非常好。 哈希计算工具 java-hash 用来计算 MD5、SHA 哈希算法的 Java 类库,支持 "MD5", "SHA", "SHA-1", "SHA-256", "SHA-384", "SHA-512". 高性能RPC...

    java开源包10

    Jackson 是一个 Java 用来处理 JSON 格式数据的类库,性能非常好。 哈希计算工具 java-hash 用来计算 MD5、SHA 哈希算法的 Java 类库,支持 "MD5", "SHA", "SHA-1", "SHA-256", "SHA-384", "SHA-512". 高性能RPC...

    java开源包4

    Jackson 是一个 Java 用来处理 JSON 格式数据的类库,性能非常好。 哈希计算工具 java-hash 用来计算 MD5、SHA 哈希算法的 Java 类库,支持 "MD5", "SHA", "SHA-1", "SHA-256", "SHA-384", "SHA-512". 高性能RPC...

    java开源包7

    Jackson 是一个 Java 用来处理 JSON 格式数据的类库,性能非常好。 哈希计算工具 java-hash 用来计算 MD5、SHA 哈希算法的 Java 类库,支持 "MD5", "SHA", "SHA-1", "SHA-256", "SHA-384", "SHA-512". 高性能RPC...

Global site tag (gtag.js) - Google Analytics