Servlet过滤器

Servlet过滤器是从Servlet2.3规范开始新增的功能,并在Servlet2.4规范中得到增强。Servlet过滤器主要用于对客户端(浏览器)的请求进行过滤处理,先将过滤后的请求转交给下一资源,它在Java Web开发中具有十分重要的作用。

1、过滤器的介绍

Servlet过滤器与Servlet十分相似,但它具有拦截客户端(浏览器)请求的功能,Servlet过滤器可以改变请求中的内容,来满足实际开发中的需要。对于程序开发人员而言,过滤器实质就是在Web应用服务器上的一个Web应用组件,用于拦截客户端(浏览器)与目标资源的请求,并对这些请求进行一定过滤处理再发送给目标资源,过滤器的处理方式如下图所示。

在Web服务器中部署了过滤器以后,不仅客户端发送的请求会经过过滤器的处理,而且请求在发送到目标资源处理以后,请求的回应信息也同样要经历过滤器。如果一个Web应用中使用一个过滤器不能解决实际中的业务需要,那么可以部署多个过滤器对业务请求进行多次处理,这样做就组成了一个过滤器链。Web服务器在处理过滤器链时,将按过滤器的先后顺序对请求进行处理。

 

2、过滤器核心对象

过滤器对象放置在javax.servlet包中,其名称为Filter,它是一个接口。除这个接口外,与过滤器相关的对象还有FilterConfig对象与FilterChain对象,这个两个对象也同样是接口对象,位于javax.servlet包中,分别为过滤器的配置对象与过滤器的传递工具。

在实际开发中,定义过滤器对象只需要直接或间接地实现Filter接口即可。如上图所示中的MyFilter1过滤器与MyFilter2过滤器,而FilterConfig对象与FilterChain对象用于对过滤器的相关操作。

2.1 Filter接口

每一个过滤器对象都要直接或间接地实现Filter接口,在Filter接口中定义了3个方法,其方法声明及说明如下表:

Filter接口的方法声明及说明:

方法声明说明
public default void init(FilterConfig filterConfig) throws ServletException过滤器初始化方法,该方法在过滤器初始化时调用。
public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException
对请求进行过滤处理。
public default void destroy()销毁方法,以便释放资源。

2.2 FilterConfig接口

FilterConfig接口由Servlet容器进行实现,主要用于获取过滤器中的配置信息,其方法声明及说明如下表:

FilterConfig接口的方法声明及说明:

方法声明说明
public String getFilterName()用于获取过滤器的名字。
public ServletContext getServletContext()获取Servlet上下文。
public String getInitParameter(String name)获取过滤器的初始化参数值。
public Enumeration<String> getInitParameterNames()获取过滤器的所有初始化参数。

2.3 FilterChain对象

FilterChain对象仍然有Servlet容器进行实现,在这个接口中只有一个方法,其方法声明如下:

public void doFilter(ServletRequest request, ServletResponse response)
            throws IOException, ServletException;

该方法用于将过滤后的请求传递给下一个过滤器,如果此过滤器已经是过滤器链中的最后一个过滤器,那么,请求将传送给目标资源。

 

3、过滤器创建与配置

示例:创建一个过滤器,实现网站访问计数器的功能,并在 web.xml 配置中将网站访问量的初始值设置为5000。

(1)创建名称为CountFilter的类,该类实现 javax.servlet.Filter 接口,同时实现Filter接口的三个方法,是一个过滤器对象,通过该过滤器实现统计网站访问人数功能。

package com.pjb.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

/**
 * 计数器过滤器
 * 
 * @author pan_junbiao
 *
 */
public class CountFilter implements Filter
{
	// 来访数量
	private int count;

	// 初始化方法
	@Override
	public void init(FilterConfig filterConfig) throws ServletException
	{
		String param = filterConfig.getInitParameter("count"); // 获取初始化参数
		count = Integer.valueOf(param); // 将字符串转换为int类型
	}

	// 过滤处理方法
	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException
	{
		count++;
		// 将ServletResponse对象转换成HttpServletRequest
		HttpServletRequest req = (HttpServletRequest) request;
		// 获取ServletContext
		ServletContext context = req.getServletContext();
		// 将来访数量保存到ServletContext对象中
		context.setAttribute("count", count);
		// 向下传递过滤器
		chain.doFilter(request, response);
	}

	// 销毁方法
	@Override
	public void destroy()
	{
		// 释放资源
	}

}

(2)过滤器的配置主要分为两个步骤,分别为:声明过滤器对象、创建过滤器映射。

配置已创建的CountFilter对象,此操作通过配置web.xml文件进行实现。

