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

 更新时间:2024年08月09日 11:37:00   作者: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;
    }

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • SpringBoot配置文件、多环境配置、读取配置的4种实现方式

    SpringBoot配置文件、多环境配置、读取配置的4种实现方式

    SpringBoot支持多种配置文件位置和格式,其中application.properties和application.yml是默认加载的文件,配置文件可以根据环境通过spring.profiles.active属性进行区分,命令行参数具有最高优先级,可覆盖其他所有配置
    2024-09-09
  • Java I/O深入学习之File和RandomAccessFile

    Java I/O深入学习之File和RandomAccessFile

    这篇文章主要介绍了Java I/O深入学习之File和RandomAccessFile, I/O系统即输入/输出系统,对于一门程序语言来说,创建一个好的输入/输出系统并非易事。在充分理解Java I/O系统以便正确地运用之前,我们需要学习相当数量的类。,需要的朋友可以参考下
    2019-06-06
  • Java实现拓扑排序的示例代码

    Java实现拓扑排序的示例代码

    这篇文章我们要讲的是拓扑排序,这是一个针对有向无环图的算法,主要是为了解决前驱后继的关系,感兴趣的小伙伴可以跟随小编一起学习一下
    2022-05-05
  • 解决表单post,get到springMVC后台乱码的问题

    解决表单post,get到springMVC后台乱码的问题

    下面小编就为大家分享一篇解决表单post,get到springMVC后台乱码的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-01-01
  • JavaGUI界面实现页面跳转方法

    JavaGUI界面实现页面跳转方法

    这篇文章主要给大家介绍了关于JavaGUI界面实现页面跳转的相关资料, GUI是指图形用户界面,指采用图形方式显示的计算机操作用户界面,需要的朋友可以参考下
    2023-07-07
  • SpringBoot管理RabbitMQ中的Channel详解

    SpringBoot管理RabbitMQ中的Channel详解

    这篇文章主要介绍了SpringBoot管理RabbitMQ中的Channel详解,channel仅存在于connection的上下文中,而不会单独存在,当channel关闭时,其上的所有channel也会关闭,需要的朋友可以参考下
    2023-08-08
  • Springboot中前端向后端传递数据的几种方式

    Springboot中前端向后端传递数据的几种方式

    在前端和后端的交互中,前端需要向后端传递数据,常见的数据传递方式包括表单提交、URL参数、JSON请求等,本文将介绍常见的几种数据传递方式,并说明如何在SpringBoot中实现这些方式,需要的朋友可以参考下
    2025-08-08
  • Java服务不可用问题排查和解决

    Java服务不可用问题排查和解决

    作为一名 java 开发者,经常会遇到服务不可用的问题排查,导致问题的原因可能是多种多样的,但是在预先不知道是什么原因导致的服务不可用的时候,通用的排查手段和流程是相似的,故本文给大家介绍了Java服务不可用问题排查方法和解决,需要的朋友可以参考下
    2025-01-01
  • springBoot mybatis 包扫描实例

    springBoot mybatis 包扫描实例

    这篇文章主要介绍了springBoot mybatis 包扫描实例,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-07-07
  • java中常用排序方法有哪些详解

    java中常用排序方法有哪些详解

    排序算法经过了很长时间的演变,产生了很多种不同的方法,这篇文章主要介绍了java中常用排序方法有哪些的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2025-07-07

最新评论