JavaRush /Blogue Java /Random-PT /Criando uma aplicação web simples usando servlets e jsp (...
Стас Пасинков
Nível 26
Киев

Criando uma aplicação web simples usando servlets e jsp (parte 2)

Publicado no grupo Random-PT
Criando uma aplicação web simples usando servlets e jsp (parte 1) Nível de conhecimento necessário para entender o artigo: você já entendeu mais ou menos o Java Core e gostaria de dar uma olhada nas tecnologias JavaEE e na programação web. Faz mais sentido se você estiver estudando atualmente a missão Java Collections, que cobre tópicos próximos ao artigo.
Criando uma aplicação web simples usando servlets e jsp (parte 2) - 1

Criando Entidades

No pacote de entidades , criaremos uma classe User , e nela haverá duas variáveis ​​de string privadas nome e senha . Vamos criar construtores (padrão e um que aceite ambos os valores), getters/setters, substituir o método toString() por precaução, bem como os métodos equals() e hashCode() . Ou seja, faremos tudo o que um desenvolvedor Java decente faz ao criar uma classe.
public class User {
    private String name;
    private String password;

    public User() {
    }

    public User(String name, String password) {
        this.name = name;
        this.password = password;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", password='" + password + '\'' +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        User user = (User) o;

        if (name != null ? !name.equals(user.name) : user.name != null) return false;
        return password != null ? password.equals(user.password) : user.password == null;

    }

    @Override
    public int hashCode() {
        int result = name != null ? name.hashCode() : 0;
        result = 31 * result + (password != null ? password.hashCode() : 0);
        return result;
    }
}
Agora podemos começar a criar uma lista de usuários. Adicionaremos usuários a ele e de onde os levaremos para exibição. No entanto, há um problema. Não criamos nossos objetos servlet, o Tomcat faz isso por nós . Os métodos que substituímos neles também já estão definidos para nós e não podemos adicionar um parâmetro. Como então podemos criar uma lista compartilhada que seja visível para ambos os nossos servlets? Se simplesmente criarmos nosso próprio objeto de lista em cada servlet, adicionaremos usuários a uma lista e exibiremos a lista de usuários usando o servlet ListServlet para outra. Acontece que precisamos de um objeto que seja comum aos dois servlets. De modo geral, precisamos de um objeto que seja comum a todas as classes do nosso programa; o único objeto para todo o programa. Espero que você tenha ouvido algo sobre padrões de design. E, talvez, para alguns esta seja a primeira necessidade real de usar o padrão Singleton em seus programas. Você pode se perverter e criar algum Singleton legal com verificações duplas e sincronização (sim, temos um aplicativo multithread, já que o Tomcat executa servlets em threads diferentes), mas usarei a opção com inicialização antecipada, pois é bastante adequada aqui suficiente e atende aos nossos propósitos.

Criando um modelo

Vamos criar uma classe (e implementar o padrão Singleton nela ) no pacote model e chamá-la de algo incomum. Digamos Modelo . Vamos criar um objeto de lista de usuários privado em nossa classe e implementar dois métodos: um para que possamos adicionar um usuário e o segundo para retornar uma lista de strings (nomes de usuários). Como nosso objeto de usuário consiste em um nome e uma senha, e não gostaríamos de “revelar” senhas de usuários, teremos apenas uma lista de nomes.
public class Model {
    private static Model instance = new Model();

    private List<User> model;

    public static Model getInstance() {
        return instance;
    }

    private Model() {
        model = new ArrayList<>();
    }

    public void add(User user) {
        model.add(user);
    }

    public List<String> list() {
        return model.stream()
                .map(User::getName)
                .collect(Collectors.toList());
    }
}

Um pouco sobre mvc

Já que você já ouviu falar de singleton , provavelmente já ouviu falar de outro padrão de design - MVC (model-view-controller, em russo model-view-controller ou apenas como em inglês model-view-controller). Sua essência é separar a lógica de negócios da apresentação. Ou seja, separe o código que determina o que fazer do código que determina como exibir. View (view ou simplesmente visualizações) é responsável pela forma como alguns dados são apresentados. No nosso caso, as visualizações são nossas páginas JSP. É por isso que os coloquei em uma pasta chamada views . O modelo são os dados reais com os quais o programa funciona. No nosso caso, são usuários (lista de usuários). Bem, os controladores são o elo de ligação entre eles. Eles pegam dados do modelo e passam para visualizações (ou recebem alguns dados do Tomcat, processam e passam para o modelo). A lógica de negócios (o que exatamente o programa deve fazer) precisa ser descrita neles, e não no modelo ou na visão. Assim, cada um faz o que quer:
  • o modelo armazena dados;
  • as visualizações desenham uma bela representação dos dados;
  • controladores lidam com o processamento de dados.
Isso permite que o programa seja bastante simples e de fácil manutenção, em vez de um despejo monstruoso de todo o código em uma classe. O MVC é adequado não apenas para programação web, mas é nesta área que é encontrado com especial frequência (quase sempre). No nosso caso, os servlets atuarão como controladores. Esta é uma descrição muito superficial e breve do padrão, mas MVC não é o tópico principal deste artigo. Quem quer saber mais – Google ao resgate! Crie um formulário para adicionar um usuário Vamos adicionar ao arquivo add.jsp um formulário composto por dois campos de entrada de texto (um normal e outro uma senha) e um botão para enviar dados ao servidor.
<form method="post">
    <label>Name:
        <input type="text" name="name"><br />
    </label>

    <label>Password:
        <input type="password" name="pass"><br />
    </label>
    <button type="submit">Submit</button>
</form>
Aqui o formulário possui um atributo de método com o valor post . Isso significa que os dados deste formulário serão enviados ao servidor na forma de uma solicitação POST. O atributo action não é especificado, o que significa que a solicitação será enviada para o mesmo endereço onde acessamos esta página ( /add ). Assim, nosso servlet, vinculado a este endereço, ao receber uma solicitação GET, retorna este jsp com o formulário para adição de usuários, e se receber uma solicitação POST, significa que o formulário enviou seus dados para lá (que iremos extrair do solicitar objeto no método doPost() Vale ressaltar que os campos de entrada possuem um parâmetro nome (para um campo com nome possui o valor nome, e para um campo com senha possui o valor pass ). Este é um ponto muito importante. Visto que para obter esses dados (nome e senha que serão inseridos) da requisição (já dentro do servlet), utilizaremos exatamente estes name e pass . Mas falaremos mais sobre isso mais tarde. O próprio botão para envio de dados é novamente feito na forma de um botão , e não como um campo de saída, como normalmente é habitual. Não sei o quão universal é essa opção, mas funciona para mim (navegador Chrome).

Processando uma solicitação POST com um servlet

Voltemos ao servlet AddServlet . Deixe-me lembrá-lo: para que nosso servlet possa “capturar” solicitações GET, substituímos o método doGet() da classe HttpServlet . Para ensinar nosso servlet a capturar também solicitações POST, também precisamos substituir o método doPost() . Ele recebe objetos de solicitação e resposta semelhantes do Tomcat , com os quais trabalharemos. Primeiro, vamos extrair da solicitação o nome e passar os parâmetros que o formulário enviou (se você os nomeou de forma diferente no formulário, então esses são os nomes que você escreve). Depois disso, criaremos nosso objeto de usuário usando os dados recebidos. Então obteremos o objeto do modelo e adicionaremos o usuário criado ao modelo.
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    String name = req.getParameter("name");
    String password = req.getParameter("pass");
    User user = new User(name, password);
    Model model = Model.getInstance();
    model.add(user);
}

Passando dados para visualizar

Vamos passar para o servlet ListServlet . O método doGet() já foi implementado aqui , que simplesmente transfere o controle para a view list.jsp . Se você ainda não tem isso, faça-o por analogia com o mesmo método do servlet AddServlet . Agora seria bom obter uma lista de nomes de usuário do modelo e passá-los para a visualização, que os receberá e os exibirá de maneira adequada. Para fazer isso, usaremos novamente o objeto request que recebemos do Tomcat . Podemos adicionar um atributo a este objeto, dando-lhe algum nome e, de fato, o próprio objeto que gostaríamos de transferir para view . Devido ao fato de que ao transferir o processo de execução de um servlet para uma visualização, passamos para lá os mesmos objetos de solicitação e resposta que o próprio servlet recebeu, então, adicionando nossa lista de nomes ao objeto de solicitação, podemos então a partir desta solicitação objeto na visualização, crie nossa lista de nomes de usuário e obtenha. Concluímos a classe ListServlet , então aqui está o código para a classe inteira:
package app.servlets;

import app.model.Model;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

public class ListServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Model model = Model.getInstance();
        List<String> names = model.list();
        req.setAttribute("userNames", names);

        RequestDispatcher requestDispatcher = req.getRequestDispatcher("views/list.jsp");
        requestDispatcher.forward(req, resp);
    }
}

Executando código java em arquivos jsp

É hora de começar a trabalhar no arquivo list.jsp . Ele só será executado quando o ListServlet passar pelo processo de execução aqui. Além disso, nesse servlet já preparamos uma lista de nomes de usuários do modelo e passamos aqui no objeto request. Como temos uma lista de nomes, podemos percorrê-la e imprimir cada nome. Como eu já disse, os arquivos jsp podem executar código java (que é o que os diferencia das páginas HTML estáticas). Para executar algum código, basta colocar a seguinte construção no local que necessitamos:
<!-- html code -->
<%
    // java code
%>
<!-- html code -->
Dentro desta construção temos acesso a diversas variáveis:
  • request é o nosso objeto request, que passamos do servlet, onde foi chamado simplesmente de req ;
  • responce - objeto de resposta, chamado resp no servlet ;
  • out é um objeto do tipo JspWriter (herdado do Writer usual ), com o qual podemos “escrever” algo diretamente na própria página html. A entrada out.println("Hello world!") é muito semelhante à entrada System.out.println("Hello world!") , mas não confunda as duas!
    out.println() “grava” na página html e System.out.println grava na saída do sistema. Se você chamar o método jsp System.out.println() dentro da seção com código Java , verá os resultados no console do Tomcat , e não na página.

