一、過濾器
1.介紹
Filter 的完整流程: Filter 對用戶請求進行預處理,接着將請求交給 Servlet 進行處理並生成響應,最後 Filter 再 對服務器響應進行後處理。在一個 web 應用中,可以開發編寫多個Filter,這些 Filter 組合 起來稱之爲一個 Filter 鏈。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-wsJrVIMB-1582630865316)(C:\Users\Hello Word\AppData\Roaming\Typora\typora-user-images\1582629150766.png)]
2.實現
init(), doFilter(), destroy()分別在相應的時機執行。後期觀察生命週期。
Filter 的實現只需要兩步:
Step1: 編寫 java 類實現 Filter 接口,並實現其 doFilter 方法。
Step2: 在 web.xml 文件中對編寫的 filter 類進行註冊,並設置它所能攔截的資源
public class Filter01 implements Filter { /** * 初始化 */ @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("Filter01 init..."); } /** * 處理請求的攔截方法 */ @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // 處理請求 System.out.println("Filter01 處理請求..."); // 放行資源 chain.doFilter(request, response); // 處理響應 System.out.println("Filter01 處理響應..."); } /** * 銷燬方法 */ @Override public void destroy() { System.out.println("Filter01 destroy..."); } } //web.xml配置 <filter> <filter-name>Filter01</filter-name> <!-- 給服務器看的,與filter-mapping標籤中filter-name保持一致 --> <filter-class>com.shsxt.filter.Filter01</filter-class> <!-- 類的全路徑 --> </filter> <filter-mapping> <filter-name>Filter01</filter-name> <!-- 給服務器看的,與filter標籤中filter-name保持一致 --> <url-pattern>/Servlet01</url-pattern> <!-- 給瀏覽器看的,需要攔截的資源路徑 --> <!-- <servlet-name>Servlet01</servlet-name> --> <!-- 想要攔截的servlet名稱,與servlet標籤的servlet-name一致 --> </filter-mapping>
3.過濾器的執行順序
過濾器
攔截請求到達指定資源之前的請求數據
攔截響應到達客戶端之前的響應數據
放行資源(chain.doFilter(request,response))
過濾器鏈
多個過濾器同時執行
執行順序:web.xml配置文件中,先配置的先執行
攔截順序:按照指定順序攔截,按照相反順序響應
請求:(1 -> 2 -> 3 )
響應:(3 -> 2 -> 1 )
4.過濾器實例
/** * 非法訪問攔截 * 當用戶訪問登錄狀態才能訪問的資源時,如果用戶未登錄,會被攔截到登錄頁面 * * 攔截的資源: 攔截所有資源 /* 需要放行的資源: 1、指定頁面,放行 無需登錄即可訪問的頁面 (例如:登錄頁面、註冊頁面等) 2、靜態資源,放行 js文件、css文件及圖片(存放在statics目錄下的資源) 3、指定操作,放行 無需登錄即可執行的操作 (登錄操作、註冊操作等) 4、登錄狀態,放行 判斷session作用域中是否存在用戶數據(有數據=登錄狀態;無數據=非登錄狀態) 當用戶未登錄時訪問資源,攔截跳轉到登錄頁面 */ public class LoginAccessFilter implements Filter { public LoginAccessFilter() { } public void destroy() { } public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain chain) throws IOException, ServletException { // 基於HTTP HttpServletRequest request = (HttpServletRequest)arg0; HttpServletResponse response = (HttpServletResponse)arg1; // 獲取當前訪問的資源路徑 String path = request.getRequestURI(); // 從端口號後開始(不包含端口),到"?"前面 /站點名/資源路徑 System.out.println(path); // 1、指定頁面,放行 無需登錄即可訪問的頁面 (例如:登錄頁面、註冊頁面等) if (path.contains("/login.html")) { // 放行資源 chain.doFilter(request, response); return; } // 2、靜態資源,放行 js文件、css文件及圖片(存放在statics目錄下的資源) if (path.contains("/statics")) { // 放行資源 chain.doFilter(request, response); return; } // 3、指定操作,放行 無需登錄即可執行的操作 (登錄操作、註冊操作等) if (path.indexOf("/loginServlet") != -1) { // 放行資源 chain.doFilter(request, response); return; } // 4、登錄狀態,放行 判斷session作用域中是否存在用戶數據(有數據=登錄狀態;無數據=非登錄狀態) String user = (String) request.getSession().getAttribute("user"); if (user != null && !"".equals(user)) { // 放行資源 chain.doFilter(request, response); return; } // chain.doFilter(request, response); // 攔截請求跳轉到登錄頁面 response.sendRedirect("login.html"); } public void init(FilterConfig fConfig) throws ServletException { } } /** * 用戶登錄 */ public class LoginServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("用戶登錄..."); // 接收參數 System.out.println(request.getParameter("uname")); // 模擬用戶在登錄狀態 request.getSession().setAttribute("user", "zhangsan"); // 登錄成功 response.sendRedirect("index.html"); } }
二、監聽器
1.介紹
web 監聽器是一種Servlet 中的特殊的類,ServletContext,HttpSession,ServletRequest 的創建和銷燬;變量的創建、銷燬和修改等。
2.實現
public class Listener01 implements HttpSessionListener,HttpSessionAttributeListener { /** * session的創建 */ @Override public void sessionCreated(HttpSessionEvent se) { System.out.println("Session Create..."); } /** * session的銷燬 */ @Override public void sessionDestroyed(HttpSessionEvent se) { System.out.println("Session Destroy..."); } /** * 設置域對象 */ @Override public void attributeAdded(HttpSessionBindingEvent se) { System.out.println("attributeAdded..."); } /** * 刪除域對象 */ @Override public void attributeRemoved(HttpSessionBindingEvent se) { System.out.println("attributeRemoved..."); } /** * 修改域對象 */ @Override public void attributeReplaced(HttpSessionBindingEvent se) { System.out.println("attributeReplaced..."); } } //servlet protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 創建session對象 HttpSession session = request.getSession(); // 設置域對象 session.setAttribute("uname", "zhangsan"); // 修改域對象 session.setAttribute("uname", "lisi"); // 刪除域對象 session.removeAttribute("uname"); // session的銷燬 session.invalidate(); }
3.監聽器案例
/** * 在線人數統計 * 當有新的session對象被創建,則在線人數+1; * 有session對象被銷燬,在線人數-1; * @author Lisa Li * */ public class OnlineListener implements HttpSessionListener { // 默認在線人數 private Integer onlineNumber = 0; /** * 當有新的session對象被創建,則在線人數+1; */ @Override public void sessionCreated(HttpSessionEvent se) { // 人數+1 onlineNumber++; // 將人數存到session作用域中 //se.getSession().setAttribute("onlineNumber", onlineNumber); // 將人數存到application作用域中 se.getSession().getServletContext().setAttribute("onlineNumber", onlineNumber); } /** * 有session對象被銷燬,在線人數-1; */ @Override public void sessionDestroyed(HttpSessionEvent se) { // 人數-1 onlineNumber--; // 將人數存到session作用域中 // se.getSession().setAttribute("onlineNumber", onlineNumber); // 將人數存到application作用域中 se.getSession().getServletContext().setAttribute("onlineNumber", onlineNumber); } }
/** * 在線人數統計 */ public class OnlineServlet extends HttpServlet { private static final long serialVersionUID = 1L; //引入日誌 //private logger logger=LoggerFactory.getLogger(OnlineServlet.class); protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //得到參數 String key=request.getParameter("key"); //判斷是否爲空 if(key==null || "".equals(key)){ //創建session對象 HttpSession session=request.getSession(); //獲取session作用域中人數application Integer onlineNumber=(Integer) session.getServletContext().getAttribute("onlineNumber"); //當前訪問用戶的ip及內容 String ip=request.getRemoteAddr(); String content=request.getParameter("content"); System.out.println(ip); System.out.println(content); //輸出 response.setContentType("text/html;charset=UTF-8"); response.getWriter().write("<h2>在線人數:"+onlineNumber+"</h2><h4><a href='Servlet01?key=logout'>退出</a><h4>"); }else{ //傳遞了參數,表示要做用戶推出操作 request.getSession().invalidate(); } } }
三、Servlet3.0註釋
1.@WebServlet
@WebServlet 註解將一個繼承於javax.servlet.http.HttpServlet 的類標註爲可以處理用戶請求的 Servlet。
//@WebServlet(value="/Servlet01") //@WebServlet(name="Servlet01",value="/Servlet01") //@WebServlet(value={"/Servlet01","/Servlet001"}) //@WebServlet(urlPatterns="/s01") //@WebServlet(urlPatterns={"/Servlet01","/Servlet001"}) @WebServlet("/s01") public class Servlet01 extends HttpServlet { private static final long serialVersionUID = 1L; protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("Servlet..."); } }
2.@WebFilter
使用註解時:過濾器鏈按照類名的字母排序(大部分情況)
@WebFilter("/*") public class Filter01 implements Filter { /** * Default constructor. */ public Filter01() { // TODO Auto-generated constructor stub } /** * @see Filter#destroy() */ public void destroy() { // TODO Auto-generated method stub } /** * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain) */ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("Filter01..."); chain.doFilter(request, response); } /** * @see Filter#init(FilterConfig) */ public void init(FilterConfig fConfig) throws ServletException { // TODO Auto-generated method stub } }
3.@WebListener
Servlet3.0 提供@WebListener 註解將一個實現了特定監聽器接口的類定義爲監聽
器。將實現了 ServletContextListener 接口的 MyServletContextListener 標註爲監聽器。
@WebListener public class Listener01 implements HttpSessionListener { /** * Default constructor. */ public Listener01() { // TODO Auto-generated constructor stub } /** * @see HttpSessionListener#sessionCreated(HttpSessionEvent) */ public void sessionCreated(HttpSessionEvent se) { // TODO Auto-generated method stub } /** * @see HttpSessionListener#sessionDestroyed(HttpSessionEvent) */ public void sessionDestroyed(HttpSessionEvent se) { // TODO Auto-generated method stub } }
4.@MultipartConfig
文件上傳
@MultipartConfig 一定要加註解!!!!!
如果前臺的表單類型設置爲enctype=" multipart/form-data",後臺servlet一定要加註解,否則所有的參數都爲null。
使用註解@MultipartConfig 將一個 Servlet 標識爲支持文件上傳。 Servlet3.0 將 multipart/form-data 的 POST 請求封裝成 Part,通過Part 對上傳的文件進行操作。
@MultipartConfig @WebServlet("/uploadServlet") public class UploadServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 獲取參數 String uname = request.getParameter("uname"); System.out.println(uname); // 得到要上傳的文件對象 getPart(name):name代表的是表單元素file文件域的name屬性值 Part part = request.getPart("myfile"); // 得到文件存放的路徑 String path = request.getServletContext().getRealPath("/"); // 得到上傳的文件名 String fileName = part.getSubmittedFileName(); // 上傳 part.write(path +"/"+fileName); } }
<body> <!-- 表單實現文件上傳 第一步:設置表單類型 enctype="multipart/form-data" (文件上傳表單) 第二步:表單提交類型 method="POST" 第三步:文件域file元素設置name屬性值 --> <form action="uploadServlet" method="POST" enctype="multipart/form-data" > 姓名:<input type="text" name="uname" /> <br> 文件:<input type="file" name="myfile" /> <br> <button>提交</button> </form> </body>