zoukankan      html  css  js  c++  java
  • 利用Jackson的JsonFilter来实现动态过滤数据列(数据列权限控制)

    利用Jackson的JsonFilter来实现动态过滤数据列。

    也就是说,同一个实体,你配置了不同的@JsonFilter,通过Jackson展现的结果可以是不一样的。

    举个栗子:

    @lombok.Data
    public class User{
      String username;
      String password;
      Integer age;
      String gender;
      String blog;
    }

    默认不做任何配置的话,通过Jackson序列化出来的结果是:

    {
      "username" : "tomcatandjerry",
      "password" : "123456",
      "age" : 36,
      "gender" : "男",
      "blog" : "http://www.cnblogs.com/tomcatandjerry/"
    }

    可是password不应该要展示,方法有多种:

    方法1:在不想序列化的字段上加注解JsonProperty:

    @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)//Jackson
    @JSONField(serialize = false)//fastjson
    String password;

    方法2:

     2.1在User类上面加注解JsonFilter:

    @JsonFilter("non-password")
    public class User {
      ...
    }

     2.2 配置FilterProvider

    测试方法&配置如下:

    public class JsonFilterTest {
    
        private ObjectMapper setupJsonFilter(){
            ObjectMapper mapper = new ObjectMapper();
            String[] beanProperties = new String[]{"password"};
            String nonPasswordFilterName = "non-password";//需要跟User类上的注解@JsonFilter("non-password")里面的一致
            FilterProvider filterProvider = new SimpleFilterProvider()
                    .addFilter(nonPasswordFilterName, SimpleBeanPropertyFilter.serializeAllExcept(beanProperties));
                    //serializeAllExcept 表示序列化全部,除了指定字段
                    //filterOutAllExcept 表示过滤掉全部,除了指定的字段
            mapper.setFilterProvider(filterProvider);
            return mapper;
        }
    
        @Test
        public void testJsonFilter() throws JsonProcessingException {
            User user = new User();
            user.setUsername("tomcatandjerry");
            user.setPassword("123456");
            user.setAge(36);
            user.setGender("男");    
            System.out.println(setupJsonFilter().writeValueAsString(user));
        }
    }

    打印测试结果:

    {
      "username" : "tomcatandjerry",
      "age" : 36,
      "gender" : "男",
      "blog" : "http://www.cnblogs.com/tomcatandjerry/"
    }

    小结:

    看上去似乎使用@JsonProperty更简单。
    但是当有一堆字段需要配置,而且整个项目都需要统一处理的时候,后者@JsonFilter是一个不错的选择。

    扩展:

    同一个API,如果我想不同的人看到不一样的结果呢?
    比如同一个用户API,有的展示username+age, 有的展示username+gender等

    这个时候JsonFilter就非常适合了。

    有人可能会问:不对啊?一个对象只能配置一个JsonFilter,怎么动态切换不同的Filter?
    对的,一个对象只能配置一个JsonFilter,但只要稍加修改,就能实现??

    思路:
    既然一个对象只能配置一个JsonFilter,那么靠一个对象来动态展示不同的属性是不可能的。
    我们可以多写几个对象,都继承User对象,不同的子类里面使用不同的JsonFilter

    @JsonFilter("normal-user")
    public class UserNormal extends User{
     //空class,里面没有任何属性
    }
    
    @JsonFilter("admin")
    public class UserAdmin extends User{
     //空class,里面没有任何属性
    }

    利用Spring的切点,根据当前用户的角色,替换返回值为不同的子类

    原本:
    public class UserService{
      
      public User get(String id){
        
      }
    }

    利用切点(可以自定义注解,加到方法上,切在注解上面),替换返回的对象为子类:

    具体需要用到的:
    1) 扫描并缓存子类
    2) @Aspect切点,@Around(value="比如:自定义注解")
    3) 利用反射,创建出子类对象,BeanUtils.copyProperties

    这样看似调用userService.get("id")返回的是User对象,其实可能已经替换成某一个子类了。

    在ObjectMapper配置多个Filter,就实现了动态展示不同属性,且对开发人员透明。

    小结:

    优点: 对开发透明
    缺点:一个对象需要写多个子类,虽然是空class

    这也算是一种数据列权限控制的一种解决方案吧。


    2018-6-5

  • 相关阅读:
    nyoj256-C小加之级数求和
    nyoj254-编号统计
    nyoj286-动物统计
    最长回文子串——manacher
    动态规划:Codeforces Round #427 (Div. 2) C Star sky
    水题:51Nod1432-独木舟
    水题:HDU1716-排列2
    水题:CF16C-Monitor
    数学基础:HUD1124-Factorial(N!末尾0的个数)
    并查集:POJ1182-食物链(并查集比较高端的应用)
  • 原文地址:https://www.cnblogs.com/tomcatandjerry/p/9139976.html
Copyright © 2011-2022 走看看