我的开源工具beanfilter:实现基于注解(Annotation)的服务端(spring)动态字段过滤

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 过滤实现的字段过滤器注解

注解字段名类型默认值说明
beanClassClass<?>Object.class字段过滤作用的Java Bean类型,如果不指定作用于所有Java Bean类型
autoCasebooleanfalse是否将snake-case和camel-case格式的字段字视为同一字段,如firstNamefirst_name,为true时视为同一个名字。在这个字段数据库对象类型上比较有用,数据库字段一般的命名习惯是snake-case,而Java Bean的字段命名为camel-case,该字段为true,就可以避免因为定义的字段名格式不匹配而导致的过滤器失效
whiteListbooleanfalse为true时为白名单模式,filterNames指定字段名被允许输入/输出,否则为黑名单模式,filterNames指定字段名被禁止输入/输出
filterNamesString[]过滤的字段名列表
activeOnClass<?>[]{}过滤器激活器类型列表,必须为Activation接口实现
activeOnClassNamesString[]{}过滤器激活器类名列表,必须为Activation接口实现类名,与activeOn参数作用相同,用字符器定义类名在特定场景可以减少依赖
activeAndbooleantrue指定多个过滤器激活器时,激活判断模式,为true为AND模式,所有激活器条件都匹配才能激活过滤器,否则为OR模式,任意一激活器条件都匹配就可以激活过滤器
deserializingUsedbooleanfalse过滤器使用场景:是否用于反序列化
serializingUsedbooleantrue过滤器使用场景:是否用于序列化
@ConstantValueFilter

@ConstantValueFilter是基于 com.gitee.l0km.beanfilter.SimpleValueFilter 过滤实现的值过滤器注解

注解字段名类型默认值说明
beanClassClass<?>Object.class同@SimpleFieldFilter
autoCasebooleanfalse同@SimpleFieldFilter
filterNameString要过滤字段名
consantString返回的字段值
constantTypeClass<?>Object.class要求的返回字段值类型
activeOnClass<?>[]{}同@SimpleFieldFilter
activeOnClassNamesString[]{}同@SimpleFieldFilter
activeAndbooleantrue同@SimpleFieldFilter
deserializingUsedbooleanfalse同@SimpleFieldFilter
serializingUsedbooleantrue同@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;}@Overridepublic 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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/27869.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

小程序的生命周期以及页面生命周期

小程序的生命周期主要分为应用生命周期和页面生命周期两部分。 应用生命周期 应用生命周期指的是小程序从启动到销毁的整个过程&#xff0c;主要包括以下几个阶段和对应的函数&#xff1a; onLaunch&#xff1a;小程序初始化时执行&#xff0c;只执行一次。这是全局的生命周…

Linux-Https协议

文章目录 前言一、Https协议二、常见的加密方式对称加密非对称加密数据摘要&&数据指纹中间人攻击 三、Https的加密历程方案1-只使用对称加密方案2-只使用非对称加密方案3-双方都使用非对称加密方案4-非对称加密对称加密 前言 之前我们学习了Http协议&#xff0c;也试着…

官方文档 搬运 MAXMIND IP定位 mysql导入 简单使用

官方文档地址&#xff1a; 官方文档 文件下载 1. 导入mysql可能报错 Error Code: 1290. The MySQL server is running with the --secure-file-priv option so it cannot execute this statement 查看配置 SHOW GLOBAL VARIABLES LIKE %secure%;secure_file_priv 原来…

laravel版本≥ 8.1

laravel10 php ≥ 8.1 且 ≤ 8.3&#xff1f; 8.1 < php < 8.3PHP版本要求在 8.1 到 8.3 之间&#xff0c;包括这两个版本。具体来说&#xff1a;"≥ 8.1" 表示 PHP 的版本至少是 8.1&#xff0c;也就是说 8.1 及以上的版本都可以。 "≤ 8.3" 表示 P…

计算机组成原理学习 Part 1

