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  extends Model{

    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 {

    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注解前
SpringBoot aop 使用jackson进行动态过滤返回对象属性_第1张图片
加上@FieldFilterAnnotation注解后
SpringBoot aop 使用jackson进行动态过滤返回对象属性_第2张图片

你可能感兴趣的:(开发功能代码,SpringBoot,aop)