springboot如何根据配置屏蔽接口返回字段
作者:warrah
这篇文章主要介绍了springboot如何根据配置屏蔽接口返回字段问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
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 { 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, jg, 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; }
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。