iT邦幫忙

0

【左京淳的JAVA WEB學習筆記】第五章 過濾器與監聽器

過濾器可以用來做權限校驗或是編碼轉換等功能。
多個過濾器可以串聯在一起,做多重過濾。
自定義的過濾器需實現javax.servlet.Filter介面。

編碼轉換案例:

  1. 設定過濾範圍及encoding方式
@WebFilter(urlPatterns = "/*",
  initParams = {@WebInitParam(name = "encoding",value = "utf-8")})
public class CharacterEncodingFilter implements Filter {…}

urlPatterns = "/*" //過濾目標為此網站下所有網頁
initParams = {@WebInitParam(name = "encoding",value = "utf-8")} //將encoding方式設為utf-8(或其他編碼)
  1. 在init方法中讀取參數
  public void init(FilterConfig fConfig) throws ServletException {
    this.encoding = fConfig.getInitParameter("encoding");
  }
  1. 在doFilter中過濾請求
  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    if(encoding != null) {
      request.setCharacterEncoding(encoding);
    }
    HttpServletRequest r = (HttpServletRequest)request;
    if(r.getMethod().equalsIgnoreCase("get")) { //只針對GET請求進行過濾,POST方法通常不會亂碼。
      Enumeration<?>names = request.getParameterNames();
      while(names.hasMoreElements()) {
        String[] values = request.getParameterValues(names.nextElement().toString());
        for(int i = 0;i < values.length; ++i) {
          values[i] = new String(values[i].getBytes("ISO-8859-1"),encoding);
        }
      }
    }
    chain.doFilter(request, response); //過濾器處理完後丟給下一個過濾器或引導至資源網頁。
  }

權限校驗案例:

  1. 用戶登入成功後,將用戶保存至session中。
    將之前寫的LoginSvl稍作修正,原本把用戶名保存在request,這次保存到session裡面
@WebServlet("/LoginSvl")
public class LoginSvl extends HttpServlet {
  protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    String uname = request.getParameter("uname");
    request.getSession().setAttribute("uname", uname);
    String pwd = request.getParameter("pwd");
    //request.setAttribute("uname", uname);
    request.getRequestDispatcher("/main/hello.jsp").forward(request, response);
  }
}
  1. 定義用戶權限過濾器
@WebFilter(filterName = "/UserFilter", urlPatterns = "/user/*")
public class UserFilter implements Filter {
  (前略…)
  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    HttpServletRequest req = (HttpServletRequest)request;
    Object object = req.getSession().getAttribute("uname");
    if(object != null) { //這邊因為是範例,所以沒有從資料庫拿使用者名單,只是簡單的從session裡確認是否有uname被儲存了。
      chain.doFilter(request, response);
    }else {
      request.setAttribute("msg", "請先登錄");
      req.getRequestDispatcher("/main/login.jsp").forward(request, response);
    }
  }
}
  1. 製作jsp頁面
    新增user/UserInfo.jsp頁面,隨意添加一行內容。
Hi,${uname}

跑看看過濾器是否起作用吧。

監聽器的種類繁多,用來監聽各種不同對象。不像Filter一樣只有一種。例如:

ServletContextListener

當伺服器啟動時會創建ServletContext物件,此時利用監聽器即可加載一些初始化資訊。

@WebListener
public class MyContextListener implements ServletContextListener {}
    public void contextDestroyed(ServletContextEvent sce)  { 
    
    }
    public void contextInitialized(ServletContextEvent sce)  { 
         System.out.println("Tomcat啟動,ServletContext被創建");
    }

HttpSessionListener

一個Session代表一個在線上的用戶,因此可以用監聽器追蹤或管理用戶狀態。
註:統計用戶對象時,如果用戶主動登出,Web應用程式會自動創建另一個會話對象,因此線上人數不會變更。只有用戶超時未操作時,線上人數才會減少。

聊天室管理

利用監聽器也可以踢掉不當發言的使用者,流程如下:

  1. 在自訂的HttpSessionListener裡新增一個Map來管理所有session
  2. 在LoginSvl裡面也新增一個Map,把所有登入後的使用者放進去。
  3. 如果有想踢掉的使用者,先從LoginSvl的Map找出使用者的sessionid,然後用此id找到在監聽器map裡相對應的session,使其失效即可。
@WebListener
public class OnlineUserListerner implements HttpSessionListener {
  public static Map<String,HttpSession> allUser;
  static {
    allUser = new ConcurrentHashMap<>();
  }
  
    public void sessionCreated(HttpSessionEvent se)  { 
         HttpSession session = se.getSession();
         allUser.put(session.getId(), session);
    }

    public void sessionDestroyed(HttpSessionEvent se)  { 
        HttpSession session = se.getSession();
        allUser.remove(session.getId(), session);
    }
}
@WebServlet("/LoginSvl")
public class LoginSvl extends HttpServlet {
  private Map<String,String> loginedUsers = new ConcurrentHashMap<>();
  (中略…)
  protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    String uname = request.getParameter("uname");
    String pwd = request.getParameter("pwd");
    LoginBiz biz = new LoginBiz();
    User user = biz.login(uname,pwd);
    request.getSession().setAttribute("user", uname);
    loginedUsers.put(uname, request.getSession().getId());
    request.getRequestDispatcher("/main/main.jsp").forward(request, response);
  }
}

踢除某用戶的方法

String sessionid = loginedUsers.get(uname);
HttpSession session = OnlineUserListerner.allUser.get(sessionid);
session.invalidate();

ServletRequestListener

監聽每一次用戶訪問紀錄,可用於統計網站被訪問次數,例如:

@WebListener
public class PageViewListener implements ServletRequestListener {
  AtomicInteger pv;
    public PageViewListener() {
        System.out.println("PageViewListener被建立");
        pv = new AtomicInteger(0);
    }

    public void requestDestroyed(ServletRequestEvent sre)  { 
    }

    public void requestInitialized(ServletRequestEvent sre)  { 
      System.out.println(pv.incrementAndGet());
    }

此監聽器在Tomcat啟動時被建立
使用AtomicInteger pv當作計數器。
每次收到客戶端的request就會觸發一次requestInitialized()。


尚未有邦友留言

立即登入留言