【Sevlet/JSP】クライアント/サーバーモデルとWebアプリケーションの仕組み

2025-08-04

はじめに

Webアプリケーション開発の基礎となるクライアント/サーバーモデルと、JSPがどのようにこのモデルの中で機能するかを理解することは、効果的なWebアプリケーションを作成する上で不可欠です。本記事では、既にHTTPプロトコルの基礎を理解している読者を対象に、JSPを用いたWebアプリケーション開発に必要なクライアント/サーバーモデルの詳細と、その内部動作について詳しく解説します。

第1章 クライアント/サーバーモデルの基本概念

1.1 クライアントとサーバーの役割分担

Webアプリケーションは、クライアント(ブラウザ)サーバーの明確な役割分担に基づいて動作します。

  • クライアントの主な役割:
  • ユーザーインターフェースの提供
  • ユーザー操作の受付
  • サーバーへのリクエスト送信
  • サーバーからのレスポンス表示
  • サーバーの主な役割:
  • クライアントからのリクエスト受信
  • ビジネスロジックの実行
  • データベースとの連携
  • クライアントへのレスポンス生成

1.2 クライアント/サーバー間の通信フロー

一般的なJSPアプリケーションのリクエスト処理フロー:

  1. ユーザーがブラウザでURLを入力またはリンクをクリック
  2. ブラウザがDNSルックアップを行い、サーバーIPを解決
  3. HTTPリクエストがサーバーに送信
  4. Webサーバー(Apache Tomcatなど)がリクエストを受信
  5. JSPコンテナが該当JSPページを処理
  6. サーバーサイドでJavaコード実行
  7. データベースとの連携(必要な場合)
  8. HTML生成
  9. HTTPレスポンスとしてクライアントに返送
  10. ブラウザがHTMLをレンダリング

1.3 ステートレスな通信の特性

HTTPはステートレスプロトコルであり、各リクエストは独立して扱われます。この特性は、以下のようなJSP開発における重要な概念につながります。

  • セッション管理の必要性: HttpSessionオブジェクトを使用
  • クッキーの利用: クライアント側に状態を保存
  • URLリライティング: セッションIDをURLに埋め込む

第2章 JSPにおけるHTTPプロトコルの詳細実装

2.1 JSPのライフサイクルとHTTP

JSPページはリクエストごとに以下のライフサイクルを経ます:

  1. 変換フェーズ: JSPファイルがServletソースコードに変換
  2. コンパイルフェーズ: 生成されたServletがJavaクラスにコンパイル
  3. 実行フェーズ:
  • jspInit(): 初期化
  • _jspService(): リクエスト処理(HTTPメソッドに応じて分岐)
  • jspDestroy(): 終了処理

2.2 HTTPリクエストの詳細解析

JSPで扱われるHTTPリクエストの主要コンポーネント:

リクエストラインの解析

<%
  String method = request.getMethod(); // "GET", "POST" etc.
  String uri = request.getRequestURI();
  String protocol = request.getProtocol();
%>

ヘッダー情報の取得

