Java からフォームを使う

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

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

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

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

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

    mvn -Plocal clean jetty:run-exploded -DprojectID=[YOUR-PROJECT-ID]
  2. ウェブブラウザで http://localhost:8080 に移動します。

App Engine フレキシブル環境へのアプリのデプロイ

  1. 次のコマンドを入力してアプリをデプロイします。

    mvn appengine:deploy -DprojectID=YOUR-PROJECT-ID
    
  2. ウェブブラウザで、次のアドレスを入力します。[YOUR_PROJECT_ID] は実際のプロジェクト ID で置き換えます。

    https://[YOUR_PROJECT_ID].appspot-preview.com
    

アプリを更新する場合は、最初にデプロイしたときと同じコマンドを使って、更新バージョンをデプロイできます。デプロイを行うと、アプリの新しいバージョンが作成され、それがデフォルトのバージョンに設定されます。古いバージョンはそのまま残り、関連付けられた VM インスタンスも同様に残ります。すべてのアプリ バージョンと VM インスタンスが課金対象のリソースとなるのでご注意ください。

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

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

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

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

  2. デフォルト以外で削除するアプリのバージョンのチェックボックスを選択します。
  3. アプリのバージョンを削除するには、[削除]()をクリックします。

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

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

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

Image of add/edit Form

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

CreateBookServlet.java には 2 つのアノテーションがあります。@MultipartConfig アノテーションは、Jetty Servlet コンテナに対して、このアプリではフォームデータのために multipart/form-data MIME タイプが使われることを知らせます。@WebServlet アノテーションは、クラスが Servlet であることを特定し、追加的な属性を指定します。この例では、サーブレットの namecreateurlPattern/create です。追加的なパラメータとして、asyncSupported(コンテナ Servlet がリクエストを非同期的に処理できるようにする)と loadOnStartup(サーブレットを読み込み、その init() メソッドを実行するようコンテナに指示する)があります。

@MultipartConfig
@WebServlet(name = "create", urlPatterns = {"/create"})

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}" enctype="multipart/form-data">

    <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 メソッドは、CloudStorageHelper および BookDao を生成します。これらのフォーム パラメータが req.getParameter() 関数からアクセスされ、ページが /read へリダイレクトされて、上記の内容が表示されます。セッションへのアクセス権と本の生成については、後ほど説明します。

@Override
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException,
    IOException {
  BookDao dao = (BookDao) this.getServletContext().getAttribute("dao");
  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();
  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);
  }
}
このページは役立ちましたか?評価をお願いいたします。