
サーブレット&JSPの基本|サーブレット処理を効率化するフィルタ
毎回書いていた共通処理を1か所にまとめる。フィルタでサーブレットの前後に処理を差し込み、開発を効率化しよう
ServletとJSPでWebアプリケーションを作っていると、複数のサーブレットで同じような処理を書く場面が出てきます。
たとえば、POST送信された日本語のリクエストパラメータを正しく扱うために、サーブレットのdoPostメソッド内でrequest.setCharacterEncoding("UTF-8")を書くことがあります。
フォームを1つだけ作っている段階なら、それほど大変ではありません。
しかし、ログイン処理、投稿処理、申込処理、検索処理、登録処理など、POSTで値を受け取るサーブレットが増えてくると、毎回同じ処理を書くことになります。
同じ処理を何度も書くと、書き忘れが起こりやすくなります。
たとえば、あるサーブレットでは文字コードを指定していたのに、別のサーブレットでは指定を忘れてしまうと、日本語の入力値が文字化けすることがあります。
このような共通処理をまとめて扱うために用意されているのが、フィルタです。
フィルタは、サーブレットのdoGetメソッドやdoPostメソッドが実行される前後に、自動的に処理を差し込める特殊なクラスです。
サーブレット本体に処理を書くのではなく、サーブレットの手前にフィルタを置くことで、文字コード指定、ログイン確認、ログ出力、共通チェックなどをまとめて実行できます。
この記事では、フィルタの基本的な考え方、前処理と後処理、複数のフィルタをつなげるフィルタチェーン、文字コード指定フィルタの作成方法を学習していきます。
フィルタとは
フィルタとは、サーブレットやJSPなどにリクエストが届いたとき、その処理の前後に自動で実行されるクラスです。
通常、ブラウザからサーブレットへリクエストが届くと、サーブレットのdoGetメソッドやdoPostメソッドが実行されます。
フィルタを設定すると、サーブレットが実行される前にフィルタの処理を通すことができます。
さらに、サーブレットの処理が終わったあとに、もう一度フィルタ側へ戻って後処理を行うこともできます。
フィルタの基本的な流れ
| 順番 | 実行される処理 |
|---|---|
| 1 | フィルタの前処理が実行される |
| 2 | サーブレットのdoGetまたはdoPostが実行される |
| 3 | フィルタの後処理が実行される |
| 4 | レスポンスがブラウザへ返される |
フィルタは、サーブレットの処理そのものを置き換えるものではありません。
サーブレットの前後に処理を差し込むための仕組みです。
図1:サーブレットの前後で動作するフィルタ

この図から分かること
フィルタは、ブラウザからのリクエストがサーブレットへ届く前に実行できます。
たとえば、リクエストパラメータの文字コード指定をフィルタに書いておけば、サーブレットのdoPostメソッドが動く前にrequest.setCharacterEncoding("UTF-8")を実行できます。
その結果、それぞれのサーブレットで毎回同じ文字コード指定を書く必要が少なくなります。
サーブレットは本来の処理に集中でき、共通処理はフィルタにまとめられます。
フィルタが役立つ場面
フィルタは、複数のサーブレットで共通して行いたい処理に向いています。
たとえば、文字コード指定は多くのサーブレットで必要になります。
ログイン済みかどうかの確認も、メイン画面、投稿画面、管理画面など、複数のサーブレットで必要になることがあります。
フィルタに向いている処理
| 処理 | 内容 |
|---|---|
| 文字コード指定 | POST送信された日本語を文字化けしないように扱う |
| ログイン確認 | ログインしていない利用者をログイン画面へ戻す |
| アクセスログ出力 | どのURLにアクセスされたかを記録する |
| 共通チェック | すべてのリクエストに対して同じ確認を行う |
| 後処理 | サーブレット実行後にログ出力やレスポンス加工を行う |
フィルタを使うと、同じ処理を複数のサーブレットに何度も書かずに済みます。
これにより、書き忘れを防ぎやすくなり、プログラム全体の見通しもよくなります。
フィルタを使わない場合の問題
フィルタを使わない場合、共通処理を各サーブレットに直接書くことになります。
たとえば、POST送信を受け取るサーブレットが5つある場合、それぞれのdoPostメソッドにrequest.setCharacterEncoding("UTF-8")を書く必要があります。
フィルタを使わない場合
| サーブレット | 必要な処理 |
|---|---|
| LoginServlet | 文字コード指定を書く |
| EntryServlet | 文字コード指定を書く |
| ProfileServlet | 文字コード指定を書く |
| MessageServlet | 文字コード指定を書く |
| CommentServlet | 文字コード指定を書く |
このように同じ処理があちこちに散らばると、あとから修正するときも大変です。
たとえば、共通処理の内容を変えたい場合、複数のファイルを確認して修正しなければなりません。
一方、フィルタを使えば、共通処理を1つのクラスにまとめられます。
複数のサーブレットに共通処理を設定できる
フィルタは、特定のサーブレットだけでなく、複数のサーブレットにまとめて設定できます。
たとえば、ログイン確認フィルタを作成して、ログインが必要なサーブレットに適用するとします。
すると、各サーブレットの中にログイン確認処理を毎回書かなくても、リクエストが届く前にフィルタ側でログイン状態を確認できます。
ログイン確認フィルタのイメージ
| 状態 | フィルタの動き |
|---|---|
| ログイン済み | サーブレットへ処理を進める |
| 未ログイン | ログイン画面へリダイレクトする |
このように、フィルタはサーブレットの前に立つ受付のような役割を持たせることができます。
サーブレット本体は、ログイン済みであることを前提に処理を書きやすくなります。
図2:共通処理をフィルタにまとめる