<%
  Enumeration headerNames = request.getHeaderNames();
  while(headerNames.hasMoreElements()) {
    String name = headerNames.nextElement();
    String value = request.getHeader(name);
    out.println(name + ": " + value + "
"); } %>

クエリパラメータの処理

<%
  // 単一パラメータ取得
  String param = request.getParameter("paramName");

  // 複数値パラメータ取得(チェックボックスなど)
  String[] values = request.getParameterValues("multiParam");
%>

2.3 HTTPレスポンスの制御

JSPでのレスポンス制御方法:

ステータスコード設定

<% response.setStatus(HttpServletResponse.SC_OK); %>
<% response.sendError(HttpServletResponse.SC_NOT_FOUND, "ページが見つかりません"); %>

ヘッダー設定

<% 
  response.setHeader("Cache-Control", "no-cache");
  response.setHeader("Pragma", "no-cache");
  response.setDateHeader("Expires", -1);
%>

コンテントタイプ設定

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

リダイレクト処理

<% response.sendRedirect("newLocation.jsp"); %>

2.4 各種HTTPメソッドの実装例

GETメソッドの処理

<%@ page import="java.util.Map" %>
<%
  if ("GET".equals(request.getMethod())) {
    Map params = request.getParameterMap();
    // GETパラメータ処理
  }
%>

POSTメソッドの処理

<%
  if ("POST".equals(request.getMethod())) {
    String username = request.getParameter("username");
    String password = request.getParameter("password");
    // 認証処理など
  }
%>

フォームの実装例

<form method="post" action="process.jsp">
  <input type="text" name="username">
  <input type="password" name="password">
  <input type="submit" value="ログイン">
</form>

第3章 セッション管理と状態維持

3.1 セッションの基本概念

HTTPのステートレス性を克服するためのセッション管理:

<%
  // セッション取得(存在しなければ新規作成)
  HttpSession session = request.getSession(true);

  // セッション属性設定
  session.setAttribute("user", "username");

  // セッション属性取得
  String user = (String) session.getAttribute("user");

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

3.2 セッション追跡のメカニズム

JSP/サーブレットコンテナは以下の方法でセッションを追跡:

  1. クッキーを使用 (JSESSIONID)
   <%
     Cookie cookie = new Cookie("JSESSIONID", session.getId());
     cookie.setMaxAge(60*60*24); // 1日
     response.addCookie(cookie);
   %>
  1. URLリライティング
<a href="<%= response.encodeURL("page.jsp") %>">リンク</a>
  1. 隠しフォームフィールド
<input type="hidden" name="jsessionid" value="<%= session.getId() %>">

3.3 セッションタイムアウト設定

web.xmlでの設定例:

<session-config>
  <session-timeout>30</session-timeout> <!-- 分単位 -->
</session-config>

JSPページ内での設定:

<% session.setMaxInactiveInterval(1800); // 秒単位 %>

第4章 JSPの高度なHTTP機能

4.1 ファイルアップロード処理

<%@ page import="org.apache.commons.fileupload.*" %>
<%@ page import="org.apache.commons.fileupload.disk.*" %>
<%@ page import="org.apache.commons.fileupload.servlet.*" %>
<%@ page import="java.io.*" %>

<%
  if (ServletFileUpload.isMultipartContent(request)) {
    DiskFileItemFactory factory = new DiskFileItemFactory();
    ServletFileUpload upload = new ServletFileUpload(factory);

    List<FileItem> items = upload.parseRequest(request);
    for (FileItem item : items) {
      if (!item.isFormField()) {
        // ファイル処理
        String fileName = new File(item.getName()).getName();
        String filePath = "uploads/" + fileName;
        item.write(new File(filePath));
      }
    }
  }
%>

<form method="post" enctype="multipart/form-data">
  <input type="file" name="file">
  <input type="submit" value="アップロード">
</form>

4.2 クッキーの操作

<%
  // クッキー作成
  Cookie cookie = new Cookie("userPref", "darkMode");
  cookie.setMaxAge(60*60*24*365); // 1年間有効
  response.addCookie(cookie);

  // クッキー読み取り
  Cookie[] cookies = request.getCookies();
  if (cookies != null) {
    for (Cookie c : cookies) {
      if ("userPref".equals(c.getName())) {
        String value = c.getValue();
        // テーマ設定などに使用
      }
    }
  }
%>

4.3 HTTPキャッシュ制御

<%
  // キャッシュ防止
  response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
  response.setHeader("Pragma", "no-cache");
  response.setDateHeader("Expires", 0);

  // 条件付きGET処理
  long lastModified = /* 最終更新日時を取得 */;
  String ifModifiedSince = request.getHeader("If-Modified-Since");
  if (ifModifiedSince != null && 
      lastModified <= Long.parseLong(ifModifiedSince)) {
    response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
    return;
  }
  response.setDateHeader("Last-Modified", lastModified);
%>

第5章 実践的なJSPアプリケーションの構築

5.1 MVCアーキテクチャの実装

HTTPリクエストを効率的に処理するためのMVCパターン:

リクエスト → コントローラ(Servlet) → モデル(JavaBean) → ビュー(JSP) → レスポンス

コントローラの例 (Servlet)

@WebServlet("/user")
public class UserController extends HttpServlet {
  protected void doGet(HttpServletRequest request, HttpServletResponse response) 
      throws ServletException, IOException {
    UserService service = new UserService();
    List users = service.getAllUsers();
    request.setAttribute("users", users);
    request.getRequestDispatcher("/userList.jsp").forward(request, response);
  }
}

JSPビューの例 (userList.jsp)

<%@ page import="java.util.List" %>
<%@ page import="com.example.User" %>
<%
  List<User> users = (List<User>) request.getAttribute("users");
%>
<table>
  <% for (User user : users) { %>
    <tr>
      <td><%= user.getId() %></td>
      <td><%= user.getName() %></td>
    </tr>
  <% } %>
</table>

5.2 RESTfulなJSPアプリケーション

HTTPメソッドを活用した設計:

<%@ page import="javax.servlet.http.HttpServlet" %>
<%
  String method = request.getMethod();
  switch(method) {
    case "GET":
      // リソース表示
      break;
    case "POST":
      // リソース作成
      break;
    case "PUT":
      // リソース更新
      break;
    case "DELETE":
      // リソース削除
      break;
  }
%>

5.3 エラーハンドリング

web.xmlでの設定:

<error-page>
  <error-code>404</error-code>
  <location>/error/404.jsp</location>
</error-page>
<error-page>
  <exception-type>java.lang.Exception</exception-type>
  <location>/error/general.jsp</location>
</error-page>

JSPでのエラーページ:

<%@ page isErrorPage="true" %>
<h1>エラーが発生しました</h1>
<p><%= exception.getMessage() %></p>

第6章 パフォーマンスとセキュリティ

6.1 HTTPパフォーマンス最適化

<%-- 静的リソースのキャッシュ --%>
<%
  response.setHeader("Cache-Control", "public, max-age=31536000");
%>

<%-- 圧縮有効化 --%>
<%@ page import="java.util.zip.GZIPOutputStream" %>
<%
  String acceptEncoding = request.getHeader("Accept-Encoding");
  if (acceptEncoding != null && acceptEncoding.indexOf("gzip") != -1) {
    response.setHeader("Content-Encoding", "gzip");
    out = new JspWriter(new GZIPOutputStream(response.getOutputStream()));
  }
%>

6.2 セキュリティ対策

CSRF対策

<%-- トークン生成 --%>
<%
  String csrfToken = UUID.randomUUID().toString();
  session.setAttribute("csrfToken", csrfToken);
%>

<%-- フォームに埋め込み --%>
<input type="hidden" name="csrfToken" value="<%= csrfToken %>">

<%-- トークン検証 --%>
<%
  String sessionToken = (String) session.getAttribute("csrfToken");
  String requestToken = request.getParameter("csrfToken");
  if (sessionToken == null || !sessionToken.equals(requestToken)) {
    throw new ServletException("CSRFトークンが無効です");
  }
%>

XSS対策

<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
<%
  // JSTLのfn:escapeXmlを使用
  String userInput = request.getParameter("input");
%>

${fn:escapeXml(userInput)}

SQLインジェクション対策

<%@ page import="java.sql.PreparedStatement" %>
<%
  // PreparedStatementを使用
  String username = request.getParameter("username");
  PreparedStatement stmt = connection.prepareStatement(
    "SELECT * FROM users WHERE username = ?");
  stmt.setString(1, username);
  ResultSet rs = stmt.executeQuery();
%>

まとめ

本記事では、JSPを用いたWebアプリケーション開発において重要なクライアント/サーバーモデルとHTTPプロトコルの詳細について解説しました。HTTPのステートレスな性質を理解し、セッション管理やクッキーを適切に扱うことで、効果的なWebアプリケーションを構築できます。また、MVCアーキテクチャの採用やRESTfulな設計、適切なエラーハンドリング、セキュリティ対策など、実践的なテクニックも紹介しました。

JSP開発においてHTTPプロトコルを深く理解することは、パフォーマンスの良い、安全で、ユーザーフレンドリーなアプリケーションを作成するための基礎となります。これらの知識を活用して、より高度なJSPアプリケーションの開発に挑戦してください。