Você pode procurar outros objetos disponíveis dentro do jsp aqui . Usando o objeto request , podemos obter a lista de nomes que foram passados ​​do servlet (anexamos o atributo correspondente a este objeto), e usando o objeto out , podemos exibir esses nomes. Vamos fazer isso (por enquanto apenas na forma de uma lista html):
<ul>
    <%
        List<String> names = (List<String>) request.getAttribute("userNames");

        if (names != null && !names.isEmpty()) {
            for (String s : names) {
                out.println("<li>" + s + "</li>");
            }
        }
    %>
</ul>
Se você precisar exibir uma lista apenas se houver usuários e, caso contrário, exibir um aviso de que ainda não há usuários, podemos reescrever um pouco esta seção:
<%
    List<String> names = (List<String>) request.getAttribute("userNames");

    if (names != null && !names.isEmpty()) {
        out.println("<ui>");
        for (String s : names) {
            out.println("<li>" + s + "</li>");
        }
        out.println("</ui>");
    } else out.println("<p>There are no users yet!</p>");
%>
Agora que podemos passar dados de servlets para visualizações, podemos melhorar um pouco nosso AddServlet para que uma notificação seja exibida quando um usuário for adicionado com sucesso. Para isso, no método doPost() , após adicionar um novo usuário ao modelo, podemos adicionar o nome desse usuário aos atributos do objeto req e passar o controle de volta para a view add.jsp . E nele já faça uma seção com código Java na qual é feita uma verificação para ver se tal atributo está na solicitação, e em caso afirmativo, emite uma mensagem informando que o usuário foi adicionado com sucesso. Após essas alterações, o código completo do servlet AddServlet ficará parecido com isto:
package app.servlets;

import app.entities.User;
import app.model.Model;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class AddServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        RequestDispatcher requestDispatcher = req.getRequestDispatcher("views/add.jsp");
        requestDispatcher.forward(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String name = req.getParameter("name");
        String password = req.getParameter("pass");
        User user = new User(name, password);
        Model model = Model.getInstance();
        model.add(user);

        req.setAttribute("userName", name);
        doGet(req, resp);
    }
}
Aqui, ao final do método doPost() , definimos um atributo com o nome do usuário adicionado ao modelo, após o qual chamamos o método doGet() , para o qual passamos a solicitação e resposta atuais. E o método doGet() já transfere o controle para a view, onde envia um objeto request com o nome do usuário adicionado anexado como atributo. Resta apenas corrigir add.jsp para que ele exiba tal notificação se tal atributo estiver presente. O add.jsp final é :
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <head>
        <title>Add new user</title>
    </head>

    <body>
        <div>
            <h1>Super app!</h1>
        </div>

        <div>
            <%
                if (request.getAttribute("userName") != null) {
                    out.println("<p>User '" + request.getAttribute("userName") + "' added!</p>");
                }
            %>
            <div>
                <div>
                    <h2>Add user</h2>
                </div>

                <form method="post">
                    <label>Name:
                        <input type="text" name="name"><br />
                    </label>
                    <label>Password:
                        <input type="password" name="pass"><br />
                    </label>
                    <button type="submit">Submit</button>
                </form>
            </div>
        </div>

        <div>
            <button onclick="location.href='/'">Back to main</button>
        </div>
    </body>
</html>
O corpo da página consiste em:
  • div-a com cabeçalho;
  • contêiner div para conteúdo, verifica se existe um atributo com o nome de usuário;
  • div com um formulário para adicionar usuários;
  • e no final há um rodapé com um botão para retornar à página principal.
Pode parecer que há muitos divs, mas iremos usá-los mais tarde, quando adicionarmos estilos. O list.jsp final é:
<%@ page import="java.util.List" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <head>
        <title>Users</title>
    </head>

    <body>
        <div>
            <h1>Super app!</h1>
        </div>

        <div>
            <div>
                <div>
                    <h2>Users</h2>
                </div>
                <%
                    List<String> names = (List<String>) request.getAttribute("userNames");

                    if (names != null && !names.isEmpty()) {
                        out.println("<ui>");
                        for (String s : names) {
                            out.println("<li>" + s + "</li>");
                        }
                        out.println("</ui>");
                    } else out.println("<p>There are no users yet!</p>");
                %>
            </div>
        </div>

        <div>
            <button onclick="location.href='/'">Back to main</button>
        </div>
    </body>
</html>
Assim, temos uma aplicação web totalmente funcional que pode armazenar e adicionar usuários, bem como exibir uma lista de seus nomes. Só falta embelezar... :)

Adicionando estilos. Usamos a estrutura W3.CSS

No momento nosso aplicativo está funcionando, mas é uma loucura. Portanto, adicionaremos fundo, cor de texto e botões, listas de estilos, alinharemos, adicionaremos recuos e assim por diante. Se você escrever estilos manualmente, pode levar muito tempo e nervosismo. Portanto, sugiro usar o framework CSS W3.CSS. Já possui classes prontas com estilos, só falta colocar nos lugares certos as classes CSS que queremos aplicar. Para adicioná-los às nossas páginas, primeiro incluiremos um arquivo com estilos. Isso pode ser feito de duas maneiras:
  1. percorra nossas páginas e na seção head insira um link direto para o arquivo com estilos

    <link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">

    Esta opção é adequada se você tiver uma conexão constante com a Internet. Então, quando você abrir suas páginas em um servidor local, os estilos serão extraídos da Internet.


  2. Se você deseja ter todos os estilos localmente e não depender de uma conexão com a Internet, baixe o arquivo com estilos e coloque-o em algum lugar dentro da pasta web (por exemplo, web/styles/w3.css ), depois passe por todos os nossos páginas ( index.html, add.jsp, list.jsp ) e insira um link para este arquivo com estilos dentro da seção head

    <link rel="stylesheet" href="styles/w3.css">

    Depois disso, basta percorrer as tags e adicionar os estilos que desejar. Não vou me alongar sobre isso em detalhes, mas darei imediatamente minhas versões prontas dos meus três arquivos com classes de estilo organizadas.

index.html

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Super app!</title>
        <link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
    </head>

    <body class="w3-light-grey">
        <div class="w3-container w3-blue-grey w3-opacity w3-right-align">
            <h1>Super app!</h1>
        </div>

        <div class="w3-container w3-center">
            <div class="w3-bar w3-padding-large w3-padding-24">
                <button class="w3-btn w3-hover-light-blue w3-round-large" onclick="location.href='/list'">List users</button>
                <button class="w3-btn w3-hover-green w3-round-large" onclick="location.href='/add'">Add user</button>
            </div>
        </div>
    </body>
</html>

