Using forms with Java for the App Engine standard environment

This part of the Bookshelf tutorial for Java shows how to access form data from servlets.

This page is part of a multi-page tutorial. To start from the beginning and read the setup instructions, go to Java Bookshelf app.

Running the app on your local machine

To run the app locally:

  1. In the getting-started-java/bookshelf-standard/2-structured-data directory, enter the following command to start a local web server:

    mvn -Plocal clean appengine:devserver
  2. In your web browser, go to http://localhost:8080.

Deploying the app to the App Engine standard environment

To deploy to the App Engine standard environment:

  1. To create a Cloud Datastore index that is uploaded to the Bookshelf app, create at least one book, and then click My Books. Note, building the app using the clean command deletes that local index so do this on the build of the app that you are going to deploy.
  2. In the getting-started-java/bookshelf-standard/2-structured-data directory, enter the following command to deploy the app:
    mvn appengine:update -Dappengine.appId=[YOUR-PROJECT-ID] -Dappengine.version=[YOUR-VERSION]
    Replace [YOUR-PROJECT-ID] with your project ID and [YOUR-VERSION] with your version, for example, 1, or 2, or some other string value you want to use.
  3. In your web browser, enter the following address:
    Replace [YOUR-PROJECT-ID] with your project ID.

After you update your app, you can redeploy the updated version by entering the same command as when you first deployed the app as well as specifying the same project ID and version. This overwrites the currently deployed app. If you specify a different version string in the updated command line, the new deployment creates a new version of your app and promotes it to be the currently serving version.

You can reduce costs by deleting the non-serving versions of your app.

To delete an app version:

  1. In the GCP Console, go to the Versions page for App Engine.

    Go to the Versions page

  2. Select the checkbox for the non-default app version you want to delete.
  3. Click Delete to delete the app version.

For complete information about cleaning up billable resources, see the Cleaning up section in the final step of this tutorial.

Handling user submissions with forms

The form lets you add and edit book submissions in the app.

Image of add/edit Form

When your browser requests /create, the servlet Google Kubernetes Engine loads the CreateBookServlet and calls the doGet method. Then the request is forwarded to the /base.jsp servlet, which includes the /form.jsp servlet. After you submit the form, the doPost method of CreateBookServlet is called.

In, the doGet method processes the request for a form and sets up attributes used by the JSP file:

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);

The base.jsp file serves as the foundation for the app's HTML pages. It starts by including the JSP Standard Tag Library. JSTL core tags are identified by tags starting with <c: and provide variable, flow control, URL management, and miscellaneous support. JSTL functions are identified by tags starting with <fn: and provide collections and string manipulation libraries. Here is a summary of JSTL tags used by the Bookshelf app:

JSTL tag Description
<c:if ... Evaluate expression test and include content if true.
<c:choose> Conditional tag that establishes context for c:when and c:otherwise.
<c:when ... Include content if test is true.
<c:otherwise> If c:when is not true, include this content.
<c:import url="" /> Include the contents of the url within the page.
<c:out value="" /> Evaluate the expression for value and display an encoded version.
${fn:escapeXml()} Escape special characters for webpages.

<%@ taglib uri="" prefix="c" %>
<%@ taglib uri="" prefix="fn" %>
<html lang="en">
    <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="//">
    <div class="navbar navbar-default">
      <div class="container">
        <div class="navbar-header">
          <div class="navbar-brand">Bookshelf</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>
        <p class="navbar-text navbar-right">
          <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:when test="${isAuthConfigured}">
          <a href="/login">Login</a>
    <c:import url="/${page}.jsp" />

The HTML form is created by using JavaServer Pages, which is like a Java template engine, but runs as servlets. The following JSP code specifies that the form include text input fields for Title, Author, Date Published, Description, Cover Image, and a Save button:

<%@ taglib uri="" prefix="c"%>
<%@ taglib uri="" prefix="fn"%>
<div class="container">
    <c:out value="${action}" /> book

  <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 class="form-group">
      <label for="author">Author</label>
      <input type="text" name="author" id="author" value="${fn:escapeXml(}" class="form-control" />

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

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

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

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

Form submission

The doPost method creates a Book object, reading in parameters from the form by the req.getParameter() calls, and then supplies the Book object to a new BookDao object that adds the new book entity to Cloud Datastore. After the book is saved to Cloud Datastore, the page is redirected to /read so you can see what was just saved. Session access and book creation are discussed later:

public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException,
    IOException {
  Book book = new Book.Builder()
      .author(req.getParameter("author"))   // form parameter

  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);
Was this page helpful? Let us know how we did:

Send feedback about...