Jackson 动态过滤属性,编程式过滤对象中的属性

Jackson 动态过滤属性,编程式过滤对象中的属性

大家好,又见面了,我是全栈君。

场景:有时候我们做系统的时候,比如两个请求,返回同一个对象,但是需要的返回字段并不相同。

常见与写前端接口的时候,尤其是手机端,一般需要什么数据就返回什么样的数据。此时对于返回同一个对象我们就要动态过滤所需要的字段…

Spring MVC 默认使用转json框架是 jackson。 大家也知道, jackson 可以在实体类内加注解,来指定序列化规则,但是那样比较不灵活,不能实现我们目前想要达到的这种情况

下面用编程式的方式实现过滤字段.

先写个json工具类:

 

public class JsonUtilJackson {

    private static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
    private static final ObjectMapper mapper;

    JacksonJsonFilter jacksonFilter = new JacksonJsonFilter();

    static {
        SimpleDateFormat dateFormat = new SimpleDateFormat(DEFAULT_DATE_FORMAT);
        mapper = new ObjectMapper();
        mapper.setDateFormat(dateFormat);
        // 允许对象忽略json中不存在的属性
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        // 允许出现特殊字符和转义符
        mapper.configure(Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
        // 允许出现单引号
        mapper.configure(Feature.ALLOW_SINGLE_QUOTES, true);
        // 忽视为空的属性
        mapper.setSerializationInclusion(Include.NON_EMPTY);
    }

    public static JsonUtilJackson me() {
        JsonUtilJackson jsonUtil = new JsonUtilJackson();
        return jsonUtil;
    }

    public void filter(Class<?> clazz, String include, String filter) {
        if (clazz == null)
            return;
        if (StringUtils.isNotBlank(include)) {
            jacksonFilter.include(clazz, include.split(","));
        }
        if (StringUtils.isNotBlank(filter)) {
            jacksonFilter.filter(clazz, filter.split(","));
        }
        mapper.addMixIn(clazz, jacksonFilter.getClass());
    }

    public String toJson(Object obj) {
        try {
            mapper.setFilterProvider(jacksonFilter);
            return mapper.writeValueAsString(obj);
        } catch (Exception e) {
            throw new RuntimeException("转换json字符失败!");
        }
    }

    public <T> T toObject(String json, Class<T> clazz) {
        try {
            return mapper.readValue(json, clazz);
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("将json字符转换为对象时失败!");
        }
    }

    public <T> T toObject(String json, TypeReference<T> clazz) {
        try {
            return mapper.readValue(json, clazz);
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("将json字符转换为对象时失败!");

        }
    }

}

 

 

 

然后写个JsonFilter

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<Class<?>, Set<String>> includeMap = new HashMap<>();
    Map<Class<?>, Set<String>> filterMap = new HashMap<>();

    public void include(Class<?> type, String[] fields) {
        addToMap(includeMap, type, fields);
    }

    public void filter(Class<?> type, String[] fields) {
        addToMap(filterMap, type, fields);
    }
    
    private void addToMap(Map<Class<?>, Set<String>> map, Class<?> type, String[] fields) {
        Set<String> filedSet=new HashSet<>();
        if(fields!=null && fields.length>0){
            for(String filed : fields){
                filedSet.add(filed);
            }
        }
        map.put(type, filedSet);
    }

    @Override
    public BeanPropertyFilter findFilter(Object filterId) {
        throw new UnsupportedOperationException("Access to deprecated filters not supported");
    }

    @Override
    public PropertyFilter findPropertyFilter(Object filterId, Object valueToFilter) {

        return new SimpleBeanPropertyFilter() {

            @Override
            public void serializeAsField(Object pojo, JsonGenerator jgen, SerializerProvider prov, PropertyWriter writer)
                    throws Exception {
                if (apply(pojo.getClass(), writer.getName())) {
                    writer.serializeAsField(pojo, jgen, prov);
                } else if (!jgen.canOmitFields()) {
                    writer.serializeAsOmittedField(pojo, jgen, prov);
                }
            }
        };
    }

