1. 过滤器概述

1.1. 什么是过滤器

Filter译为过滤器,是JavaWeb的三大组件之一,用于在Servlet之外对Request或者Response进行修改。对于Web应用程序来说,过滤器是一个驻留在服务器端的Web组件,它可以截取客户端和服务器端之间的请求与响应信息。

1.2. 发展历史

由于Servlet规范是开放的,借助于公众与开源社区的力量,Servlet规范越来越科学,功能也越来越强大。2000年,Sun公司在Servlet2.3规范中添加了Filter功能,并在Servlet2.4中对Filter进行了细节上的补充。目前主流版本为Servlet2.5的Filter。

1.3. 运行原理

Servlet是服务器端用于处理客户端的请求与响应的,而Filter就是介于客户端与服务器端拦截客户端的请求或服务器端的响应,并对其修改或过滤。具体实现流程如下:

当客户端向服务器端发送一个请求时,如果有对应的过滤器进行拦截,过滤器可以改变请求的内容、或者重新设置请求协议的相关信息等,然后再将请求发送给服务器端的Servlet进行处理。当Servlet对客户端做出响应时,过滤器同样可以进行拦截,将响应内容进行修改或者重新设置后,再响应给客户端浏览器。在上述过程中,客户端与服务器端并不需要知道过滤器的存在。

在一个Web应用程序中,可以部署多个过滤器进行拦截,这些过滤器组成了一个过滤器链。过滤器链中的每个过滤器负责特定的操作和任务,客户端的请求在这些过滤器之间传递,直到服务器端的Servlet。具体执行流程如下:

1.4. 第一个过滤器

在Servlet API中提供了一个Filter接口,实现过滤器只需要实现该接口即可。以下是Filter接口的API:

Method Summary

void

destroy() 
Called by the web container to indicate to a filter that it is being taken out of service.

void

doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
The doFilter method of the Filter is called by the container each time a request/response pair is passed through the chain due to a client request for a resource at the end of the chain.

void

init(FilterConfig filterConfig) 
Called by the web container to indicate to a filter that it is being placed into service.

实现过滤器的具体步骤如下:

  • 创建一个Java类,并实现Filter接口,重写该接口的方法。
public class MyFitler implements Filter {
/**
* init()方法用于Filter的初始化
*/
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("执行了Filter的init()方法...");
}
/**
* doFilter()方法用于Filter的拦截
*/
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
System.out.println("执行了Filter的doFilter()方法...");
}
/**
* destory()方法用于Filter的销毁
*/
public void destroy() {
System.out.println("执行了Filter的destroy()方法...");
}
}
  • 在Web工程的web.xml文件中配置过滤器。
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<!-- 配置过滤器 -->
<filter>
<!-- 配置过滤器的名称 -->
<filter-name>MyFitler</filter-name>
<!-- 配置对应过滤器类的完整路径 -->
<filter-class>app.java.fitler.MyFitler</filter-class>
</filter>
<!-- 配置过滤器的拦截路径 -->
<filter-mapping>
<!-- 配置过滤器的名称 -->
<filter-name>MyFitler</filter-name>
<!-- 配置过滤器的拦截的路径 -->
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
  • 创建Web动态资源Servlet。
public class HelloServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<h1>Hello Servlet.</h1>");
out.flush();
out.close();
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
  • 在Web工程的web.xml文件中配置Servlet。
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<servlet>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>app.java.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>
  • 创建Web工程的静态资源JSP页面。
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>hello.jsp</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
</head>
<body>
<h1>Hello JSP.</h1>
</body>
</html>
  • 发布Web工程并访问,无论是访问动态资源Servlet还是静态资源JSP,过滤器都会拦截,并执行过滤器的doFilter()方法。
  • 这时访问的Servlet或者JSP并没有被执行,原因是过滤器只进行了拦截,并没有将请求发送到对应的Servlet或者JSP。在过滤器的doFilter()方法中执行FilterChain对象的doFilter()方法将进行放行。
public class MyFitler implements Filter {
/**
* init()方法用于Filter的初始化
*/
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("执行了Filter的init()方法...");
}
/**
* doFilter()方法用于Filter的拦截
*/
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
System.out.println("执行了Filter的doFilter()方法...");
chain.doFilter(request, response);
}
/**
* destory()方法用于Filter的销毁
*/
public void destroy() {
System.out.println("执行了Filter的destroy()方法...");
}
}

2. 深入过滤器

