Filter

Filter là một thành phần được gọi trong quá trình tiền xử lýhậu xử lý của một request.

🎯 Filter dùng để làm gì?

  • 🔐 Xác thực (Authentication): Kiểm tra người dùng đã đăng nhập hay chưa, có quyền hay không.
  • 📝 Ghi log (Logging): Ghi lại các request, IP truy cập.
  • 📊 Thống kê truy cập (Monitoring): Đếm số lượt truy cập vào từng tài nguyên.
  • ...

Cấu trúc cơ bản của Filter

public class MyFilter implements Filter {
  public void init(FilterConfig filterConfig) { }

  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
      throws IOException, ServletException {
    // xử lý trước khi chuyển tiếp
    doBeforeProcessing(request, response);

    // chuyển tiếp (chuyển request đến filter tiếp theo trong chuỗi,
    // nếu không còn filter nào thì đến Servlet đích)
    chain.doFilter(request, response);

    // xử lý sau khi chuyển tiếp
    doAfterProcessing(request, response);
  }

  public void destroy() { }
}

Ví dụ 1: Kiểm tra quyền truy cập trang

@WebFilter(filterName = "AuthFilter", urlPatterns = {"/add", "/edit", "/delete"})
public class AuthFilter implements Filter {
  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
      throws IOException, ServletException {
    // ServletRequest là interface chung cho mọi loại request (HTTP, FTP, SOAP...)
    // nên hông có các phương thức HTTP cụ thể như: getSession()
    // -> cần ép kiểu về HttpServletRequest (là interface dành riêng cho HTTP)
    HttpServletRequest req = (HttpServletRequest) request;
    
    // ServletResponse không có sendRedirect
    // -> cần ép kiểu về HttpServletResponse
    HttpServletResponse res = (HttpServletResponse) response;
    
    // req.getSession(false): Lấy session hiện tại, nếu không có thì trả về null. Không tạo mới.
    // req.getSession(true): Lấy session hiện tại, nếu không có thì tạo mới.
    HttpSession session = req.getSession(false);

    if (session == null || session.getAttribute("username") == null) {
        res.sendRedirect(req.getContextPath() + "/login");
    } else {
        // chuyển tiếp
        chain.doFilter(request, response);
    }
  }
}

Ví dụ 2: Đếm số lượt truy cập trang hiện tại

@WebFilter(filterName = "AccessCounterFilter", urlPatterns = {"/*"})
public class AccessCounterFilter implements Filter {
  private static final Map<String, AtomicInteger> counter = new ConcurrentHashMap<>();

  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
      throws IOException, ServletException {
    HttpServletRequest httpRequest = (HttpServletRequest) request;

    // Tăng số lượt truy cập cho trang hiện tại
    String path = httpRequest.getRequestURI();
    counter.computeIfAbsent(path, k -> new AtomicInteger(0)).incrementAndGet();

    request.setAttribute("visitCount", counter.get(path));

    chain.doFilter(request, response);
  }
}