    public boolean apply(Class<?> type, String name) {
        Set<String> includeFields = includeMap.get(type);
        Set<String> filterFields = filterMap.get(type);
        if (includeFields != null && includeFields.contains(name)) {
            return true;
        } else if (filterFields != null && !filterFields.contains(name)) {
            return true;
        } else if (includeFields == null && filterFields == null) {
            return true;
        }
        return false;
    }

}

最后就是我们测试了

 

    public static void main(String[] args) throws Exception {
        
        A a=new A();
        a.setName("AAAAA");
        a.setNo("011111");
        
        Role r=new Role();
        r.setName("zhangsan");
        r.setCode("11");
        r.setCreateTime(new Date().getTime());
        r.setRemark("who am i");

        a.setR(r);
        
        
        JsonUtilJackson jtk= new JsonUtilJackson();
        // 设置转换 Article 类时,只包含 id, name
        jtk.filter(A.class, "no,r", null);  
        jtk.filter(Role.class, "name,remark", null);
        String ss=jtk.toJson(a);
        System.out.println(ss);
        
    }

结果:{“no”:”011111″,”r”:{“name”:”zhangsan”,”remark”:”who am i”}}

 

参考:https://my.oschina.net/diamondfsd/blog/836727?p=3&temp=1490578919756#blog-comments-list

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/108594.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • CCF-CSP认证历年真题解

    CCF-CSP认证历年真题解CSP认证考什么怎么考?CCF计算机职业资格认证的每一道试题都十分经典,覆盖现实世界中方方面面的问题。这个历年试题解主要使用C/C++语言编写,将逐步增加Python和Java的解题程序。程序中附有注释,力求解题思路清晰简洁,值得珍藏与模仿。逐题改写过程中,富文本编辑器写的博客将全部用Markdown编辑器改写。改写的第一题,都增加了Python和Java的解题程序。2021.04第22次:CCF202104-1灰度直方图(100分)【计数】CCF202104-2邻域均值(100分.

    2022年6月7日
    107
  • system.Exception:端口已被占用1080「建议收藏」

    system.Exception:端口已被占用1080「建议收藏」找出是哪个程序占用了1080端口打开cmd.exe,输入命令:netstat-aon|findstr"1080"1最后一列就是PID了,我的是3104. 要想知道此PID对应什么程序,可以继续输入:tasklist|findstr"4568"1打开任务管理器,在进程里面找下wpscloudsvr.exe,或者在服务里面找PID为3104。…

    2025年9月30日
    2
  • tracert命令的原理是什么_tracert命令的原理

    tracert命令的原理是什么_tracert命令的原理1. Tracert 命令的原理与作用Tracert命令诊断实用程序通过向目标计算机发送具有不同生存时间的ICMP数据包,来确定至目标计算机的路由,也就是说用来跟踪一个消息从一台计算机到另一台计算机所走的路径。该诊断实用程序将包含不同生存时间 (TTL

    2022年9月24日
    6
  • 安卓root权限管理_root权限在哪里设置

    安卓root权限管理_root权限在哪里设置Android权限说明Android系统是运行在Linux内核上的,Android与Linux分别有自己的一套严格的安全及权限机制,Android系统权限相关的内容,(一)linux文件系统上的权限-rwxr-x–xsystemsystem41562012-06-3016:12test.apk.代表的是相应的用户/用户组及其他人对此文件的访问权限,与此文件运行起来

    2025年6月28日
    4
  • Java NIO与IO的区别

    Java NIO与IO的区别Java.nio 俗称 New IO (从1.4开始),全称是Java Non-blocking IO,即非阻塞的IO,为所有的原始类型(boolean类型除外)提供缓存支持的数据容器,使用它可以提供非阻塞式的高伸缩性网络IO。

    2022年6月24日
    28
  • word2010求和符号上下标的打法_求和符号只有下标是什么意思

    word2010求和符号上下标的打法_求和符号只有下标是什么意思想输入的公式:只要在公式旁边继续加文字就会变成这样:解决方法只能在office上实现不能在wps上先输入Alt+=,得到下图在里面进行输入输入\below,空格键按两次在得到的大框里输入\sum空格键按一次在总和符号旁边输入\above空格键两次得到想要的符合。转载于https://jingyan.baidu.com/article/a17d528558c3bbc199c8f25d.html…

    2022年10月7日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号