2.1. 生命周期

Servlet API提供的Filter接口中含有三个方法,分别为init()、doFilter()和destroy()方法。该三个方式就是Filter的生命周期方法。

  • Filter的构造函数
  • 在Tomcat服务器启动时执行。
  • 在Filter的生命周期中只执行一次。
  • init(FilterConfig)方法
    • 在Tomcat服务器启动时执行。
    • 在Filter的生命周期中只执行一次。
    • 用于Filter的初始化工作。
  • doFilter(ServletRequest, ServletResponse, FilterChain)方法
    • 在每次拦截时执行。
    • 在Filter的生命周期中只执行多次。
    • 用于Filter的拦截处理工作。
  • destroy()方法
    • 在Tomcat服务器关闭时执行。
    • 在Filter的生命周期中只执行一次。
    • 用于Filter的销毁工作。

2.2. 过滤器链

在一个Web应用程序中,可以部署多个过滤器进行拦截,这些过滤器组成了一个过滤器链。完成过滤器链的功能,具体步骤如下:

  • 创建一个Java类,并实现Filter接口,重写该接口的方法。
public class MyFitler1 implements Filter {
/**
* init()方法用于Filter的初始化
*/
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("执行了Filter1的init()方法...");
}
/**
* doFilter()方法用于Filter的拦截
*/
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
System.out.println("执行了Filter1的doFilter()方法...");
}
/**
* destory()方法用于Filter的销毁
*/
public void destroy() {
System.out.println("执行了Filter1的destroy()方法...");
}
}
  • 再创建一个Java类,并实现Filter接口,重写该接口的方法。
public class MyFilter2 implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("执行了Filter2的init()方法...");
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
System.out.println("执行了Filter2的doFilter()方法...");
}
public void destroy() {
System.out.println("执行了Filter2的destroy()方法...");
}
}
  • 在Web工程的web.xml文件中配置过滤器。
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<!-- 配置过滤器 -->
<filter>
<!-- 配置过滤器的名称 -->
<filter-name>MyFitler</filter-name>
<!-- 配置对应过滤器类的完整路径 -->
<filter-class>app.java.fitler.MyFitler</filter-class>
</filter>
<!-- 配置过滤器的拦截路径 -->
<filter-mapping>
<!-- 配置过滤器的名称 -->
<filter-name>MyFitler</filter-name>
<!-- 配置过滤器的拦截的路径 -->
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>MyFitler2</filter-name>
<filter-class>app.java.fitler.MyFilter2</filter-class>
</filter>
<filter-mapping>
<filter-name>MyFitler2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>

需要注意的是,FilterChain的doFilter()方法执行时,如果只有一个过滤器的话,执行该方法会将请求发送给服务器端的动态或静态资源。如果是过滤器链的话,只有在执行过滤器链的最后一个过滤器的FilterChain的doFilter()方法时,才会将请求发送给服务器端的动态或静态资源。如果不是在过滤器链的最后一个过滤器的FilterChain的doFilter()方法时,将请求发送给下一个过滤器进行拦截。

在过滤器链中的过滤器执行的先后顺序是按照Web工程的web.xml文件配置过滤器的先后顺序被执行。

2.3. FilterConfig

在过滤器接口的init()方法中提供了FilterConfig参数,通过该参数可以获取web.xml配置过滤器的参数内容,或者获取ServletContext对象等。FilterConfig API内容如下:

Method Summary

String

getFilterName() 
Returns the filter-name of this filter as defined in the deployment descriptor.

String

getInitParameter(String name) 
Returns a String containing the value of the named initialization parameter, or null if the parameter does not exist.

Enumeration

getInitParameterNames() 
Returns the names of the filter's initialization parameters as an Enumeration of String objects, or an empty Enumeration if the filter has no initialization parameters.

ServletContext

getServletContext() 
Returns a reference to the ServletContext in which the caller is executing.

具体使用方式如下:

  • 创建一个Java类,并实现Filter接口,重写该接口的方法。
public class MyFitler implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("执行了Filter的init()方法...");
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
System.out.println("执行了Filter的doFilter()方法...");
}
public void destroy() {
System.out.println("执行了Filter的destroy()方法...");
}
}
  • 在Web工程的web.xml文件中配置过滤器,并且设置初始化参数内容。
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<filter>
<filter-name>MyFitler</filter-name>
<filter-class>app.java.fitler.MyFitler</filter-class>
<init-param>
<param-name>longestory</param-name>
<param-value>http://www.baidu.com.com</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>MyFitler</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
  • 在过滤器的init()方法中获取配置文件的初始化参数。
public class MyFitler implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("执行了Filter的init()方法...");
System.out.println(filterConfig.getInitParameter("longestory"));
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
System.out.println("执行了Filter的doFilter()方法...");
}
public void destroy() {
System.out.println("执行了Filter的destroy()方法...");
}
}

需要注意的是,通过getInitParameter()方法获取的初始化参数是私有参数。只有当前过滤器才能获取到,而其他过滤器并不能访问。如果配置全局初始化参数,可以使用<context-param>来配置,并使用ServletContext对象获取。

2.4. Filter映射配置

过滤器需要配置在web.xml中才能生效。一个过滤器需要配置<filter>和<filter-mapping>标签,例如如下:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<!-- 配置过滤器 -->
<filter>
<!-- 配置过滤器的名称 -->
<filter-name>MyFitler</filter-name>
<!-- 配置对应过滤器类的完整路径 -->
<filter-class>app.java.fitler.MyFitler</filter-class>
</filter>
<!-- 配置过滤器的拦截路径 -->
<filter-mapping>
<!-- 配置过滤器的名称 -->
<filter-name>MyFitler</filter-name>
<!-- 配置过滤器的拦截的路径 -->
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>

<filter>配置过滤器的名称,实现类以及初始化参数。<filter-mapping>配置当前过滤器拦截的路径。<filter-mapping>中的<url-pattern>标签用于配置当前过滤器拦截的路径,配置方式与Servlet的<url-pattern>配置方式类似,共有三种方式:

  • 完全匹配
  • 目录匹配
  • 扩展名匹配

如果需要拦截的是Servlet的话,有两种方式配置拦截路径:

  • 使用<url-pattern>标签:<url-pattern>/hello</url-pattern>
  • 使用<servlet-name>标签:<servlet-name>HelloServlet</servlet-name>

<dispatcher>标签配置到达Servlet的方法,有四种取值:REQUEST、FORWARD、INCLUDE和ERROR。可以同时配置多个<dispatcher>标签,如果没有配置<dispatcher>标签,默认为REQUEST。这四种取值的区别如下:

  • REQUEST:表示仅当直接请求Servlet时才生效。
  • FORWARD:表示仅当某Servlet通过FORWARD到该Servlet时才生效。
  • INCLUDE:JSP中可以通过<jsp:include>标签请求某Servlet或调用RequestDispatcher的include()方法请求某Servlet,仅这种情况下有效。
  • ERROR:JSP中可以通过<%@ page errorPage=”error.jsp”>标签指定错误处理页面,仅这种情况下有效。

<url-pattern>标签与<dispatcher>标签的关系是“且”的关系。只有满足<url-pattern>标签的条件,且满足<dispatcher>标签的条件时,当前过滤器才能生效。

3. 过滤器案例

3.1. 全站乱码案例

中文乱码问题一直都是Web应用开发的问题,想要解决整个Web应用程序的中文乱码问题,可以如下操作:

  • 创建一个Java类继承于HttpServletRequestWrapper类,用于重写HttpServletRequest,解决GET方式的中文乱码问题。
public class MyRequest extends HttpServletRequestWrapper {
public MyRequest(HttpServletRequest request) {
super(request);
}
@Override
public String getParameter(String name) {
String value = super.getParameter(name);
if (getMethod().equalsIgnoreCase("GET")) {
try {
value = new String(value.getBytes("ISO-8859-1"),"utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
return value;
}
}
  • 创建一个过滤器用于解决整个Web应用程序的中文乱码问题。
public class EncodingFilter implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
MyRequest req = new MyRequest((HttpServletRequest)request);
chain.doFilter(req, response);
}
public void destroy() {}
}
  • 配置Web工程的web.xml文件。
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<filter>
<filter-name>EncodingFilter</filter-name>
<filter-class>app.java.demo4.EncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>EncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
  • 创建一个JSP页面用于中文乱码问题的测试。
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'login.jsp' starting page</title>
</head>
<body>
<form id="userinfo" action="encoding" method="post">
用户名:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
<input type="submit" value="登录">
</form>
<a href="/encoding?username=张无忌">GET方式的中文乱码问题</a>
</body>
</html>
  • 创建一个Servlet用于测试中文乱码问题。
public class EncodingServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = request.getParameter("username");
response.getWriter().println("<h1>username : "+username+"</h1>");
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
  • 配置Web工程的web.xml文件。
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<servlet>
<servlet-name>EncodingServlet</servlet-name>
<servlet-class>app.java.servlet.EncodingServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>EncodingServlet</servlet-name>
<url-pattern>/encoding</url-pattern>
</servlet-mapping>
</web-app>

3.2. 自动登录案例

所谓自动登录就是当用户第一次登录后,并且选择“自动登录”选项,用户从第二次访问开始,用户都无需再登录,完成直接登录的功能。具体实现步骤如下:

  • 创建一个JSP页面用于用户登录功能。
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'login.jsp' starting page</title>
</head>
<body>
<h3 style="color:red;">${msg }</h3>
<form id="userinfo" action="login" method="post">
用户名:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
<input type="checkbox" name="autologin" value="true">自动登录<br>
<input type="submit" value="登录">
</form>
</body>
</html>
  • 创建一个JavaBean用于封装用户信息。
public class User {
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
  • 创建一个Servlet用于处理用户登录逻辑。
public class LoginServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
if("admin".equals(username)&&"admin".equals(password)){
User user = new User();
user.setUsername(username);
user.setPassword(password); HttpSession session = request.getSession();
session.setAttribute("user", user); if("true".equals(request.getParameter("autologin"))){
Cookie cookie = new Cookie("autologin", username+"#"+password);
cookie.setPath("/");
cookie.setMaxAge(60 * 60 * 24 * 90);
response.addCookie(cookie);
}
response.sendRedirect("index.jsp");
return;
}else{
request.setAttribute("msg", "用户名或密码错误,请重新输入.");
request.getRequestDispatcher("login.jsp").forward(request, response);
return;
}
}
}
  • 配置Web工程的web.xml文件。
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<servlet>
<servlet-name>LoginServlet</servlet-name>
<servlet-class>app.java.servlet.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
</web-app>
  • 创建一个JSP页面用于显示主页面,显示用户登录信息。
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'index.jsp' starting page</title>
</head>
<body>
<c:if test="${empty user }">
<h1>您还未登录,请去<a href="login.jsp">登录</a></h1>
</c:if>
<c:if test="${not empty user }">
<h1>欢迎您,${user.username }</h1>
</c:if>
</body>
</html>
  • 创建一个过滤器用于完成自动登录功能。
public class AutoLoginFilter implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest)request;
// 判断用户是否选择手动登录
if(req.getSession().getAttribute("user") != null){
// 已经登录
chain.doFilter(request, response);
return;
}else{
// 没有登录,查找是否含有自动登录Cookie
Cookie autoLoginCookie = findCookie(req.getCookies(), "autologin");
if (autoLoginCookie == null){
// 没有自动登录信息
chain.doFilter(request, response);
return;
}else{
// 存在自动登录信息
String username = autoLoginCookie.getValue().split("#")[0];
String password = autoLoginCookie.getValue().split("#")[1];
if (!"admin".equals(username)||!"admin".equals(password)) {
// 自动登录信息有问题
chain.doFilter(request, response);
}else{
// 完成自动登录功能
User user = new User();
user.setUsername(username);
user.setPassword(password);
req.getSession().setAttribute("user", user);
chain.doFilter(request, response);
return;
}
}
}
}
public Cookie findCookie(Cookie[] cookies, String name) {
if (cookies == null) {
return null;
} else {
for (Cookie cookie : cookies) {
if (cookie.getName().equals(name)) {
return cookie;
}
}
return null;
}
}
public void destroy() {}
}
  • 配置Web工程的web.xml文件。
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<filter>
<filter-name>AutoLoginFilter</filter-name>
<filter-class>app.java.demo2.AutoLoginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>AutoLoginFilter</filter-name>
<url-pattern>/index.jsp</url-pattern>
</filter-mapping>
</web-app>

3.3. 权限控制案例

一般情况下,Web应用程序不能允许所有用户可以访问所有功能。换句话讲,不同的用户具有访问不同功能的权限。所以,需要完成权限控制功能,具体操作如下:

  • 创建JavaBean用于封装用户信息(包含权限信息)。
public class User {
private String username;
private String password;
private String role;
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
  • 创建Web应用程序的主页面,用于用户功能的显示。
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'index.jsp' starting page</title>
</head>
<body>
<c:if test="${empty user }">
<h1>您还未登录,请去<a href="login.jsp">登录</a></h1>
</c:if>
<c:if test="${not empty user }">
<h1>欢迎您,${user.username }</h1>
<h1><a href="user/userlist.jsp">用户操作功能列表</a></h1>
<h1><a href="admin/adminlist.jsp">管理员操作功能列表</a></h1>
</c:if>
</body>
</html>
  • 创建用户可以访问的功能列表页面。
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'userlist.jsp' starting page</title>
</head>
<body>
<h1>这里是用户操作的功能列表!</h1>
</body>
</html>
  • 创建管理员可以访问的功能列表页面。
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'adminlist.jsp' starting page</title>
</head>
<body>
<h1>这里是管理员操作的功能列表!</h1>
</body>
</html>
  • 创建一个过滤器用于完成权限控制功能。
public class AuthoFilter implements Filter {
private FilterConfig config;
private Map<String, String> map = new HashMap<String, String>();
public void init(FilterConfig filterConfig) throws ServletException {
this.config = filterConfig;
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
Enumeration names = config.getInitParameterNames();
while (names.hasMoreElements()) {
String name = (String) names.nextElement();
String value = config.getInitParameter(name);
map.put(value, name);
}
HttpServletRequest req = (HttpServletRequest) request;
String path = req.getRequestURI().substring(req.getContextPath().length());
for (String needPath : map.keySet()) {
if (path.startsWith(needPath)) {
String needRole = map.get(needPath);
User user = (User) req.getSession().getAttribute("user");
if (user == null) {
req.getRequestDispatcher("login.jsp").forward(request, response);
return;
}else {
String role = user.getRole();
if (needRole.equals(role)) {
chain.doFilter(request, response);
return;
}else {
throw new RuntimeException("权限不足,无法访问!");
}
}
}
}
chain.doFilter(request, response);
}
public void destroy() {}
}
  • 配置Web工程的web.xml文件。
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<filter>
<filter-name>AuthoFilter</filter-name>
<filter-class>app.java.demo3.AuthoFilter</filter-class>
<init-param>
<param-name>user</param-name>
<param-value>/user</param-value>
</init-param>
<init-param>
<param-name>admin</param-name>
<param-value>/admin</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>AuthoFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>

3.4. 禁用缓存案例

之前完成过禁止浏览器缓存功能,使用的是响应协议头中的三个内容,如下:

Expires: -1

禁用浏览器缓存(考虑不同浏览器兼容性,存在三个字段)

Cache-Control: no-cache

Pragma: no-cache

在服务器端Servlet代码如下:

//设置响应头信息,禁止浏览器缓存.
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Pragma", "no-cache");
response.setDateHeader("Expires", -1);

但这种方式只能适用于一个JSP页面,而一个Web应用程序中可能包含多个JSP页面。如果想要整个Web应用程序的所有JSP页面都禁止缓存,需要使用过滤器功能来完成,具体操作如下:

  • 创建一个过滤器类,实现Filter接口,并重写所有方法。
public class NoCacheFilter implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
//1 将ServletResponse强转为HttpServletResponse
HttpServletResponse res = (HttpServletResponse)response;
//2 禁止浏览器缓存功能
res.setHeader("Cache-Control", "no-cache");
res.setHeader("Pragma", "no-cache");
res.setDateHeader("Expires", -1);
//3 过滤器放行
chain.doFilter(request, response);
}
public void destroy() {}
}
  • 配置Web工程中的web.xml文件。
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<filter>
<filter-name>NoCacheFilter</filter-name>
<filter-class>app.java.demo1.NoCacheFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>NoCacheFilter</filter-name>
<url-pattern>*.jsp</url-pattern>
</filter-mapping>
</web-app>

