Spring boot 实现jackson自定义字段过滤

一、问题描述

  • 当VO应用于不同的请求接口,可能需要的请求字段不一样
@Getter
@Setter
@ToString
@JsonInclude(JsonInclude.Include.NON_NULL)
public class User {
	
	private Integer id;
	
	private String name;
	
	private String sex;
	
	private String adress;
	
	private String phoneNumber;
	
	private Date gmtCreate;
	
	private Date gmtModified;

}

如上VO,对于插人接口,如下

public ApiResult addUser(@RequestBody User user) {
		ApiResult apiResult = ApiResult.SUCCESS();
		List<User> users = new ArrayList<User>();
		users.add(user);
		apiResult.setRows(users);
		return apiResult;
	}

可能只需要除id,gmtCreate,gmtModified的其它的字段,
但是对于edit接口,需要主键id,

public ApiResult editUser(@RequestBody User user) {
		ApiResult apiResult = ApiResult.SUCCESS();
		List<User> users = new ArrayList<User>();
		users.add(user);
		apiResult.setRows(users);
		return apiResult;
	}
  • 当VO应用于同一接口,请求VO与返回VO使用同一个类,所需必要字段不同
public ApiResult listUsers(@RequestBody User user) {
		ApiResult apiResult = ApiResult.SUCCESS();
		List<User> users = new ArrayList<User>();
		
		User user1 = new User();
		user1.setId(1);
		user1.setAdress("dd");
		user1.setName("dongzhi");
		user1.setPhoneNumber("15859637**8");
		user1.setSex("male");
		users.add(user1);
		
		User user2 = new User();
		user2.setId(1);普遍立场ObjectMapperaddMixIn(Class<?>他融个铜, 
		user2.setName("zhang");
		user2.setPhoneNumber("158596372**7");
		user2.setSex("female");
		users.add(user2);
		apiResult.setRows(users);
		return apiResult;
		
	}

针对此情况,入参可能只需要id参数,而返回的参数可能需要全部字段,或者根据需求返回需要字段。

**针对上述情况,现有的Jackson注解无法完成。如@JsonIgnore

因此需要基于此需求,利用Jackson内置机制,,利用AOP,注解的方式,进行指定字段的过滤。
参考博客

二、实现方式

结合@JsonFilter 与 public ObjectMapper addMixIn(Class<?> target, Class<?> mixinSource)方法。
@JsonFilter可以实现自定义字段过滤,主要用到其中两个方法

if (isInclude) {
			objectMapper.setFilterProvider(new SimpleFilterProvider().addFilter(filterId,
					SimpleBeanPropertyFilter.filterOutAllExcept(toBeFilterFields)));
		} else {
			objectMapper.setFilterProvider(new SimpleFilterProvider().addFilter(filterId,
					SimpleBeanPropertyFilter.serializeAllExcept(toBeFilterFields)));
		}

filterOutAllExcept:序列化指定字段
serializeAllExcept:除指定的字段都要序列化

addMixIn 可以实现要过滤的Vo和@JsonFilter解耦;
不使用用addMixIn,需要在VO加注解@JsonFilter,示例代码(参考博客)如下方式如下:

//"ID-TITLE"为filter 的id
@JsonFilter("ID-TITLE")
class Article {
 private String id;
 private String title;
 private String content;
 // ... getter/setter
}
 
// Demo
class Demo {
 public void main(String args[]) {
  ObjectMapper mapper = new ObjectMapper();
  // SimpleBeanPropertyFilter.filterOutAllExcept("id,title")
  // 过滤除了 id,title 以外的所有字段,也就是序列化的时候,只包含 id 和 title
  mapper.setFilterProvider(new SimpleFilterProvider().addFilter("ID-TITLE",
          SimpleBeanPropertyFilter.filterOutAllExcept("id,title"))); 
 
  String filterOut = mapper.writeValueAsString(new Article());
 
  mapper = new ObjectMapper();
  // SimpleBeanPropertyFilter.serializeAllExcept("id,title")
  // 序列化所有字段,但是排除 id 和 title,也就是除了 id 和 title之外,其他字段都包含进 json
  mapper.setFilterProvider(new SimpleFilterProvider().addFilter("ID-TITLE",
      SimpleBeanPropertyFilter.serializeAllExcept(filter.split("id,title"))));
 
  String serializeAll = mapper.writeValueAsString(new Article());
 
  System.out.println("filterOut:" + filterOut);
  System.out.println("serializeAll :" + serializeAll);  
 }
}

利用addMixIn方法示例(参考博客)

封装json转换

通过上面的代码,我们发现,可以使用 setFilterProvider 来灵活的处理需要过滤的字段。不过上面的方法还有一些缺陷就是,还是要在 原来的 model 上加注解,这里我们使用 ObjectMapper.addMixIn(Class<?> type, Class<?> mixinType) 方法,这个方法就是讲两个类的注解混合,让第一个参数的类能够拥有第二个参数类的注解。让需要过滤的 model 和 @JsonFilter 注解解除耦合

package diamond.cms.server.json;
 
import com.fasterxml.jackson.annotation.JsonFilter;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
 
/**
 * depend on jackson
 * @author Diamond
 */
public class CustomerJsonSerializer {
 
  static final String DYNC_INCLUDE = "DYNC_INCLUDE";
  static final String DYNC_FILTER = "DYNC_FILTER";
  ObjectMapper mapper = new ObjectMapper();
 
  @JsonFilter(DYNC_FILTER)
  interface DynamicFilter {
  }
 
  @JsonFilter(DYNC_INCLUDE)
  interface DynamicInclude {
  }
 
  /**
   * @param clazz 需要设置规则的Class
   * @param include 转换时包含哪些字段
   * @param filter 转换时过滤哪些字段
   */
  public void filter(Class<?> clazz, String include, String filter) {
    if (clazz == null) return;
    if (include != null && include.length() > 0) {
      mapper.setFilterProvider(new SimpleFilterProvider().addFilter(DYNC_INCLUDE,
          SimpleBeanPropertyFilter.filterOutAllExcept(include.split(","))));
      mapper.addMixIn(clazz, DynamicInclude.class);
    } else if (filter !=null && filter.length() > 0) {
      mapper.setFilterProvider(new SimpleFilterProvider().addFilter(DYNC_FILTER,
          SimpleBeanPropertyFilter.serializeAllExcept(filter.split(","))));
      mapper.addMixIn(clazz, DynamicFilter.class);
    }
  }
 
  public String toJson(Object object) throws JsonProcessingException {
    return mapper.writeValueAsString(object);
  }
}
我们之前的 Demo 可以变成:


// Demo
class Demo {
 public void main(String args[]) {
  CustomerJsonSerializer cjs= new CustomerJsonSerializer();
  // 设置转换 Article 类时,只包含 id, name
  cjs.filter(Article.class, "id,name", null); 
 
  String include = cjs.toJson(new Article()); 
 
  cjs = new CustomerJsonSerializer();
  // 设置转换 Article 类时,过滤掉 id, name
  cjs.filter(Article.class, null, "id,name"); 
 
  String filter = cjs.toJson(new Article());
 
  System.out.println("include: " + include);
  System.out.println("filter: " + filter);  
 }
}
输出结果
include: {id: "", title: ""}
filter: {content:""}

三、实现步骤

考虑利用Spring AOP机制,以及方法级别注解,可以实现在特定方法上,针对特定类的特定字段进行过滤,主要有三种情况,

  • 只过滤请求VO

  • 过滤返回VO的字段

  • 同时过滤请求VO和返回VO

  • 实现基本功能:只针对VO比较单一的情况进行过滤,对于VO嵌套其它VO的情况,暂时未做处理,对于继承字段可以进行过滤。

  • 当前仅支持入参为一个参数,且为对象的情况,其它情况暂未考虑。

  • 入参Vo和出餐VO可以不是同一个VO对象

3.1 注解定义

package com.learn.jackson.common.annotation;
 
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
 
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
 
@Documented
@Retention(RUNTIME)
@Target({ FIELD, METHOD })
public @interface JacksonFilters {
 
    JacksonFilter[] value();
 
}

package com.learn.jackson.common.annotation;
 
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
 
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
 
@Documented
@Retention(RUNTIME)
@Target(value = { ElementType.METHOD,FIELD})
@Repeatable(value=JacksonFilters.class)
public @interface JacksonFilter {
 
    Class<?> value();
 
    /**
     * include为对象需要包含的字段,默认使用include,如果include为空,则使用exclude字段
     * 
     * @Title: include
     * @Description: TODO(这里用一句话描述这个方法的作用)
     * @param param
     * @return String[]
     */
    String[] include() default {};
 
    /**
     * exclude 要排除的字段
     * 
     * @Title: exclude
     * @Description: TODO(这里用一句话描述这个方法的作用)
     * @param param
     * @return String[]
     */
    String[] exclude() default {};
    
 
    JscksonFilterType type() default  JscksonFilterType.RESPONSE;
 
    enum JscksonFilterType {
        REQUEST, RESPONSE;
    }
 
}

支持注解数组

3.2 filter定义
自定义四种filter,实现功能如下:

  • 入参包含字段
  • 入参排出字段
  • 出参包含字段
  • 出参排除字段
    系统默认使用include指定的字段,如果include为空,则使用exclude指定的字段
package com.learn.jackson.common.core;
 
import com.fasterxml.jackson.annotation.JsonFilter;
 
public class JacksonFilterBean {
 
    /** @Fields INCOME_PARAMETER_INCLUDE_FILTER : TODO */
    public static final String INCOME_PARAMETER_INCLUDE_FILTER = "income_include_filter";
 
    /** @Fields INCOME_PARAMETER_EXCLUDE_FILTER : TODO */
    public static final String INCOME_PARAMETER_EXCLUDE_FILTER = "income_exclude_filter";
 
    /** @Fields OUTCOME_PARAMETER_INCLUDE_FILTER : TODO */
    public static final String OUTCOME_PARAMETER_INCLUDE_FILTER = "outcome_include_filter";
 
    /** @Fields OUTCOME_PARAMETER_EXCLUDE_FILTER : TODO */
    public static final String OUTCOME_PARAMETER_EXCLUDE_FILTER = "outcome_exclude_filter";
    
 
    @JsonFilter(INCOME_PARAMETER_INCLUDE_FILTER)
    public interface IncomeParameterIncludeFillter {
 
    }
 
    @JsonFilter(INCOME_PARAMETER_EXCLUDE_FILTER)
    public interface IncomeParameterExcludeFillter {
 
    }
 
    @JsonFilter(OUTCOME_PARAMETER_INCLUDE_FILTER)
    public interface OutcomeParameterIncludeFillter {
 
    }
 
    @JsonFilter(OUTCOME_PARAMETER_EXCLUDE_FILTER)
    public interface OutcomeParameterExcludeFillter {
 
    }
 
}

3.3 AOP实现anntaion解析

package com.learn.jackson.common.component;
 
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
 
import org.apache.commons.lang3.reflect.FieldUtils;
import org.aspectj.lang.ProceedingJoinPoint;
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 org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
import com.learn.jackson.common.annotation.JacksonFilter;
import com.learn.jackson.common.annotation.JacksonFilters;
import com.learn.jackson.common.core.JacksonFilterBean;
import com.learn.jackson.common.core.JacksonFilterBean.IncomeParameterExcludeFillter;
import com.learn.jackson.common.core.JacksonFilterBean.IncomeParameterIncludeFillter;
import com.learn.jackson.common.core.JacksonFilterBean.OutcomeParameterExcludeFillter;
import com.learn.jackson.common.core.JacksonFilterBean.OutcomeParameterIncludeFillter;
 
@Component
@Aspect
public class JacksonFiltersComponent {
 
    private static Logger log = LoggerFactory.getLogger(JacksonFiltersComponent.class);
 
    /**
     * @Title: jacksonFilterPointCut
     * @Description: TODO(这里用一句话描述这个方法的作用)
     * @param param
     * @return void
     */
    @Pointcut("@annotation(com.learn.jackson.common.annotation.JacksonFilters) "
            + "|| @annotation(com.learn.jackson.common.annotation.JacksonFilter)")
    public void jacksonFiltersPointCut() {
    }
 
    /**
     * @Title: jacksonFilter
     * @Description: TODO(这里用一句话描述这个方法的作用)
     * @param param
     * @return void
     * @throws Throwable
     */
    @Around(value = "jacksonFiltersPointCut()")
    public Object jacksonFiltersAroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        Parameter[] parameters = method.getParameters();
        // 获取注解
        JacksonFilter jacksonFilterElem = method.getAnnotation(JacksonFilter.class);
        JacksonFilter[] jacksonFiterArray = null;
        JacksonFilters jacksonFilters = null;
        if (jacksonFilterElem != null) {
            jacksonFiterArray = new JacksonFilter[1];
            jacksonFiterArray[0] = jacksonFilterElem;
        } else if ((jacksonFilters = method.getAnnotation(JacksonFilters.class)) != null) {
            jacksonFiterArray = jacksonFilters.value();
        }
        List<JacksonFilter> requestFilters = new ArrayList<>();
        List<JacksonFilter> responseFilters = new ArrayList<>();
        if (jacksonFiterArray == null || jacksonFiterArray.length <= 0) {
            return joinPoint.proceed();
        }
        // 对于含有多个输入VO时,过滤参数要考虑参数的顺序问题,当前只支持一个VO参数
        // 解析出request请求和response请求
        requestFilters = Arrays.stream(jacksonFiterArray)
                .filter(jacksonFilter -> jacksonFilter.type() == JacksonFilter.JscksonFilterType.REQUEST)
                .collect(Collectors.toList());
        responseFilters = Arrays.stream(jacksonFiterArray)
                .filter(jacksonFilter -> jacksonFilter.type() == JacksonFilter.JscksonFilterType.RESPONSE)
                .collect(Collectors.toList());
        // 处理request前置通知
        Object[] proprocessArgs = jacksonRequestFilterHanlder(joinPoint, requestFilters, parameters);
        // 方法执行
        Object result = (proprocessArgs == null) ? joinPoint.proceed() : joinPoint.proceed(proprocessArgs);
        // 处理response通知
        return jacksonResponseFilterHanlder(joinPoint, responseFilters, result);
 
    }
 
    /**
     * 获取request过滤的对象数组,用于传递到下一个通知中去,只支持包含一个REQUEST注解
     * 
     * @Title: jacksonRequestFilterHanlder
     * @Description: TODO(这里用一句话描述这个方法的作用)
     * @param param
     * @return Object[] 如果为null,不做前置通知处理
     */
    private Object[] jacksonRequestFilterHanlder(ProceedingJoinPoint joinPoint, List<JacksonFilter> requestFilters,
            Parameter[] parameters) throws IOException {
        // 只支持参数为一个,如果含有多个参数,要解决方法参数列表中,哪个参数的值为要过滤的类型,joinPoint.getArgs(),不能确定参数类型
        Object[] methodArgs = joinPoint.getArgs();
        if (requestFilters == null || requestFilters.size() != 1 || methodArgs == null || methodArgs.length != 1) {
            return null;
        }
        JacksonFilter jacksonFilter = requestFilters.get(0);
        // 获取解析的要过滤的class
        final Class<?> clazz = jacksonFilter.value();
        if (clazz == null) {
            return null;
        }
        // 判断类型参数是否包含此class
        if (parameters == null || parameters.length <= 0
                || Arrays.asList(parameters).stream().noneMatch(parameter -> parameter.getType() == clazz)) {
            return null;
        }
        // 判断对应参数值是否合法,暂时只支持参数列表为一个的情况,对于多个的情况,要过滤的VO必须放在第一个
        // 取第一个作为参数值
 
        // 判断要include filter和exclude filter过滤
        // 获取注解参数,不包含父类参数(对于继承暂时不考虑,继承类要考虑参数相同的情况,)
        Field[] fields = getClassFields(clazz);
        final String[] includeFileds = jacksonFilter.include();
        final String[] excludeFileds = jacksonFilter.exclude();
 
        // 获取可以进行过滤的属性,優先使用inlucde中屬性,如果inlucde為空,使用exclude屬性,(如果都不为空使用include)
        Set<String> inclueFiltFields = getFilterFields(fields, includeFileds);
        ;
        Set<String> exclueFiltFields = getFilterFields(fields, excludeFileds);
        ;
        if (inclueFiltFields == null && exclueFiltFields == null) {
            return null;
        }
        // 处理request参数
        ObjectMapper objectMapper = null;
        if (inclueFiltFields != null) {
            objectMapper = getMixObjectMapper(clazz, IncomeParameterIncludeFillter.class, inclueFiltFields,
                    JacksonFilterBean.INCOME_PARAMETER_INCLUDE_FILTER, true);
        } else if (exclueFiltFields != null) {
            objectMapper = getMixObjectMapper(clazz, IncomeParameterExcludeFillter.class, exclueFiltFields,
                    JacksonFilterBean.INCOME_PARAMETER_EXCLUDE_FILTER, false);
        } else if (objectMapper == null) {
            return null;
        }
        // 对于多个参数,获取类型clazz,的值,依次更改Object的值
        String argsJson = objectMapper.writeValueAsString(joinPoint.getArgs()[0]);
        Object[] filterArgs = new Object[] { objectMapper.readValue(argsJson, clazz) };
        log.debug("Request method =[{}],parameter=[{}],filterParameter=[{}]", joinPoint.getSignature().getName(),
                Arrays.toString(joinPoint.getArgs()), argsJson);
        return filterArgs;
    }
 
    /**
     * 咱只支持一个的情况
     * 
     * @Title: jacksonResponseFilterHanlder
     * @Description: TODO(这里用一句话描述这个方法的作用)
     * @param param
     * @return ProceedingJoinPoint
     */
    private Object jacksonResponseFilterHanlder(ProceedingJoinPoint joinPoint, List<JacksonFilter> responseFilters,
            Object result) throws IOException {
        // 只支持参数为一个VO的情况
        if (responseFilters == null || responseFilters.size() != 1) {
            return result;
        }
        JacksonFilter jacksonFilter = responseFilters.get(0);
        // 获取解析的要过滤的class
        final Class<?> clazz = jacksonFilter.value();
        if (clazz == null) {
            return result;
        }
        // 判断要include filter和exclude filter过滤
        // 获取注解参数,不包含父类参数(对于集成暂时不考虑)
        Field[] fields = getClassFields(clazz);
        final String[] includeFileds = jacksonFilter.include();
        final String[] excludeFileds = jacksonFilter.exclude();
        JacksonFilter.JscksonFilterType type = jacksonFilter.type();
 
        // 获取可以进行过滤的属性,優先使用inlucde中屬性,如果inlucde為空,使用exclude屬性,(如果都不为空使用include)
        Set<String> inclueFiltFields = getFilterFields(fields, includeFileds);
        Set<String> exclueFiltFields = getFilterFields(fields, excludeFileds);
        if (inclueFiltFields == null && exclueFiltFields == null) {
            return result;
        }
        // 处理request参数
        ObjectMapper objectMapper = null;
        if (inclueFiltFields != null) {
            objectMapper = getMixObjectMapper(clazz, OutcomeParameterIncludeFillter.class, inclueFiltFields,
                    JacksonFilterBean.OUTCOME_PARAMETER_INCLUDE_FILTER, true);
        } else if (exclueFiltFields != null) {
            objectMapper = getMixObjectMapper(clazz, OutcomeParameterExcludeFillter.class, exclueFiltFields,
                    JacksonFilterBean.OUTCOME_PARAMETER_EXCLUDE_FILTER, false);
        } else if (objectMapper == null) {
            return result;
        }
        String argsJson = objectMapper.writeValueAsString(result);
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        return objectMapper.readValue(argsJson, methodSignature.getReturnType());
    }
 
    private Field[] getClassFields(Class<?> clazz) {
        if(clazz == null) {
            return null;
        }
        return FieldUtils.getAllFields(clazz);
 
    }
 
    /**
     * 
     * @Title: getFilterFields
     * @Description: TODO(这里用一句话描述这个方法的作用)
     * @param fields:object
     * @includeFileds field must filter
     * 
     * @return Set<String>
     */
    private Set<String> getFilterFields(Field[] fields, final String[] toBeFilterFileds) {
        if (fields == null || fields.length <= 0 || toBeFilterFileds == null || toBeFilterFileds.length <= 0) {
            return null;
        }
        Set<String> inclueFiltFields = Arrays.stream(fields)
                .filter(filed -> Arrays.asList(toBeFilterFileds).contains(filed.getName()))
                .map(filed -> filed.getName()).collect(Collectors.toSet());
        return inclueFiltFields;
 
    }
 
    private ObjectMapper getMixObjectMapper(Class<?> toBeMixVo, Class<?> toBeMixFilter, Set<String> toBeFilterFields,
            String filterId, boolean isInclude) {
        ObjectMapper objectMapper = new ObjectMapper();
        if (isInclude) {
            objectMapper.setFilterProvider(new SimpleFilterProvider().addFilter(filterId,
                    SimpleBeanPropertyFilter.filterOutAllExcept(toBeFilterFields)));
        } else {
            objectMapper.setFilterProvider(new SimpleFilterProvider().addFilter(filterId,
                    SimpleBeanPropertyFilter.serializeAllExcept(toBeFilterFields)));
        }
        objectMapper.addMixIn(toBeMixVo, toBeMixFilter);
        return objectMapper;
    }
}

