项目简介

一个轻量级的 Java 字段过滤工具,只需两个注解即可优雅地控制接口返回字段。

为何开发这个项目?

​ Java 在平时开发中,我们难免会遇到不想返回某些字段的情况,又或者某些字段的值过于敏感不方便展示,这种情况我们通常会新建一个类,包装成一个视图对象。那么随着业务的增长,视图对象会越来越多,所以开发了这个项目。

会不会有使用成本?

​ 不会,仅需配置 2 个注解即可完成所有功能。并且可以将粒度细分到方法,返回同一对象,A 方法返回所有字段,B 方法返回需要的字段。

GitHub 地址:sensitive-field-filter

快速开始

引入依赖

目前仅支持 Spring Boot 项目,引入依赖

1
2
3
4
5
<dependency>
<groupId>io.github.soora33</groupId>
<artifactId>sft</artifactId>
<version>1.0.0</version>
</dependency>

注解说明

注解共有三个,其中 @SftFilter 加在需要过滤的实体类字段上,@SftObjectFilter@SftResponseFilter 根据方法的返回值选择其中一个。注解详情如下:

@SftFilter:配置在实体类上需要过滤的字段

可配置项:

value:过滤后的字段值,默认为 null

@SftObjectFilter: 配置在方法上,适用于直接返回对象,配置后会对该方法的返回值按照 SftFilter 配置的字段进行过滤

可配置项:

entity:方法的返回值类型

preserveField:是否需要保留字段,默认为 true

@SftResponseFilter:配置在方法上,适用于封装格式对象,配置后会对该方法的返回值按照 SftFilter 配置的字段进行过滤(默认获取封装对象中 data 中的对象)

可配置项:

entity:方法的返回值类型

key:封装数据体中存储数据的字段名,默认为 data

preserveField:是否需要保留字段,默认为 true

对于 @SftObjectFilter:用在直接返回视图对象的方法

对于 @SftResponseFilter:用在返回经过统一格式封装的对象,如 Result.success (data),AjaxResult.success (data) 等等

⚠️⚠️⚠️ 注意:如果配置 preserveField 为 false,则会将返回值中的实体类对象转为 LinkedHashMap。因为去除过滤字段的实现方式是通过将非过滤字段加入到 Map 内实现的。如果对业务有影响,请不要使用!!!

如果看不明白没关系,下面提供了示例,结合示例更容易明白。

使用示例

实体类说明:

以下面 Person 举例说明,并设置 name 字段为 null,email 为 Nah

1
2
3
4
5
6
7
8
9
10
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
private String id;
@SftFilter // 默认将该字段值设为 null
private String name;
@SftFilter(value = "Nah") // 修改默认值为 Nah
private String email;
}

SftObjectFilter

SftObjectFilter 注解用于对象的过滤,可配置的参数有 2 个:

entity:方法的返回值类型

preserveField:是否需要保留字段,默认为 true

下面介绍常见的两种场景

1. 返回单个对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 保留字段
@SftObjectFilter(entity = Person.class)
public Person getPerson() {
Person person = new Person("1","azki","azki@email.com");
return person;
}

// 返回值类型以及返回值
class com.sora.domain.Person
Person(id=1, name=null, email=Nah)


// 不保留字段
@SftObjectFilter(entity = Person.class, preserveField = false)
public Person getPerson() {
Person person = new Person("1","azki","azki@email.com");
return person;
}

// 返回值类型以及返回值
class java.util.LinkedHashMap
{id=1}
2. 返回集合类型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 保留字段
@SftObjectFilter(entity = Person.class)
public List<Person> getPerson() {
Person person = new Person("1","azki","azki@email.com");
Person person2 = new Person("2","nayuta","nayuta@email.com");
Person person3 = new Person("3","aznayu","aznayu@email.com");
ArrayList<Person> list = Lists.newArrayList(person, person2, person3);
return list;
}

// 返回值类型以及返回值
class java.util.ArrayList
[Person(id=1, name=null, email=Nah), Person(id=2, name=null, email=Nah), Person(id=3, name=null, email=Nah)]


// 不保留字段
@SftObjectFilter(entity = Person.class, preserveField = false)
public List<Person> getPerson() {
Person person = new Person("1","azki","azki@email.com");
Person person2 = new Person("2","nayuta","nayuta@email.com");
Person person3 = new Person("3","aznayu","aznayu@email.com");
ArrayList<Person> list = Lists.newArrayList(person, person2, person3);
return list;
}

// 返回值类型以及返回值
class java.util.ArrayList
[{id=1}, {id=2}, {id=3}]

SftResponseFilter

在使用 SftResponseFilter 之前,我先来介绍一下目前 Java 项目的统一返回值格式,大体上分为两种:

第一种是以对象的形式,通过字段存储数据,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class AjaxResult implements Serializable {
@Serial
private static final long serialVersionUID = -7126327333321005351L;
private String msg;
private Integer code;
private Object data;

// get...set...方法

private static AjaxResult rest(Object object) {
AjaxResult ajaxResult = new AjaxResult();
ajaxResult.setMsg("success");
ajaxResult.setData(object);
ajaxResult.setCode(200);
return ajaxResult;
}

public static AjaxResult success(Object object) {
return rest(object);
}
}

第二种则是 Map 的形式存储数据,内部通过 put 的方式存储数据,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class AjaxResultMap extends HashMap<Object,Object> implements Serializable {
@Serial
private static final long serialVersionUID = -7127333321005351L;
private static String msg;
private Integer code;
private Object data;


private AjaxResultMap(Object object) {
super.put("msg", "success");
super.put("data", object);
super.put("code", 200);
}

public static AjaxResultMap success(Object object) {
return new AjaxResultMap(object);
}
}

无论你使用的是哪种格式包装数据,项目内部都对其进行了实现,使用方法上是完全一样的!这里仅使用其中一种进行演示。下面是具体的使用方法。

SftResponseFilter 注解用于被封装格式封装的数据,可配置的参数有 3 个:

entity:方法的返回值类型

key:封装数据体中存储数据的字段名,默认为 data

preserveField:是否需要保留字段,默认为 true

1. 返回单个对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 保留字段
@SftResponseFilter(entity = AjaxResult.class)
public AjaxResult getPerson() {
Person person = new Person("1","azki","azki@email.com");
return AjaxResult.success(person);
}

// 返回值类型以及返回值
class com.sora.result.AjaxResult
AjaxResult(code=200, msg=success, data=Person(id=1, name=null, email=Nah))


// 不保留字段
@SftResponseFilter(entity = AjaxResult.class, preserveField = false)
public AjaxResult getPerson() {
Person person = new Person("1","azki","azki@email.com");
return AjaxResult.success(person);
}

// 返回值类型以及返回值
class com.sora.result.AjaxResult
AjaxResult(code=200, msg=success, data={id=1})
2. 返回集合类型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 保留字段
@SftResponseFilter(entity = AjaxResult.class)
public AjaxResult getPerson() {
Person person = new Person("1","azki","azki@email.com");
Person person2 = new Person("2","nayuta","nayuta@email.com");
Person person3 = new Person("3","aznayu","aznayu@email.com");
ArrayList<Person> list = Lists.newArrayList(person, person2, person3);
return AjaxResult.success(list);
}

// 返回值类型以及返回值
class com.sora.result.AjaxResult
AjaxResult(code=200, msg=success, data=[Person(id=1, name=null, email=Nah), Person(id=2, name=null, email=Nah), Person(id=3, name=null, email=Nah)])

// 不保留字段
@SftResponseFilter(entity = AjaxResult.class, preserveField = false)
public AjaxResult getPerson() {
Person person = new Person("1","azki","azki@email.com");
Person person2 = new Person("2","nayuta","nayuta@email.com");
Person person3 = new Person("3","aznayu","aznayu@email.com");
ArrayList<Person> list = Lists.newArrayList(person, person2, person3);
return AjaxResult.success(list);
}

// 返回值类型以及返回值
class com.sora.result.Result
Result(code=200, msg=操作成功, data=[{id=1}, {id=2}, {id=3}])
3. 自定义 key 演示

如果说你存储数据的字段不叫 data ,那么使用 key 配置正确的字段名就可以,例如小明的项目使用类名为 Result 作为封装对象,并且使用 body 字段存储数据,那么可以这么写:

1
2
3
4
5
6
7
8
@SftResponseFilter(entity = Result.class, key = "body")
public Result getPerson() {
Person person = new Person("1","azki","azki@email.com");
Person person2 = new Person("2","nayuta","nayuta@email.com");
Person person3 = new Person("3","aznayu","aznayu@email.com");
ArrayList<Person> list = Lists.newArrayList(person, person2, person3);
return Result.success(list);
}

结束语

欢迎各位提出建议,后续也会优化性能不断扩展新功能