Servlet介绍(4)——Filter

filter的意思简单的说就是过滤器,它的作用就是当用户请求一个url之前,可以预先做一些处理,当请求完url返回给用户之前还可以做一些处理(所以filter的功能十分的强大,如果想做的话可以强大到让用户,不能访问请求的url的程度。。。)

接口javax.servlet.Filter

void init(FilterConfig filterConfig)
可以在此方法中完成Filter需要初始化的内容,在一个filter提供服务之前肯定会先调用此方法

void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
当用户访问的url或者servlet被配置了使用此filter时,servlet/jsp容器会调用此方法,每次访问调用一次。chain参数为一个FilterChain接口的对象,可以简单的理解成chain包含了访问一个url上所有的需要调用的方法。

void destroy()
当不需要一个filter再提供服务时调用,容器会调用此方法

filter的工作模式如附件图片:

假如用户访问的一个url有两个filter的时候。
servlet容器会先调用最外层的filter(Filter1)的doFilter()方法,然后在由Filter1中调用的chain.doFilter方法将控制权返回给容器,接着容器调用第二层filter(Filter2)的doFilter方法,然后在由Filter2中调用的chain.doFilter方法将控制权返回给容器,这个时候容器才能去访问真正的需要请求的servlet和jsp,但servlet和jsp执行完毕以后,会运行Filter2中doFilter方法调用的chain.doFilter方法后剩余的代码片断,之后再运行Filter1中doFilter方法调用的chain.doFilter方法后剩余的代码片断。


Filter对应的请求方式有4种:request、forward、include、error


request:当用户直接请求一个网页时才会通过此filter,当用户通过RequestDispatcher(会再后面详细介绍该类的方法)的forward不会通过该filter

forward: 当用户通过RequestDispatcher的forward方法访问对应的url时才会通过该filter

include:当用户通过RequestDispatcher的include方法访问对应的url时才会通过该filter

error:当用户的请求通过错误处理机制的时候才会通过该filter(目前不准备详细论述)。


一个filter可以对应几种请求方式,但是如果配置时不写请求方式的话,默认方式为request。


下面先举一个例子看下filter工作的过程:


FilterFirst:


package squall.servlet.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 FilterFirst implements Filter

{


public void destroy()

{


}


public void doFilter(ServletRequest request, ServletResponse response,

FilterChain chain) throws IOException, ServletException

{

System.out.println("Begin First Filter!");

chain.doFilter(request, response);

System.out.println("After First Filter!");

}


public void init(FilterConfig config) throws ServletException

{


}


}


FilterSecond:


package squall.servlet.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 FilterSecond implements Filter

{


public void destroy()

{


}


public void doFilter(ServletRequest request, ServletResponse response,

FilterChain chain) throws IOException, ServletException

{

System.out.println("Begin Second Filter!");

chain.doFilter(request, response);

System.out.println("After Second Filter!");

}


public void init(FilterConfig config) throws ServletException

{



}


}


部署时修改web.xml如下:

在第一个<servlet>标签前添加:




<filter>

<filter-name>FilterFirst</filter-name>

<filter-class>squall.servlet.filter.FilterFirst</filter-class>

</filter>

<filter>

<filter-name>FilterSecond</filter-name>

<filter-class>squall.servlet.filter.FilterSecond</filter-class>

</filter>



<filter-mapping>

<filter-name>FilterFirst</filter-name>

<url-pattern>/HelloServlet</url-pattern>

</filter-mapping>

<filter-mapping>

<filter-name>FilterSecond</filter-name>

<url-pattern>/HelloServlet</url-pattern>

</filter-mapping>


将filter标签放置在一起,将filter-mapping标签放在再一起,顺序根据filter-name一致。这里的filter-mapping的顺序即为:假如我们访问的一个url有两个filter时,filter的先后顺序,web.xml中filter-mapping在前面的filter先被执行。


部署完毕之后我们访问:http://127.0.0.1:8080/train/HelloServlet

可以看到tomcat管理控制台输出如下:

Begin First Filter!

Begin Second Filter!

After Second Filter!

After First Filter!


上面的例子可以看出filter工作的过程和我们上面的图片一致。


下面我们来举一个比较贴近实际的例子看一下filter的方便之处。

下面的例子用于常见的解决中文乱码的问题,我们为了防止中文乱码经常需要调用

