在向服务端请求数据时,可能会返回一些无用的字段或者一些敏感信息,这时候就需要把一些不需要返回的字段过滤掉。
在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);
}
}