完美解决json循环问题(使用javassist增强):Spring MVC中使用jackson的MixInAnnotations方法动态过滤JSON字段

问题描述

项目使用SpringMVC框架,并用jackson库处理JSONPOJO的转换。在POJO转化成JSON时,有些属性我们不需要输出或者有些属性循环引用会造成无法输出。

例如:实体User其中包括用户名、密码、邮箱等,但是我们在输出用户信息不希望输出密码、邮箱信息;

例如:实体userdepartment是多对一的关系,user内保存着department的信息,那么json输出时会导致这两个实体数据的循环输出;

jackson默认可以使用JsonIgnoreProperties接口来定义要过滤的属性,然后使用ObjectMapper#addMixInAnnotations来设置对应实体对应的JsonIgnoreProperties接口,这样就能达到过滤的目的。可是这样很不爽,因为如果你对n个实体对应有m种过滤需求就至少要建n*mJsonIgnoreProperties接口。

解决方案

主要逻辑如下图

 


大致处理流程:

1、使用自定义注解controller方法

2、然后定义aop捕获所有controller方法

3、当aop捕获到controller方法时调用JavassistFilterPropertyHandler#filterProperties方法;

4、filterProperties读取注解并根据自定义注解使用javassist创建JsonIgnoreProperties临时实现类(同时缓存到map内,下次可直接取出)并存入当前线程内(ThreadJacksonMixInHolder, 使用threadlocal实现),

5、在springmvc输出json的类内自定义ObjectMapper, 从当前线程内取出JsonIgnoreProperties临时类, 调用ObjectMapper# addMixInAnnotations使之起效

6、最后使用ObjectMapper输出


用法:

1、定义aop, 用来捕获springmvc的controller方法,

package com.xiongyingqi.json.filter.aop;

import com.xiongyingqi.jackson.FilterPropertyHandler;
import com.xiongyingqi.jackson.impl.JavassistFilterPropertyHandler;
import org.apache.log4j.Logger;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;

import java.lang.reflect.Method;

/**
 * @author 瑛琪 <a href="http://xiongyingqi.com">xiongyingqi.com</a>
 * @version 2013-9-27 下午5:41:12
 */
@Aspect
public class IgnorePropertyAspect {
    public static final Logger LOGGER = Logger.getLogger(IgnorePropertyAspect.class);

    @Pointcut("execution(* com.kingray.web.*.*(..))")
    private void anyMethod() {

    }

    @Around("anyMethod()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        Object returnVal = pjp.proceed(); // 返回源结果
        try {
            FilterPropertyHandler filterPropertyHandler = new JavassistFilterPropertyHandler(true);
            Method method = ((MethodSignature) pjp.getSignature()).getMethod();
            returnVal = filterPropertyHandler.filterProperties(method, returnVal);
        } catch (Exception e) {
            LOGGER.error(e);
            e.printStackTrace();
        }

        return returnVal;
    }

    @AfterThrowing(pointcut = "anyMethod()", throwing = "e")
    public void doAfterThrowing(Exception e) {
        System.out.println(" -------- AfterThrowing -------- ");
    }
}


spring配置:

<!-- 启动mvc对aop的支持,使用aspectj代理 -->
<aop:aspectj-autoproxyproxy-target-class="true" />
<beanid="ignorePropertyAspect" class="com.xiongyingqi.json.filter.aop.IgnorePropertyAspect"></bean>


2、配置spring-mvc的messageconverter

<pre name="code" class="java">	<bean
		class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
		<property name="cacheSeconds" value="0" />
		<!--日期格式转换 -->
		<property name="webBindingInitializer">
			<bean class="com.kingray.spring.http.convert.DateConverter" />
		</property>
		<property name="messageConverters">
			<list>
				<bean
					class="com.xiongyingqi.spring.http.convert.json.Jackson2HttpMessageConverter">
				</bean>
				<bean
					class="com.xiongyingqi.spring.http.convert.json.JacksonHttpMessageConverter">
				</bean>
				<bean
					class="org.springframework.http.converter.BufferedImageHttpMessageConverter">
				</bean>
				<bean
					class="org.springframework.http.converter.ResourceHttpMessageConverter">
				</bean>
				<bean class="org.springframework.http.converter.FormHttpMessageConverter">
				</bean>
				<bean
					class="org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter">
				</bean>
				<bean
					class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter">
				</bean>
				<bean
					class="org.springframework.http.converter.feed.AtomFeedHttpMessageConverter">
				</bean>
				<bean
					class="org.springframework.http.converter.feed.RssChannelHttpMessageConverter">
				</bean>
				<bean
					class="org.springframework.http.converter.xml.Jaxb2CollectionHttpMessageConverter">
				</bean>
				<bean
					class="org.springframework.http.converter.xml.SourceHttpMessageConverter">
				</bean>
				<bean
					class="org.springframework.http.converter.ByteArrayHttpMessageConverter">
				</bean>
			</list>
		</property>
		
	</bean>


3、重写spring的MappingJackson2HttpMessageConverter类,这样输出的json内容就能自定义

package com.xiongyingqi.spring.http.convert.json;

import java.io.IOException;

import com.xiongyingqi.jackson.helper.ThreadJacksonMixInHolder;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;

import com.fasterxml.jackson.core.JsonEncoding;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jack
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值