Como usar formulários com Java para o ambiente padrão do App Engine

Nesta parte do tutorial do Bookshelf para Java, saiba como acessar dados de formulário do Servlets.

Esta página faz parte de um tutorial com várias páginas. Para começar do início e ver as instruções de configuração, consulte App Bookshelf em Java.

Execução do app na máquina local

Para executar o app localmente:

  1. No diretório getting-started-java/bookshelf-standard/2-structured-data, digite o seguinte comando para iniciar um servidor da Web local:

    mvn package appengine:run
  2. No seu navegador da Web, acesse http://localhost:8080.

Como implantar o app no ambiente padrão do App Engine

Para implantar no ambiente padrão do App Engine:

  1. Para criar um índice do armazenamento de dados carregado no aplicativo Bookshelf, crie pelo menos um livro e clique em Meus Livros. Observe que a criação do aplicativo usando o comando clean exclui esse índice local. Faça isso na construção do aplicativo que você irá implantar.
  2. No diretório getting-started-java/bookshelf-standard/2-structured-data, digite o seguinte comando para implantar o aplicativo:
    mvn appengine:deploy -Dappengine.appId=[YOUR-PROJECT-ID] -Dappengine.version=[YOUR-VERSION]
    Substitua [YOUR-PROJECT-ID] pelo código do projeto e [YOUR-VERSION] pela versão, por exemplo, 1, 2 ou outro valor de string que você queira usar.
  3. No navegador da Web, digite este URL:

    https://PROJECT_ID.REGION_ID.r.appspot.com

    Substitua:

Depois de atualizar seu aplicativo, você pode reimplementar a versão atualizada digitando o mesmo comando de quando o aplicativo foi implantado pela primeira vez, além de especificar o mesmo ID e versão do projeto. Isso substitui o aplicativo implantado no momento. Se você especificar uma sequência de versão diferente na linha de comando atualizada, a nova implantação criará uma nova versão do seu aplicativo e promoverá que ela seja a versão atualmente veiculada.

Reduza custos excluindo as versões do app que não estão veiculadas.

Para excluir uma versão do app:

  1. No Console do Cloud, acesse a página Versões do App Engine.

    Acessar a página "Versões"

  2. Marque a caixa de seleção da versão não padrão do app que você quer excluir.
  3. Clique em Excluir para remover a versão do app.

Para informações detalhadas sobre a remoção de recursos faturáveis, consulte a seção Como fazer a limpeza na etapa final deste tutorial.

Como processar envios do usuário com formulários

O formulário permite adicionar e editar envios de livros no aplicativo.

Imagem do formulário de adição/edição

Quando o navegador solicita /create, o servlet Google Kubernetes Engine carrega o CreateBookServlet e chama o método doGet. Em seguida, a solicitação é encaminhada para o servlet /base.jsp, que inclui o servlet /form.jsp. Depois de enviar o formulário, o método doPost de CreateBookServlet é chamado.

Em CreateBookServlet.java, o método doGet processa a solicitação de um formulário e configura os atributos usados pelo arquivo 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);
}

O arquivo base.jsp serve como base para as páginas HTML do aplicativo. Ele começa com a inclusão da Biblioteca padrão de tags JSP. Tags principais JSTL são identificadas por tags começando com <c: e fornecem suporte variável, controle de fluxo, gerenciamento de URL e diversos. Funções JSTL são identificadas por tags começando com <fn: e fornecem coleções e bibliotecas de manipulação de cadeia. Aqui está um resumo das tags JSTL usadas pelo aplicativo Bookshelf:

Tag JSTL Descrição
<c:if ... A expressão test é avaliada e, se verdadeira, o conteúdo é incluído.
<c:choose> Com essa tag condicional, o contexto para c:when e c:otherwise é estabelecido.
<c:when ... Inclua conteúdo se test for verdadeiro.
<c:otherwise> Se c:when não for verdadeiro, inclua este conteúdo.
<c:import url="" /> Inclua o conteúdo de url na página.
<c:out value="" /> Avalie a expressão para value e exiba uma versão codificada.
${fn:escapeXml()} Promove o escape de caracteres especiais para as páginas da Web.


<%@ 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>

O formulário HTML é criado usando páginas do JavaServer. Esse é um mecanismo de modelos do Java, mas é executado como Servlets. Com este código JSP, é especificado que o formulário inclui campos de entrada de texto para "Título", "Autor", "Data de publicação", "Descrição", "Imagem de capa" e botão "Salvar":

<%@ 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>

Envio do formulário

O método doPost cria um objeto Book, lendo os parâmetros do formulário pelas chamadas req.getParameter() e fornece o objeto Book a um novo objeto BookDao que adiciona o novo livro entidade para o armazenamento de dados. Depois que o livro é salvo no armazenamento de dados, a página é redirecionada para /read para que você possa ver o que acabou de ser salvo. O acesso à sessão e a criação de livros serão discutidos posteriormente:

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