本文最后更新于:2024-12-01T08:55:14+08:00
在看源码之前首先来回顾一下,装饰着模式。
定义
装饰者模式 在不改动对象的情况下,动态地将功能附加到对象上。若要扩展功能,应该提供一个包装器,把要扩展的对象包装起来,以提供更加强大的功能。
结构
- Component 被包装的组件,可单独使用。
- Decorator 包装器,扩展包装的对象。
使用场景
- 扩展一个类的功能(这个继承也可以做到)。
- 动态增加功能,动态撤销功能。
RepeatedlyRequestWrapper类
接下来我们正式学习RepeatedlyRequestWrapper
开发javaweb的时候我们经常会获取 ServletRequest 这个对象,这个对象里面有一个方法叫 getInputStream(),他是用来获取用户提交在body里面的数据流,这个数据流一旦读取就没了。
如果我们在过滤器或者拦截器之类的地方直接或者间接调用了getInputStream()这个方法,那么在controller控制层就会获取不到数据。
现在假设我们有一个过滤器就是要过滤body中的数据,这该怎么处理?基于现在的 ServletRequest 的对象明显是做不了这件事的。
这时我们就可以使用 装饰者模式 动态的扩展 ServletRequest 对象,以实现我们现在的需求。
扩展步骤
- 我们创建一个类 RepeatedlyRequestWrapper 继承 HttpServletRequestWrapper(HttpServletRequestWrapper 是一个实现 ServletRequest 接口的装饰者,我们也可以直接实现ServletRequest 接口,但是那样我们要实现的方法太多了)。
- 我们在 RepeatedlyRequestWrapper 中把结果保存下来,让getInputStream()方法去获取我们保存下来的内容,而不是去调用原始的方法,这样getInputStream()就可以一直获取到内容了。
现在我们只需要在需要获取 body 里面的内容的时候,创建一个 RepeatedlyRequestWrapper ,传入HttpServletRequest,然后调用调用getInputStream()就可以获取到body数据流了。
当然传入的HttpServletRequest对象必须要还存在body数据流,如果之前被获取了,再包装也不会有数据,所以我们应该在数据进来就立刻把HttpServletRequest进行包装,以确保数据能准确的包装。
这时我们定义一个权重最大的过滤器,在里面包装一下,让后面调用getInputStream()能一值获取到值。
我们现在注册这个过滤器,把权重调到最大
测试
创建一个测试接口,在接口中获取两次body中的内容。
在没有注册Repeatable过滤器前:
在注册了Repeatable过滤器后: