beanfilter是我最近完成的一个开源Java工具,
项目地址 https://gitee.com/l0km/beanfilter
才做完成第一阶段,发布了第一个版本0.1.0
完成对spring的支持,后续还要实现对thrift服务的支持,以下为工具的使用说明
beanfilter
基于注解(Annotation)实现的服务端(spring/thrift)对JavaBean类型数据在序列化和反序列化阶段动态字段过滤(IFieldFilter)和值过滤(IValueFilter)工具。
为服务端提供了一个动态过滤服务方法输入输出的Java Bean参数字段的功能,字段过滤用于控制字段是否被输入/输出,值过滤用于控制字段输入/输出时的内容。
比如在字段安全保护场景,可以使用字段过滤器,将不允许用户自己修改的字段(balance)在作为服务方法输入参数反序列化时忽略处理,避免客户端远程修改该字段。
比如在隐私保护场景,可以使用值过滤器,将用户名字段 (name)在作为服务方法结果输出时加*号显示为王*华
特性
- 基于服务方法注解支持服务端为每个服务方法定义不同的字段过滤
- 支持jackson,fastjson的对Java Bean类型在序列化和反序列化时的字段过滤和值过滤
- 支持Thrift Struct在序列化和反序列化时的字段过滤和值过滤【暂未实现】
- 支持过滤器动态激活
- 支持自定义字段过滤器和值过滤
- 支持自定义过滤器注解
快速入门
beanfilter使用非常简单,只要如下两步。
服务方法注解定义
需要引入依赖
<dependency>
<groupId>com.gitee.l0km</groupId>
<artifactId>beanfilter-annotations</artifactId>
<version>0.1.0</version>
</dependency>
如下在服务方法上定义一组过滤器注解,指定要过滤的字段,通过注解定义了服务方法上使用的过滤器
public class TestService {
/**
* [序列化]字段过滤器定义:指定tokenTime字段在序列化时不输出,该方法返回的 TestUserBean 在序列化为JSON时就没有该字段
* activeOn指定了自定义的过滤器激活器,只有激活器返回true时才启用过滤器
*/
@FieldNameFilter(beanClass = TestUserBean.class,filterNames = {"tokenTime"},activeOn=MyAction.class)
/** [反序列化]字段过滤器定义:指定tokenTime字段在反序列化时不输出,该方法反序列化时得到的输入参数TestDevice的 tokenTime 不会被赋值,为null */
@FieldNameFilter(beanClass = TestDevice.class,filterNames = {"tokenTime"},serializingUsed =false,deserializingUsed = true)
/** [序列化]字段过滤器定义:为TestUserGroupBean类型数据指定使用自定义字段过滤器用于反序列化 */
@FieldFilter(filterClass=MyFieldFilter.class,beanClass=TestUserGroupBean.class)
/** [序列化]字段过滤器定义:为TestUserGroupBean类型数据指定使用自定义值过滤器用于反序列化 */
@FieldFilter(filterClass=IFieldFilter.DefaultFieldFilter.class,beanClass=TestUserGroupBean.class)
/** [序列化]值过滤器定义:指定TestUserBean的 password 字段在序列化时输出为 '***' */
@ConstantValueFilter(beanClass = TestUserBean.class,filterName = "password",consant = "***")
/** [序列化]值过滤器定义:指定TestUserBean的 name 字段在序列化时输出为 'anonymous' */
@ConstantValueFilter(beanClass = TestUserBean.class,filterName = "name",consant = "anonymous")
public TestUserBean addUserFilterOut(TestUserBean input,TestUserGroupBean group) {
return input;
}
}
Spring 启动拦截器
需要引入依赖
<dependency>
<groupId>com.gitee.l0km</groupId>
<artifactId>beanfilter-interceptor</artifactId>
<version>0.1.0</version>
</dependency>
如下在Spring服务启动注解(@SpringBootApplication)上指定扫描beanfilter spring拦截器FilterInterceptorConfig所在包就可以启动服务方法拦截器,激活了服务方法上定义的beanfilter过滤器
import org.springframework.boot.autoconfigure.SpringBootApplication;
import com.gitee.l0km.beanfilter.spring.FilterInterceptorConfig;
/**
* 应用服务启动配置
*/
@SpringBootApplication(scanBasePackageClasses = {FilterInterceptorConfig.class})
public class ApplicationBoot{
//////..../////
}
过滤器说明
beanfilter-annotations定义了基本的字段过滤和值过滤器注解,可以直接用于服务方法上。
beanfilter-core中定义基本的字段过滤器和值过滤器实现类
内置过滤器注解
@SimpleFieldFilter
@SimpleFieldFilter是基于 com.gitee.l0km.beanfilter.SimpleFieldFilter 过滤实现的字段过滤器注解
| 注解字段名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| beanClass | Class<?> | Object.class | 字段过滤作用的Java Bean类型,如果不指定作用于所有Java Bean类型 |
| autoCase | boolean | false | 是否将snake-case和camel-case格式的字段字视为同一字段,如firstName和first_name,为true时视为同一个名字。在这个字段数据库对象类型上比较有用,数据库字段一般的命名习惯是snake-case,而Java Bean的字段命名为camel-case,该字段为true,就可以避免因为定义的字段名格式不匹配而导致的过滤器失效 |
| whiteList | boolean | false | 为true时为白名单模式,filterNames指定字段名被允许输入/输出,否则为黑名单模式,filterNames指定字段名被禁止输入/输出 |
| filterNames | String[] | 过滤的字段名列表 | |
| activeOn | Class<?>[] | {} | 过滤器激活器类型列表,必须为Activation接口实现 |
| activeOnClassNames | String[] | {} | 过滤器激活器类名列表,必须为Activation接口实现类名,与activeOn参数作用相同,用字符器定义类名在特定场景可以减少依赖 |
| activeAnd | boolean | true | 指定多个过滤器激活器时,激活判断模式,为true为AND模式,所有激活器条件都匹配才能激活过滤器,否则为OR模式,任意一激活器条件都匹配就可以激活过滤器 |
| deserializingUsed | boolean | false | 过滤器使用场景:是否用于反序列化 |
| serializingUsed | boolean | true | 过滤器使用场景:是否用于序列化 |
@ConstantValueFilter
@ConstantValueFilter是基于 com.gitee.l0km.beanfilter.SimpleValueFilter 过滤实现的值过滤器注解
| 注解字段名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| beanClass | Class<?> | Object.class | 同@SimpleFieldFilter |
| autoCase | boolean | false | 同@SimpleFieldFilter |
| filterName | String | 要过滤字段名 | |
| consant | String | 返回的字段值 | |
| constantType | Class<?> | Object.class | 要求的返回字段值类型 |
| activeOn | Class<?>[] | {} | 同@SimpleFieldFilter |
| activeOnClassNames | String[] | {} | 同@SimpleFieldFilter |
| activeAnd | boolean | true | 同@SimpleFieldFilter |
| deserializingUsed | boolean | false | 同@SimpleFieldFilter |
| serializingUsed | boolean | true | 同@SimpleFieldFilter |
自定义过滤器和注解
用户可以参照 SimpleFieldFilter实现 IFieldFilter接口来实现自定义的字段过滤器,同理可以参照 SimpleValueFilter实现IValueFilter接口来实现自定义的值过滤器。
有了自定义过滤器,用户可以参照@FieldNameFilter和@ConstantValueFilter来定义对应的注解。
以自定义字段过滤为例,如下,我们定义一个字段过滤器:
public class MyFieldFilterImpl implements IFieldFilter{
final String testName;
final Class<?> testType;
public MyFieldFilterImpl(String testName, Class<?> testType) {
super();
this.testName = testName;
this.testType = testType;
}
@Override
public boolean permit(Class<?> clazz, String fieldName) {
return false;
}
}
根据上面的字段过滤器,可以定义如下注解@MyFieldFilter,我们希望该注解是可重复的,所以同时定义了@MyFieldFilters:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@FieldFilter(filterClass = MyFieldFilterImpl.class,beanClass = Object.class)
@Repeatable(MyFieldFilters.class)
public @interface MyFieldFilter {
@CtorArg(0)
String testName();
@CtorArg(1)
Class<?> testType() default Object.class;
@AliasFor(annotation = FieldFilter.class,attribute = "deserializingUsed")
boolean deserializingUsed() default false;
@AliasFor(annotation = FieldFilter.class,attribute = "serializingUsed")
boolean serializingUsed() default true;
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyFieldFilters {
MyFieldFilter[] value();
}
上面的@MyFieldFilter注解中@CtorArg用于定义该字段是过滤器实现类MyFieldFilterImpl类的构造方法MyFieldFilterImpl(String testName, Class<?> testType)的参数,@CtorArg中定义的数字为该字段在构造方法参数列表中的索引 ,@CtorArg(0)即为构造方法的第一个参数,以此类推,不能搞错否则服务方法拦截器在构造过滤器实例时会抛出异常。
上面的注解中deserializingUsed,serializingUsed字段可以不定义,如果不定义则默认该过滤器只用于序列化。参见 @com.gitee.l0km.beanfilter.annotations.FieldFilter中deserializingUsed,serializingUsed字段的默认值
自定义过滤器完整的示例代码参见 :
com.gitee.l0km.beanfilter.CustomFilterTest
Spring服务方法拦截
beanfilter-interceptor中com.gitee.l0km.beanfilter.spring.InstallFilterInterceptor 基于org.springframework.web.servlet.HandlerInterceptor实现了Spring WEB请求拦截,在请求被序列化之前,根据服务方法上的注解构建过滤器,注入Java Bean对应的序列化器和反序列化器。在请求执行完成之后,删除过滤器。
完整说明参见项目仓库: https://gitee.com/l0km/beanfilter
1万+

被折叠的 条评论
为什么被折叠?



