JavaRush /Blog Java /Random-ES /Creando una aplicación web simple usando servlets y jsp (...
Стас Пасинков
Nivel 26
Киев

Creando una aplicación web simple usando servlets y jsp (parte 2)

Publicado en el grupo Random-ES
Creación de una aplicación web sencilla utilizando servlets y jsp (parte 1) Nivel de conocimiento necesario para comprender el artículo: ya comprende más o menos Java Core y le gustaría conocer las tecnologías JavaEE y la programación web. Tiene más sentido si actualmente está estudiando la búsqueda de Colecciones de Java, que cubre temas cercanos al artículo.
Creando una aplicación web simple usando servlets y jsp (parte 2) - 1

Creando entidades

En el paquete de entidades , crearemos una clase Usuario y en ella habrá dos variables de cadena privada, nombre y contraseña . Creemos constructores (predeterminado y uno que acepte ambos valores), getters/setters, anulemos el método toString() por si acaso, así como los métodos equals() y hashCode() . Es decir, haremos todo lo que hace un desarrollador Java decente al crear una clase.
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;
    }
}
Ahora podemos comenzar a crear una lista de usuarios. Le agregaremos usuarios y desde donde los tomaremos para mostrarlos. Sin embargo, hay un problema. No creamos nuestros objetos servlet, Tomcat lo hace por nosotros . Los métodos que anulamos en ellos también ya están definidos para nosotros y no podemos agregar un parámetro. Entonces, ¿cómo podemos crear una lista compartida que sea visible para ambos servlets? Si simplemente creamos nuestro propio objeto de lista en cada servlet, resultará que agregaremos usuarios a una lista y mostraremos la lista de usuarios que usan el servlet ListServlet en otra. Resulta que necesitamos un objeto que sea común a ambos servlets. En términos generales, necesitamos un objeto que sea común a todas las clases de nuestro programa; el único objeto para todo el programa. Espero que hayas oído algo sobre los patrones de diseño. Y, quizás, para algunos esta sea la primera necesidad real de utilizar el patrón Singleton en su programa. Puedes pervertirte y crear un Singleton genial con doble verificación y sincronización (sí, tenemos una aplicación multiproceso, ya que Tomcat ejecuta servlets en diferentes subprocesos), pero usaré la opción con inicialización temprana, ya que es bastante adecuada aquí. suficiente y se adapta a nuestros propósitos.

Creando un modelo

Creemos una clase (e implementemos el patrón Singleton en ella ) en el paquete del modelo y llamémosla algo inusual. Digamos Modelo . Creemos un objeto de lista de usuarios privado en nuestra clase e implementemos dos métodos: uno para que podamos agregar un usuario y el segundo para devolver una lista de cadenas (nombres de usuario). Dado que nuestro objeto de usuario consta de un nombre y una contraseña, y no nos gustaría "revelar" las contraseñas de los usuarios, solo tendremos una lista de nombres.
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());
    }
}

Un poco sobre mvc

Como has oído hablar de singleton , probablemente hayas oído hablar de otro patrón de diseño: MVC (model-view-controller, en ruso model-view-controller, o simplemente como en inglés model-view-controller). Su esencia es separar la lógica empresarial de la presentación. Es decir, separe el código que determina qué hacer del código que determina cómo mostrar. Ver (ver o simplemente vistas) es responsable de la forma en que se presentan algunos datos. En nuestro caso, las vistas son nuestras páginas JSP. Por eso los puse en una carpeta llamada vistas . El modelo son los datos reales con los que trabaja el programa. En nuestro caso, se trata de usuarios (lista de usuarios). Bueno, los controladores son el vínculo que los une. Toman datos del modelo y los pasan a las vistas (o reciben algunos datos de Tomcat, los procesan y los pasan al modelo). La lógica empresarial (qué debería hacer exactamente el programa) debe describirse en ellos, y no en el modelo o en la vista. Así, cada uno hace lo suyo:
  • el modelo almacena datos;
  • las vistas dibujan una hermosa representación de los datos;
  • Los responsables del tratamiento se ocupan del tratamiento de los datos.
Esto permite que el programa sea bastante simple y fácil de mantener, en lugar de un volcado monstruoso de todo el código en una clase. MVC es adecuado no solo para la programación web, sino que es en esta área donde se encuentra con especial frecuencia (casi siempre). En nuestro caso, los servlets actuarán como controladores. Esta es una descripción muy superficial y breve del patrón, pero MVC no es el tema principal de este artículo. ¿Quién quiere saber más? ¡Google al rescate! Cree un formulario para agregar un usuario Agreguemos al archivo add.jsp un formulario que consta de dos campos de entrada de texto (uno normal y el otro una contraseña) y un botón para enviar datos al 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>
Aquí el formulario tiene un atributo de método con el valor post . Esto significa que los datos de este formulario se enviarán al servidor en forma de solicitud POST. El atributo de acción no está especificado, lo que significa que la solicitud se enviará a la misma dirección donde fuimos a esta página ( /add ). Así, nuestro servlet vinculado a esta dirección, al recibir una solicitud GET, devuelve este jsp con el formulario para agregar usuarios, y si recibe una solicitud POST, significa que el formulario envió allí sus datos (que extraeremos del solicitar objeto en el método doPost() Vale la pena señalar que los campos de entrada tienen un parámetro de nombre (para un campo con nombre tiene el valor nombre, y para un campo con contraseña tiene el valor pasar ). Este es un punto bastante importante. Dado que para obtener estos datos (nombre y contraseña que se ingresarán) de la solicitud (ya dentro del servlet), usaremos exactamente estos nombre y contraseña . Pero hablaremos de eso más adelante. El botón para enviar datos en sí vuelve a tener la forma de un botón y no como un campo de salida, como suele ser habitual. No sé qué tan universal es esta opción, pero a mí me funciona (navegador Chrome).

Procesar una solicitud POST con un servlet

Volvamos al servlet AddServlet . Permítame recordarle: para que nuestro servlet pueda "captar" solicitudes GET, anulamos el método doGet() de la clase HttpServlet . Para enseñarle a nuestro servlet a capturar también solicitudes POST, también debemos anular el método doPost() . Recibe objetos de solicitud y respuesta similares de Tomcat , con los que trabajaremos. Primero, extraigamos de la solicitud el nombre y pasemos los parámetros que envió el formulario (si los nombró de manera diferente en el formulario, entonces esos serán los nombres que escriba). Después de esto, crearemos nuestro objeto de usuario utilizando los datos recibidos. Luego obtendremos el objeto del modelo y agregaremos el usuario creado al 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);
}

Pasando datos para ver

Pasemos al servlet ListServlet . El método doGet() ya se ha implementado aquí , que simplemente transfiere el control a la vista list.jsp . Si aún no lo tienes, hazlo por analogía con el mismo método del servlet AddServlet . Ahora sería bueno obtener una lista de nombres de usuario del modelo y pasarlos a la vista, que los recibirá y los mostrará correctamente. Para hacer esto, usaremos nuevamente el objeto de solicitud que recibimos de Tomcat . Podemos agregar un atributo a este objeto, dándole algún nombre y, de hecho, el objeto en sí que nos gustaría transferir a la vista . Debido al hecho de que al transferir el proceso de ejecución de un servlet a una vista, pasamos allí los mismos objetos de solicitud y respuesta que recibió el servlet, luego, al agregar nuestra lista de nombres al objeto de solicitud, podemos desde esta solicitud El objeto en la vista crea nuestra lista de nombres de usuarios y obtiene. Hemos terminado con la clase ListServlet , así que aquí está el código para toda la clase:
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);
    }
}

Ejecutando código java en archivos jsp

Es hora de empezar a trabajar en el archivo list.jsp . Solo se ejecutará cuando ListServlet pase el proceso de ejecución aquí. Además, en ese servlet ya preparamos una lista de nombres de usuarios del modelo y la pasamos aquí en el objeto de solicitud. Como tenemos una lista de nombres, podemos recorrerla e imprimir cada nombre. Como ya dije, los archivos jsp pueden ejecutar código java (que es lo que los diferencia de las páginas html estáticas). Para ejecutar algún código, basta con colocar la siguiente construcción en el lugar que necesitamos:
<!-- html código -->
<%
    // java código
%>
<!-- html código -->
Dentro de esta construcción tenemos acceso a varias variables:
  • request es nuestro objeto de solicitud, que pasamos desde el servlet, donde simplemente se llamó req ;
  • respuesta : objeto de respuesta, llamado resp en el servlet ;
  • out es un objeto del tipo JspWriter (heredado del Writer habitual ), con la ayuda del cual podemos "escribir" algo directamente en la página html. La entrada out.println("Hello world!") es muy similar a la entrada System.out.println("Hello world!") , ¡pero no las confundas!
    out.println() "escribe" en la página html y System.out.println escribe en la salida del sistema. Si llama al método jsp System.out.println() dentro de la sección con código Java , verá los resultados en la consola de Tomcat , y no en la página.

