App Engine スタンダード環境で Java からフォームを使う

Bookshelf の Java チュートリアルのこのパートでは、サーブレットからフォームデータにアクセスする方法を説明します。

このページは複数ページからなるチュートリアルの一部です。説明の最初から設定手順を確認するには、Java Bookshelf アプリに移動してください。

ローカルマシンでのアプリの実行

アプリをローカルで実行するには:

  1. getting-started-java/bookshelf-standard/2-structured-data ディレクトリで次のコマンドを入力し、ローカル ウェブサーバーを起動します。

    mvn -Plocal clean appengine:devserver
  2. ウェブブラウザで http://localhost:8080 に移動します。

App Engine スタンダード環境へのアプリのデプロイ

アプリを App Engine スタンダード環境にデプロイするには:

  1. Bookshelf アプリケーションのローカルでの演習を完了します。特に、少なくとも 1 つの書籍を作成して [My Books] をクリックしておきます。これにより、Bookshelf とともにアップロードされる、必要な Cloud Datastore のインデックスが作成されます。clean を使用してアプリケーションをビルドすると、そのローカル インデックスが削除されます。したがって、デプロイするアプリケーションのビルドでは必ずこの作業を行ってください。
  2. getting-started-java/bookshelf-standard/2-structured-data ディレクトリで、次のコマンドを入力してアプリをデプロイします。
    mvn appengine:update -Dappengine.appId=[YOUR-PROJECT-ID] -Dappengine.version=[YOUR-VERSION]
    [YOUR-PROJECT-ID] を実際のプロジェクト ID に、[YOUR-VERSION] を実際のバージョン(12 などの文字列値)に置き換えます。
  3. ウェブブラウザに次のアドレスを入力します。
    https://[YOUR-PROJECT-ID].appspot.com
    [YOUR-PROJECT-ID] を実際のプロジェクト ID に置き換えます。

アプリを更新した場合は、最初にデプロイしたときと同じコマンドを使って更新バージョンを再デプロイできます。同じプロジェクト ID とバージョンを指定することにより、現在デプロイされているアプリが上書きされます。更新の際に別のバージョン文字列を指定すると、アプリの新しいバージョンが作成されて、それが現在の提供バージョンに昇格されます。

アプリの提供バージョン以外のバージョンを削除することで、コストを削減できます。

アプリのバージョンを削除する手順は次のとおりです。

  1. GCP Console の [App Engine のバージョン] ページに移動します。

    [バージョン] ページに移動

  2. 削除したい、デフォルト以外のアプリのバージョンの横にあるチェックボックスをクリックします。
  3. ページ上部にある [削除] ボタンをクリックし、アプリのバージョンを削除します。

課金対象のリソースをクリーンアップする方法の詳細については、このチュートリアルの最後のステップにあるクリーンアップ セクションを参照してください。

フォームによるユーザーの投稿に対応する

次の追加 / 編集フォームにより、ユーザーはアプリ内で書籍情報の投稿を追加または編集できます。

追加 / 編集フォームの画像

ユーザーのブラウザが /create リクエストを出すと、Servlet Container Engine が CreateBookServlet を読み込み、doGet メソッドを呼び出します。その後、このリクエストは /base.jsp サーブレット(ここに /form.jsp サーブレットが含まれる)に転送されます。このフォームをユーザーが送信すると、CreateBookServletdoPost メソッドが呼び出されます。

CreateBookServlet.java 内の doGet メソッドは、フォームに対するリクエストを処理し、JSP ファイルで使われる属性をセットアップします。

@Override
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException,
    IOException {
  req.setAttribute("action", "Add");          // Part of the Header in form.jsp
  req.setAttribute("destination", "create");  // The urlPattern to invoke (this Servlet)
  req.setAttribute("page", "form");           // Tells base.jsp to include form.jsp
  req.getRequestDispatcher("/base.jsp").forward(req, resp);
}

base.jsp ファイルは、このアプリの HTML ページの基礎となります。これを使うには、最初に JSP Standard Tag Library(JSTL)をインクルードします。 <c: で始まるタグは JSTL コアタグを示しています。これらのタグにより、変数、フロー制御、URL 管理、その他のサポートが提供されます。 <fn: で始まるタグは JSTL 関数を示します。これらの関数により、コレクションや文字列を操作するライブラリが提供されます。Bookshelf アプリで使用している JSTL のタグを以下に要約します。

JSTL のタグ 説明
<c:if ... test を評価し、結果が true ならコンテンツをインクルードする。
<c:choose> c:when および c:otherwise の場合のコンテキストを確立する条件付きタグ。
<c:when ... test が true の場合にコンテンツをインクルードする。
<c:otherwise> c:when が true でない場合は、このコンテンツをインクルードする。
<c:import url="" /> url のコンテンツをページ内にインクルードする。
<c:out value="" /> 式を評価して value を求め、エンコード後の結果を出力する。
${fn:escapeXml()} ウェブページの特殊文字をエスケープする。


<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
<html lang="en">
  <head>
    <title>Bookshelf - Java on Google Cloud Platform</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
  </head>
  <body>
    <div class="navbar navbar-default">
      <div class="container">
        <div class="navbar-header">
          <div class="navbar-brand">Bookshelf</div>
        </div>
        <ul class="nav navbar-nav">
          <li><a href="/">Books</a></li>
          <c:if test="${isAuthConfigured}"><li><a href="/books/mine">My Books</a></li></c:if>
        </ul>
        <p class="navbar-text navbar-right">
          <c:choose>
          <c:when test="${not empty token}">
          <!-- using pageContext requires jsp-api artifact in pom.xml -->
          <a href="/logout">
            <c:if test="${not empty userImageUrl}">
              <img class="img-circle" src="${fn:escapeXml(userImageUrl)}" width="24">
            </c:if>
            ${fn:escapeXml(userEmail)}
          </a>
          </c:when>
          <c:when test="${isAuthConfigured}">
          <a href="/login">Login</a>
          </c:when>
          </c:choose>
        </p>
      </div>
    </div>
    <c:import url="/${page}.jsp" />
  </body>
</html>

この HTML フォームの作成には JavaServer Pages が使われています。これは Java テンプレート エンジンの一種ですが、サーブレットとして実行されます。次の JSP コードは、このフォームで Title(タイトル)、Author(著者)、Date Published(出版日)、Description(説明)の各テキスト入力フィールドと Cover Image(表紙画像)および Save(保存)ボタンがインクルードされるようにします。

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn"%>
<div class="container">
  <h3>
    <c:out value="${action}" /> book
  </h3>

  <form method="POST" action="${destination}">

    <div class="form-group">
      <label for="title">Title</label>
      <input type="text" name="title" id="title" value="${fn:escapeXml(book.title)}" class="form-control" />
    </div>

    <div class="form-group">
      <label for="author">Author</label>
      <input type="text" name="author" id="author" value="${fn:escapeXml(book.author)}" class="form-control" />
    </div>

    <div class="form-group">
      <label for="publishedDate">Date Published</label>
      <input type="text" name="publishedDate" id="publishedDate" value="${fn:escapeXml(book.publishedDate)}" class="form-control" />
    </div>

    <div class="form-group">
      <label for="description">Description</label>
      <textarea name="description" id="description" class="form-control">${fn:escapeXml(book.description)}</textarea>
    </div>

    <div class="form-group ${isCloudStorageConfigured ? '' : 'hidden'}">
      <label for="image">Cover Image</label>
      <input type="file" name="file" id="file" class="form-control" />
    </div>

    <div class="form-group hidden">
      <label for="imageUrl">Cover Image URL</label>
      <input type="hidden" name="id" value="${book.id}" />
      <input type="text" name="imageUrl" id="imageUrl" value="${fn:escapeXml(book.imageUrl)}" class="form-control" />
    </div>

    <button type="submit" class="btn btn-success">Save</button>
  </form>
</div>

フォームの送信

doPost メソッドは、req.getParameter() を呼び出してフォームのパラメータを読み取り、Book オブジェクトを作成します。その Book オブジェクトが新しい BookDao オブジェクトに渡されて、新しい Book エンティティがデータストアに追加されます。書籍がデータストアに保存されると、ページが /read へリダイレクトされて、データストアに保存された内容がユーザーに表示されます。セッションへのアクセス権と書籍の生成については、後ほど説明します。

@Override
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException,
    IOException {
  Book book = new Book.Builder()
      .author(req.getParameter("author"))   // form parameter
      .description(req.getParameter("description"))
      .publishedDate(req.getParameter("publishedDate"))
      .title(req.getParameter("title"))
      .imageUrl(null)
      .build();

  BookDao dao = (BookDao) this.getServletContext().getAttribute("dao");
  try {
    Long id = dao.createBook(book);
    resp.sendRedirect("/read?id=" + id.toString());   // read what we just wrote
  } catch (Exception e) {
    throw new ServletException("Error creating book", e);
  }
}
このページは役立ちましたか?評価をお願いいたします。