`
zcw_java
  • 浏览: 303775 次
  • 性别: 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注解上的属性都没有被忽略。

谢谢你了。

相关推荐

    spring mvc拦截器过滤json中的null值

    接下来,我们将实现一个拦截器来过滤JSON中的null值。在`preHandle`方法中,我们可以读取请求体(request body),将其转换为JSON对象,然后遍历并替换null值为""(空字符串)。 ```java import org.spring...

    springMVC4-rest-jackson-jsonview-annotation.zip

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

    spring MVC 对 ResponseBody返回json数据进行脱敏处理

    默认情况下,Spring MVC使用`HttpMessageConverter`来完成这个转换,其中最常用的转换器是`MappingJackson2HttpMessageConverter`,它依赖于Jackson库来序列化对象为JSON。 接下来,我们将探讨如何实现JSON数据的...

    Apache CXF + Spring3 + REST + JSON配置

    以上是关于"Apache CXF + Spring3 + REST + JSON配置"的基本介绍,实际应用中可能涉及更多的细节和高级特性,如错误处理、分页、过滤器、拦截器等。在具体实践中,应结合项目需求灵活运用这些技术,以构建高效、可靠...

    Json字段过滤器

    通过这种方式,我们实现了通过自定义注解动态过滤JSON字段的功能,使得后端开发人员能够更灵活地控制返回给客户端的数据,提高系统的安全性。这种技术尤其适用于那些具有大量API且需要对返回数据进行精细控制的项目...

    Spring4.2.9+mybatis3.4.4集成(整合Jackson、防御XSS版)支持JDK1.6、Tomcat6

    2. 配置Spring MVC,使它能够使用Jackson进行JSON转换,通常在`web.xml`中配置`MappingJackson2HttpMessageConverter`。 **防御XSS攻击** XSS(Cross-Site Scripting)是一种常见的Web应用安全漏洞,允许攻击者...

    jackson2.7.8

    Jackson还支持更高级的功能,如处理复杂类型(如嵌套对象、集合、泛型),处理日期和时间,自定义序列化和反序列化逻辑,以及使用`JsonView`进行数据过滤等。此外,对于大型项目,可以通过配置`ObjectMapper`实例来...

    spring boot 下对JSON返回值去除null和空字段操作

    首先,Spring Boot默认使用的JSON库是Jackson,它提供了强大的JSON序列化和反序列化功能。为了去除JSON中的`null`值和空字符串,我们可以通过自定义Jackson配置来实现。以下是一个简单的配置类`JacksonConfig`示例:...

    Spring boot中Jackson的操作指南

    Jackson 是一个功能强大且灵活的 JSON 处理器,在 Spring Boot 项目中,我们可以方便地使用 Jackson 来对 Java 对象进行 JSON 序列化和反序列化。但是,我们需要了解 Jackson 的基本使用和配置,以便更好地使用 ...

    jackson-dynamic-filter:一种使用Jackson来动态确定过滤器的简便方法

    杰克逊动态属性过滤器基本上,当您使用Gson时,需要从目标对象上的序列化WITHOUT批注中排除特定字段,您将...要求Java 8 支持的Spring IO平台: 下载要使用Maven添加依赖项,请使用以下命令: &lt; dependency&gt;&lt; groupId&gt;...

    Spring MVC 更灵活的控制 json 返回问题(自定义过滤字段)

    本文将围绕如何在Spring MVC中灵活控制JSON返回数据,即自定义过滤返回字段的问题,介绍几种不同的实现方法。 首先,我们了解到Spring MVC默认的JSON转换器是Jackson,它支持通过注解在实体类上定义序列化规则。...

    彻底根治Spring @ResponseBody JavaScript HTML特殊字符

    其中,`MappingJackson2HttpMessageConverter`是处理JSON的主要转换器,它使用Jackson库进行序列化。 - Jackson提供了配置选项来自动进行HTML转义。可以通过配置`ObjectMapper`来实现,例如: ```java ...

    使用json-lib将java对象转换成json字符串

    - 使用Gson或Jackson等更现代的库,它们提供了更强大和灵活的JSON处理功能,性能也更好。 - 对于大型项目,考虑使用Spring Boot等框架集成的自动转换服务,以减少手动编码的工作量。 6. **异常处理**: - 在进行...

    使用json的jar包

    可以使用库提供的安全模式,或者在解析JSON前进行预处理,过滤掉潜在的恶意输入。 总之,JSON是现代Web应用中不可或缺的数据交换格式,而Java的JSON库为我们提供了便捷的操作接口。无论是在SSH还是SSM框架下,熟练...

    ssh整合中的jsonjar包

    在SSH框架中,可以通过验证和过滤输入,或者使用如Jackson的`@JsonAutoDetect`注解限制序列化范围来防止。 6. **测试和调试**:使用Postman等工具进行API接口的测试,检查JSON数据是否正确传输和解析。对于调试,...

    java解析json的jar包

    在解析JSON时,这个库可以用于处理和操作解析后的JSON数据,例如创建自定义的集合类型,进行数据过滤和转换。 除了以上提到的库,还有其他一些流行的Java JSON解析库,如: - **Jackson**:一个高效的、功能丰富的...

    完整jersey包和jackson-all-1.9.2.jar

    而“jackson-all-1.9.2.jar”则指的是Jackson库的一个早期版本,Jackson是Java中广泛使用的JSON处理库,用于序列化和反序列化Java对象到JSON格式,以及反之。 **jersey知识点** 1. **Jersey简介**:Jersey是开源的...

    java转json的jar包

    例如,在Spring框架中,你可以使用`@CrossOrigin`注解或配置CORS过滤器来启用跨域请求。 在给定的“java转json的jar包”压缩文件中,可能包含了这些库的JAR文件,如Jackson、Gson或org.json的JAR。将这些JAR添加到...

    Spring3.2Jar官方jar包

    在这个"Spring3.2Jar官方jar包"中,我们找到了一系列与Spring 3.2版本相关的库,这些库不仅包括Spring的核心组件,还包含了一些常用的依赖库,如Hibernate、AspectJ和Jackson等。下面将详细阐述这些文件及其在Spring...

    spring in action的jar包

    在"lib"目录下,这些jar包可能包含了Spring框架的上述所有或部分模块,以及运行示例代码可能需要的其他库,如JDBC驱动、JSON处理库(如Jackson或Gson)、HTTP客户端库(如Apache HttpClient)等。确保这些jar包正确...

Global site tag (gtag.js) - Google Analytics