<!-- 过滤器声明 -->
<filter>
	<!-- 过滤器的名称 -->
	<filter-name>CountFilter</filter-name>
	<!-- 过滤器的完整类名 -->
	<filter-class>com.pjb.filter.CountFilter</filter-class>
	<!-- 设置初始化参数 -->
	<init-param>
		<!-- 参数名 -->
		<param-name>count</param-name>
		<!-- 参数值 -->
		<param-value>5000</param-value>
	</init-param>
</filter>

<!-- 过滤器映射 -->
<filter-mapping>
	<!-- 过滤器名称 -->
	<filter-name>CountFilter</filter-name>
	<!-- 过滤器URL映射 -->
	<url-pattern>/index.jsp</url-pattern>
</filter-mapping>

<filter>标签用于声明过滤器对象,在这个标签中必须配置两个子元素,分别为过滤器的名称与过滤器完整类名,其中:

<filter-name>子标签:用于定义过滤器的名称。

<filter-class>子标签:用于指定过滤器的完整类名。

<init-param>子标签:用于指定过滤器的初始化参数,非必填项。

<filter-mapping>标签用于创建过滤器的映射,它的主要作用就是指定Web应用中,哪些URL应用哪一个过滤器进行处理。在<filter-mapping>标签中需要指定过滤器的名称与过滤器的URL映射,其中:

<filter-name>子标签:用于定义过滤器的名称,它需要与<filter>标签中的<filter-name>一一对应。

<url-pattern>子标签:用于指定过滤器应用的URL。

问题:如何匹配所有页面的请求?

答:使用 “/*” 来匹配所有页面的请求。在 web.xml 文件中配置过滤器,其过滤器的URL映射可以使用正则表达进行配置。

(3)创建程序中的首页 index.jsp ,在该页面中通过JSP内置对象 Application 获取计数器的值。

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>人数统计</title>
</head>
<body>
	<h2>欢迎访问 pan_junbiao的博客</h2>
	您是本站的第【
		<%= application.getAttribute("count") %>
	】位访客!
</body>
</html>

执行结果:

由于在 web.xml 文件中将计数器的初始值设置为5000,所以实例运行后,计数器的数值变为大于5000的数,在多次刷新页面后,计数器的数值会跟着变大。

 

4、Servlet3.0新特性

4.1 @WebFilter注释

在Servlet3.0中新增了@WebFilter注释,通过使用该注释就无需在web.xml文件中对过滤器进行配置。@WebFilter注释用于声明过滤器,该注释将会在部署时被容器处理,容器将根据具体的属性配置将相应的类部署为过滤器。

@WebFilter注释主要属性列表:

属性名类型描述
filterNameString指定过滤器的name属性,等价于<filter-name>标签。
valueString[]该属性等价于urlPatterns属性,但是两者不应该同时使用。
urlPatternsString[]指定一组过滤器的URL匹配模式,等价于<url-pattern>标签。
servletNamesString[]指定过滤器将应用于哪些Servlet,是@WebServlet中的name属性的取值,或者是web.xml文件中的<servlet-name>标签的取值。
initParamsWebInitParam[]指定一组过滤器初始化参数,等价于<init-param>标签。
asyncSupportedboolean声明过滤器是否支持异步操作模式,等价于<async-supported>标签。
descriptionString该过滤器的描述信息,等价于<description>标签。
displayNameString该过滤器的显示名,通常配合工具使用,等价于<display-name>标签。
dispatcherTypesDispatcherType[]指定过滤器的转发模式。具体取值包括:ASYNC、ERROR、FORWARD、INCLUDE 和 REQUEST。

4.2 @WebInitParam注释

@WebInitParam注释等价于web.xml文件中的<servlet>和<filter>的<init-param>子标签,该注释通常不单独使用,而是配合@WebServlet或者@WebFilter使用。

@WebInitParam注释主要属性列表:

属性名类型描述
nameString指定参数的名字,等价于<param-name>标签,必填项。
valueString指定参数的值,等价于<param-value>标签,必填项。
descriptionString关于参数的描述,等价于<description>标签,非必填项。

示例:创建过滤器,使用@WebFilter注释和@WebInitParam注释进行配置。

/**
 * 计数器过滤器
 * 
 * @author pan_junbiao
 *
 */
@WebFilter(filterName = "CountFilter", urlPatterns = "/index.jsp", 
initParams = { @WebInitParam(name = "count", value = "5000") })
public class CountFilter implements Filter
{
	// 省略了过滤器中间的代码
}

如此配置之后,就不需要在 web.xml 文件中配置相应的<filter>、<filter-mapping>和<init-param>元素了,容器会在部署时根据指定的属性将该类发布为过滤器。使用@WebFilter注释,等价于在 web.xml 文件中进行如下配置:

<filter>
  <filter-name>CountFilter</filter-name>
  <filter-class>com.pjb.filter.CountFilter</filter-class>
  <init-param>
    <param-name>count</param-name>
    <param-value>5000</param-value>
  </init-param>
</filter>
<filter-mapping>
  <filter-name>CountFilter</filter-name>
  <url-pattern>/index.jsp</url-pattern>
</filter-mapping>

 

5、字符编码过滤器

在Java Web程序开发中,由于Web容器内部所使用编码格式并不支持中文字符集,所以,处理浏览器请求中的中文数据,就会出现乱码现象。如下图:

由于Web容器使用了ISO-8859-1的编码格式,所以在Web应用的业务处理中也会使用ISO-8859-1的编码格式。虽然浏览器提交的使用的是中文编码格式UTF-8,但经过业务处理中的ISO-8859-1编码,仍然会出现中文乱码现象。解决此问题的方法非常简单,在业务处理中重新指定中文字符集进行编码即可解决。在实际开发过程中,如果通过每一个业务处理指定中文字符集编码,则操作过于烦琐,而且容易遗漏某一个业务中的字符编码设置;如果通过过滤器来处理字符编码,就可以做到简单又万无一失。

示例:实现图书信息的添加功能,并创建字符编码过滤器,避免中文乱码现象的产生。

(1)创建字符编码过滤器对象,其名称为CharactorFilter类。该类实现了 javax.servlet.Filter 接口,并在doFilter()方法中对请求中的字符编码进行设置。

package com.pjb.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.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;

/**
 * 字符编码过滤器
 * 
 * @author pan_junbiao
 */
@WebFilter(filterName = "CharactorFilter", urlPatterns = "/*", 
initParams = { @WebInitParam(name = "encoding", value = "UTF-8") })
public class CharactorFilter implements Filter
{
	// 字符编码
	String encoding = null;

	// 初始化方法
	@Override
	public void init(FilterConfig filterConfig) throws ServletException
	{
		// 获取初始化参数
		encoding = filterConfig.getInitParameter("encoding");
	}

	// 过滤处理方法
	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException
	{
		// 判断字符编码是否为空
		if (encoding != null)
		{
			// 设置request的编码格式
			request.setCharacterEncoding(encoding);
			// 设置response字符编码
			response.setContentType("text/html; charset=" + encoding);
		}
		// 传递给下一过滤器
		chain.doFilter(request, response);
	}

	// 销毁方法
	@Override
	public void destroy()
	{
		encoding = null;
	}
}

(2)创建名称为AddServlet的类,该类继承 HttpServlet,是处理添加图书信息请求的Servlet对象。

package com.pjb.servlet;

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

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 添加图书信息请求的Servlet类
 * 
 * @author pan_junbiao
 *
 */
@WebServlet(name = "AddServlet", urlPatterns = "/servlet/AddServlet")
public class AddServlet extends HttpServlet
{
	private static final long serialVersionUID = 1L;

	// 处理GET请求
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
	{
		doPost(request, response);
	}

	// 处理POST请求
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
	{
		// 获取 PrintWriter
		PrintWriter out = response.getWriter();
		// 获取图书编号
		String id = request.getParameter("id");
		// 获取名称
		String name = request.getParameter("name");
		// 获取作者
		String author = request.getParameter("author");
		// 获取价格
		String price = request.getParameter("price");
		// 输出图书信息
		out.print("<h2>图书信息添加成功</h2><hr>");
		out.print("图书编号:" + id + "<br>");
		out.print("图书名称:" + name + "<br>");
		out.print("作者:" + author + "<br>");
		out.print("价格:" + price + "<br>");
		// 刷新流
		out.flush();
		// 关闭流
		out.close();
	}
}

(3)创建名称为AddBook.jsp的页面,该页面主要用于放置添加图书信息的表单。

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>添加图书信息</title>
</head>
<body>
	<form action="servlet/AddServlet" method="post">
		<table align="center" border="1" width="350">
			<tr>
				<td class="2" align="center" colspan="2">
					<h2>添加图书信息</h2>
				</td>
			</tr>
			<tr>
				<td align="right">图书编号:</td>
				<td>
					<input type="text" name="id">
				</td>
			</tr>
			<tr>
				<td align="right">图书名称:</td>
				<td>
					<input type="text" name="name">
				</td>
			</tr>
			<tr>
				<td align="right">作  者:</td>
				<td>
					<input type="text" name="author">
				</td>
			</tr>
			<tr>
				<td align="right">价  格:</td>
				<td>
					<input type="text" name="price">
				</td>
			</tr>
			<tr>
				<td class="2" align="center" colspan="2">
					<input type="submit" value="添 加">
				</td>
			</tr>
		</table>
	</form>
</body>
</html>

执行结果:

(1)添加图书信息:

(2)显示图示信息:

 

  • 9
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

pan_junbiao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值