Java Servletフィルタは、クライアントのリクエストを傍受し、いくつかの前処理を行うために使用されます。また、レスポンスを傍受し、ウェブアプリケーションのクライアントに送信する前にポスト処理を行うこともできます。これはWebアプリケーションチュートリアルシリーズの4番目の記事であり、以前の記事もチェックしてみてください。
Servletフィルタ
この記事では、JavaでのServletフィルタについて学びます。さまざまなServletフィルタの使用法、フィルタの作成方法、およびシンプルなウェブアプリケーションでの使用法について説明します。
-
サーブレットフィルターをなぜ使用するのですか?
前の記事では、ウェブアプリケーションでセッションを管理する方法を学びました。ユーザーセッションが有効な場合にのみリソースにアクセスできるようにするには、サーブレットセッション属性を使用することができます。このアプローチはシンプルですが、多くのサーブレットとJSPがある場合、冗長なコードのためにメンテナンスが困難になります。将来的に属性名を変更したい場合、セッション認証が行われているすべての場所を変更する必要があります。それがサーブレットフィルターがある理由です。サーブレットフィルターは、サーブレットがリクエストを受け取る前にインターセプトおよび処理するために使用できるプラグイン可能なJavaコンポーネントです。サーブレットのコードが終了し、コンテナがクライアントにレスポンスを送信する前のレスポンスを処理します。サーブレットフィルターでできる一般的なタスクは次のとおりです:
- リクエストパラメータをログファイルに記録する。
- リソースへのリクエストの認証と認可。
- サーブレットに送信する前に、リクエストボディやヘッダーのフォーマットを変更する。
- クライアントに送信されるレスポンスデータの圧縮。
- クッキーやヘッダー情報などを追加してレスポンスを変更する。
先ほど述べたように、サーブレットフィルターはプラグイン可能で、デプロイメント記述子(web.xml)ファイルで設定されます。サーブレットとフィルターは互いに気づいていないため、web.xmlを編集するだけでサーブレットフィルターを追加または削除することができます。単一のリソースに対して複数のフィルターを持つことができ、web.xmlで単一のリソースに対してフィルターチェーンを作成することができます。サーブレットフィルターは、
javax.servlet.Filter
インターフェースを実装することで作成できます。 -
Servlet Filterインターフェース
Servlet Filterインターフェースは、Servletインターフェースに似ており、独自のサーブレットフィルタを作成するために実装する必要があります。Servlet Filterインターフェースには、フィルタのライフサイクルメソッドが含まれており、サーブレットコンテナによって管理されます。Servlet Filterインターフェースのライフサイクルメソッドは以下の通りです:
- void init(FilterConfig paramFilterConfig) – コンテナがフィルタを初期化する際に呼び出されるメソッドです。このメソッドはフィルタのライフサイクルで一度だけ呼び出され、このメソッドでリソースの初期化を行う必要があります。FilterConfigはコンテナによって初期化パラメータとサーブレットコンテキストオブジェクトを提供するために使用されます。このメソッドではServletExceptionをスローすることができます。
- doFilter(ServletRequest paramServletRequest, ServletResponse paramServletResponse, FilterChain paramFilterChain) – コンテナがリソースにフィルタを適用する必要があるたびに呼び出されるメソッドです。コンテナはフィルタに対してリクエストとレスポンスオブジェクトの参照を引数として提供します。FilterChainはチェーン内の次のフィルタを呼び出すために使用されます。これはChain of Responsibilityパターンの素晴らしい例です。
- void destroy() – コンテナがフィルタインスタンスを解放する際にdestroy()メソッドが呼び出されます。このメソッドでは、フィルタが開いたリソースをクローズすることができます。このメソッドはフィルタのライフタイムで一度だけ呼び出されます。
-
Servlet WebFilterアノテーション
javax.servlet.annotation.WebFilter
はServlet 3.0で導入され、このアノテーションを使用してサーブレットフィルタを宣言することができます。このアノテーションを使用して、初期化パラメータ、フィルタ名と説明、サーブレット、URLパターン、ディスパッチャータイプを定義することができます。フィルタの設定を頻繁に変更する場合は、web.xmlを使用する方が良いです。それによってフィルタクラスを再コンパイルする必要がありません。参照:Javaアノテーションチュートリアル -
web.xmlでのServletフィルターの設定
以下のように、web.xmlでServletフィルターを宣言することができます。
<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>
以下のように、Filterをサーブレットクラスまたはurlパターンにマッピングすることができます。
<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-patternを処理し、その後servlet-nameを処理します。したがって、フィルターが特定の順序で実行されることを確認する場合は、フィルターマッピングの定義に特に注意を払う必要があります。Servletフィルターは通常、クライアントリクエストに対して使用されますが、RequestDispatcherでもフィルターを適用したい場合があります。その場合は、dispatcher要素を使用します。可能な値はREQUEST、FORWARD、INCLUDE、ERROR、ASYNCです。dispatcherが定義されていない場合、クライアントリクエストにのみ適用されます。
-
ログ記録とセッションの検証のためのServletフィルタの例
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. [](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
```
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 {
// userIDと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");
//セッションを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. [](https://journaldev.nyc3.cdn.digitaloceanspaces.com/2013/08/Servlet-Filter-Login.png) [](https://journaldev.nyc3.cdn.digitaloceanspaces.com/2013/08/Servlet-Filter-Login-Success.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のServletフィルタです。これはJava EEウェブアプリケーションの重要な機能の一つであり、様々なサーブレットで実行される共通のタスクに使用するべきです。今後の投稿では、サーブレットリスナーやクッキーについても説明します。更新:ダウンロード可能なプロジェクトのリクエストが多かったため、以下のリンクからダウンロードしてください。
Servletリスナーに関する次の記事をチェックしてください。 更新 Struts 2は、クライアントのリクエストをインターセプトし、適切なアクションクラスに転送するためにServletフィルタを使用します。これらはStruts 2インターセプタと呼ばれます。Struts 2初心者チュートリアルをご覧ください。
Source:
https://www.digitalocean.com/community/tutorials/java-servlet-filter-example-tutorial