开发者

springboot如何根据配置屏蔽接口返回字段

目录
  • springboot根据配置屏蔽接口返回字段
    • 1.类的数据域
    • 2.开启的注解
    • 3.json过滤器
    • 4.过滤器切面
    • 5.如何使用
  • 总结

    springboot根据配置屏蔽接口返回字段

    很多时候就是为了偷懒,swagger可以屏蔽接口文档中的字段,却不能屏蔽真实返回的数据,故而需要再controller返回的时候再做处理

    参考了springboot2 jackson实现动态返回类字段,做了一些改动

    经验证对简单接口,还可以,稍微复杂的嵌套就不行,可以使用@JsonIgnore,路径为

    com.fasterXML.jackson.annotation.JsonIgnore
    <dependency>
                <groupId>org.ASPectj</groupId>
                <artifactId>aspectjweaver</artifactId>
                <version>1.9.6</version>
            </dependency>

    1.类的数据域

    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    @NoArgsConstructor
    @AllArgsConstructor
    @Data
    public class JsonFields {
    js
        boolean include = true;
    
        String[] fields = {};
    
    }

    2.开启的注解

    写在controller的方法上

    import Java.lang.annotation.*;
    
    @Target({ ElementType.PARAMETER, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface JsonInclude {
        /**
         * 排除
         * @return
         */
        boolean include() default true;
    
        /**
         * 字段类型
         * @return
         */
        Class clazz();
    
        /**
         * 过滤的字段名
         * @return
         */
        String[] fields() default {};
    }

    3.json过滤器

    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.PropertyWriter;
    import com.fasterxml.jackson.databind.ser.PropertyFilter;
    import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
    
    import java.util.HashMap;
    import java.util.Map;
    
    public class JsonFilter extends FilterProvider {
    
        /**
         * 对于规则我们采用 ThreadLocal 封装,防止出现线程安全问题
         */
        private static final ThreadLocal<Map<Class<?>, JsonFields>> include = new ThreadLocal<>();
    
        /**
         * 清空规则
         */
        public static void clear() {
            include.remove();
        }
    
    
        /**
         * 设置过滤规则
         * @param clazz 规则
         */
        public static void add(boolean isInclude, Class<?> clazz, String... fields) {
            Map<Class<?>, JsonFields> map = include.get();
            if (map == null) {
                map = new HashMap<>();
             编程客栈   include.set(map);
            }
            JsonFields jsonFields = new JsonFields(isInclude,fields);
            map.put(clazz, jsonFields);
        }
    
        /**
         * 重写规律规则
         */
        @Override
        public PropertyFilter findPropertyFilter(Object filterId, Object valueToFilter) {
            return new SimpleBeanPropertyFilter() {
                @Override
                public void serializeAsField(
                        Object pojo,
                        JsonGenerator jg,
                        SerializerProvider sp,
                        PropertyWriter pw
                ) throws Exception {
                    if (apply(pojo.getClass(), pw.getName())) {
                        pw.serializeAsField(pojo, jg, sp);
                    } else if (!jg.canOmitFields()) {
                        pw.serializeAsOmittedField(pojo, pythonjg, sp);
                    }
                }
            };
        }
    
        @Deprecated
        @Override
        public BeanPropertyFilter findFilter(Object filterId) {
            throw new UnsupportedOperationException("不支持访问即将过期的过滤器");
        }
    
        /**
         * 判断该字段是否需要,返回 true 序列化,返回 false 则过滤
         * @param type 实体类类型
         * @param name 字段名
         */
        public boolean apply(Class<?> type, String name) {
            Map<Class<?>, JsonFields> map = include.get();
            if (map == null) {
                return true;
            }
            JsonFields jsonFields = map.get(type);
            String[] fields = jsonFields.getFields();
            if (jsonFields.isInclude()){
                for (String field : fields) {
                    if (field.equals(name)) {
                        return true;
                    }
                }
                return false;
            } else{
                for (String field : fields) {
                    if (field.equals(name)) {
                        return false;
                    }
                }
                return true;
            }
        }
    }
    

    4.过滤器切面

    JsonFilter.clear();解决多线程下面的并发的问题

    import lombok.extern.slf4j.Slf4j;
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.annotation.Pointcut;
    import org.aspectj.lang.reflect.MethodSignature;
    import org.springframework.stereotype.Component;
    
    import java.lang.reflect.Method;
    
    @Slf4j
    @Component
    @Aspect
    public class JsonFilterAop {
    
        @Pointcut("@annotation(com.tt.framework.web.filter.JsonInclude)")
        public void controllerAspect(){}
    
    
        /**
         * (1)@annotation:用来拦截所有被某个注解修饰的方法
         * (2)@within:用来拦截所有被某个注解修饰的类
         * (3)within:用来指定扫描的包的范围
         */
        @Before("controllerAspect()")
        public void doBefore(JoinPoint joinPoint) throws Throwable{
            JsonFilter.clear();
            //从切面织入点处通过反射机制获取织入点处的方法
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            //获取切入点所在的方法
            Method method = signature.getMethod();
            JsonInclude jsonInclude = method.getAnnotation(JsonInclude.class);
            JsonFilter.add(jsonInclude.include(),jsonInclude.clazz(),jsonInclude.fields());
        }
    
    
    }

    5.如何使用

    启动类增加此过滤器

    @Slf4j
    @SpringBootApplication
    public class FayServerApplication {
    
        public static void main(String[] args) {
            try {
                ConfigurableApplicationContext context = SpringApplication.run(FayServerApplication.class, args);
                ObjectMapper objectMapper = context.getBean(ObjectMapper.class);
                objectMapper.setFilterProvider(new JsonFilter());
    
            } finally {
                log.info("server start finish");
            }
        }
    }

    include = true包含则表示仅显示包含的数据,include = false则排除这配置的fields,显示没有配置的字段。

    没有此注解的则不受影响

     @JsonInclude(include = true,clazz = LxrJbhYsth.class,fields = {"dg","mz"})
        @ApiOperation("金不换规则")
        @GetMapping("jbhRule")
        public ResponseResult<List<LxrJbhYsth>> jbhRule(String dg){
            List<LxrJbhYsth> lxrJbhYsths = extLxrJbhYsthService.selectByDg(dg);
            ResponseResult<List<LxrJbhYsth>> resp = new ResponseResult<>(true);
            resp.setData(lxrJbhYsths);
            return resp;
        }

    总结

    以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程客栈js(www.devze.com)。

    0

    上一篇:

    下一篇:

    精彩评论

    暂无评论...
    验证码 换一张
    取 消

    最新开发

    开发排行榜