jersey 拦截器,过滤器

个人感觉jersey中的拦截器和过滤器局限性比较大,没有spring mvc中好用。

因为我用jersey开发服务端,所以只记录服务端的过滤器和拦截器。

 

一、拦截器

有两种拦截器:ReaderInterceptor是针对输入流的,WriterInterceptor是针对输出流的。

拦截器旨在通过操纵实体输入/输出流来操纵实体。

1.如何实现拦截器

(1)写一个拦截器类,并且实现ReaderInterceptor/WriterInterceptor接口

例如:

(2)记住要注册这个拦截器类

在jersey配置类中register这个拦截器类

之后就可以启用这个拦截器了。

因为这里没有配置名称绑定@NameBinding,所以这里的拦截器是全局的。名称绑定将在下面提到。

2.这个拦截器可以用来做些什么

ReaderInterceptor我基本上没使用过。WriterInterceptor倒是可以用来做GZIP压缩,提高网页资源访问速度。官网给出的拦截器示例也是GZIP压缩的例子。

官方文档介绍:拦截器旨在通过操纵实体输入/输出流来操纵实体。所以拦截器一般用于针对实体的操作。而过滤器主要旨在操纵请求和响应参数,如HTTP头部,URI和/或HTTP方法。所以不要把拦截器当成过滤器使用,拦截器缺少很多对应的方法。

我之前做权限管理,就错误使用了拦截器。我把web token放在了cookie中,尝试在拦截器中取获取cookie,结果上下文context中根本就没有获取cookie的方法(但是context有获取header的方法,这是怎么回事,我也是醉了)。看了官方文档之后,我换用了过滤器来获取cookie,就解决了这个问题。

二、过滤器

有两种拦截器:ContainerRequestFilter是针对输入流的,ContainerResponseFilter是针对输出流的。

过滤器主要旨在操纵请求和响应参数,如HTTP头部,URI和/或HTTP方法。

1.如何实现过滤器

(1)写一个过滤器类,并且实现ContainerRequestFilter/ContainerResponseFilter接口

(2)记住要注册这个过滤器类

在jersey配置类中register这个过滤器类

之后就可以启用这个拦截器了。

因为这里没有配置名称绑定@NameBinding,所以这里的拦截器是全局的。

(3)全局过滤器如何配置不需要过滤的路径?

需要手动无视掉不需要过滤的路径,写成这样:

个人认为这样的处理方式和原生的servlet中很相似。在spring mvc中,可以使用配置文件进行路径的配置,不需要在代码层面进行控制。spring boot中则可以使用注解的形式进行配置。

哪种方式比较优秀,见仁见智。因为习惯问题,我个人比较喜欢spring mvc中的方式。

2.这个拦截器可以用来做些什么

官方文档介绍:过滤器主要旨在操纵请求和响应参数,如HTTP头部,URI、HTTP方法。所以可以用来进行一些身份验证(操作header,cookie什么的),更换请求方法等等操作。

过滤器中依然有操作输入输出流的方法,但是不建议这样使用(这是拦截器的工作)。

三、名称绑定

我的理解:

自定义一个注解,然后通过这个注解同时绑定(注释)请求方法和过滤器/拦截器,这样就可以把请求方法和过滤器/拦截器关联起来,只要一执行请求方法就启用相应的过滤器/拦截器,其他未绑定注解的方法就不受影响。

名称绑定对过滤器和拦截器都有效,都可以进行名称绑定。

1.如何实现名称绑定

(1)先实现一个注解,用于进行名称绑定

注意这个@NameBinding注解,是用来修饰注解的。作用是告诉jersey:这个注解待会用来进行名称绑定。

你写的这个注解也是可以加上字段参数的。可以加上一个value参数,就像这样:

其实这里有个让我迷惑不解的问题,在拦截器中有获取这个注解的方法,但是在过滤器中居然没有这个方法。也就是说,只有在拦截器中才能获取此注解中的参数,但是过滤器中无法获取。为什么非要有这样的不同呢,我也是醉了。

(2)写一个过滤器/拦截器,然后使用你写的新注解进行修饰,完成第一步绑定

(3)使用你写的注解修饰需要你需要进行拦截/过滤的方法,完成第二部绑定

现在,只要使用了这个helloworld方法(即访问了该路径)就会启用绑定的过滤器/拦截器了。

2.名称绑定可以用来做什么

用途多了去了,名称绑定可以实现对接口的方法的粒度控制。我个人用来实现接口权限验证。记得之前的ContainerResponseFilter吗,绑定之后可以实现一些资源的回收什么的操作。其实还是和spring挺相似的。

四、动态绑定

动态绑定是一种如何以动态方式为资源方法分配过滤器和拦截器的方法。名称绑定使用静态方法,对绑定的更改需要更改和重新编译源代码。使用动态绑定,可以实现在应用程序初始化时定义绑定的代码。

我的理解:

动态绑定又是一种全局的方法。需要用代码找到相应的方法,然后再去注册相应的过滤器/拦截器,并且执行。(应该是用java的动态代理实现的)

干脆举个官网的例子:

CompressionDynamicBinding监视着整个运行过程。一旦getVeryLongString()方法运行,configure就会适配这个方法,并且注册GZIPWriterInterceptor拦截器,之后getVeryLongString()就会经过GZIPWriterInterceptor的处理。

我个人认为这个动态绑定应该蛮好用的,因为可以实现各种动态效果。

这个特性值得好好研究。

五、拦截/过滤的顺序

1.具体顺序

还是以官网的为准吧,我也不想翻译出来了。

https://jersey.java.net/documentation/latest/filters-and-interceptors.html

2.举个例子

在jersey中拦截器/过滤器的优先级特别重要,我举个权限控制的情景

现在有两个过滤器,一个用于负责登录的校验,一个负责权限的校验,那么按照常识,登录校验当然是全局过滤器,权限校验只作用于某些接口,当然使用名称绑定设计成局部过滤。

如用户录都没有登录,当然不允许访问接口,那么就不需要进行权限校验。所以我们现在需要安排一下两个过滤器的执行顺序,把登录校验放在权限校验之前。

那么现在问题来了,名称绑定的过滤器优先级似乎是一直高于普通过滤器的,要怎么解决这个问题呢?

网上给出的解决方法全都是:在jersey配置文件中配置优先级

或者使用注解配置优先级@Priority,我都试过了,一点用都没有,也不报错。

我个人认为:名称绑定优先于普通过滤器,而普通的过滤器就可以用以上方法来设置优先级。

后来发现有个预匹配注解:@PreMatching,是先于所有过滤器的,所以我就尝试注解了登录过滤器,果然让过滤顺序改变了,先登录校验,再权限校验。

六、总结

对我个人来说,jersey的拦截器和过滤器有迷惑性,误导了我几次,感觉比spring mvc要难用很多。

最气人的是,有一些方法不但不起作用,而且没有报错,感觉很坑。

有一说一,名称绑定用起来感觉挺舒服的,思路值得借鉴。

1 对 “jersey 拦截器,过滤器”的想法;

发表评论

电子邮件地址不会被公开。 必填项已用*标注