Using forms with Java

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/2-structured-data directory, enter the following command to start a local web server. Replace [YOUR_PROJECT_ID] with your GCP project ID:

    mvn -Plocal clean jetty:run-exploded -DprojectID=[YOUR-PROJECT-ID]
  2. In your web browser, go to http://localhost:8080.

Deploying the app to the App Engine flexible environment

  1. Deploy the app.

    mvn appengine:deploy -DprojectID=YOUR-PROJECT-ID
  2. In your web browser, enter the following address. Replace [YOUR_PROJECT_ID] with your project ID.


When you update your app, you can deploy the updated version using the same command you used when you first deployed the app. The new deployment creates a new version of your app and promotes it to the default version. The older versions of your app remain, as do their associated VM instances. All of these app versions and VM instances are billable resources.

You can reduce costs by deleting the non-default versions of your app. 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, there are two annotations:

  • The @MultipartConfig annotation tells the Jetty Servlet container that the app uses the multipart/form-data MIME type for form data.

  • The @WebServlet annotation identifies the class as a Servlet and specifies additional attributes. In this case, the Servlet has a name of create and a urlPattern of /create.

Additional parameters include asyncSupported, which specifies that the container Servlet can process requests asynchronously, and loadOnStartup, which tells the container to load the servlet and execute its init() method:

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

The doGet method processes the request for a form and sets up attributes to be 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 the form 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}" 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 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 CloudStorageHelper and a BookDao. The form parameters are accessed by the req.getParameter() functions, and the page is redirected to /read, which lets you see what was written.

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
  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...