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() |
void |
doFilter(ServletRequest request, ServletResponse response, FilterChain chain) |
void |
init(FilterConfig filterConfig) |
實現過濾器的具體步驟如下:
- 創建一個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 |
|
getFilterName() |
|
getInitParameter(String name) |
|
getInitParameterNames() |
|
getServletContext() |
具體使用方式如下:
- 創建一個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>