JSP/Servlet | サーブレットとJSP/HTML | redirectを使って結果を表示する

フォワードの場合、URLアドレスバーに表示されるアドレスは変更されないため、/mygaeappと表示されたままhello.jspの内容が表示される。大きな問題ではないが、リロードするとサーブレットのdoGetが表示されてしまう。

hello.jspへ正しくアドレスを戻すには、フォワードではなくリダイレクトを利用する必要がある。ただし、リダイレクトを使う場合は、フォワードとは別の形で値を渡す必要がある。

以下では、前にフォワードを使った例をリダイレクトを使う形に修正している。

<%@ page language="java" contentType="text/html; charset=utf-8"
        pageEncoding="utf-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Sample jsp</title>
<style>
h1{
    font-size: 16pt;
    background: #AAFFAA;
    padding: 5px;
}
</style>
</head>
<body>
    <h1>Hello App Engine!</h1>
    <p>Result :  <%=session.getAttribute("result") %></p>
    <hr>
    <p id="msg">整数入力: </p>
    <form method="post" action="/mygaeapp">
    <table>
        <tr>
            <td>入力</td>
            <td><input type="text" id="input" name="text1" value="<%=session.getAttribute("input") %>"></td>
        </tr>
        <tr>
            <td></td>
            <td><input type="submit" value="送信"></td>
        </tr>
    </table>
    </form>
</body>
</html>

MyGaeAppServlet.java

package com.devkuma.mygaeapp;

import java.io.*;

import javax.servlet.http.*;

@SuppressWarnings("serial")
public class MyGaeAppServlet4 extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        response.setContentType("text/plain");
        request.setCharacterEncoding("utf8");
        response.setCharacterEncoding("utf8");
        PrintWriter out = response.getWriter();
        out.println("Hello, world!");
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
        response.setContentType("text/html");
        request.setCharacterEncoding("utf8");
        response.setCharacterEncoding("utf8");
        String param = request.getParameter("text1");
        PrintWriter out = response.getWriter();
        int result = 0;
        try {
            int n = Integer.parseInt(param);
            for (int i = 1; i <= n; i++) {
                result += i;
            }
        } catch (NumberFormatException e) {
            out.println(e);
        }
        HttpSession session = request.getSession();
        session.setAttribute("input", param);
        session.setAttribute("result", result);
        response.sendRedirect("/hello.jsp");
    }
}

これを動作させてみよう。フォームを送信すると再びフォームの表示に戻り、合計が計算されて表示される。このとき、URLアドレスは正しくhello.jspに戻っている。これならリロードしても問題ない。

リダイレクトはフォワードと違って、より簡単に使用できる。次のようなメソッドを呼び出すだけである。

"HttpServletResponse".sendRedirect(リダイレクト先アドレス);

フォワードに比べて非常に簡単である。リダイレクト先アドレスを引数に指定すればよい。しかし、リダイレクトを使う場合、移動先で「HttpServletRequestのsetAttributeを使って値を受け取る」ことはできない。

HttpServletRequestはリクエストを管理するものである。フォワードではサーバーで表示される内容が変更されるだけなので、リクエストが中断されることはない。しかしリダイレクトは、HTTPヘッダー情報を使ってブラウザーを指定されたページへ移動させるものである。つまり、ブラウザーが受け取ったヘッダー情報をもとに別ページへ移動する段階で、リクエストはいったん終了する。したがってHttpServletRequestはそこで消え、新しいHttpServletRequestが再び提供される。だからRequestのsetAttributeに値を保存しても、その値を取得できない。

ではどうすればよいのか。このような場合のためにあるのがセッションである。セッションはJSPでも少し使用した。セッションはサーバーとクライアント間の継続的な接続を維持するための仕組みであった。

このセッションはHttpSessionというクラスとして用意されている。これはrequestから取り出せる。

HttpSession session = request.getSession();

リクエストにあるHttpServletRequestインスタンスのgetSessionを呼び出すことで、現在のセッションを管理するHttpSessionインスタンスを取得できる。そして、このインスタンスのsetAttributeを呼び出してセッションに値を保存できる。

session.setAttribute("input", param);
session.setAttribute("result", result);

その後は、JSP側で値を取得する部分をrequestからsessionへ変更すればよい。次のような形である。JSPではHttpSessionをsessionという暗黙オブジェクトとして使用できる。

<%= session.getAttribute("result") %>
<%= session.getAttribute("input") %>

セッションはリクエストが終わってもそのまま維持されるため、リダイレクトされたJSPでも値を正しく取り出せる。これで安心してページ移動ができるようになった。