一、什么是过滤器
Servlet过滤器是在Java Servlet规范2.3中定义的,它能够对Servlet容器的请求和响应对象进行检查和修改。
Servlet过滤器本身并不产生请求和响应对象,它只能提供过滤作用。Servlet过期能够在Servlet被调用之前检查Request对象,修改Request Header和Request内容;在Servlet被调用之后检查Response对象,修改Response Header和Response内容。
Servlet过期负责过滤的Web组件可以是Servlet、JSP或者HTML文件。
过滤器是一个服务器端的组件,它可以截取用户端的请求与响应信息,并对这些信息过滤。
二、过滤器链
一个 Web 应用中可以一次编写多个过滤器,这些过滤器的组合
称之为过滤器链。
在过滤器链中,过滤器的执行顺序依据过滤器在部署描述符web .xml 中注册的顺序
过滤器链体现了一种职责链模式,是设计模式中的一种。
职责链模式:
能够使多个对象,都有机会处理请求,它将多个对象连成一个链条,
并沿着这个链条传递请求,直到有一个对象最终处理它为止。
职责链模式能够避免请求的发送者和接受者之间的耦合关系。
对于过滤器而言,请求传递给具体的Web 资源之前,都会经过
过滤器的处理,在 Web 资源处理完该请求之后-返回响应给客户
端之前,响应信息也会被过滤器处理一遍
一个简单的过滤器链实例:
访问指定资源之前打印若干日志,访问指定资源之后再打印若干日志
点击选择工程名,右键->New->Filter,包名为:com.whohim.filter,
类名为:FilterOne、FilterTwo
FilterOne.java:
package com.whohim.filter;
import java.io.IOException;
import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse;
public class FilterOne implements Filter {
public FilterOne() { System.out.println("===== FilterOne 构造方法 ====="); }
publicvoid init(FilterConfig fConfig) throws ServletException { System.out.println("===== FilterOne 初始化方法 ====="); String initParam=fConfig.getInitParameter("param"); System.out.println("param = "+initParam); }
publicvoid doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("===== 开始执行FilterOne doFilter方法 ====="); chain.doFilter(request, response); System.out.println("===== 结束执行FilterOne doFilter方法 ====="); }
publicvoid destroy() { System.out.println("===== FilterOne 销毁方法 ====="); }
} |
FilterTwo.java:
package com.whohim.filter;
import java.io.IOException;
import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse;
/** * 多个过滤器组合起来,为过滤器链 * 在过滤器链中,过滤器的执行顺序是部署描述符中注册的顺序 * * 过滤器链体现了一种职责链模式是设计模式中的一种 */ public class FilterTwo implements Filter {
public FilterTwo() { System.out.println("===== FilterTwo 构造方法 ====="); }
publicvoid init(FilterConfig fConfig) throws ServletException { System.out.println("===== FilterTwo 初始化方法 ====="); }
publicvoid doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("===== 开始执行FilterTwo doFilter方法 ====="); chain.doFilter(request, response); System.out.println("===== 结束执行FilterTwo doFilter方法 ====="); }
publicvoid destroy() { System.out.println("===== FilterTwo 销毁方法 ====="); }
} |
在部署描述符web.xml 中注册 filter:
<?xmlversion="1.0"encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns="http://xmlns.jcp.org/xml/ns/javaee"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"version="3.1"> <display-name>MyServlet</display-name> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list>
<filter> <filter-name>FilterOne</filter-name> <filter-class>com.whohim.filter.FilterOne</filter-class> <init-param> <param-name>param</param-name> <param-value>whohim</param-value> </init-param> </filter> <filter-mapping> <filter-name>FilterOne</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
<filter> <filter-name>FilterTwo</filter-name> <filter-class>com.whohim.filter.FilterTwo</filter-class> </filter> <filter-mapping> <filter-name>FilterTwo</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
</web-app> |
部署描述符web.xml 在 WEB-INF 目录下,如果没有,手动创建即可
点击选择工程名,右键->Java EE Tools->Generate Deployment Descriptor Stub
启动 Tomcat 时,过滤器的执行:
<!-- 定义Filter -->
<filter>
<!-- Filter的名字 -->
<filter-name>log</filter-name>
<!-- Filter的实现类 -->
<filter-class>lee.LogFilter
</filter-class>
</filter>
<!-- 定义Filter拦截的URL地址 -->
<filter-mapping>
<!-- Filter的名字 -->
<filter-name>log</filter-name>
<!-- Filter负责拦截的URL 全部以/的请求,如果<url-pattern>/*.action </>,将会以拦截*.action的请求-->
<url-pattern>/*</url-pattern></filter-mapping>
在Servlet2.4中filter-mapping中加入了新的标签<dispatcher> ,里面有4个值即REQUEST, FORWARD,INCLUDE和ERROR,默认不写这个标签的时候是REQUEST,该标签是根据客户端传过来的地址进行过滤,FORWARD方法传过来的request方法可以拦截,<ERROR-PAGE>错误页面传过来的拦截,INCLUDE包含过来的过滤,一般REQUEST传过来的拦截.该标签可以加入多个.
下面例子是引用网上的:
例1:
Xml代码
<filter-mapping>
<filter-name>Logging Filter</filter-name>
<url-pattern>/products/*</url-pattern>
</filter-mapping>
这种情况下,过滤器将会作用于直接从客户端发过来的以/products/…开始的请求。因为这里没有制定任何的< dispatcher >元素,默认值是REQUEST。
例2:
Xml代码
<filter-mapping>
<filter-name>Logging Filter</filter-name>
<servlet-name>ProductServlet</servlet-name>
<dispatcher>INCLUDE</dispatcher>
</filter-mapping>
这种情况下,如果请求是通过request dispatcher的include方法传递过来的对ProductServlet的请求,则要经过这个过滤器的过滤。其它的诸如从客户端直接过来的对ProductServlet的请求等都不需要经过这个过滤器。
指定filter的匹配方式有两种方法:直接指定url-pattern和指定servlet,后者相当于把指定的servlet对应的url-pattern作为filter的匹配模式
filter的路径匹配和servlet是一样的,都遵循servlet规范中《SRV.11.2 Specification of Mappings》一节的说明
例3:
Xml代码
<filter-mapping>
<filter-name>Logging Filter</filter-name>
<url-pattern>/products/*</url-pattern>
<dispatcher>FORWARD</dispatcher>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
在这种情况下,如果请求是以/products/…开头的,并且是通过request dispatcher的forward方法传递过来或者直接从客户端传递过来的,则必须经过这个过滤器。
三、过滤器的分类
第一个案例:
public class FirstFilter implements Filter {
@Override
public void destroy() {
System.out.println("destroy---FirstFilter");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throwsIOException, ServletException {
System.out.println("start----doFilter--FirstFilter");
// chain.doFilter(request, response);
HttpServletRequest req =(HttpServletRequest)request;
HttpServletResponse response2 =(HttpServletResponse) response;
//重定向
response2.sendRedirect(req.getContextPath()+"/main.jsp");
//转发
// req.getRequestDispatcher("main.jsp").forward(request, response);
// req.getRequestDispatcher("main.jsp").include(request, response);
System.out.println("end------doFilter--FirstFilter");
}
@Override
public void init(FilterConfig filterConfig) throwsServletException {
System.out.println("init----FirstFilter");
}
}
public class ErrorFilter implements Filter {
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2) throwsIOException, ServletException {
// TODO Auto-generated method stub
System.out.println("检测到有错误信息");
arg2.doFilter(arg0, arg1);//加上这句就能拦截404网页
}
@Override
public void init(FilterConfig arg0) throwsServletException {
// TODO Auto-generated method stub
}
}
web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<display-name></display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<filter>
<filter-name>FirstFilter</filter-name>
<filter-class>com.imooc.filter.FirstFilter</filter-class>
<init-param>
<param-name>name</param-name>
<param-value>zhangsan</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>FirstFilter</filter-name>
<url-pattern>/index.jsp</url-pattern>
</filter-mapping>
<!-- <filter-mapping>
<filter-name>FirstFilter</filter-name>
<url-pattern>/main.jsp</url-pattern>
<dispatcher>FORWARD</dispatcher>
</filter-mapping> -->
<!--
<filter>
<filter-name>SecondFilter</filter-name>
<filter-class>com.imooc.filter.SecondFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>SecondFilter</filter-name>
<url-pattern>/index.jsp</url-pattern>
</filter-mapping>
-->
<error-page>
<error-code>404</error-code>
<location>/error.jsp</location>
</error-page>
<!--
<error-page>
<error-code>500</error-code>
<location>/error500.jsp</location>
</error-page>
-->
<filter>
<filter-name>ErrorFilter</filter-name>
<filter-class>com.imooc.filter.ErrorFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ErrorFilter</filter-name>
<url-pattern>/error.jsp</url-pattern>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
</web-app>
@WebFilter是什么?
@WebFilter用于将一个类声明为过滤器,该注解将会在部署时被容器处理,容器将根据具体的属性配置将相应的类部署为过滤器。
例子:
@WebFilter(filterName = "AsynFilter",value = {"/index.jsp"},dispatcherTypes = {DispatcherType.REQUEST,DispatcherType.ASYNC})
public class AsyncFilter implements Filter {
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2)
throws IOException, ServletException {
System.out.println("begin..Filter");
arg2.doFilter(arg0, arg1);
System.out.println("end..Filter");
}
@Override
public void init(FilterConfig arg0) throwsServletException {
// TODO Auto-generated method stub
}
}
(异步)AsyncFilter:
/**
* Servlet implementation class AsynServlet
*/
@WebServlet(asyncSupported = true, urlPatterns = {"/AsynServlet" })
public class AsynServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("Servlet执行完成" + new Date());
AsyncContext context = request.startAsync();
new Thread(new Executor(context)).start();
System.out.println("Servlet执行完成" + new Date());
}
public class Executor implements Runnable {
private AsyncContext context;
public Executor(AsyncContext context) {
this.context = context;
}
@Override
public void run() {
// 执行复杂业务
try {
Thread.sleep(1000 * 5);
context.getRequest();
context.getResponse();
System.out.println("业务执行完成" + newDate());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
登录及转码案例:
public class LoginServlet extends HttpServlet {
/**
* Constructor of the object.
*/
public LoginServlet() {
super();
}
/**
* Destruction of the servlet. <br>
*/
public void destroy() {
super.destroy(); // Just puts "destroy" string in log
// Put your code here
}
/**
* The doPost method of the servlet. <br>
*
* This method is called when a form has its tag value method equals to post.
*
* @param request the request send by the client to the server
* @param response the response send by the server to the client
* @throws ServletException if an error occurred
* @throws IOException if an error occurred
*/
public void doPost(HttpServletRequest request, HttpServletResponse response) throwsServletException, IOException {
String username =request.getParameter("username");
String password =request.getParameter("password");
System.out.println(username);
if("admin".equals(username) &&"admin".equals(password)){
//校验通过
HttpSession session = request.getSession();
session.setAttribute("username", username);
response.sendRedirect(request.getContextPath()+"/sucess.jsp");
}else{
//校验失败
response.sendRedirect(request.getContextPath()+"/fail.jsp");
}
}
/**
* Initialization of the servlet. <br>
*
* @throws ServletException if an error occurs
*/
public void init() throws ServletException {
// Put your code here
}
}
public class LoginFilter implements Filter {
private FilterConfig config;
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)arg0;
HttpServletResponse response = (HttpServletResponse) arg1;
HttpSession session = request.getSession();
/*
* 编码转换
*/
String charset = config.getInitParameter("charset");
if (charset == null) {
charset = "UTF-8";
}
request.setCharacterEncoding(charset);
/*
* 编码转换
*/
String noLoginPaths =config.getInitParameter("noLoginPaths");
if (noLoginPaths != null) {
String[] strArray = noLoginPaths.split(";");
for (int i = 0; i < strArray.length; i++) {
if (strArray[i] == null || "".equals(strArray[i]))
continue;
if(request.getRequestURI().indexOf(strArray[i]) != -1) {
// indexOf 字符在字串strArray[i]后出现的第一个位置.没有找到返回-1
arg2.doFilter(arg0, arg1);
return;
}
}
}
if (session.getAttribute("username") != null) {
arg2.doFilter(arg0, arg1);
} else {
response.sendRedirect("login.jsp");
}
}
@Override
public void init(FilterConfig arg0) throwsServletException {
config = arg0;
}
}
web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<display-name></display-name>
<servlet>
<description>This is the description of my J2EE component</description>
<display-name>This is the display name of my J2EE component</display-name>
<servlet-name>LoginServlet</servlet-name>
<servlet-class>com.imooc.serlvet.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<url-pattern>/servlet/LoginServlet</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<filter>
<filter-name>LoginFilter</filter-name>
<filter-class>com.imooc.filter.LoginFilter</filter-class>
<init-param>
<param-name>noLoginPaths</param-name>
<param-value>login.jsp;fail.jsp;LoginServlet</param-value>
</init-param>
<init-param>
<param-name>charset</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>LoginFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>