Puedes buscar otros objetos disponibles dentro de jsp aquí . Usando el objeto de solicitud , podemos obtener la lista de nombres que se pasaron desde el servlet (adjuntamos el atributo correspondiente a este objeto), y usando el objeto de salida , podemos mostrar estos nombres. Hagamos esto (por ahora solo en forma de 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>
Si necesita mostrar una lista solo si hay usuarios y, en caso contrario, muestra una advertencia de que aún no hay usuarios, podemos reescribir un poco esta sección:
<%
    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>");
%>
Ahora que podemos pasar datos de servlets a vistas, podemos mejorar ligeramente nuestro AddServlet para que se muestre una notificación cuando un usuario se haya agregado exitosamente. Para hacer esto, en el método doPost() , después de agregar un nuevo usuario al modelo, podemos agregar el nombre de este usuario a los atributos del objeto req y devolver el control a la vista add.jsp . Y en él ya crea una sección con código Java en la que se verifica si dicho atributo está en la solicitud y, de ser así, se muestra un mensaje que indica que el usuario se agregó correctamente. Después de estos cambios, el código completo del servlet AddServlet se verá así:
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);
    }
}
Aquí, al final del método doPost() , configuramos un atributo con el nombre del usuario agregado al modelo, después de lo cual llamamos al método doGet() , al que le pasamos la solicitud y la respuesta actuales. Y el método doGet() ya transfiere el control a la vista, donde envía un objeto de solicitud con el nombre del usuario agregado adjunto como atributo. Todo lo que queda es corregir add.jsp para que muestre dicha notificación si dicho atributo está presente. El add.jsp final es :
<%@ 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>
El cuerpo de la página consta de:
  • div-a con encabezado;
  • contenedor div para contenido, verifica si existe un atributo con el nombre de usuario;
  • div con un formulario para agregar usuarios;
  • y al final hay un pie de página con un botón para volver a la página principal.
Puede parecer que hay demasiados divs, pero los usaremos más adelante cuando agreguemos estilos. El list.jsp final es:
<%@ 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>
Por lo tanto, tenemos una aplicación web completamente funcional que puede almacenar y agregar usuarios, así como mostrar una lista de sus nombres. Ya sólo queda embellecerlo... :)

Añadiendo estilos. Usamos el marco W3.CSS.

Por el momento nuestra aplicación está funcionando, pero es una locura. Por lo tanto, agregaremos un fondo, color de texto y botones, listas de estilo, alinearemos, agregaremos sangrías y cosas por el estilo. Si escribe estilos manualmente, puede llevar mucho tiempo y nervios. Por lo tanto, sugiero utilizar el marco CSS W3.CSS. Ya tiene clases listas con estilos, solo queda colocar las clases CSS que queremos aplicar en los lugares correctos. Para poder añadirlos a nuestras páginas, primero incluiremos un archivo con estilos. Esto se puede hacer de dos formas:
  1. recorra nuestras páginas y en la sección de encabezado inserte un enlace directo al archivo con estilos

    <enlace rel="hoja de estilo" href="https://www.w3schools.com/w3css/4/w3.css">

    Esta opción es adecuada si tiene una conexión constante a Internet. Luego, cuando abra sus páginas en un servidor local, los estilos se extraerán de Internet.


  2. Si desea tener todos los estilos localmente y no depender de una conexión a Internet, descargue el archivo con estilos y colóquelo en algún lugar dentro de la carpeta web (por ejemplo, web/styles/w3.css ), luego revise todos nuestros páginas ( index.html, add.jsp, list.jsp ) e ingrese un enlace a este archivo con estilos dentro de la sección principal

    <enlace rel="hoja de estilo" href="estilos/w3.css">

    Después de eso, simplemente revise las etiquetas y agregue los estilos que desee. No me detendré en esto en detalle, pero inmediatamente daré mis versiones listas para usar de mis tres archivos con clases de estilo ordenadas.

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

agregar.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>
Eso es todo :) Si todavía tienes alguna pregunta o algún comentario, o por el contrario, algo no funciona, deja un comentario. UPD: si tienes problemas con errores 404 al hacer clic en botones, aunque todo se hizo correctamente, quizás deberías corregir la configuración de implementación en la idea. Para hacer esto, debe ir a Editar configuraciones (en la parte superior, cerca del botón de inicio), ir a la pestaña Implementación en el lado derecho de la ventana y asegurarse de que en el contexto de la Aplicación simplemente se indique / Bueno, yo'. Adjuntaremos un par de capturas de pantalla de lo que surgió de todo esto.
Creando una aplicación web simple usando servlets y jsp (parte 2) - 2
Creando una aplicación web simple usando servlets y jsp (parte 2) - 3
Creando una aplicación web simple usando servlets y jsp (parte 2) - 4
Y por último , si quieres practicar con este proyecto, puedes probar:
  • cree un servlet y jsp para eliminar un usuario y un par más para cambiar/editar un usuario existente. Obtendrá una aplicación web CrUD real :) en servlets));
  • reemplace la lista (Lista) trabajando con una base de datos para que los usuarios agregados no desaparezcan después de reiniciar el servidor :)
¡Buena suerte!
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION