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>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM