持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第7天,点击查看活动详情
介绍
在项目开发中我们往往需要考虑用户访问时是否有权限进行访问,而没有权限的用户我们就需要将它过滤掉,此时我们就需要使用到过滤器来帮助我们。过滤器可以动态地拦截请求和响应,可以对请求或响应中的信息做额外处理。
过滤器 Filter 的基本功能是对 Servlet 的调用过程进行干预,在 Servlet 处理请求及响应的过程中增加一些特定的功能。可以使用过滤器实现的功能有:URL 级别的权限访问控制、过滤敏感词汇、压缩响应信息、统一编码方式等。
程序中的过滤器就好比生活中的自来水过滤器,过滤器原理如下图:
当客户端向服务器中的资源发出请求时,会先被过滤器 Filter 拦截处理,之后再将处理后的请求转发给真正的服务器资源( JSP 或 Servlet 等)。此外服务器做出响应前,响应结果也会先被过滤器拦截处理,之后再将处理后的响应转发给客户端。
实现
程序中的过滤器,在语法上是实现了 javax.servlet.Filter 接口的类。javax.servlet.Filter 接口中定义了下表所示的三个方法。
| 方 法 | 简 介 |
|---|---|
| void init(FilterConfig conf) | 用于执行过滤器的初始化工作。Web 容器会在 Web 项目启动前,自动调用该方法。该方法类似于 Servlet 的 init() 方法。 |
| void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) | 当请求和响应被过滤器拦截后,就会交给 doFilter() 方法来处理:参数 request 就是拦截的请求对象,参数 response 就是拦截的响应对象,可以使用参数 chain 的 doFilter() 方法来将拦截的请求和响应放行。 该方法类似于 Servlet 的 doGet()、doPost() 等方法。 |
| void destroy() | 用于释放或关闭被 Filter 对象打开的资源,例如关闭数据库、关闭 IO 流等操作。在 Web 项目关闭时,由 Web 容器自动调用该方法。该方法类似于 Servlet 的 destroy() 方法。 |
与 Servlet 类似,Filter 的 init() 和 destroy() 方法都只会被调用一次,而 doFilter() 方法会在每次客户端发出请求时被调用。init() 方法里的 FilterConfig 参数,主要是为过滤器提供初始化参数。FilterConfig 是一个接口,提供了如下表所示的常用方法。
| 方 法 | 简 介 |
|---|---|
| String getFilterName() | 获取 web.xml 中的过滤器的名称。 |
| String getInitParameter(String param) | 获取 web.xml 中参数名对应的参数值。 |
| ServletContext getServletContext() | 获取 web 应用程序的 ServletContext。 |
实现第一个过滤器程序
1.创建项目
2.创建完成后,在项目中的 pom.xml 中写入以下配置:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.shiyan</groupId>
<artifactId>ServletProject</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>ServletProject Maven Webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
<!-- servlet 依赖 jar 包 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
<!-- jsp 依赖 jar 包 -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
<scope>provided</scope>
</dependency>
</dependencies>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<configuration>
<!-- 端口 -->
<port>8080</port>
<!-- 编码-->
<uriEncoding>UTF-8</uriEncoding>
<!-- 项目的启动路径-->
<path>/</path>
<!-- 项目名称 -->
<finalName>ServletProject </finalName>
<!-- 启动的命令名称-->
<server>tomcat7</server>
</configuration>
</plugin>
</plugins>
</build>
</project>
3.在 webapp 下新建用于发送请求的客户端 JSP — index.jsp。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>index</title>
</head>
<body>
<a href="MyServlet">访问MyServlet…</a>
</body>
</html>
4.在 main 目录下新建 Java 代码所在的目录 java,并在该目录下新建 java 包 org/shiyan/servlet,并在该目录下新建用于处理请求的控制器 Servlet — MyServlet.java。
package org.shiyan.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class MyServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("doPost…");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("doGet…");
}
}
5.在 WEB-INF 目录下的 web.xml 中配置此 Servlet。
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<servlet>
<servlet-name>MyServlet</servlet-name>
<servlet-class>org.shiyan.servlet.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyServlet</servlet-name>
<url-pattern>/MyServlet</url-pattern>
</servlet-mapping>
</web-app>
6.在 org/shiyan 包下新建 filter 包并新建 MyFirstFilter 类。
package org.shiyan.filter;
import java.io.IOException;
import javax.servlet.*;
public class MyFirstFilter implements Filter{
public void init(FilterConfig arg0) throws ServletException{
System.out.println("过滤器01的初始化init()方法…");
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException{
System.out.println("过滤器01的执行方法:doFilter()方法…");
}
public void destroy(){
System.out.println("过滤器01的销毁destroy()方法…");
}
}
7.在 web.xml 中新增以下配置注册 Filter。
<filter>
<filter-name>MyFirstFilter</filter-name>
<filter-class>
org.shiyan.filter.MyFirstFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>MyFirstFilter</filter-name>
<url-pattern>/MyServlet</url-pattern>
</filter-mapping>
8.运行
控制台结果如图:
可以发现 index.jsp 通过超链接向 Servlet 发出的请求确实被 Filter 拦截了,并且在 Tomcat 服务启动的过程中 init() 方法就已经自动执行了。
修改
本次只执行了 Filter 中的 doFilter() 方法,而没有执行 Servlet 中的 doGet() 方法。如果想让被 Filter 拦截的请求能传递给最初所请求的 Servlet,就需要在 Filter 的 doFilter() 方法里加上 chain.doFilter(); 这句代码,表示本次拦截结束、释放本次的请求及响应,代码如下:
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException{
System.out.println("过滤器01的执行方法:doFilter()方法…");
chain.doFilter(request, response);
}
修改过滤器 MyFirstFilter.java 后重启服务,再次运行并点击超链接,可在控制台看到如下结果:
从输出结果可以得知 index.jsp 发出的请求确实先被过滤器进行了拦截处理,然后又执行了 Servlet 中的 doGet() 方法。
之前讲过,Filter 能对请求和响应都进行拦截。在 Filter 中,在 chain.doFilter() 之前的代码用于拦截处理请求,chain.doFilter() 之后的代码用于拦截处理响应,现将过滤器修改如下。
…
public class MyFirstFilter implements Filter{
…
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException{
System.out.println("拦截请求01…");
chain.doFilter(request, response);
System.out.println("拦截响应01…");
}
}
再次重启服务,点击超链接,可在控制台看到如下结果。