计算机系统 组成 计算机系统 { 硬件 计算机的实体&#xff0c;如主机、外设等 软件 由具有各类特殊功能的信息&#xff08;程序&#xff09;组成 计算机系统 \begin{cases} 硬件 &\text 计算机的实体&#xff0c;如主机、外设等\\ 软件 &\text 由具有各类特殊功能的信…

【报错】无法找到模块“element-plus/es/locale/index.mjs”的声明文件。

报错&#xff1a; 无法找到模块“element-plus/es/locale/index.mjs”的声明文件。“E:/codeAll/work/test1/test2/HealinLikeMe-ui/node_modules/.pnpm/element-plus2.7.3_vue3.4.27_typescript5.4.5_/node_modules/element-plus/es/locale/index.mjs”隐式拥有 "any&quo…

Linux笔记--vi编辑器

vi编辑器 基本操作 对于vi编辑器有这几种模式 移动 当编辑一个过大的文件时通过方向键移动光标过慢所以可以使用快捷键进行移动 编辑 dw指令只能在单词第一个字母处使用 D指令删除的是当前行 查找替换 pattern指代想要搜索的内容

056、PyCharm 快速代码重构的方法

在实际的编程过程中&#xff0c;如果有一段代码需要在多个地方重复使用&#xff0c;我们应该将这段代码封装成一个函数。这样可以提高代码的可重用性和可维护性。 在PyCharm编辑器里&#xff0c;可以使用以下操作对代码块进行快速的重构。 &#xff08;1&#xff09;、选中一…

【Photoshop】PS修改文字内容

Photoshop(PS)修改图片上文字内容&#xff0c;网上教材不少&#xff0c;本人整理实践过的方法&#xff0c;分享给各位。本人实践方法&#xff1a; 内容识别填充&#xff1a;适用于背景色复杂的图片内容修补工具&#xff1a;适用于背景色为纯色的图片 方式一&#xff1a;内容识…

java入门-文件与IO流

File类 提供一些方法(api)来操纵文件和获取文件的信息 File常用API 属性 获取系统分隔符 不同操作系统的分隔符 windows的目录分割符号是用向右的斜线&#xff0c;java中\ 表示转义字符&#xff0c;所以向右的斜线需要写两个 \; linux目录分割符号是向左的斜线: / private st…

MySQL 考证作用

提升个人技能&#xff1a;参加MySQL考证的过程本身就是一个学习和提升的过程。考生需要系统地复习和掌握MySQL的相关知识和技能&#xff0c;这有助于提升个人的专业能力和技术水平。增强就业竞争力&#xff1a;在求职过程中&#xff0c;拥有MySQL认证证书可以作为一个加分项&am…

Github 2024-06-15 开源项目日报Top10

根据Github Trendings的统计,今日(2024-06-15统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量C++项目3Python项目2TypeScript项目1Java项目1HTML项目1Vue项目1Go项目1JavaScript项目1C项目1ComfyUI:强大而模块化的稳定扩散GUI 创建周期:…

Gobject tutorial 三

Derivable type and abstract type Derivable type 在GLib中&#xff0c;类型可以分为两种。一种是可以被继承的(derivable)&#xff0c;一种是不能被继承的(final)。二者的主要区别是&#xff0c;final 类型对象的类结构中&#xff0c;除了其父类外&#xff0c;再无其他成员…

Linux内核中的锁

不同的锁&#xff0c;作用对象是不一样的&#xff0c;也就是作用域不一样下面分别是作用于临界区、CPU、内存、cache 的各种锁的归纳&#xff1a; 补充&#xff1a;cache是一种缓存&#xff0c;包含硬件缓存&#xff08;CPU缓存&#xff09;以及软件缓存&#xff08;网页缓存&a…

Cocos2d-x 4.0 工程首次建立与编译(Mac m1)

Mac m1芯片下将cocos2d-x升级至4.0版本后&#xff0c;官方剔除了不同平台的工程以及变更了编译方式&#xff0c;直接使用cmake构建&#xff0c;需要做一些前置的准备工作。 环境准备&#xff1a; 项 版本 备注 MacOS10.3 or laterpython2.7.16(建议>2.7.10)cmake3.29.3Do…

自动驾驶场景下TCP协议参数优化调整案例分享

RTT 往返时间&#xff0c;从tcp协议栈决定发包&#xff0c;到收到回包的时间。 包含本地驱动&#xff0c;网卡硬件&#xff0c;网线&#xff0c;交换机&#xff0c;收包方处理的耗时。需注意如果开了delayed ack&#xff0c;协议栈未做特殊处理&#xff08;默认没做&#xff…

C++中字符字面量的使用细节

C中字符字面量的使用细节 如何在 C中书写字符字面值:将字符用单引号括起&#xff0c;如M(注意&#xff0c;示例中没有使用双引号。C对字符用单引号&#xff0c;对字符串使用双引号。cout对象能够处理这两种情况&#xff0c;但正如第4章将讨论的&#xff0c;这两者有天壤之别)。…

【项目管理知识】挣值管理的概念与计算

【项目管理知识】挣值管理的概念与计算 四个基础概念&#xff1a;BAC、AC、PV、EV四个绩效概念&#xff1a;CV、CPI、SV、SPI四个延伸概念&#xff1a;ETC、EAC、非典型偏差、典型偏差挣值管理-非典型偏差挣值管理-典型偏差 完工尚需绩效指数&#xff1a;TCPI 四个基础概念&…

探索交互的本质:从指令到界面的演进与Linux基础指令的深入剖析

目录 1.指令 vs 界面//选读 1.1交互的需求 满足需求的第一阶段-指令 满足需求的第二阶段-界面 1.2 指令 和 界面交互 区别 2.操作系统介绍 2.1 举例说明 驱动软件层 2.2 为什么要有操作系统&#xff1f; 0x03 为什么要进行指令操作&#xff1f; 3.Linux基本指令 l…

模型量化 剪枝bevfusion

量化 剪枝 shared mem 只在block内共享&#xff0c;device glob mem能够所有线程共享