Servlet/JSPとは?
ServletはJava EEでサーバーサイドのWebアプリケーションを開発するための基盤技術です。JSP(JavaServer Pages)はHTML内にJavaコードを埋め込んでビューを構築する技術で、ServletとMVCパターンで連携します。ServletがController・Model、JSPがViewを担当する構成が一般的です。
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パターン実装フロー
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()で値を設定済みか確認。スコープの有効範囲を理解する