4.4 过滤器
4.4.1 过滤器(Filter)简介
Servlet过滤器是服务器与客户端请求和响应的中间层组件。在实际项目开发中,Servlet过滤器主要用于拦截浏览器与服务间的请求与响应,根据过滤器内部的设置,查看、提取或修改交互的数据,之后再转给下一个资源。
主要作用有:
1)对请求的访问进行预处理,如防止乱码、添加必要的安全信息或安全处理等
2)对被过滤资源进行身份验证,实现一定程度上的权限控制
3)对请求进行合理的转发指派,降低服务器负载,提高服务器效率
可以把过滤器看成银行大堂经理,当用户去办理业务时,大堂经理会询问客户需要做什么,根据业务内容进行引导。如果表格填写错误,还会帮忙修正,如果用户去错了银行,也会进行提醒。
从工作原理看,过滤器可以改变一个request或修改一个response。过滤器并不是一个Servlet,它不会生成response,只是在request要离开Servlet时再处理response。以一种Servlet链的方式完成响应。一个过滤器的处理过程包括:
1)在客户端发起对Servlet文件的request时截获请求
2)在Servlet被调用前检查request
3)根据过滤器的设计,修改request头和request数据
4)根据过滤器的设计,修改response头和response数据
5)在Servlet被调用之后截获这个对象
开发者在创建自己的Filter时,必须要实现javax.servlet.Filter这个接口。该接口包含3个抽象方法:init()、doFilter()、destroy()。大多数情况下,Filter的销毁使用Java系统的自动回收机制,如果没有初始化配置的特殊要求,init()方法也不需要重载。
4.4.2 创建过滤器
首先创建被过滤文件First.java
package cy.filter;
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 implementation class First
*/
@WebServlet("/First")
public class First extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public First() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
response.setContentType("text/html;charset=UTF-8");
request.setCharacterEncoding("UTF-8");
PrintWriter out=response.getWriter();
try {
String getInfo=(String) getServletContext().getAttribute("Message");
out.println("<html");
out.println("<head>");
out.println("<title></title>");
out.println("</head>");
out.println("<body>");
out.println("lalala");
out.println("</body>");
out.println("</html");
}finally {
out.close();
}
System.out.println("执行当前的Servlet文件");
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
右键项目名-new-Filter-填写类和包名
添加被过滤文件
package cy.filter;
import java.io.IOException;
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;
/**
* Servlet Filter implementation class Filter
*/
@WebFilter(urlPatterns = { "/First"}, filterName = "Filter", servletNames = { "First" })
public class Filter implements javax.servlet.Filter {
/**
* Default constructor.
*/
public Filter() {
// TODO Auto-generated constructor stub
}
/**
* @see Filter#destroy()
*/
public void destroy() {
// TODO Auto-generated method stub
}
/**
* @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
*/
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// TODO Auto-generated method stub
// place your code here
System.out.println("执行doFilter之前");
// pass the request along the filter chain
chain.doFilter(request, response);
System.out.println("执行doFilter之后");
}
/**
* @see Filter#init(FilterConfig)
*/
public void init(FilterConfig fConfig) throws ServletException {
// TODO Auto-generated method stub
}
}
执行First.java:
从执行结果可以好好体会一下过滤过程。
下面举一个相对复杂一些的例子。实际上网过程中经常遇到这样的情况,没有登录浏览贴吧帖子时,看到帖子点击回复按钮时系统会弹出错误提示,提醒用户登录后才可以回复。这个功能可以使用过滤器方式实现。
下面将通过3个文件模拟上述过程:
回帖文件sendInfo.java,需要输入title和id两个参数,然后显示出来
package cy.filter;
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 implementation class First
*/
@WebServlet("/sendInfo")
public class sendInfo extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public sendInfo() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
response.setContentType("text/html;charset=UTF-8");
PrintWriter out=response.getWriter();
String title=request.getParameter("title");
String id=request.getParameter("id");
try {
out.println("<html");
out.println("<head>");
out.println("<title></title>");
out.println("</head>");
out.println("<body>");
out.println("一个测试的信息:”"+title+"”来自于"+id);
out.println("</body>");
out.println("</html");
}finally {
out.close();
}
System.out.println("执行当前的Servlet文件");
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
可以先运行一下这个文件,不过要注意这个文件不是直接运行的,回忆一下前面URL传参的知识,在地址栏给出参数即可得到信息:
过滤器文件MyFilter.java,过滤第一个文件,依据是检查里面的参数id的值是否不为空且值为“Hedy”,如果是则不作任何处理,让
Servlet向浏览器发送内容,如果不是,则拦截请求,直接重定向到错误文件
package cy.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.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet Filter implementation class MyFilter
*/
@WebFilter(urlPatterns = { "/sendInfo" },filterName="MyFilter", servletNames = { "sendInfo" })
public class MyFilter implements Filter {
/**
* Default constructor.
*/
public MyFilter() {
// TODO Auto-generated constructor stub
}
/**
* @see Filter#destroy()
*/
public void destroy() {
// TODO Auto-generated method stub
}
/**
* @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
*/
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// TODO Auto-generated method stub
// place your code here
HttpServletRequest req=(HttpServletRequest)request;//对这两个参数进行强制转换的原因是:doFilter()方法本身的请求与响应的参数类型为ServletRequest和ServletResponse,而Servlet请求与响应的参数类型为HttpServletRequest和HttpServletResponse.为了让过滤器拦截请求的同时可以获取客户端传过来的参数id,需要转换这个类型,从而通过getParameter()方法获取参数值。
HttpServletResponse res=(HttpServletResponse)response;
String isLog=req.getParameter("id");
System.out.println(isLog);
if((isLog!=null)&&(isLog.equals("Hedy"))) {
// pass the request along the filter chain
chain.doFilter(request, response);
}
else {
res.sendRedirect("/JSPLab/error.jsp");
}
}
/**
* @see Filter#init(FilterConfig)
*/
public void init(FilterConfig fConfig) throws ServletException {
// TODO Auto-generated method stub
}
}
错误页面error.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<h2>出错啦!请先登录</h2>
</body>
</html>
这时再次运行sendInfo.java,修改id参数值不为Hedy: