Java Servlet Filter 예제 튜토리얼

Java Servlet Filter는 클라이언트 요청을 가로채고 일부 전처리를 수행하는 데 사용됩니다. 또한 웹 애플리케이션에서 클라이언트에게 응답을 보내기 전에 응답을 가로챌 수도 있습니다. 이 글은 웹 애플리케이션 튜토리얼 시리즈의 네 번째 글입니다. 이전 글도 확인하실 수 있습니다.

  1. Java 웹 애플리케이션
  2. Java Servlet 튜토리얼
  3. Servlet 세션 관리

Servlet 필터

이 글에서는 Java에서 Servlet 필터에 대해 알아보겠습니다. Servlet 필터의 여러 사용법, 필터를 생성하는 방법 및 간단한 웹 애플리케이션에서의 사용법을 살펴보겠습니다.

  1. 왜 Servlet 필터가 필요한가요?

  2. Servlet 필터 인터페이스

  3. Servlet WebFilter 주석

  4. web.xml에서의 Servlet Filter 구성

  5. 로깅 및 세션 유효성 검사를 위한 Servlet Filter 예제

  6. 우리는 왜 Servlet Filter를 갖고 있나요?

    지난 기사에서 웹 애플리케이션에서 세션을 관리하는 방법과 사용자 세션이 유효할 때에만 리소스에 액세스할 수 있도록하려면 서블릿 세션 속성을 사용하여이를 달성할 수 있다는 것을 배웠습니다. 이 접근 방식은 간단하지만 많은 서블릿과 JSP가있는 경우 중복 코드로 인해 유지 관리가 어려워집니다. 나중에 속성 이름을 변경하려면 세션 인증이있는 모든 위치를 변경해야합니다. 이것이 서블릿 필터가있는 이유입니다. Servlet Filter는 서블릿이나 응답이 클라이언트로 다시 전송되기 전에 요청을 가로 채고 처리할 수있는 플러그 가능한 자바 구성 요소입니다. Servlet 필터를 사용하여 수행 할 수있는 일반적인 작업은 다음과 같습니다:

    • 로그 파일에 요청 매개 변수 기록.
    • 리소스에 대한 요청의 인증 및 권한 부여.
    • 서블릿으로 보내기 전에 요청 본문 또는 헤더의 형식 지정.
    • 클라이언트로 보낸 응답 데이터 압축.
    • 쿠키, 헤더 정보 등을 추가하여 응답 변경.

    이전에 언급했듯이, 서블릿 필터는 플러그 가능하며 배치 설명자 (web.xml) 파일에서 구성됩니다. 서블릿 및 필터는 서로에 대해 알지 못하며 web.xml을 편집하여 서블릿 필터를 추가하거나 제거 할 수 있습니다. 단일 리소스에 대해 여러 필터를 가질 수 있으며 web.xml에서 단일 리소스에 대한 필터 체인을 만들 수 있습니다. Servlet Filter를 만들려면 javax.servlet.Filter 인터페이스를 구현하면 됩니다.

  7. 서블릿 필터 인터페이스

    서블릿 필터 인터페이스는 서블릿 인터페이스와 유사하며, 우리 자신의 서블릿 필터를 생성하기 위해 이를 구현해야 합니다. 서블릿 필터 인터페이스에는 필터의 라이프사이클 메서드가 포함되어 있으며 서블릿 컨테이너에 의해 관리됩니다. 서블릿 필터 인터페이스의 라이프사이클 메서드는 다음과 같습니다:

    1. void init(FilterConfig paramFilterConfig) – 컨테이너가 필터를 초기화할 때 호출되는 메서드입니다. 이 메서드는 필터의 라이프사이클에서 한 번만 호출되며, 이 메서드에서는 모든 리소스를 초기화해야 합니다. FilterConfig는 컨테이너가 필터에 init 매개변수와 서블릿 컨텍스트 개체를 제공하기 위해 사용됩니다. 이 메서드에서 ServletException을 던질 수 있습니다.
    2. doFilter(ServletRequest paramServletRequest, ServletResponse paramServletResponse, FilterChain paramFilterChain) – 컨테이너가 리소스에 필터를 적용해야 할 때마다 호출되는 메서드입니다. 컨테이너는 필터에 요청 및 응답 객체 참조를 인수로 제공합니다. FilterChain은 체인 내의 다음 필터를 호출하는 데 사용됩니다. 이는 책임 연쇄 패턴(Chain of Responsibility Pattern)의 훌륭한 예입니다.
    3. void destroy() – 컨테이너가 필터 인스턴스를 언로드할 때 destroy() 메서드가 호출됩니다. 이 메서드에서는 필터에 의해 열린 모든 리소스를 닫을 수 있습니다. 이 메서드는 필터의 수명 내에서 한 번만 호출됩니다.
  8. Servlet WebFilter 어노테이션

    javax.servlet.annotation.WebFilter은 Servlet 3.0에서 소개되었으며, 서블릿 필터를 선언하기 위해 이 어노테이션을 사용할 수 있습니다. 이 어노테이션을 사용하여 필터 구성요소, 필터 이름 및 설명, 서블릿, URL 패턴 및 디스패처 유형을 정의할 수 있습니다. 필터 구성을 자주 변경해야하는 경우, 필터 클래스를 다시 컴파일할 필요가 없으므로 web.xml을 사용하는 것이 좋습니다. 읽기: Java 어노테이션 튜토리얼

  9. web.xml에서의 Servlet 필터 구성

    아래와 같이 web.xml에서 서블릿 필터를 선언할 수 있습니다.

    <filter>
      <filter-name>RequestLoggingFilter</filter-name> <!-- 필수 -->
      <filter-class>com.journaldev.servlet.filters.RequestLoggingFilter</filter-class> <!-- 필수 -->
      <init-param> <!-- 선택 사항 -->
      <param-name>test</param-name>
      <param-value>testValue</param-value>
      </init-param>
    </filter>
    

    아래와 같이 필터를 서블릿 클래스나 url-pattern에 매핑할 수 있습니다.

    <filter-mapping>
      <filter-name>RequestLoggingFilter</filter-name> <!-- 필수 -->
      <url-pattern>/*</url-pattern> <!-- url-pattern 또는 servlet-name 중 하나는 필수 -->
      <servlet-name>LoginServlet</servlet-name>
      <dispatcher>REQUEST</dispatcher>
    </filter-mapping>
    

    참고: 서블릿에 대한 필터 체인을 생성할 때 컨테이너는 먼저 url-patterns를 처리한 다음 servlet-names를 처리합니다. 따라서 필터가 특정 순서대로 실행되도록 보장하려면 필터 매핑을 정의할 때 특별한 주의를 기울여야 합니다. 서블릿 필터는 일반적으로 클라이언트 요청에 사용되지만 가끔은 RequestDispatcher와 함께 필터를 적용하고 싶은 경우도 있습니다. 이 경우 dispatcher 요소를 사용할 수 있으며, 가능한 값은 REQUEST, FORWARD, INCLUDE, ERROR 및 ASYNC입니다. dispatcher가 정의되지 않은 경우에는 클라이언트 요청에만 적용됩니다.

  10. 로깅 및 세션 유효성 검사를 위한 Servlet Filter 예제

In our **servlet filter example**, we will create filters to log request cookies and parameters and validate session to all the resources except static HTMLs and LoginServlet because it will not have a session. We will create a dynamic web project **ServletFilterExample** whose project structure will look like the below image. [![Servlet Filter Example, Java Filter](https://journaldev.nyc3.cdn.digitaloceanspaces.com/2013/08/Servlet-Filter-Example-Project.png)](https://journaldev.nyc3.cdn.digitaloceanspaces.com/2013/08/Servlet-Filter-Example-Project.png) login.html is the entry point of our application where the user will provide the login id and password for authentication. login.html code:

```



























Login Page


Username:
Password:
``` LoginServlet is used to authenticate the request from the client for login. ``` package com.journaldev.servlet.session; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; /** * Servlet implementation class LoginServlet */ @WebServlet("/LoginServlet") public class LoginServlet extends HttpServlet { private static final long serialVersionUID = 1L; private final String userID = "admin"; private final String password = "password"; protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 사용자 ID 및 암호에 대한 요청 매개변수 가져오기 String user = request.getParameter("user"); String pwd = request.getParameter("pwd"); if(userID.equals(user) && password.equals(pwd)){ HttpSession session = request.getSession(); session.setAttribute("user", "Pankaj"); // 세션 만료를 30분으로 설정 session.setMaxInactiveInterval(30*60); Cookie userName = new Cookie("user", user); userName.setMaxAge(30*60); response.addCookie(userName); response.sendRedirect("LoginSuccess.jsp"); }else{ RequestDispatcher rd = getServletContext().getRequestDispatcher("/login.html"); PrintWriter out= response.getWriter(); out.println("Either user name or password is wrong."); rd.include(request, response); } } } ``` When the client is authenticated, it's forwarded to LoginSuccess.jsp LoginSuccess.jsp code: ``` <%@ page language="java" contentType="text/html; charset=US-ASCII" pageEncoding="US-ASCII"%> Login Success Page <% // 세션이 존재하는 경우에만 액세스 허용 String user = (String) session.getAttribute("user"); String userName = null; String sessionID = null; Cookie[] cookies = request.getCookies(); if(cookies !=null){ for(Cookie cookie : cookies){ if(cookie.getName().equals("user")) userName = cookie.getValue(); if(cookie.getName().equals("JSESSIONID")) sessionID = cookie.getValue(); } } %>

Hi <%=userName %>, Login successful. Your Session ID=<%=sessionID %>


User=<%=user %>
Checkout Page
``` Notice that there is no session validation logic in the above JSP. It contains a link to another JSP page, CheckoutPage.jsp. CheckoutPage.jsp code: ``` <%@ page language="java" contentType="text/html; charset=US-ASCII" pageEncoding="US-ASCII"%> Login Success Page <% String userName = null; String sessionID = null; Cookie[] cookies = request.getCookies(); if(cookies !=null){ for(Cookie cookie : cookies){ if(cookie.getName().equals("user")) userName = cookie.getValue(); } } %>

Hi <%=userName %>, do the checkout.


``` LogoutServlet is invoked when a client clicks on the Logout button in any of the JSP pages. ``` package com.journaldev.servlet.session; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; /** * Servlet implementation class LogoutServlet */ @WebServlet("/LogoutServlet") public class LogoutServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); Cookie[] cookies = request.getCookies(); if(cookies != null){ for(Cookie cookie : cookies){ if(cookie.getName().equals("JSESSIONID")){ System.out.println("JSESSIONID="+cookie.getValue()); break; } } } // 세션이 존재하는 경우 세션 무효화 HttpSession session = request.getSession(false); System.out.println("User="+session.getAttribute("user")); if(session != null){ session.invalidate(); } response.sendRedirect("login.html"); } } ``` Now we will create logging and authentication servlet filter classes. ``` package com.journaldev.servlet.filters; import java.io.IOException; import java.util.Enumeration; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.annotation.WebFilter; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; /** * Servlet Filter implementation class RequestLoggingFilter */ @WebFilter("/RequestLoggingFilter") public class RequestLoggingFilter implements Filter { private ServletContext context; public void init(FilterConfig fConfig) throws ServletException { this.context = fConfig.getServletContext(); this.context.log("RequestLoggingFilter initialized"); } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; Enumeration params = req.getParameterNames(); while(params.hasMoreElements()){ String name = params.nextElement(); String value = request.getParameter(name); this.context.log(req.getRemoteAddr() + "::Request Params::{"+name+"="+value+"}"); } Cookie[] cookies = req.getCookies(); if(cookies != null){ for(Cookie cookie : cookies){ this.context.log(req.getRemoteAddr() + "::Cookie::{"+cookie.getName()+","+cookie.getValue()+"}"); } } // 필터 체인을 통해 요청 전달 chain.doFilter(request, response); } public void destroy() { // 여기서 리소스를 닫을 수 있음 } } ``` ``` package com.journaldev.servlet.filters; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; @WebFilter("/AuthenticationFilter") public class AuthenticationFilter implements Filter { private ServletContext context; public void init(FilterConfig fConfig) throws ServletException { this.context = fConfig.getServletContext(); this.context.log("AuthenticationFilter initialized"); } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse res = (HttpServletResponse) response; String uri = req.getRequestURI(); this.context.log("Requested Resource::"+uri); HttpSession session = req.getSession(false); if(session == null && !(uri.endsWith("html") || uri.endsWith("LoginServlet"))){ this.context.log("Unauthorized access request"); res.sendRedirect("login.html"); }else{ // 필터 체인을 통해 요청 전달 chain.doFilter(request, response); } } public void destroy() { // 여기서 리소스를 닫음 } } ``` Notice that we are not authenticating any HTML page or LoginServlet. Now we will configure these filters mapping in the web.xml file. ``` ServletFilterExample login.html RequestLoggingFilter com.journaldev.servlet.filters.RequestLoggingFilter AuthenticationFilter com.journaldev.servlet.filters.AuthenticationFilter RequestLoggingFilter /* REQUEST AuthenticationFilter /* ``` Now when we will run our application, we will get response pages like below images. [![Servlet Filter Example](https://journaldev.nyc3.cdn.digitaloceanspaces.com/2013/08/Servlet-Filter-Login-450x141.png)](https://journaldev.nyc3.cdn.digitaloceanspaces.com/2013/08/Servlet-Filter-Login.png) [![Servlet Filter, Java Filter](https://journaldev.nyc3.cdn.digitaloceanspaces.com/2013/08/Servlet-Filter-Login-Success-450x229.png)](https://journaldev.nyc3.cdn.digitaloceanspaces.com/2013/08/Servlet-Filter-Login-Success.png) [![Servlet Filter Tutorial, Java Servlet Filter](https://journaldev.nyc3.cdn.digitaloceanspaces.com/2013/08/Servlet-Filter-Checkout-450x181.png)](https://journaldev.nyc3.cdn.digitaloceanspaces.com/2013/08/Servlet-Filter-Checkout.png) If you are not logged in and try to access any JSP page, you will be forwarded to the login page. In the server log file, you can see the logs written by servlet filters as well as servlets. ``` Aug 13, 2013 1:06:07 AM org.apache.catalina.core.ApplicationContext log INFO: 0:0:0:0:0:0:0:1%0::Cookie::{JSESSIONID,B7275762B8D23121152B1270D6EB240A} Aug 13, 2013 1:06:07 AM org.apache.catalina.core.ApplicationContext log INFO: Requested Resource::/ServletFilterExample/ Aug 13, 2013 1:06:07 AM org.apache.catalina.core.ApplicationContext log INFO: Unauthorized access request Aug 13, 2013 1:06:07 AM org.apache.catalina.core.ApplicationContext log INFO: 0:0:0:0:0:0:0:1%0::Cookie::{JSESSIONID,B7275762B8D23121152B1270D6EB240A} Aug 13, 2013 1:06:07 AM org.apache.catalina.core.ApplicationContext log INFO: Requested Resource::/ServletFilterExample/login.html Aug 13, 2013 1:06:43 AM org.apache.catalina.core.ApplicationContext log INFO: 0:0:0:0:0:0:0:1%0::Request Params::{pwd=password} Aug 13, 2013 1:06:43 AM org.apache.catalina.core.ApplicationContext log INFO: 0:0:0:0:0:0:0:1%0::Request Params::{user=admin} Aug 13, 2013 1:06:43 AM org.apache.catalina.core.ApplicationContext log INFO: 0:0:0:0:0:0:0:1%0::Cookie::{JSESSIONID,B7275762B8D23121152B1270D6EB240A} Aug 13, 2013 1:06:43 AM org.apache.catalina.core.ApplicationContext log INFO: Requested Resource::/ServletFilterExample/LoginServlet Aug 13, 2013 1:06:43 AM org.apache.catalina.core.ApplicationContext log INFO: 0:0:0:0:0:0:0:1%0::Cookie::{JSESSIONID,8BDF777933194EDCAC1D8F1B73633C56} Aug 13, 2013 1:06:43 AM org.apache.catalina.core.ApplicationContext log INFO: 0:0:0:0:0:0:0:1%0::Cookie::{user,admin} Aug 13, 2013 1:06:43 AM org.apache.catalina.core.ApplicationContext log INFO: Requested Resource::/ServletFilterExample/LoginSuccess.jsp Aug 13, 2013 1:06:52 AM org.apache.catalina.core.ApplicationContext log INFO: 0:0:0:0:0:0:0:1%0::Cookie::{JSESSIONID,8BDF777933194EDCAC1D8F1B73633C56} Aug 13, 2013 1:06:52 AM org.apache.catalina.core.ApplicationContext log INFO: 0:0:0:0:0:0:0:1%0::Cookie::{user,admin} Aug 13, 2013 1:06:52 AM org.apache.catalina.core.ApplicationContext log INFO: Requested Resource::/ServletFilterExample/CheckoutPage.jsp Aug 13, 2013 1:07:00 AM org.apache.catalina.core.ApplicationContext log INFO: 0:0:0:0:0:0:0:1%0::Cookie::{JSESSIONID,8BDF777933194EDCAC1D8F1B73633C56} Aug 13, 2013 1:07:00 AM org.apache.catalina.core.ApplicationContext log INFO: 0:0:0:0:0:0:0:1%0::Cookie::{user,admin} Aug 13, 2013 1:07:00 AM org.apache.catalina.core.ApplicationContext log INFO: Requested Resource::/ServletFilterExample/LogoutServlet JSESSIONID=8BDF777933194EDCAC1D8F1B73633C56 User=Pankaj Aug 13, 2013 1:07:00 AM org.apache.catalina.core.ApplicationContext log INFO: 0:0:0:0:0:0:0:1%0::Cookie::{JSESSIONID,8BDF777933194EDCAC1D8F1B73633C56} Aug 13, 2013 1:07:00 AM org.apache.catalina.core.ApplicationContext log INFO: 0:0:0:0:0:0:0:1%0::Cookie::{user,admin} Aug 13, 2013 1:07:00 AM org.apache.catalina.core.ApplicationContext log INFO: Requested Resource::/ServletFilterExample/login.html Aug 13, 2013 1:07:06 AM org.apache.catalina.core.ApplicationContext log INFO: 0:0:0:0:0:0:0:1%0::Cookie::{JSESSIONID,8BDF777933194EDCAC1D8F1B73633C56} Aug 13, 2013 1:07:07 AM org.apache.catalina.core.ApplicationContext log INFO: 0:0:0:0:0:0:0:1%0::Cookie::{user,admin} Aug 13, 2013 1:07:07 AM org.apache.catalina.core.ApplicationContext log INFO: Requested Resource::/ServletFilterExample/LoginSuccess.jsp Aug 13, 2013 1:07:07 AM org.apache.catalina.core.ApplicationContext log INFO: Unauthorized access request Aug 13, 2013 1:07:07 AM org.apache.catalina.core.ApplicationContext log INFO: 0:0:0:0:0:0:0:1%0::Cookie::{JSESSIONID,8BDF777933194EDCAC1D8F1B73633C56} Aug 13, 2013 1:07:07 AM org.apache.catalina.core.ApplicationContext log INFO: 0:0:0:0:0:0:0:1%0::Cookie::{user,admin} Aug 13, 2013 1:07:07 AM org.apache.catalina.core.ApplicationContext log INFO: Requested Resource::/ServletFilterExample/login.html ```

자바에서의 서블릿 필터에 관한 모든 것입니다. 이것은 Java EE 웹 애플리케이션의 중요한 기능 중 하나이며 다양한 서블릿에서 수행되는 일반적인 작업에 사용해야 합니다. 향후 게시물에서는 서블릿 리스너와 쿠키를 살펴보겠습니다. 업데이트: 다운로드 가능한 프로젝트에 대한 많은 요청을 받은 후, 해당 게시물에 첨부했습니다. 아래 링크에서 다운로드하십시오.

서블릿 필터 예제 프로젝트 다운로드

다음 기사를 확인하십시오. Servlet Listener에 관한 시리즈의 다음 기사입니다. 업데이트 Struts 2는 클라이언트 요청을 가로채어 해당 액션 클래스로 전달하기 위해 Servlet Filter를 사용하며, 이를 Struts 2 Interceptor라고합니다. Struts 2 초보자 튜토리얼를 확인하세요.

Source:
https://www.digitalocean.com/community/tutorials/java-servlet-filter-example-tutorial