adicionar.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <head>
        <title>Add new user</title>
        <link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
    </head>

    <body class="w3-light-grey">
        <div class="w3-container w3-blue-grey w3-opacity w3-right-align">
            <h1>Super app!</h1>
        </div>

        <div class="w3-container w3-padding">
            <%
                if (request.getAttribute("userName") != null) {
                    out.println("<div class=\"w3-panel w3-green w3-display-container w3-card-4 w3-round\">\n" +
                            "   <span onclick=\"this.parentElement.style.display='none'\"\n" +
                            "   class=\"w3-button w3-margin-right w3-display-right w3-round-large w3-hover-green w3-border w3-border-green w3-hover-border-grey\">×</span>\n" +
                            "   <h5>User '" + request.getAttribute("userName") + "' added!</h5>\n" +
                            "</div>");
                }
            %>
            <div class="w3-card-4">
                <div class="w3-container w3-center w3-green">
                    <h2>Add user</h2>
                </div>
                <form method="post" class="w3-selection w3-light-grey w3-padding">
                    <label>Name:
                        <input type="text" name="name" class="w3-input w3-animate-input w3-border w3-round-large" style="width: 30%"><br />
                    </label>
                    <label>Password:
                        <input type="password" name="pass" class="w3-input w3-animate-input w3-border w3-round-large" style="width: 30%"><br />
                    </label>
                    <button type="submit" class="w3-btn w3-green w3-round-large w3-margin-bottom">Submit</button>
                </form>
            </div>
        </div>

        <div class="w3-container w3-grey w3-opacity w3-right-align w3-padding">
            <button class="w3-btn w3-round-large" onclick="location.href='/'">Back to main</button>
        </div>
    </body>
</html>

lista.jsp

<%@ page import="java.util.List" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <head>
        <title>Users list</title>
        <link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
    </head>

    <body class="w3-light-grey">
        <div class="w3-container w3-blue-grey w3-opacity w3-right-align">
            <h1>Super app!</h1>
        </div>

        <div class="w3-container w3-center w3-margin-bottom w3-padding">
            <div class="w3-card-4">
                <div class="w3-container w3-light-blue">
                    <h2>Users</h2>
                </div>
                <%
                    List<String> names = (List<String>) request.getAttribute("userNames");

                    if (names != null && !names.isEmpty()) {
                        out.println("<ul class=\"w3-ul\">");
                        for (String s : names) {
                            out.println("<li class=\"w3-hover-sand\">" + s + "</li>");
                        }
                        out.println("</ul>");

                    } else out.println("<div class=\"w3-panel w3-red w3-display-container w3-card-4 w3-round\">\n"
+
                            "   <span onclick=\"this.parentElement.style.display='none'\"\n" +
                            "   class=\"w3-button w3-margin-right w3-display-right w3-round-large w3-hover-red w3-border w3-border-red w3-hover-border-grey\">×</span>\n" +
                            "   <h5>There are no users yet!</h5>\n" +
                            "</div>");
                %>
            </div>
        </div>

        <div class="w3-container w3-grey w3-opacity w3-right-align w3-padding">
            <button class="w3-btn w3-round-large" onclick="location.href='/'">Back to main</button>
        </div>
    </body>
</html>
Isso é tudo :) Se você ainda tiver alguma dúvida ou comentário, ou pelo contrário, algo não deu certo - deixe um comentário. UPD: se você tiver problemas com erro 404 ao clicar nos botões, embora tudo tenha sido feito corretamente, talvez você deva corrigir a configuração de implantação na ideia. Para fazer isso, você precisa ir em Editar configurações (na parte superior perto do botão Iniciar), ir até a aba Deployment no lado direito da janela e certificar-se de que no contexto do Aplicativo está simplesmente indicado / Bem, eu' Anexarei algumas capturas de tela do que resultou de tudo isso.
Criando uma aplicação web simples usando servlets e jsp (parte 2) - 2
Criando uma aplicação web simples usando servlets e jsp (parte 2) - 3
Criando uma aplicação web simples usando servlets e jsp (parte 2) - 4
E finalmente , se quiser praticar com este projeto, você pode tentar:
  • crie um servlet e jsp para excluir um usuário e mais alguns para alterar/editar um usuário existente. Você obterá um aplicativo Web CrUD real :) em servlets));
  • substitua a lista (List) por trabalhar com um banco de dados para que os usuários adicionados não desapareçam após reiniciar o servidor :)
Boa sorte!
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION