JavaWeb Filter

1. 过滤器概述

1.1. 什么是过滤器

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

1.2. 发展历史

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

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>

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

在过滤器链中的过滤器执行的先后顺序是按照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的方法,有四种取值:REQUESTFORWARDINCLUDEERROR。可以同时配置多个<dispatcher>标签,如果没有配置<dispatcher>标签,默认为REQUEST。这四种取值的区别如下:

  • REQUEST:表示仅当直接请求Servlet时才生效。
  • FORWARD:表示仅当某Servlet通过FORWARD到该Servlet时才生效。
  • INCLUDEJSP中可以通过<jsp:include>标签请求某Servlet或调用RequestDispatcherinclude()方法请求某Servlet,仅这种情况下有效。
  • ERRORJSP中可以通过<%@ 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>
posted @ 2017-12-13 18:15  Mr.Aaron  阅读(1805)  评论(0编辑  收藏  举报