JavaWeb Filter的更多相关文章

  1. JavaWeb——Filter

    一.基本概念 之前我们用一篇博文介绍了Servlet相关的知识,有了那篇博文的知识积淀,今天我们学习Filter将会非常轻松,因为Filter有很多地方和Servlet类似,下面在讲Filter的时候 ...

  2. JAVAWEB Filter使用

    Filter学习 1Filter是什么:是过滤器简称 2Filter有什么作用:在filter中可以得到代表用户请求和响应的request.response对象,因此在编程中可以使用Decorator ...

  3. JavaWeb——Filter过滤器

    1.Filter的目的 Filter用于在Servlet之前检测和修改请求和响应,它可以拒绝.重定向或转发请求.常见的有这几种: 日志过滤器 使用过滤器记录请求,提供请求日志记录,还可以添加追踪信息用 ...

  4. JavaWeb—过滤器Filter

    1.Filter简介 Filter称之为过滤器,是用来做一些拦截的任务.比如客户端请求服务器的某个资源时(可以是Servlet.JSP.HTML等等),我们可以拦截.当服务器返回资源给客户端的时候,我 ...

  5. Filter、Listener 学习总结

    今天我们来介绍 Filter.Listener 这两个模块一些简单的知识和应用,接下来我们开始我们的正题 ! 1. Filter(过滤器) 1.1 对 Servlet 容器调用 Servlet 的过程 ...

  6. filter和listener的生命周期

    filter(过滤器)和listener(监听器)的生命周期 老实说 生命周期要是说成作用的时间范围我会理解的更好 filter package com.javaweb.filter; import ...

  7. Filter的常见应用

    1.字符编码过滤器 实现功能,在a.jsp中填写用户名提交到b.jsp,在b.jsp中读取参数名. a.jsp <body> <form action="encoding/ ...

  8. Filter内容

    1.利用Filter来过滤的时候大都是Http请求和Http响应,在doFilter()方法中,参数类是ServletRequest和ServletResponse  ,使用的时候一般需要强制转换为H ...

  9. jsp版ueditor图片在线管理返回绝对路径

    引用:http://zhengyunfei.iteye.com/blog/2149979 如果你有富文本编辑器的功能需要开发,我推荐你用百度的ueditor.本文将与你分享jsp版ueditor开发中 ...

随机推荐

  1. python数据表的合并(python pandas join() 、merge()和concat()的用法)

    merage# pandas提供了一个类似于关系数据库的连接(join)操作的方法<Strong>merage</Strong>,可以根据一个或多个键将不同DataFrame中 ...

  2. Redis性能调优

    Redis性能调优 尽管Redis是一个非常快速的内存数据存储媒介,也并不代表Redis不会产生性能问题.前文中提到过,Redis采用单线程模型,所有的命令都是由一个线程串行执行的,所以当某个命令执行 ...

  3. 《从零开始学Swift》学习笔记(Day 57)——Swift编码规范之注释规范:文件注释、文档注释、代码注释、使用地标注释

    原创文章,欢迎转载.转载请注明:关东升的博客 前面说到Swift注释的语法有两种:单行注释(//)和多行注释(/*...*/).这里来介绍一下他们的使用规范. 1.文件注释 文件注释就在每一个文件开头 ...

  4. Android编译系统入门(一)

    做过Android平台开发的朋友对make,mm或make clean命令应该很熟悉,但也许大家只是熟知这些命令的作用却不知道这些命令底下有些什么原理?那么今天我就带着大家推开Android编译系统的 ...

  5. Avalondock 第四步 边缘停靠

    前一章介绍了分组功能,这一章主要介绍细节信息,LayoutRoot的side属性 LayoutRoot包含四个属性,LeftSide,RightSide,TopSide,BottomSide,分别用于 ...

  6. hadoop namenode

    存储文件系统元数据,例如:文件目录结构,不同文件的分块情况,每块存储在那个节点,权限等 这些元数据全部存储在内存中,所以,namenode要求内存比较大 hdfs在存文件的时候会按照块存储,每一块默认 ...

  7. Android图片加载框架Picasso最全使用教程2

    前言 前面我们已经介绍了Picasso的基本用法及如何将一张图片加载到ImageView中,下面我们就利用Picasso在ListView中加载图片;Let’s Go! 一个ListView的简单应用 ...

  8. Myeclipse中文乱码解决方式

    我们刚刚安装的Myeclipse有可能使用的是GBK的编码方式,而通常我们的程序都是使用的是UTF-8的编码方式,所以当我们导入一个项目的时候,会产生乱码,解决方式如下: 一.将整个project设置 ...

  9. python全栈开发从入门到放弃之网络基础

    一.操作系统基础 操作系统:(Operating System,简称OS)是管理和控制计算机硬件与软件资源的计算机程序,是直接运行在“裸机”上的最基本的系统软件,任何其他软件都必须在操作系统的支持下才 ...

  10. VS2015配置安卓Android和iOS开发环境

    http://www.cjjjs.cn/paper/gzsh/627201502818357.aspx [摘要] 本文按照步骤一步步的介绍要下载安装的东西,都提供了下载地址.最后将所有需要的程序都打包 ...