这篇文章主要讲 Spring MVC 如何动态的去返回 Json 数据 在我们做 Web 接口开发的时候, 经常会遇到这种场景。
两个请求,返回同一个对象,但是需要的返回字段并不相同。如以下场景
/**
* 返回所有名称以及Id
*/
@RequestMapping("list")
@ResponseBody
public List findAllNameAndId() {
return articleService.findAll();
}
/**
* 返回所有目录详情
*/
@RequestMapping("list-detail")
@ResponseBody
public List findAllDetail() {
return articleService.findAll();
}
Spring MVC 默认使用转json框架是 jackson。 大家也知道, jackson 可以在实体类内加注解,来指定序列化规则,但是那样比较不灵活,不能实现我们目前想要达到的这种情况。
这篇文章主要讲的就是通过自定义注解,来更加灵活,细粒化控制 json 格式的转换。
最终我们需要实现如下的效果:
@RequestMapping(value = "{id}", method = RequestMethod.GET)
// 返回时候不包含 filter 内的 createTime, updateTime 字段
@JSON(type = Article.class, filter="createTime,updateTime")
public Article get(@PathVariable String id) {
return articleService.get(id);
}
@RequestMapping(value="list", method = RequestMethod.GET)
// 返回时只包含 include 内的 id, name 字段
// 可以使用多个 @JSON 注解,如果是嵌套对象的话
@JSON(type = Article.class , include="id,name,createTime")
@JSON(type = Tag.class, include="id,name")
public List findAll() {
return articleService.findAll();
}
jackson 编程式过滤字段
jackson 中, 我们可以通过 ObjectMapper.setFilterProvider 来进行过滤规则的设置,jackson 内置了一个 SimpleFilterProvider 过滤器,这个过滤器功能比较单一,不能很好的支持我们想要的效果。于是我自己实现了一个过滤器 JacksonJsonFilter
package diamond.cms.server.json;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import com.fasterxml.jackson.annotation.JsonFilter;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.BeanPropertyFilter;
import com.fasterxml.jackson.databind.ser.FilterProvider;
import com.fasterxml.jackson.databind.ser.PropertyFilter;
import com.fasterxml.jackson.databind.ser.PropertyWriter;
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
@SuppressWarnings("deprecation")
@JsonFilter("JacksonFilter")
public class JacksonJsonFilter extends FilterProvider{
Map, Set> includeMap = new HashMap<>();
Map, Set> filterMap = new HashMap<>();
public void include(Class> type, String[] fields) {
addToMap(includeMap, type, fields);
}
public void filter(Class> type, String[] fields) {
addToMap(filterMap, t