Servlet/JSP チートシート

Javaエンジニアのための実践リファレンス

Servlet/JSPとは?

ServletはJava EEでサーバーサイドのWebアプリケーションを開発するための基盤技術です。JSP(JavaServer Pages)はHTML内にJavaコードを埋め込んでビューを構築する技術で、ServletとMVCパターンで連携します。ServletがController・Model、JSPがViewを担当する構成が一般的です。

Java EE サーバーサイド MVCパターン Tomcat/GlassFish

Servlet基本構造

HttpServletを継承し、doGet/doPostメソッドでリクエストを処理

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;

@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request,
                         HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html; charset=UTF-8");
        PrintWriter out = response.getWriter();
        out.println("

Hello, Servlet!

"); } }

@WebServletアノテーションでURL マッピング

doGet: GETリクエスト処理

doPost: POSTリクエスト処理

JSP基本構文

<%@ page contentType="text/html; charset=UTF-8" %>

JSP Example

Hello, <%= request.getParameter("name") %>

<%-- コメント --%> <% String msg = "Welcome"; out.println(msg); %>

UserName: ${sessionScope.userName}

スクリプトレット

<% ... %>

式(Expression)

<%= ... %>

ディレクティブ

<%@ ... %>

式言語(EL)

${...}

リクエスト/レスポンス処理

リクエストパラメータ取得

// 単一パラメータ取得
String name = request.getParameter("name");

// 複数値取得
String[] hobbies = request.getParameterValues("hobby");

// 全パラメータマップ取得
Map params = request.getParameterMap();

レスポンス送信

// Content-Type設定
response.setContentType("text/html; charset=UTF-8");

// リダイレクト
response.sendRedirect("result.jsp");

// ステータスコード設定
response.setStatus(HttpServletResponse.SC_OK);

セッション管理

// セッション取得(なければ作成)
HttpSession session = request.getSession();

// 値の保存
session.setAttribute("user", userObj);

// 値の取得
User user = (User) session.getAttribute("user");

// セッション無効化
session.invalidate();

Forward/Include

// Forward(制御を移譲)
RequestDispatcher dispatcher =
    request.getRequestDispatcher("/result.jsp");
dispatcher.forward(request, response);

// Include(内容を含める)
dispatcher.include(request, response);

4つのスコープオブジェクト

Page Scope

JSPページ内のみ有効

pageContext.setAttribute("key", value);

ページが処理されている間のみ

Request Scope

リクエスト内で有効

request.setAttribute("key", value);

Forward先でも有効

Session Scope

セッション内で有効

session.setAttribute("key", value);

ブラウザセッション中有効

Application Scope

アプリ全体で共有

application.setAttribute("key", value);

アプリ起動中ずっと有効

JSP標準アクション・JSTL

JSP標準アクション

<%-- Forward --%>
<jsp:forward page="result.jsp" />

<%-- Include --%>
<jsp:include page="header.jsp" />

<%-- JavaBeans利用 --%>
<jsp:useBean id="user" class="com.example.User" scope="session" />
<jsp:setProperty name="user" property="name" value="Taro" />
<jsp:getProperty name="user" property="name" />

JSTL コアタグ

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<%-- 変数セット --%>
<c:set var="message" value="Hello JSTL" />

<%-- 条件分岐 --%>
<c:if test="${user.age >= 20}">
    成人です
</c:if>

<%-- ループ --%>
<c:forEach var="item" items="${itemList}">
    <li>${item.name}</li>
</c:forEach>

実務で役立つTips

XSS対策

ユーザー入力値を表示する際は必ずエスケープ処理(JSTL <c:out> または ${fn:escapeXml()})を使用

CSRF対策

POSTフォームには必ずトークンを含め、Servlet側でトークン検証を実施する

スクリプトレット削減

JSP内のJavaコードは最小限に。ロジックはServletやビジネスロジック層へ移動

接続プール

JDBCは直接使わず、DataSourceと接続プールを利用して性能と安定性を向上

MVCパターン実装フロー

1 ブラウザ → Servlet
2 Servlet → Model
3 Model → DB
4 Servlet → JSP
5 JSP → ブラウザ

Servlet(Controller)がリクエストを受け、Model(JavaBeans/DAO)でビジネスロジック実行後、JSP(View)にForwardして画面表示

よく使うパターン

ログインフォーム処理

@WebServlet("/login")
public class LoginServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request,
                          HttpServletResponse response)
            throws ServletException, IOException {
        String username = request.getParameter("username");
        String password = request.getParameter("password");

        // 認証処理(簡略版)
        if (authenticate(username, password)) {
            HttpSession session = request.getSession();
            session.setAttribute("user", username);
            response.sendRedirect("home.jsp");
        } else {
            request.setAttribute("error", "認証失敗");
            request.getRequestDispatcher("login.jsp")
                   .forward(request, response);
        }
    }
}

データ一覧表示

@WebServlet("/userlist")
public class UserListServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request,
                         HttpServletResponse response)
            throws ServletException, IOException {
        // DAOでデータ取得
        UserDAO dao = new UserDAO();
        List users = dao.findAll();

        // リクエストスコープに格納
        request.setAttribute("users", users);

        // JSPにForward
        request.getRequestDispatcher("userlist.jsp")
               .forward(request, response);
    }
}

フィルター(Filter)実装

@WebFilter("/*")
public class EncodingFilter implements Filter {
    public void doFilter(ServletRequest request,
                         ServletResponse response,
                         FilterChain chain)
            throws IOException, ServletException {
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html; charset=UTF-8");
        chain.doFilter(request, response);
    }
}

文字コード設定やログイン認証などの前処理を実装

リスナー(Listener)実装

@WebListener
public class AppListener implements ServletContextListener {
    public void contextInitialized(ServletContextEvent sce) {
        // アプリ起動時処理
        System.out.println("Application started");
    }

    public void contextDestroyed(ServletContextEvent sce) {
        // アプリ停止時処理
        System.out.println("Application stopped");
    }
}

アプリケーション起動・停止時の初期化処理を実装

よくあるエラーと解決策

文字化け発生

原因: 文字エンコーディング未設定

解決策: request.setCharacterEncoding("UTF-8"); をdoPost/doGetの最初に追加、またはFilterで一括設定

404エラー(Servletが見つからない)

原因: URLマッピングの誤り、または@WebServletアノテーション未指定

解決策: @WebServlet("/正しいパス")を確認、またはweb.xmlのservlet-mappingを確認

java.lang.IllegalStateException: Cannot forward after response has been committed

原因: レスポンス送信後にforwardしようとしている

解決策: forward前にout.flush()やresponse.sendRedirect()を呼ばない。forward後はreturnで処理を終了

NullPointerException(getAttribute()の結果がnull)

原因: スコープに値が設定されていない、またはスコープ範囲外でアクセス

解決策: setAttribute()で値を設定済みか確認。スコープの有効範囲を理解する

参考リンク