SpringBoot aop 使用jackson进行动态过滤返回对象属性

使用jackson进行动态过滤返回对象属性

在向服务端请求数据时,可能会返回一些无用的字段或者一些敏感信息,这时候就需要把一些不需要返回的字段过滤掉。
在springboot 中默认使用的jackson来进行json转换,虽然jackson中@jsonignore注解可以实现属性不被jackson解析,但是并不适用与项目当中。

代码部分

jackson过滤工具类

import com.fasterxml.jackson.annotation.JsonFilter;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;

public class FieldFilterSerializer {
    //想要保留的字段标识
    private static final String DYNC_INCLUDE = "DYNC_INCLUDE";
    //想要过滤的字段标识
    private static final String DYNC_EXCLUDE = "DYNC_EXCLUDE";
    //jackson核心类 过滤属性全部由这个类完成
    private ObjectMapper mapper = new ObjectMapper();

    @JsonFilter(DYNC_EXCLUDE)
    interface DynamicExclude {}

    @JsonFilter(DYNC_INCLUDE)
    interface DynamicInclude {}

    /**
     * 过滤字段
     *
     * @param clazz   需要过滤的class
     * @param include 需要保留的字段
     * @param exclude 需要过滤的字段
     */
    public void filter(Class<?> clazz, String include, String exclude) {
        if (include != null && include.length() > 0) {
            mapper.setFilterProvider(new SimpleFilterProvider()
                    .addFilter(DYNC_INCLUDE, SimpleBeanPropertyFilter.filterOutAllExcept(include.split(","))));
            mapper.addMixIn(clazz, DynamicInclude.class);
        } else if (exclude != null && exclude.length() > 0) {
            mapper.setFilterProvider(new SimpleFilterProvider()
                    .addFilter(DYNC_EXCLUDE, SimpleBeanPropertyFilter.serializeAllExcept(exclude.split(","))));
            mapper.addMixIn(clazz, DynamicExclude.class);
        }
    }

    /**
     * 返回过滤后的json格式的字符串
     *
     * @param object
     * @return
     * @throws JsonProcessingException
     */
    public String toJSONString(Object object) throws JsonProcessingException {
        //解决jackson2无法反序列化LocalDateTime的问题 
        //这里要注意时间属性上要加入 @JsonFormat 注解 否则无法正常解析
        mapper.registerModule(new JavaTimeModule());
        //将类转换成json字符串返回
        return mapper.writeValueAsString(object);
    }
}

自定义注解

import com.alibaba.fastjson.JSONObject;
import com.common.constant.FieldFilterConstants;
import java.lang.annotation.*;

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FieldFilterAnnotation {
    //想要保留的字段,用逗号(,)分隔
    String include()  default "";

    //想要过滤的字段,用逗号(,)分隔    这里默认过滤数据库的公共字段
    //"createBy,remarks,createTime,updateTime,updateBy,delFlag,tenantId"
    String exclude()  default FieldFilterConstants.EXCLUDE_DEFAULT;

    //返回到前端数据类型 这里使用JOSNObject 如果是纯集合可以使用JSONArray
    Class classez() default JSONObject.class;
}

自定义注解实现

import com.alibaba.fastjson.JSON;
import com.common.core.util.R;
import com.common.base.BaseModel;
import com.common.util.FieldFilterSerializer;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;

@Aspect
@Component
public class FieldFilterAspect {

    @Pointcut("@annotation(com.common.annotations.FieldFilterAnnotation)")
    public void fieldFilterAspect(){}

	//Around注解改变服务的返回值
    //统一返回值使用R工具类,所以返回结果都是在R的data属性中
    @Around("fieldFilterAspect()")
    public R around(ProceedingJoinPoint pjp) throws Throwable {
        R r = (R) pjp.proceed();
        if(r.getCode() == 1)return r;
        Object object = r.getData();
        if(object == null) return r;
        MethodSignature methodSignature =  (MethodSignature) pjp.getSignature();
        Method method = methodSignature.getMethod();
        FieldFilterAnnotation annotation = method.getAnnotation(FieldFilterAnnotation.class);
        FieldFilterSerializer fieldFilter = new FieldFilterSerializer();
        
        //这里传入公共类 由于所有类都继承了mybatis的公共字段类BaseModel
         //所以只要传入BaseModel就可以进行全部类的过滤
        fieldFilter.filter(BaseModel.class, annotation.include(), annotation.exclude());
        //返回过滤后的json字符串
        String jsonString = fieldFilter.toJSONString(r.getData());
        //将返回的json字符串转换成 JSONObject 或者 JSONArray并放入到R的data属性中返回到前端
        r.setData(JSON.parseObject(jsonString, annotation.classez()));
        return r;
    }
}

BaseModel类


import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import lombok.Data;
import java.util.Date;


@Data
public class BaseModel <T extends Model> extends Model<T>{

    private Integer id;

    private String remarks;

    @TableField(value = "create_time",fill = FieldFill.INSERT)
    private Date createTime;
    @TableField(value = "create_by",fill =FieldFill.INSERT)
    private String createBy;
    @TableField(value = "update_time",fill =FieldFill.UPDATE)
    private Date updateTime;
    @TableField(value = "update_by",fill =FieldFill.UPDATE)
    private String updateBy;
    @TableLogic(value = "0",delval = "1")
    private String delFlag;
    @TableField(value = "tenant_id",fill =FieldFill.INSERT)
    private Integer tenantId;
}

测试类

import com.fasterxml.jackson.annotation.JsonFormat;
import com.common.base.BaseModel;
import lombok.Data;
import java.time.LocalDateTime;

@Data
public class TestEntity extends BaseModel<TestEntity> {

    private String name;

    @JsonFormat(pattern = "yyyy-MM-dd")
    private LocalDateTime time;

}

Controller层

import com.common.core.util.R;
import com.common.annotations.FieldFilterAnnotation;
import com.common.entity.TestEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDateTime;

@RestController
@RequestMapping("/entity" )
public class TestEntityController {

    @GetMapping
    @FieldFilterAnnotation
    public R testEntity(){
        TestEntity testEntity = new TestEntity();
        testEntity.setTime(LocalDateTime.now());
        testEntity.setName("name");
        testEntity.setRemarks("备注");
        return R.ok(testEntity);
    }
}

使用postman测试结果

在没有加上@FieldFilterAnnotation注解前
在这里插入图片描述
加上@FieldFilterAnnotation注解后
在这里插入图片描述

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot是一个用于构建独立的、生产级别的Spring应用程序的框架,它提供了丰富的功能和特性,方便开发人员快速搭建和开发项目。 在Spring Boot中使用AOP(面向切面编程)可以实现将一些公共的功能逻辑代码从业务逻辑代码中解耦出来,提高代码的复用性和可维护性。通过AOP可以在方法的前后注入一些通用的逻辑,例如日志记录、异常处理、权限校验等。 其中,使用AOP进行结果的统一封装是很常见的需求。通过AOP可以在方法执行后对返回的结果进行封装,统一处理返回结果的格式,并可以对结果进行一些统一的处理操作,例如添加统一的返回码、返回信息、返回时间等。 在Spring Boot中使用AOP进行结果的统一封装可以按照以下步骤进行: 1. 创建一个切面(Aspect),通过在切面类上加上@Aspect注解标识该类是一个切面类。 2. 在切面类中定义一个切点(Pointcut),通过定义一个方法并添加@Pointcut注解来指定切入点。 3. 在切面类中定义一个通知(Advice),通过@Before、@After、@Around等注解来指定通知类型,并在通知方法中编写需要执行的逻辑。 4. 在通知方法中获取方法的返回结果,并进行相应的封装和处理。 5. 在Spring Boot的配置类中添加@EnableAspectJAutoProxy注解来启用AOP使用以上步骤可以实现对方法返回结果的统一封装,使得返回结果具有统一的格式和处理逻辑。这样可以提高代码的重用性和可维护性,并且可以在一处对结果进行集中处理,减少了代码的重复性,提高了开发效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值