JavaWeb------Servlet过滤器
(1)过滤器是web服务器上的组件,它们对客户和资源之间的请求和响应进行过滤。Servlet 过滤器可以动态地拦截请求和响应,以变换或使用包含在请求或响应中的信息。
@(2)过滤器的工作原理是:
当servlet容器接收到对某个资源的请求,它要检查是否有过滤器与之关联。如果有过滤器与该资源关联,servlet容器将把该请求发送给过滤器。在过滤器处理完请求后,它将做下面3件事:
• 产生响应并将其返回给客户;
• 如果有过滤器链,它将把(修改过或没有修改过)请求传递给下一个过滤器;
• 将请求传递给不同的资源。
当请求返回到客户时,它是以相反的方向经过同一组过滤器返回。过滤器链中的每个过滤器够可能修改响应。
(3)过滤器API主要包括:Filter、FilterConfig和FilterChain接口。
1.FilterConfig 使用
Filter 的 init 方法中提供了一个 FilterConfig 对象。
如 web.xml 文件配置如下:
<filter>
<filter-name>LoginFilter</filter-name>
<filter-class>com.runoob.test.LogFilter</filter-class>
<init-param>
<param-name>Site</param-name>
<param-value>abc</param-value>
</init-param>
</filter>
2.在 init 方法使用 FilterConfig 对象获取参数:
public void init(FilterConfig config) throws ServletException {
// 获取初始化参数
String site = config.getInitParameter("Site");
// 输出初始化参数
System.out.println("网站名称: " + site);
}
(4)回答一下两个问题
1. 试简述过滤器有哪些功能?
1)转换字符编码
中文网页编码常用的就是gb2312或是UTF-8,但TOMCAT会默认用编码iso-8859-1,所以需要把所有经过TOMCAT的中文字符进行转换,如果手动在request里改很麻烦,可以用一个filter对所有的request进行拦截,进行编码转换。
2)管理Hibernate的session
在Web 里用Hibernate常常是把session绑定到线程,但往往要求一个session在一个请求的活动中都有效,这样可以保证同一活动中能共享 lazy bean。用filter能到达这个目的,在doFilter之前绑定session到线程,在doFilter后关闭session,这样既可以保证 session不会泄漏,也能让lazy bean在同一请求周期里共享
3)做权限审查
在web层里需要对很多资源进行逻辑类似的安全保障,通过filter可以在调用这些资源前加上一个屏障,这样既可以把安全代码和逻辑代码相分离,也可以很好的reuse这些安全模块
4)做cache
在web层常常需要对一些请求返回进行缓存,这样可以有效的减轻服务器的压力,filter可以对请求进行拦截,查询缓存,若有效则直接返回缓存内容,若无效则进行实际的服务器请求,返回给用户,并对缓存进行更新,以备下次请求
5)做拦截器的代理
有的时候需要把一些拦截器用到web层,filter可以很好地充当代理的角色,比如可以在Spring里做好拦截器的Bean,再通过filter把这些Bean和相应的web请求桥接起来。
6)过滤特殊字符
有时需要过滤特殊字符,比如防止sql注入,Filter可以很好达到这个目的
(5)web.xml配置各节点说明
~~<filter>指定一个过滤器。
~~<filter-name>用于为过滤器指定一个名字,该元素的内容不能为空。
~~<filter-class>元素用于指定过滤器的完整的限定类名。
~~<init-param>元素用于为过滤器指定初始化参数,它的子元素param-name>指定参数的名字,<param-value>指定参数的值。
~~在过滤器中,可以使用FilterConfig接口对象来访问初始化参数。
~~<filter-mapping>元素用于设置一个 Filter 所负责拦截的资源。一个Filter拦截的资源可通过两种方式来指定:Servlet 名称和资源访问的请求路径 filter-name>子元素用于设置filter的注册名称。该值必须是在filter>元素中声明过的过滤器的名字
<url-pattern>设置 filter 所拦截的请求路径(过滤器关联的URL样式)
~~<servlet-name>指定过滤器所拦截的Servlet名称。
~~<dispatcher>指定过滤器所拦截的资源被 Servlet 容器调用的方式,可以是REQUEST,INCLUDE,FORWARD和ERROR之一,默认REQUEST。用户可以设置多个<dispatcher>子元素用来指定 Filter 对资源的多种调用方式进行拦截。
~~<dispatcher>子元素可以设置的值及其意义 REQUEST:当用户直接访问页面时,Web容器将会调用过滤器。如果目标资源是通过RequestDispatcher的include()或forward()方法访问时,那么该过滤器就不会被调用。
~~INCLUDE:如果目标资源是通过RequestDispatcher的include()方法访问时,那么该过滤器将被调用。除此之外,该过滤器不会被调用。
~~FORWARD:如果目标资源是通过RequestDispatcher的forward()方法访问时,那么该过滤器将被调用,除此之外,该过滤器不会被调用。
~~ERROR:如果目标资源是通过声明式异常处理机制调用时,那么该过滤器将被调用。除此之外,过滤器不会被调用。
总结:过滤器中我们可以根据 doFilte() 方法中的 request 对象获取表单参数信息,例如:我们可以获取到请求的用户名和密码进行逻辑处理,也可以通过 response 对用户做出回应。比如,如果验证用户名不正确,禁止用户访问 web 资源,并且向浏览器输出提示,告诉用户用户名或者密码不正确等等;
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException {
//获取请求信息(测试时可以通过get方式在URL中添加name)
//http://localhost:8080/servlet_demo/helloword?name=123
String name = req.getParameter("name");
// 过滤器核心代码逻辑
System.out.println("过滤器获取请求参数:"+name);
System.out.println("第二个过滤器执行--网站名称:www.runoob.com");
if("123".equals(name)){
// 把请求传回过滤链
chain.doFilter(req, resp);
}else{
//设置返回内容类型
resp.setContentType("text/html;charset=GBK");
//在页面输出响应信息
PrintWriter out = resp.getWriter();
out.print("<b>name不正确,请求被拦截,不能访问web资源</b>");
System.out.println("name不正确,请求被拦截,不能访问web资源");
}
}
(6)实验题目:编写一个过滤器改变请求编码。
【步骤1】编写一个loginform.html文件
//loginform.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>使用过滤器改变请求编码</title>
<meta http-equiv="Content-Type" content="text/html;charset=GB2312">
</head>
<body>
<center>
<h2>请输入用户名和口令:</h2>
<form method="post" action="servlet/CheckParamServlet">
<table>
<tr>
<td>用户名:</td>
<td><input name="name" type="text"></td>
</tr>
<tr>
<td>口 令:</td>
<td><input name="pass" type="password"></td>
</tr>
<tr>
<td></td>
<td>
<input name="ok" type="submit" value="提交">
<input name="cancel" type="reset" value="重置">
</td>
</tr>
</table>
</form>
</center>
</body>
</html>
【步骤2】编写处理请求参数的Servlet
package servlets;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class CheckParamServlet extends HttpServlet{
private static final long serialVersionUID = 1L;
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
String name = request.getParameter("name");
String pass = request.getParameter("pass");
response.setContentType("text/html;charset=gb2312");
PrintWriter out = response.getWriter();
out.println("<html><head><title>Param Test</title></head>");
out.println("<h3 align=center>你的用户名为:"+name+"</h3>");
out.println("<h3 align=center>你的口令为:"+pass+"</h3>");
out.println("</body></html>");
}
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
doGet(request,response);
}
}
【步骤3】修改web.xml文件,加入下面代码:
<servlet>
<servlet-name>CheckParamServlet</servlet-name>
<servlet-class>CheckParamServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CheckParamServlet</servlet-name>
<url-pattern>/servlet/check</url-pattern>
</servlet-mapping>
实验结果:当用户点击提交会出现用户名会变成问号的情况
【步骤5】过滤器代码如下:
package filter;
import java.io.IOException;
import javax.servlet.*;
public class EncodingFilter implements Filter {
protected String encoding = null;
protected FilterConfig config;
public void init(FilterConfig filterConfig) throws ServletException {
this.config = filterConfig;
// 得到在web.xml中配置的编码
this.encoding = filterConfig.getInitParameter("Encoding");
}
public void doFilter(
ServletRequest request,
ServletResponse response,
FilterChain chain)
throws IOException, ServletException {
if (request.getCharacterEncoding() == null) {
// 得到指定的编码
String encode = getEncoding();
if (encode != null) {
//设置request的编码
request.setCharacterEncoding(encode);
response.setCharacterEncoding(encode);
}
}
chain.doFilter(request, response);
}
protected String getEncoding() {
return encoding;
}
public void destroy() {
}
}
【步骤6】在web.xml文件中配置过滤器,加入下面代码:
<filter>
<filter-name>EncodingFilter</filter-name>
<filter-class>filter.EncodingFilter</filter-class>
<init-param>
<param-name>Encoding</param-name>
<param-value>gb2312</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>EncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
实验结果:输入的用户名实现了中文转换