HttpServletRequest和HttpServletResponse的setCharacterEncoding方法,底下的这个filter的例子实现了,采用filter来解决这个问题。

Filterparam.html:


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">

<head>

<META http-equiv="Content-Type" content="text/html; charset=GBK" />

<script type="text/javascript">...





function changeaction()

{

var a = document.getElementsByName("filter");

for(i = 0; i < a.length; i++)

{

if(a[i].checked==true)

{

fm.action=a[i].value;

break;

}

}

}

</script>


<title>filterparameter.html</title>

</head>


<body bgcolor="#FDF5E6">


<h2>Filter中文乱码示范</h2>


<form name ="fm" method="post" action="FilterShowParameter/No">



<p>姓名:<input type="text" name="username" size="15" /> </p>



<p>使用filter:

<input name="filter" value="FilterShowParameter/No" type="radio" οnclick="changeaction()" checked />

不使用

<input name="filter" value="FilterShowParameter/Yes" type="radio" οnclick="changeaction()" />

使用

</p>

<p>

<input value="确认" type="submit" />

<input value="清除" type="reset" />

</p>

</form>


</body>

</html>


直接放在train目录下


FilterShow:


package squall.servlet.basic;


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;


public class FilterShow extends HttpServlet

{

protected void doGet(HttpServletRequest req, HttpServletResponse resp)

throws ServletException, IOException

{

showParam( req, resp);

}


protected void doPost(HttpServletRequest req, HttpServletResponse resp)

throws ServletException, IOException

{

showParam( req, resp);

}



private void showParam(HttpServletRequest req, HttpServletResponse resp) throws IOException

{

resp.setContentType("text/html");

PrintWriter out = resp.getWriter();

String docType = "<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> ";


String name = req.getParameter("username");



out.println(docType + "<HTML> " + "<HEAD><TITLE> showparam"

+ "</TITLE></HEAD> " + "<BODY BGCOLOR="#FDF5E6"> "

+" 姓名:" + name + " </br>"

);


out.println("</body></html>");

}

}


部署时将FilterShow mapping至/FilterShowParameter/*


EncodingFilter:


package squall.servlet.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 EncodingFilter implements Filter

{


public void init(FilterConfig config) throws ServletException

{

String str = config.getInitParameter("encoding");

if (str != null && !"".equals(str))

encoding = str;

}


public void doFilter(ServletRequest request, ServletResponse response,

FilterChain chain) throws IOException, ServletException

{

System.out.println("encoding is " + encoding);

if(encoding != null)

{

request.setCharacterEncoding(encoding);

response.setCharacterEncoding(encoding);

}

chain.doFilter(request, response);

}


public void destroy()

{


}


private String encoding = null;


}


EncodingFilter的功能就是将request和response setCharacterEncoding为预先定义好的encoding。getInitParameter 将在以后介绍。


EncodingFilter部署方式:

在web.xml最后一个</filter>下添加


<filter>

<filter-name>EncodingFilter</filter-name>

<filter-class>squall.servlet.filter.EncodingFilter</filter-class>

<init-param>

<param-name>encoding</param-name>

<param-value>GBK</param-value>

</init-param>

</filter>


然后在最后一个</filter-mapping>下添加:


<filter-mapping>

<filter-name>EncodingFilter</filter-name>

<url-pattern>/FilterShowParameter/Yes</url-pattern>

<dispatcher>REQUEST</dispatcher>

<dispatcher>FORWARD</dispatcher>

</filter-mapping>


部署完毕后访问http://127.0.0.1:8080/train/filterparam.html

输入姓名为中文以后,如果使用filter 选择为 不使用 则会看到乱码

选择使用filter后 则会看到正确的中文。


上面的例子是对REQUEST和FORWARD使用filter。

关于filter-mapping的include方式做一个简单的说明,如下:


<filter-mapping>

<filter-name>FilterName</filter-name>

<servlet-name>HelloServlet</servlet-name>

<dispatcher>INCLUDE</dispatcher>

</filter-mapping>


include方式时必须将<url-pattern>修改为<servlet-name>

上面的filter-mapping的含义为:

当HelloServlet这个servlet里调用RequestDispatcher的include时,才会通过此filter。


filter的功能远远不只上面举的例子,filter还可以对servlet和jsp输出至客户端的内容进行修改,还可以用来判断是否满足一些条件,假如不满足条件就不让访问者访问相应的条件,这里就不做一一的介绍了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值