3.3 示例

@RestController
@RequestMapping("/user/info")
public class UserInfoController {
 
    @PostMapping("/add")
    @JacksonFilters(value= {@JacksonFilter(exclude= {"id","tag","pageSize"},value=UserInfo.class,type=JscksonFilterType.REQUEST)})
    public ApiResult addUserInfo(@RequestBody UserInfo userInfo) {
        ApiResult apiResult = ApiResult.SUCCESS();
        List<UserInfo> infos = new ArrayList<UserInfo>();
        infos.add(userInfo);
        apiResult.setRows(infos);
        return apiResult;
 
    }
 
    @JacksonFilter(exclude= {"id"},value=UserInfo.class,type=JscksonFilterType.REQUEST)
    @PostMapping("/insert")
    public ApiResult addUserInfos(@RequestBody List<UserInfo> userInfos) {
        ApiResult apiResult = ApiResult.SUCCESS();
        List<UserInfo> infos = new ArrayList<UserInfo>();
        infos.addAll(userInfos);
        apiResult.setRows(infos);
        return apiResult;
 
    }
 
    @PostMapping("/list")
    @JacksonFilter(exclude= {"id"},value=User.class,type=JscksonFilterType.REQUEST)
    @JacksonFilter(include= {"id"},value=UserInfo.class,type=JscksonFilterType.RESPONSE)
    public ApiResult listUserInfo(@RequestBody User user) {
        System.out.println("==============>"+ user.toString());
        ApiResult apiResult = ApiResult.SUCCESS();
        List<UserInfo> infos = new ArrayList<UserInfo>();
        UserInfo info1 = new UserInfo();
        info1.setCompanyAdress("11");
        info1.setCompanyName("ddd");
        info1.setId(1);
        info1.setTag("wd");
        info1.setWife("zh");
        info1.setPageNumber(1);
        info1.setPageSize(1);
        infos.add(info1);
 
        UserInfo info2 = new UserInfo();
        info2.setCompanyAdress("dd");
        info2.setCompanyName("ddd");
        info2.setId(1);
        info2.setTag("wd");
        info2.setWife("zh");
        info2.setPageNumber(1);
        info2.setPageSize(1);
        infos.add(info2);
 
        apiResult.setRows(infos);
        return apiResult;
 
    }
 
}

3.4 测试用例

package com.learn.jackson.controller;
 
import static org.junit.Assert.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
 
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
 
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
 
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import com.learn.jackson.vo.User;
import com.learn.jackson.vo.UserInfo;
 
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class UserInfoControllerTest {
 
    @Autowired
    protected MockMvc mvc;
 
    @Autowired
    protected ObjectMapper objectMapper;
 
    protected ObjectWriter objectWriter;
 
    @Before
    public void init() {
        objectWriter = objectMapper.writer();
    }
 
    /**
     * Test method for
     * {@link com.learn.jackson.controller.UserInfoController#addUserInfo(com.learn.jackson.vo.UserInfo)}.
     */
    @Test
//    @Ignore
    public void testAddUserInfoUserInfo() {
        UserInfo info1 = new UserInfo();
        info1.setCompanyAdress("dfff");
        info1.setCompanyName("ddd");
        info1.setId(1);
        info1.setTag("wd");
        info1.setWife("zh");
        info1.setPageNumber(1);
        info1.setPageSize(1);
        try {
            String content = objectWriter.writeValueAsString(info1);
            String message = mvc
                    .perform(post("/user/info/add").contentType(MediaType.APPLICATION_PROBLEM_JSON_UTF8)
                            .content(content))
                    .andDo(print()).andExpect(status().isOk()).andReturn().getResponse().getContentAsString();
            System.out.println(message);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
 
    /**
     * Test method for,需要支持复杂类型吗?
     * {@link com.learn.jackson.controller.UserInfoController#addUserInfo(java.util.List)}.
     */
    @Test
//    @Ignore
    public void testAddUserInfos() {
        List<UserInfo> infos = new ArrayList<UserInfo>();
        UserInfo info1 = new UserInfo();
        info1.setCompanyAdress("detla");
        info1.setCompanyName("ddd");
        info1.setId(1);
        info1.setTag("wd");
        info1.setWife("zh");
        info1.setPageNumber(1);
        info1.setPageSize(1);
        infos.add(info1);
 
        UserInfo info2 = new UserInfo();
        info2.setCompanyAdress("ddww");
        info2.setCompanyName("ddd1");
        info2.setId(1);
        info2.setTag("wd1");
        info2.setWife("zh1");
        info2.setPageNumber(11);
        info2.setPageSize(11);
        infos.add(info2);
        try {
            String content = objectWriter.writeValueAsString(infos);
            String message = mvc
                    .perform(post("/user/info/insert").contentType(MediaType.APPLICATION_PROBLEM_JSON_UTF8)
                            .content(content))
                    .andDo(print()).andExpect(status().isOk()).andReturn().getResponse().getContentAsString();
            System.out.println(message);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
 
    /**
     * Test method for
     * {@link com.learn.jackson.controller.UserInfoController#listUserInfo(com.learn.jackson.vo.UserInfo)}.
     */
    @Test
//    @Ignore
    public void testListUserInfo() {
        User user = new User();
        user.setId(1);
        user.setAdress("cc");
        user.setName("dongzhi");
        user.setPhoneNumber("15859637258");
        user.setSex("male");
        user.setGmtCreate(new Date());
        user.setGmtModified(new Date());
        try {
            String content = objectWriter.writeValueAsString(user);
            String message = mvc.perform(post("/user/info/list").contentType(MediaType.APPLICATION_PROBLEM_JSON_UTF8).content(content)).andDo(print()).andExpect(status().isOk()).andReturn().getResponse().getContentAsString();
            System.out.println(message);
            
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
 
}

3.5 github地址如下:。https://github.com/dongzhi1129/spring-boot/tree/master/spring-boot-jackson

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页