この図から分かること
フィルタを使うと、複数のサーブレットに共通する処理を1つのクラスにまとめられます。
たとえば、ログイン確認処理をフィルタに書いておけば、ProfileServlet、MessageServlet、AdminServletなどの各サーブレットに同じ確認処理を書く必要が少なくなります。
未ログインの場合はフィルタでログイン画面へ戻し、ログイン済みの場合だけサーブレットへ処理を進める、という構成にできます。
フィルタチェーンとは
1つのサーブレットに対して、複数のフィルタを設定することもできます。
複数のフィルタが順番に実行される仕組みを、フィルタチェーンと呼びます。
たとえば、次のような順番で処理を通すことができます。
フィルタチェーンの例
| 順番 | 処理 |
|---|---|
| 1 | 文字コード指定フィルタ |
| 2 | ログ出力フィルタ |
| 3 | ログイン確認フィルタ |
| 4 | サーブレット |
| 5 | ログイン確認フィルタの後処理 |
| 6 | ログ出力フィルタの後処理 |
| 7 | 文字コード指定フィルタの後処理 |
フィルタチェーンでは、サーブレットへ進む前に複数のフィルタを順番に通ります。
サーブレットの処理が終わると、今度は逆向きにフィルタへ戻って後処理を行います。
chain.doFilterの役割
フィルタの中で重要なのが、chain.doFilter(request, response)です。
この処理を実行すると、次のフィルタ、または対象のサーブレットへ処理が進みます。
chain.doFilterの前後
| 書く場所 | 実行タイミング |
|---|---|
| chain.doFilter(request, response)より前 | サーブレット実行前の前処理 |
| chain.doFilter(request, response) | 次のフィルタまたはサーブレットへ進む |
| chain.doFilter(request, response)より後 | サーブレット実行後の後処理 |
文字コード指定は、サーブレットでrequest.getParameterを実行する前に済ませる必要があります。
そのため、request.setCharacterEncoding("UTF-8")はchain.doFilter(request, response)より前に書きます。
フィルタの作成に必要なもの
フィルタは、HttpFilterクラスを継承して作成します。
また、フィルタとして動かすためにWebFilterアノテーションを付けます。
フィルタ作成の基本
| 項目 | 内容 |
|---|---|
| アノテーション | @WebFilter |
| 継承するクラス | HttpFilter |
| 実装するメソッド | doFilter |
| 処理を進める命令 | chain.doFilter(request, response) |
| 主な用途 | サーブレットの前処理や後処理 |
WebFilterアノテーションでは、どのURLに対してフィルタを適用するかを指定します。
たとえば、すべてのリクエストに適用する場合は、/*を指定します。
WebFilterアノテーションで対象を指定する
フィルタは、WebFilterアノテーションで適用先を指定します。
URLパターンを指定することで、どのリクエストに対してフィルタを動かすかを決められます。
WebFilterの指定例
| 指定 | 適用される対象 |
|---|---|
| @WebFilter("/ProfileServlet") | URLパターンが/ProfileServletのサーブレット |
| @WebFilter("/member/*") | /member/から始まるURL |
| @WebFilter("/*") | Webアプリケーション内のすべてのURL |
/*を指定すると、すべてのサーブレットだけでなく、JSPファイルやHTMLファイルにもフィルタが適用されます。
そのため、Webアプリケーション全体に共通で行いたい処理を書くときに便利です。
文字コードを指定するフィルタを作成する
ここでは、リクエストパラメータの文字コードをUTF-8に指定するフィルタを作成します。
このフィルタを作成すると、対象となるサーブレットでは、毎回request.setCharacterEncoding("UTF-8")を書く必要が少なくなります。
文字コード指定フィルタの動き
| タイミング | 処理 |
|---|---|
| サーブレット実行前 | request.setCharacterEncoding("UTF-8")を実行する |
| その後 | chain.doFilter(request, response)でサーブレットへ進む |
| サーブレット側 | request.getParameterで日本語を取得する |
文字コード指定は、request.getParameterより前に行う必要があります。
そのため、フィルタの前処理として書くのが自然です。
リクエストパラメータの文字コードを指定するフィルタの例
ファイル名: SetEncodingFilter.java
package filter;
import java.io.IOException;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.HttpFilter;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
@WebFilter("/*")
public class SetEncodingFilter extends HttpFilter implements Filter {
private static final long serialVersionUID = 1L;
public void doFilter(HttpServletRequest request,
HttpServletResponse response,
FilterChain chain)
throws IOException, ServletException {
// リクエストパラメータの文字コードを指定
request.setCharacterEncoding("UTF-8");
// 次のフィルタまたはサーブレットへ処理を進める
chain.doFilter(request, response);
}
}SetEncodingFilter.javaは、filterパッケージに作成します。
WebFilter("/*")を指定しているため、Webアプリケーション内のすべてのURLに対して、このフィルタが適用されます。
doFilterメソッドでは、まずrequest.setCharacterEncoding("UTF-8")を実行しています。
その後、chain.doFilter(request, response)によって、次のフィルタまたは対象のサーブレットへ処理を進めています。
SetEncodingFilter.javaのポイント
SetEncodingFilter.javaでは、サーブレット実行前の前処理として文字コード指定を行っています。
処理のポイント
| 処理 | 内容 |
|---|---|
| @WebFilter("/*") | すべてのURLにフィルタを適用する |
| extends HttpFilter | HTTP用のフィルタとして作成する |
| doFilter | フィルタの処理を書く |
| request.setCharacterEncoding("UTF-8") | リクエストパラメータの文字コードを指定する |
| chain.doFilter(request, response) | 次の処理へ進める |
request.setCharacterEncoding("UTF-8")をchain.doFilter(request, response)より前に書いている点が大切です。
サーブレット側でrequest.getParameterを実行する前に文字コードを指定しておくことで、日本語の入力値を正しく扱いやすくなります。
図3:文字コード指定フィルタの処理順

この図から分かること
日本語を含むフォーム送信では、サーブレット側でrequest.getParameterを実行する前に文字コードを指定することが大切です。
SetEncodingFilter.javaでは、chain.doFilter(request, response)より前にrequest.setCharacterEncoding("UTF-8")を実行しています。
その後、ProfileServlet.javaへ処理が進むため、ProfileServlet.javaでは文字コード指定を毎回書かなくても、日本語のリクエストパラメータを扱いやすくなります。
フィルタの動作を確認するサーブレットを作成する
次に、フィルタの動作を確認するためのサーブレットを作成します。
今回は、プロフィール登録をイメージしたProfileServlet.javaを作成します。
このサーブレットでは、doGetメソッドで入力フォームを表示し、doPostメソッドで送信された値を受け取って表示します。
文字コード指定はSetEncodingFilter.javaで行うため、ProfileServlet.javaのdoPostメソッドにはrequest.setCharacterEncoding("UTF-8")を書きません。
これにより、フィルタによって文字コード指定が行われていることを確認できます。
フィルタの動作を確認するサーブレットクラスの例
ファイル名: ProfileServlet.java
package servlet;
import java.io.IOException;
import java.io.PrintWriter;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
@WebServlet("/ProfileServlet")
public class ProfileServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html; charset=UTF-8");
PrintWriter out = response.getWriter();
out.println("<!DOCTYPE html>");
out.println("<html>");
out.println("<head>");
out.println("<meta charset=\"UTF-8\">");
out.println("<title>プロフィール登録</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>プロフィール登録</h1>");
out.println("<form action=\"ProfileServlet\" method=\"post\">");
out.println("<p>名前:<input type=\"text\" name=\"name\"></p>");
out.println("<p>学習中の技術:");
out.println("<input type=\"radio\" name=\"skill\" value=\"Servlet\">Servlet");
out.println("<input type=\"radio\" name=\"skill\" value=\"JSP\">JSP");
out.println("<input type=\"radio\" name=\"skill\" value=\"JavaBeans\">JavaBeans");
out.println("</p>");
out.println("<p>ひとこと:</p>");
out.println("<p><textarea name=\"comment\" rows=\"4\" cols=\"40\"></textarea></p>");
out.println("<input type=\"submit\" value=\"登録\">");
out.println("</form>");
out.println("</body>");
out.println("</html>");
}
protected void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
// 文字コード指定はSetEncodingFilterで行うため、
// ここではrequest.setCharacterEncoding("UTF-8")を書かない
// リクエストパラメータを取得
String name = request.getParameter("name");
String skill = request.getParameter("skill");
String comment = request.getParameter("comment");
response.setContentType("text/html; charset=UTF-8");
PrintWriter out = response.getWriter();
out.println("<!DOCTYPE html>");
out.println("<html>");
out.println("<head>");
out.println("<meta charset=\"UTF-8\">");
out.println("<title>プロフィール登録結果</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>プロフィール登録結果</h1>");
out.println("<p>名前:" + name + "</p>");
out.println("<p>学習中の技術:" + skill + "</p>");
out.println("<p>ひとこと:" + comment + "</p>");
out.println("<a href=\"ProfileServlet\">入力画面へ戻る</a>");
out.println("</body>");
out.println("</html>");
}
}ProfileServlet.javaは、servletパッケージに作成します。
プロジェクト名をstudyとしている場合、ブラウザから次のURLで実行できます。
ブラウザの表示例:プロフィール登録

ブラウザの表示例:プロフィール登録

ProfileServlet.javaのポイント
ProfileServlet.javaでは、doGetメソッドでフォームを表示し、doPostメソッドでフォームから送信された値を取得しています。
ProfileServlet.javaで行っていること
| メソッド | 内容 |
|---|---|
| doGet | プロフィール登録フォームを表示する |
| doPost | 送信された名前、学習中の技術、ひとことを取得して表示する |
doPostメソッドでは、request.getParameterを使って値を取得しています。
しかし、request.setCharacterEncoding("UTF-8")は書いていません。
文字コード指定は、先ほど作成したSetEncodingFilter.javaがサーブレット実行前に行ってくれるためです。
動作確認の手順
SetEncodingFilter.javaとProfileServlet.javaを作成したら、動作を確認します。
確認手順
| 手順 | 内容 |
|---|---|
| 1 | 動的Webプロジェクトstudyにfilterパッケージとservletパッケージを作成する |
| 2 | filterパッケージにSetEncodingFilter.javaを作成する |
| 3 | servletパッケージにProfileServlet.javaを作成する |
| 4 | studyをTomcat11_Java25に追加する |
| 5 | サーバを起動する |
| 6 | ブラウザでhttp://localhost:8080/study/ProfileServletへアクセスする |
| 7 | 名前やひとことに日本語を入力して登録する |
| 8 | 結果画面で日本語が正しく表示されることを確認する |
確認するときは、ProfileServlet.javaのdoPostメソッドにrequest.setCharacterEncoding("UTF-8")を書いていない点に注目しましょう。
それでも日本語が正しく表示されれば、SetEncodingFilter.javaの前処理が働いています。
フィルタの作り方
フィルタは、次の流れで作成できます。
フィルタ作成の手順
| 手順 | 内容 |
|---|---|
| 1 | WebFilterアノテーションを付け、適用するURLパターンを指定する |
| 2 | HttpFilterクラスを継承する |
| 3 | doFilterメソッドを実装する |
| 4 | chain.doFilter(request, response)の前後に前処理や後処理を書く |
今回のSetEncodingFilter.javaでは、chain.doFilter(request, response)より前にrequest.setCharacterEncoding("UTF-8")を書きました。
これは、サーブレットでリクエストパラメータを取得する前に実行したい処理だからです。
後処理を書きたい場合は、chain.doFilter(request, response)より後に処理を書きます。
Eclipseでフィルタを作成する場合
Eclipseには、フィルタ作成を補助する機能があります。
Eclipseの画面からフィルタを作成すると、WebFilterアノテーション、HttpFilterの継承、doFilterメソッドのひな形などを自動で作成できます。
Eclipseで補助される内容
| 作業 | Eclipseの補助 |
|---|---|
| フィルタクラスの作成 | クラスの基本形を作成できる |
| WebFilterアノテーション | URLパターンを指定して付与できる |
| HttpFilterの継承 | 必要な継承関係を設定できる |
| doFilterメソッド | ひな形を作成できる |
| import文 | 必要なクラスを自動で追加できる |
Eclipseを使うと、メソッド名やimport文の書き間違いを減らしやすくなります。
ただし、フィルタの本質は、chain.doFilter(request, response)の前後にどの処理を書くかです。
JSPファイルやHTMLファイルにもフィルタを適用できる
フィルタは、サーブレットだけに適用されるものではありません。
WebFilterアノテーションで指定したURLパターンに一致すれば、JSPファイルやHTMLファイルにも適用できます。
たとえば、トップ画面のindex.jspだけにフィルタを適用したい場合は、次のように指定できます。
@WebFilter("/index.jsp")
また、すべてのURLに適用したい場合は、次のように指定します。
@WebFilter("/*")
フィルタの適用対象
| 指定 | 適用対象 |
|---|---|
| @WebFilter("/index.jsp") | index.jsp |
| @WebFilter("/ProfileServlet") | ProfileServlet |
| @WebFilter("/*") | サーブレット、JSP、HTMLなどWebアプリケーション内のすべてのURL |
今回のSetEncodingFilter.javaでは、@WebFilter("/*")を指定しています。
そのため、ProfileServletだけでなく、Webアプリケーション内のさまざまなリクエストに対してフィルタが動作します。
フィルタを使うときに意識したいこと
フィルタは便利ですが、何でもフィルタに書けばよいというわけではありません。
フィルタには、複数の処理で共通して必要になるものや、サーブレットの前後にまとめて差し込みたい処理を書くのが向いています。
フィルタに向いている処理と向いていない処理
| 種類 | 例 |
|---|---|
| 向いている処理 | 文字コード指定、ログイン確認、アクセスログ、共通チェック |
| 向いていない処理 | 特定画面だけの表示内容作成、個別業務処理、1つのサーブレットだけで完結する処理 |
フィルタに共通処理を任せることで、サーブレット側のコードをすっきりさせられます。
一方で、フィルタに処理を詰め込みすぎると、どこで何が実行されているのか分かりにくくなることもあります。
どのサーブレットに対して、どのタイミングで、何のためにフィルタを適用するのかを意識して使いましょう。
サーブレットとフィルタの役割分担
最後に、サーブレットとフィルタの役割を整理しておきます。
役割の違い
| 種類 | 主な役割 |
|---|---|
| サーブレット | リクエストを受け取り、画面表示や業務処理を行う |
| フィルタ | サーブレットの前後に共通処理を差し込む |
| JSP | サーブレットから渡された情報を画面として表示する |
サーブレットは、利用者の操作に応じた中心的な処理を担当します。
フィルタは、そのサーブレットの前後で共通処理を担当します。
JSPは、画面表示を担当します。
このように役割を分けることで、Webアプリケーションの処理を整理しやすくなります。
フィルタを使えるようになると、毎回書いていた共通処理をまとめられるため、ServletとJSPを使った開発をより効率よく進められます。
