一. 过滤器
二. 拦截器
三. 监听器
一. 过滤器 (过滤器依赖与 servlet 容器)
SpringMVC 框架是一个成熟的优秀 java web 开发框架, 学习研究框架设计有助于我们更好的理解和掌握 spring MVC, 设计和写出更符合的结构和代码.
本节主要是研读 SpringMVC 框架中的过滤器设置, 以编码处理过滤器为例来学习框架内是怎样设置过滤器的.
如上所示的 spring-Web.jar 包结构所示, Spring 的 Web 包中中提供有很多过滤器, 这些过滤器位于 org.springframework.Web.filter 并且理所当然地实现了 javax.servlet.Filter,
不过实现的方式有以下几类:
(1) 直接实现 Filter, 这一类过滤器只有 CompositeFilter;
(2) 继承抽象类 GenericFilterBean, 该类实现了 javax.servlet.Filter, 这一类的过滤器只有一个, 即 DelegatingFilterProxy;
(3) 继承抽象类 OncePerRequestFilter, 该类为 GenericFilterBean 的直接子类, 这一类过滤器包括 CharacterEncodingFilter,HiddenHttpMethodFilter,HttpPutFormContentFilter,RequestContextFilter 和 ShallowEtagHeaderFilter;
(4) 继承抽象类 AbstractRequestLoggingFilter, 该类为 OncePerRequestFilter 的直接子类, 这一类过滤器包括 CommonsRequestLoggingFilter,Log4jNestedDiagnosticContextFilter 和 ServletContextRequestLoggingFilter.
过滤器放在容器结构的什么位置?
过滤器放在 Web 资源之前, 可以在请求抵达它所应用的 Web 资源 (可以是一个 Servlet, 一个 Jsp 页面, 甚至是一个 html 页面) 之前截获进入的请求, 并且在它返回到客户之前截获输出请求. Filter: 用来拦截请求, 处于客户端与被请求资源之间, 目的是重用代码. Filter 链, 在 Web.xml 中哪个先配置, 哪个就先调用. 在 filter 中也可以配置一些初始化参数.
Java 中的 Filter 并不是一个标准的 Servlet , 它不能处理用户请求, 也不能对客户端生成响应. 主要用于对 HttpServletRequest 进行预处理, 也可以对 HttpServletResponse 进行后处理, 是个典型的处理链.
Filter 有如下几个种类:
l 用户授权的 Filter: Filter 负责检查用户请求, 根据请求过滤用户非法请求.
l 日志 Filter: 详细记录某些特殊的用户请求.
l 负责解码的 Filter: 包括对非标准编码的请求解码.
l 能改变 xml 内容的 XSLTFilter 等.
Filter 有如下几个用处:
l 在 HttpServletRequest 到达 Servlet 之前, 拦截客户的 HttpServletRequest .
l 根据需要检查 HttpServletRequest , 也可以修改 HttpServletRequest 头和数据.
l 在 HttpServletResponse 到达客户端之前, 拦截 HttpServletResponse .
l 根据需要检查 HttpServletResponse , 可以修改 HttpServletResponse 头和数据.
创建一个 Filter 只需两个步骤:(1)创建 Filter 处理类:
(2)在 Web.xml 文件中配置 Filter .
创建 Filter 必须实现 javax.servlet.Filter 接口, 在该接口中定义了三个方法.
• void init(FilterConfig config): 用于完成 Filter 的初始化.
• void destroy(): 用于 Filter 销毁前, 完成某些资源的回收.
• void doFilter(ServletRequest request, ServletResponse response,FilterChain chain): 实现过滤功能, 该方法就是对每个请求及响应增加的额外处理.
过滤器 Filter 也具有生命周期: init()->doFilter()->destroy(), 由部署文件中的 filter 元素驱动.
参照编码过滤器示例来查看怎么实现的
- <!-- 编码处理过滤器 -->
- <filter>
- <filter-name>encodingFilter</filter-name>
- <filter-class>org.springframework.Web.filter.CharacterEncodingFilter</filter-class>
- <init-param>
- <param-name>encoding</param-name>
- <param-value>utf-8</param-value>
- </init-param>
- <init-param>
- <param-name>forceEncoding</param-name>
- <param-value>true</param-value>
- </init-param>
- </filter>
- <filter-mapping>
- <filter-name>encodingFilter</filter-name>
- <url-pattern>*.do</url-pattern>
- </filter-mapping>
其中, filter-class 为过滤器 Filter 类, init-prama 为注入的 set 参数
Filter-mapping 中的 url-pattern 为过滤的 url 类型
类的继承关系
CharacterEncodingFilter r 类继承了 OncePerRequestFilter 类
public class CharacterEncodingFilter extends OncePerRequestFilter
而 OncePerRequestFilter 类又继承了 GenericFilterBean 类
- public abstract class OncePerRequestFilter extends GenericFilterBean
- public abstract class GenericFilterBean implements
Filter, BeanNameAware, EnvironmentAware, ServletContextAware, InitializingBean, DisposableBean
设置编码的核心代码为
- @Override
- protected void doFilterInternal(
- HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
- throws ServletException, IOException {
- if (this.encoding != null && (this.forceEncoding || request.getCharacterEncoding() == null)) {
- request.setCharacterEncoding(this.encoding);
- if (this.forceEncoding) {
- response.setCharacterEncoding(this.encoding);
- }
- }
- filterChain.doFilter(request, response);
- }
其中 filterChain 为过滤器链, 表示执行完这个过滤器之后接着执行下一个过滤器
区别
我们在使用过滤器时, 通常没必要知道 GenericFilterBean,OncePerRequestFilter 和 AbstractRequestLoggingFilter, 但不防碍我们了解这几个类, 就上文所述, AbstractRequestLoggingFilter 继承自 OncePerRequestFilter,OncePerRequestFilter 继承自 GenericFilterBean, 所以我们知道, genericFilterBean 是任何类型的过滤器的一个比较方便的超类, 这个类主要实现的就是从 Web.xml 文件中取得 init-param 中设定的值, 然后对 Filter 进行初始化(当然, 其子类可以覆盖 init 方法).
OncePerRequestFilter 继承自 GenericFilterBean, 那么它自然知道怎么去获取配置文件中的属性及其值, 所以其重点不在于取值, 而在于确保在接收到一个 request 后, 每个 filter 只执行一次, 它的子类只需要关注 Filter 的具体实现即 doFilterInternal.
AbstractRequestLoggingFilter 是对 OncePerRequestFilter 的扩展, 它除了遗传了其父类及祖先类的所有功能外, 还在 doFilterInternal 中决定了在过滤之前和之后执行的事件, 它的子类关注的是 beforeRequest 和 afterRequest.
总体来说, 这三个类分别执行了 Filter 的某部分功能, 当然, 具体如何执行由它们的子类规定, 若你需要实现自己的过滤器, 也可以根据上文所述继承你所需要的类.
自定义过滤器
参数名称相同, 设置 set 方法可以自动初始化
- package com.my.dm.filter;
- import java.io.IOException;
- import javax.servlet.FilterChain;
- import javax.servlet.ServletException;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import org.apache.logging.log4j.LogManager;
- import org.apache.logging.log4j.Logger;
- import org.springframework.Web.filter.OncePerRequestFilter;
- public class TestFilter extends OncePerRequestFilter{
- private Logger logger =LogManager.getLogger(TestFilter.class);
- private String demo;
- /**
- * @return the demo
- */
- public String getDemo() {
- return demo;
- }
- /**
- * @param demo the demo to set
- */
- public void setDemo(String demo) {
- this.demo = demo;
- }
- @Override
- protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
- throws ServletException, IOException {
- // TODO Auto-generated method stub
- // 请求的 uri
- String url = request.getRequestURI();
- String hoString = request.getRemoteHost();
- String ip = getIPAddress(request);
- logger.info("url :" + url);
- logger.info("ip :" + ip);
- logger.info("demo :" + demo);
- // 将请求转发到目的地
- filterChain.doFilter(request, response);
- }
- public void destroy() {
- }
- public void init(){
- }
- // 获取真实 ip
- public static String getIPAddress(HttpServletRequest request) {
- String ip = null;
- //X-Forwarded-For:Squid 服务代理
- String ipAddresses = request.getHeader("X-Forwarded-For");
- if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
- //Proxy-Client-IP:apache 服务代理
- ipAddresses = request.getHeader("Proxy-Client-IP");
- }
- if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
- //WL-Proxy-Client-IP:weblogic 服务代理
- ipAddresses = request.getHeader("WL-Proxy-Client-IP");
- }
- if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
- //HTTP_CLIENT_IP: 有些代理服务器
- ipAddresses = request.getHeader("HTTP_CLIENT_IP");
- }
- if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
- //X-Real-IP:nginx 服务代理
- ipAddresses = request.getHeader("X-Real-IP");
- }
- // 有些网络通过多层代理, 那么获取到的 ip 就会有多个, 一般都是通过逗号 (,) 分割开来, 并且第一个 ip 为客户端的真实 IP
- if (ipAddresses != null && ipAddresses.length() != 0) {
- ip = ipAddresses.split(",")[0];
- }
- // 还是不能获取到, 最后再通过 request.getRemoteAddr(); 获取
- if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
- ip = request.getRemoteAddr();
- }
- return ip.equals("0:0:0:0:0:0:0:1")?"127.0.0.1":ip;
- }
- }
- <!-- 获取登陆者信息 -->
- <filter>
- <filter-name>testFilter</filter-name>
- <filter-class>com.my.dm.filter.TestFilter</filter-class>
- <init-param>
- <param-name>demo</param-name>
- <param-value>112.2.36</param-value>
- </init-param>
- </filter>
- <filter-mapping>
- <filter-name>testFilter</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
- [21:31:48:620] [INFO] - url : /dm/device/toUploadFile - com.my.dm.filter.TestFilter.doFilterInternal(TestFilter.java:46)
- [21:31:48:641] [INFO] - ip : 127.0.0.1 - com.my.dm.filter.TestFilter.doFilterInternal(TestFilter.java:47)
- [21:31:48:641] [INFO] - demo : 112.2.36 - com.my.dm.filter.TestFilter.doFilterInternal(TestFilter.java:49)
二. 拦截器
三. 监听器
来源: http://www.bubuko.com/infodetail-3102904.html