웹사이트 검색

Java 서블릿 필터 예제 자습서


Java 서블릿 필터는 클라이언트 요청을 가로채고 일부 사전 처리를 수행하는 데 사용됩니다. 또한 웹 애플리케이션에서 클라이언트에 보내기 전에 응답을 가로채고 사후 처리를 수행할 수 있습니다. 이것은 Web Applications Tutorial 시리즈의 네 번째 기사입니다. 이전 기사도 확인하고 싶을 수 있습니다.

  1. 자바 웹 애플리케이션
  2. 자바 서블릿 자습서
  3. 서블릿 세션 관리

서블릿 필터

이 기사에서는 Java의 서블릿 필터에 대해 알아봅니다. 서블릿 필터의 다양한 사용법, 필터를 만드는 방법, 간단한 웹 애플리케이션으로 사용법을 배울 것입니다.

서블릿 필터가 있는 이유는 무엇입니까?\n\n\n서블릿 필터 인터페이스\n\n\n서블릿 WebFilter 주석 web.xml의 서블릿 필터 구성\n\n\n로깅 및 세션 유효성 검사를 위한 서블릿 필터 예\n\n\n서블릿 필터가 있는 이유는 무엇입니까?\n지난 기사에서 우리는 웹 애플리케이션에서 세션을 관리하는 방법을 배웠고 사용자 세션이 유효한 경우에만 리소스에 액세스할 수 있도록 하려면 서블릿 세션 속성을 사용하여 이를 달성할 수 있습니다. 접근 방식은 간단하지만 서블릿과 JSP가 많으면 중복 코드로 인해 유지 관리가 어려워집니다. 나중에 속성 이름을 변경하려면 세션 인증이 있는 모든 위치를 변경해야 합니다. 이것이 서블릿 필터가 있는 이유입니다. 서블릿 필터는 서블릿 코드가 완료된 후 컨테이너가 클라이언트에 응답을 다시 보내기 전에 요청이 서블릿으로 전송되고 응답하기 전에 요청을 가로채고 처리하는 데 사용할 수 있는 플러그형 Java 구성 요소입니다. 서블릿 필터로 수행할 수 있는 몇 가지 일반적인 작업은 다음과 같습니다.\n\n요청 매개변수를 로그 파일에 기록합니다.\n리소스 요청의 인증 및 권한 부여.\n요청 본문 또는 헤더를 서블릿으로 보내기 전에 형식화.\n클라이언트에 보낸 응답 데이터를 압축합니다.\n일부 쿠키, 헤더 정보 등을 추가하여 응답을 변경합니다.\n\n앞에서 언급했듯이 서블릿 필터는 플러그형이며 배포 설명자(web.xml) 파일에 구성되어 있습니다. 서블릿과 필터는 모두 서로를 인식하지 못하며 web.xml을 편집하여 서블릿 필터를 추가하거나 제거할 수 있습니다. 단일 리소스에 대해 여러 필터를 가질 수 있으며 web.xml에서 단일 리소스에 대한 필터 체인을 만들 수 있습니다. javax.servlet.Filter 인터페이스를 구현하여 서블릿 필터를 생성할 수 있습니다.\n\n\n서블릿 필터 인터페이스\nServlet Filter 인터페이스는 Servlet 인터페이스와 유사하며 이를 구현하여 자체 Servlet 필터를 생성해야 합니다. Servlet Filter 인터페이스는 Filter의 라이프사이클 메소드를 포함하며 서블릿 컨테이너에서 관리합니다. 서블릿 필터 인터페이스 수명 주기 방법은 다음과 같습니다.\n\nvoid init(FilterConfig paramFilterConfig) - 컨테이너가 필터를 초기화할 때 호출되는 메서드입니다. 이 메서드는 필터의 수명 주기에서 한 번만 호출되며 이 메서드의 모든 리소스를 초기화해야 합니다. FilterConfig는 필터에 초기 매개변수 및 서블릿 컨텍스트 객체를 제공하기 위해 컨테이너에서 사용됩니다. 이 메소드에서 ServletException을 던질 수 있습니다. doFilter(ServletRequest paramServletRequest, ServletResponse paramServletResponse, FilterChain paramFilterChain) - 리소스에 필터를 적용해야 할 때 컨테이너가 매번 호출하는 메서드입니다. 컨테이너는 필터에 대한 요청 및 응답 개체 참조를 인수로 제공합니다. FilterChain은 체인에서 다음 필터를 호출하는 데 사용됩니다. 이것은 책임 사슬 패턴의 좋은 예입니다. void destroy() - 컨테이너가 Filter 인스턴스를 오프로드할 때 destroy() 메서드를 호출합니다. 필터로 열린 모든 리소스를 닫을 수 있는 방법입니다. 이 메서드는 필터 수명 동안 한 번만 호출됩니다.

서블릿 WebFilter 주석

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

web.xml의 서블릿 필터 구성

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

<filter>
  <filter-name>RequestLoggingFilter</filter-name> <!-- mandatory -->
  <filter-class>com.journaldev.servlet.filters.RequestLoggingFilter</filter-class> <!-- mandatory -->
  <init-param> <!-- optional -->
  <param-name>test</param-name>
  <param-value>testValue</param-value>
  </init-param>
</filter>

필터를 아래와 같이 서블릿 클래스 또는 URL 패턴에 매핑할 수 있습니다.

<filter-mapping>
  <filter-name>RequestLoggingFilter</filter-name> <!-- mandatory -->
  <url-pattern>/*</url-pattern> <!-- either url-pattern or servlet-name is mandatory -->
  <servlet-name>LoginServlet</servlet-name>
  <dispatcher>REQUEST</dispatcher>
</filter-mapping>

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

로깅 및 세션 유효성 검사를 위한 서블릿 필터 예

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.digitaloceanspaces.com/2013/08/Servlet-Filter-Example-Project.png)](https://journaldev.nyc3.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:

```
<!DOCTYPE html>
<html>
<head>
<meta charset="US-ASCII">
<title>Login Page</title>
</head>
<body>

<form action="LoginServlet" method="post">

Username: <input type="text" name="user">
<br>
Password: <input type="password" name="pwd">
<br>
<input type="submit" value="Login">
</form>
</body>
</html>
```

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 {

		// get request parameters for userID and password
		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");
			//setting session to expiry in 30 mins
			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("<font color=red>Either user name or password is wrong.</font>");
			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"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Login Success Page</title>
</head>
<body>
<%
//allow access only if session exists
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();
}
}
%>
<h3>Hi <%=userName %>, Login successful. Your Session ID=<%=sessionID %></h3>
<br>
User=<%=user %>
<br>
<a href="CheckoutPage.jsp">Checkout Page</a>
<form action="LogoutServlet" method="post">
<input type="submit" value="Logout" >
</form>
</body>
</html>
```

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"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Login Success Page</title>
</head>
<body>
<%
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();
}
}
%>
<h3>Hi <%=userName %>, do the checkout.</h3>
<br>
<form action="LogoutServlet" method="post">
<input type="submit" value="Logout" >
</form>
</body>
</html>
```

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;
    		}
    	}
    	}
    	//invalidate the session if exists
    	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<String> 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()+"}");
			}
		}
		// pass the request along the filter chain
		chain.doFilter(request, response);
	}

	public void destroy() {
		//we can close resources here
	}

}
```

```
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{
			// pass the request along the filter chain
			chain.doFilter(request, response);
		}
		
		
	}

	public void destroy() {
		//close any resources here
	}

}
```

Notice that we are not authenticating any HTML page or LoginServlet. Now we will configure these filters mapping in the web.xml file.

```
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns="https://java.sun.com/xml/ns/javaee" xsi:schemaLocation="https://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
  <display-name>ServletFilterExample</display-name>
  <welcome-file-list>
    <welcome-file>login.html</welcome-file>
  </welcome-file-list>
  
  <filter>
    <filter-name>RequestLoggingFilter</filter-name>
    <filter-class>com.journaldev.servlet.filters.RequestLoggingFilter</filter-class>
  </filter>
  <filter>
    <filter-name>AuthenticationFilter</filter-name>
    <filter-class>com.journaldev.servlet.filters.AuthenticationFilter</filter-class>
  </filter>
  
  <filter-mapping>
    <filter-name>RequestLoggingFilter</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
  </filter-mapping>
  <filter-mapping>
    <filter-name>AuthenticationFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
</web-app>
```

Now when we will run our application, we will get response pages like below images. [![Servlet Filter Example](https://journaldev.nyc3.digitaloceanspaces.com/2013/08/Servlet-Filter-Login-450x141.png)](https://journaldev.nyc3.digitaloceanspaces.com/2013/08/Servlet-Filter-Login.png) [![Servlet Filter, Java Filter](https://journaldev.nyc3.digitaloceanspaces.com/2013/08/Servlet-Filter-Login-Success-450x229.png)](https://journaldev.nyc3.digitaloceanspaces.com/2013/08/Servlet-Filter-Login-Success.png) [![Servlet Filter Tutorial, Java Servlet Filter](https://journaldev.nyc3.digitaloceanspaces.com/2013/08/Servlet-Filter-Checkout-450x181.png)](https://journaldev.nyc3.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 웹 애플리케이션의 중요한 기능 중 하나이며 다양한 서블릿에서 수행하는 일반적인 작업에 사용해야 합니다. 향후 게시물에서는 서블릿 리스너와 쿠키에 대해 살펴보겠습니다. 업데이트: 다운로드 가능한 프로젝트에 대한 많은 요청을 받은 후 게시물에 첨부했습니다. 아래 링크에서 다운로드하십시오.

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

Struts 2 Beginners Tutorial에 대한 시리즈의 다음 기사를 확인하십시오.