【Web】过滤器

JavaWeb过滤器

 

过滤器是一个服务器端的组件,它可以截取用户端的请求与响应信息,并对这些信息过滤。

 

过滤器的工作原理

 

不存在过滤器的情况下,用户直接访问Web资源。

存在过滤器的情况下:


过滤器的生命周期


创建第一个过滤器程序

创建 FirstFilter.java 实现 java.servlet.Filter 接口

package com.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 FirstFilter implements Filter {
	public void destroy() {
		/**
		 * Web容器在销毁过滤器实例前调用该方法,在这个方法中可以释放过滤器中占用的资源。
		 */
	}
	public void doFilter(ServletRequest arg0, ServletResponse arg1,
			FilterChain arg2) throws IOException, ServletException {
		/**
		 * 这个方法完成实际的过滤操作,这个地方是过滤器的核心方法,当用户请求访问与过滤器关联的URL时,Web容器将先调用过滤器的doFilter方法。
		 * FilterChain参数可以调用chain。doFilter方法,将请求传给下一个过滤器(或目标资源),或利用转发、重定向将请求转发到其他资源。
		 */
	}
	public void init(FilterConfig arg0) throws ServletException {
		/**
		 * 这是过滤器的初始化方法,Web容器创建过滤器实例后将调用这个方法,这个方法可以读取Web。xml文件中过滤器的参数
		 */
	}
}

Web.xml中的配置

过滤器可以改变用户请求的路径。

过滤器不能直接返回数据,处理用户请求。

 

过滤器链

 

当有多个过滤器处理一个用户请求的时候,服务器会按照web.xml中过滤器定义的先后顺序组装成一条链。

过滤器链执行顺序案例

FirstFilter.java

package com.filter;

public class FirstFilter implements Filter {
	public void destroy() {
		System.out.println("onDestroy");
	}
	public void doFilter(ServletRequest arg0, ServletResponse arg1,
			FilterChain arg2) throws IOException, ServletException {
		System.out.println("start ---do first filter");
		arg2.doFilter(arg0, arg1);
		System.out.println("end-----do first filter");
	}
	public void init(FilterConfig arg0) throws ServletException {
		System.out.println("init");
	}
}

SecondFilter.java

package com.filter;

import java.io.IOException;

public class SecondFilter implements Filter {
	public void destroy() {
		// TODO Auto-generated method stub
	}
	public void doFilter(ServletRequest arg0, ServletResponse arg1,
			FilterChain arg2) throws IOException, ServletException {
		System.out.println("start do second Filter");
		arg2.doFilter(arg0, arg1);
		System.out.println("end do secondfilter");
	}
	public void init(FilterConfig arg0) throws ServletException {
		// TODO Auto-generated method stub
	}
}

Web.xml 

<filter>
        <filter-name>FirstFilter</filter-name>
        <filter-class>com.filter.FirstFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>FirstFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <filter>
        <filter-name>SecondFilter</filter-name>
        <filter-class>com.filter.SecondFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>SecondFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
两个过滤器同时过滤一个请求的结果如下:



过滤器的分类 Dispatch

Request

用户直接访问页面时,Web容器会调用过滤器

Forward

目标资源是通过RequestDispatcher的 forward访问时,该过滤器会被调用。

Include

目标资源是通过RequestDispatcher的include方法调用时,过滤器被调用。

Error

目标资源是通过声明式异常处理机制调用时,过滤器将被调用。

当跳转到error.jsp 时 ErrorFilter 将被调用。

<error-page>

            <error-code>404</error-code>

            <location>/error.jsp</location>

     </error-page>

    <filter>

        <filter-name>ErrorFilter</filter-name>

        <filter-class>com.filter.ErrorFilter</filter-class>

    </filter>

    <filter-mapping>

        <filter-name>ErrorFilter</filter-name>

        <url-pattern>/error.jsp</url-pattern>

        <dispatcher>ERROR</dispatcher>

    </filter-mapping>

ASYNC

Servlet 3.0 的,支持异步处理

当跳转到Servlet,Servlet会处理一些用户业务,这个业务非常耗时,那么用户就要等待,用户体验不好。

3.0 增加了 @WebFilter 用于将一个类声明为过滤器,该注解将会在部署时被容器处理,容器将根据具体的属性配置将相应的类部署为过滤器。

3.0 声明一个过滤器,无需在xml中配置

@WebFilter(servletNames ={“SimpleServlet”),filterName=”SimpleFilter”}

Public class Servelt3Filter implements Filter{…}

@WebFilter的常用属性

属性名

类型

描述

FilterName

String

指定过滤器的name属性,等价于<filter-name>

value

String[]

该属性等价于urlPatterns属性,但是两者不应该同时使用。

urlPatterns

String[]

指定一组过滤器的URL匹配模式。等价于<url-pattern>标签、

servletNames

String[]

指定过滤器将应用于哪些Servlet。取值是@WebServlet中的name属性的取值,或者是web.xml 中 <servlet-name> 的取值

dispatcherTypes

DispatcherType

指定过滤器的转发模式

ASYNC ERROR FORWARD INCLUDE REQUEST

initParams

WebInitParam[]

指定一组过滤器初始化参数,等价于<init-param>标签

asyncSupported

Boolean

声明过滤器是否支持异步操作模式,等价于<async-supported> 标签

description

String

该过滤器的描述信息,等价于<description>标签

displayName

String

该过滤器的显示名,通常配合工具使用,等价于<display-name>标签

异步过滤器案例:

创建一个AsyncFilter.java 过滤器

@WebFilter(filterName="AsyncFilter",value={"/servlet/AsyncServlet"},asyncSupported=true,dispatcherTypes={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 {
		// TODO Auto-generated method stub
		System.out.println("dofilter before");
		arg2.doFilter(arg0, arg1);
		System.out.println("dofilter after");
	}
	@Override
	public void init(FilterConfig arg0) throws ServletException {
		// TODO Auto-generated method stub
	}
}

创建一个Servlet 用来处理一些耗时操作

public class AsyncServlet extends HttpServlet {

	public AsyncServlet() {
		super();
	}

	public void destroy() {
		super.destroy(); // Just puts "destroy" string in log
	}

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		//通过这个对象在线程中过去reqeust和reponse
		System.out.println("Servlet 执行开始");
		AsyncContext context = request.startAsync();
		new Thread(new Executor(context)).start();
		System.out.println("Servelt 执行结束");
	}
	public class Executor implements Runnable{
		private AsyncContext mContext;
		public Executor(AsyncContext context){
			this.mContext = context;
		}

		@Override
		public void run() {
			// 执行复杂任务
			try {
//				mContext.getRequest();
//				mContext.getResponse();
				Thread.sleep(1000*10);
				System.out.println("业务执行完成时间"+new Date());
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
	}
	public void init() throws ServletException {
		// Put your code here
	}
}
在web.xml 中配置Servlet   注意  需要配置async-supported 为true

<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>AsyncServlet</servlet-name>
    <servlet-class>com.servlet.AsyncServlet</servlet-class>
    <async-supported>true</async-supported>
  </servlet>

执行结果:


根据顾虑器的规则,过滤器需要等待servlet执行结束才能停止,所以如果servlet执行很久,过滤器需要等待很久,为了让过滤器早点结束,让servlet在后台执行,使用异步过滤器。

 

过滤器实际应用场景

对用户请求进行统一认证

编码转换

对用户发送的数据进行过滤替换

转换图像格式

对响应的内容进行压缩

 

案例:登录过滤与字符编码

 Login.jsp 登录界面

<%@ page language="java" import="java.util.*"
	contentType="text/html; charset=utf-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">

<title>My JSP 'index.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
	<link rel="stylesheet" type="text/css" href="styles.css">
	-->
</head>

<body>
	<form action="<%=request.getContextPath() %>/servlet/LoginInServlet" method="post">
		用户名:<input type="text" name="username" /><br /> 
		密码:<input type="password" name="password"><br /> 
		<input type="submit" value="提交" />
	</form>
</body>
</html>


登录成功界面 success.jsp

<%@ page language="java" import="java.util.*"
	contentType="text/html; charset=utf-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">

<title>My JSP 'index.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
	<link rel="stylesheet" type="text/css" href="styles.css">
	-->
</head>

<body>
	恭喜你,登录成功 欢迎你 <%=request.getSession().getAttribute("username") %>
</body>
</html><strong>
</strong>

登录失败界面 fail.jsp

<%@ page language="java" import="java.util.*"
	contentType="text/html; charset=utf-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">

<title>My JSP 'index.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
	<link rel="stylesheet" type="text/css" href="styles.css">
	-->
</head>

<body>
	Sorry,登录失败
</body>
</html><strong>
</strong>
LoginInServlet.java 用来处理登录并且保存session

package com.servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

public class LoginInServlet extends HttpServlet {

	/**
	 * Constructor of the object.
	 */
	public LoginInServlet() {
		super();
	}

	/**
	 * Destruction of the servlet. <br>
	 */
	public void destroy() {
		super.destroy(); // Just puts "destroy" string in log
		// Put your code here
	}


	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, 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()+"/success.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
	}

}

LoginInFilter.java 用来处理过滤请求

package com.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;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

public class LoginInFilter implements Filter {
	//获取web.xml 中的过滤器的配置信息
	private FilterConfig config = null;
	@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 noLoginPaths = config.getInitParameter("noLoginPath");
		
		//处理中文乱码问题
		String charSet = config.getInitParameter("charSet");
		if(charSet == null){
			charSet = "UTF-8";
		}
		request.setCharacterEncoding(charSet);
		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){
					arg2.doFilter(arg0, arg1);
					return;
				}
			}
		}
		//下面这种做法不好,如果有多个需要放行的请求,则需要一直修改代码
		/*if(request.getRequestURI().indexOf("login.jsp")!=-1
				|| request.getRequestURI().indexOf("LoginInServlet")!= -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) throws ServletException {
		config = arg0;// 初始化配置的参数
	}

}

web.xml 配置过滤器和Servlet

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
  <display-name>LoginInFilter</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>LoginInServlet</servlet-name>
    <servlet-class>com.servlet.LoginInServlet</servlet-class>
  </servlet>

  <servlet-mapping>
    <servlet-name>LoginInServlet</servlet-name>
    <url-pattern>/servlet/LoginInServlet</url-pattern>
  </servlet-mapping>
  <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>LoginInFilter</filter-name>
        <filter-class>com.filter.LoginInFilter</filter-class>
        <init-param>
            <param-name>noLoginPath</param-name>
            <param-value>login.jsp;fail.jsp;LoginInServlet</param-value>
        </init-param>
        <init-param>
            <param-name>charSet</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>LoginInFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

使用过滤器可以对某些非法请求进行过滤,比如,用户没有登录就直接进入 success.jsp 页面,这都是不允许的,使用过滤器可以进行过滤。过滤所有请求使用/*  不需要过滤的请求我们可以在FilterConfig 中配置参数,进行放行。可以在过滤器中设置所有请求的编码,防止乱码。





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值