CodeGym /Blog Java /Random-ES /Creación de una aplicación web sencilla mediante servlets...
John Squirrels
Nivel 41
San Francisco

Creación de una aplicación web sencilla mediante 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) Conocimientos necesarios para comprender el artículo: ya ha descubierto más o menos Java Core y le gustaría ver las tecnologías JavaEE y la programación web. Sería más sensato que estuvieras estudiando actualmente la búsqueda de colecciones de Java, que trata temas cercanos al artículo.
Creando una aplicación web simple usando servlets y JSPs (parte 2) - 1

Creando entidades

En el paquete de entidades , crearemos una Userclase que tiene dos variables de cadena privadas: nombre y contraseña . Cree constructores (predeterminados y uno que tome ambos valores) y getters/setters, y anule el toString()método por si acaso, junto con los métodos equals()y hashCode(). En otras palabras, haremos todo lo que hace un desarrollador de Java respetable 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 los tomaremos para mostrarlos. Sin embargo, tenemos un problema. No creamos nuestros objetos de servlet. Tomcat hace esto por nosotros. Los métodos que anulamos en ellos ya están definidos para nosotros y no podemos establecer parámetros. Entonces, ¿cómo creamos una lista compartida que será visible en nuestros dos servlets? Si solo creamos un objeto de lista en cada servlet, estaríamos agregando usuarios a una lista, pero mostrando usuarios de otro en ListServlet. Entonces necesitamos un objeto que sea compartido por ambos servlets. En términos generales, necesitamos un objeto que sea compartido por todas las clases de nuestro programa: un objeto para todo el programa. Espero que hayas oído algo sobre los patrones de diseño. Para algunas personas, esta puede ser la primera necesidad real del patrón Singleton en su programa. Podría volverse loco y generar un Singleton dulce con doble verificación y sincronización (sí, nuestra aplicación es multiproceso, ya que los servlets de Tomcat se ejecutan en subprocesos separados). Pero voy a usar la técnica de inicialización temprana, porque es completamente adecuada para nuestros propósitos aquí.

Creando un modelo

Cree una clase (e implemente el patrón Singleton ) en el paquete del modelo y llámelo algo inusual. Por ejemplo, Modelo . Crearemos una lista privada de usuarios en nuestra clase e implementaremos dos métodos: uno para agregar un usuario y otro para devolver una lista de cadenas (nombres de usuario). Dado que nuestro objeto de usuario consta de un nombre de usuario y una contraseña, y no queremos 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 ya ha oído hablar de singleton , probablemente haya oído hablar de otro patrón de diseño modelo-vista-controlador (MVC). Su propósito es separar la lógica empresarial de la vista. Es decir, separar el código que determina qué hacer del código que determina cómo mostrar las cosas. La vista es responsable de cómo se presentan los datos. En nuestro caso, las vistas son nuestras páginas JSP . Precisamente por eso los puse en una carpeta llamada views . El modelo son los datos con los que el programa realmente trabaja. En nuestro caso, se trata de los usuarios (lista de usuarios). Y los controladores son el vínculo entre ellos. Toman datos del modelo y los pasan a las vistas (o obtienen algunos datos de Tomcat, procesarlo y pasarlo al modelo). Usted define su lógica comercial (lo que debe hacer el programa) en ellos, no en el modelo o la vista. Así, cada parte maneja su propio negocio:
  • el modelo almacena datos;
  • las vistas brindan bellas representaciones de los datos;
  • los controladores manejan el procesamiento de datos.
Esto permite que el programa sea bastante simple y mantenible, en lugar de un montón monstruoso de todo el código en una clase. MVC no solo es adecuado para la programación web, sino que se usa especialmente a menudo en esta área (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. Si alguien quiere saber más, ¡Google es tu amigo! Cree un formulario para agregar un usuario. Agregue el formulario a add.jsp . Debe constar de dos campos de entrada de texto (uno ordinario, el otro, un campo de contraseña) y un botón para enviar los 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 la publicación de valor . Esto indica que los datos de este formulario irán al servidor como una solicitud POST . El atributo de acción no se especifica, lo que significa que la solicitud se enviará a la misma dirección desde la que llegamos a esta página ( /add ). Por lo tanto, al recibir una solicitud GET , nuestro servlet vinculado a esta dirección devuelve el JSP con el formulario de agregar usuario. Y si recibe una solicitud POST , entonces sabemos que el formulario envió sus datos aquí (que extraemos del objeto de solicitud en eldoPost()método, proceso y paso al modelo para guardar). Vale la pena señalar que los campos de entrada tienen un parámetro llamado nombre (para nombres de usuario o pase para contraseñas). Este es un punto muy importante. Por lo tanto, para recibir estos datos (el nombre de usuario y la contraseña que se ingresarán) desde la solicitud (dentro del servlet), usaremos estos campos de nombre y contraseña . Pero más sobre eso más adelante. Mi botón para enviar datos se hizo nuevamente como un botón , no como un campo de salida como es habitual. No sé cuán ampliamente adoptado es este enfoque, pero funciona para mí (navegador Chrome).

Manejo de servlet de solicitudes POST

Volvamos al AddServlet . Le recuerdo que para permitir que nuestro servlet "atrape" las solicitudes GET , anulamos el doGet()método en la clase HttpServlet . Para enseñar a nuestro servlet a capturar también solicitudes POST , también debemos anular el doPost()método. Tomcat le pasa objetos de solicitud y respuesta similares con los que trabajaremos. Para comenzar, extraiga el nombre de la solicitud y pase los parámetros enviados por el formulario (si especificó nombres diferentes en el formulario, use esos nombres). Después de eso, cree un objeto de usuario utilizando los datos recibidos. Luego obtenemos el objeto modelo y agregamos 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);
}

Pasar datos a la vista

Pasemos al ListServlet . El doGet()método ya está implementado. Simplemente transfiere el control a la vista ( list.jsp ). Si aún no tiene esto, créelo por analogía con el método en AddServlet . Ahora sería bueno obtener la lista de nombres de usuario del modelo y pasarlos a la vista, que los recibirá y los mostrará de forma hermosa. Para hacer esto, usaremos nuevamente el objeto de solicitud que recibimos de Tomcat . Podemos agregar un atributo a este objeto, dándole algún tipo de nombre. De hecho, podemos agregar el objeto que queremos pasar a la vista. Debido al hecho de que al transferir el control del servlet a la vista, le pasamos a la vista los mismos objetos de solicitud y respuesta que recibió el servlet, podemos agregar nuestra lista de nombres al objeto de solicitud y luego obtener nuestra lista de nombres de usuario de la solicitud. objeto en la vista. Hemos terminado con la clase ListServlet , así que presentaré el código de toda la clase aquí:

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

Ejecutar código Java en archivos JSP

Es hora de mirar list.jsp . Solo se ejecutará cuando ListServlet le transfiera el control. Además, ya preparamos la lista de nombres de usuario del modelo en el servlet y la pasamos aquí en el objeto de solicitud. Como tenemos la lista de nombres, podemos iterar sobre ella usando un forbucle y mostrar cada nombre. Como dije antes, 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, todo lo que necesitamos hacer es colocar la siguiente construcción en el lugar apropiado:

<!-- html code -->
<%
    // Java code
%>
<!-- html code -->
Dentro de este constructo, tenemos acceso a varias variables:
  • request : nuestro objeto de solicitud, que pasamos desde el servlet, donde simplemente se llamó req ;
  • respuesta : el objeto de respuesta (llamado resp en el servlet);
  • out : un objeto JspWriter (que hereda un Writer ordinario ), que podemos usar para "escribir" algo directamente en la página HTML . La declaración out.println("¡Hola, mundo!") es muy similar a System.out.println("¡Hola, mundo!") , ¡pero no los confunda!
  • out.println() "escribe" en una página HTML , mientras que System.out.println escribe en el flujo de salida del sistema . Si llama a System.out.println() dentro de una sección JSP con código Java , verá los resultados en la consola de Tomcat , pero no en la página.
Puede buscar otros objetos disponibles dentro de un JSP aquí . Podemos usar el objeto de solicitud para obtener la lista de nombres pasados ​​desde el servlet (adjuntamos el atributo correspondiente a este objeto), y usamos el objeto de salida para mostrar estos nombres. Mostrémoslos (por el momento, como una simple 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 necesitamos mostrar la lista solo si hay usuarios y, de lo contrario, mostrar una advertencia de que aún no hay usuarios, entonces 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 sabemos cómo pasar datos de servlets a vistas, podemos mejorar nuestro AddServlet para que muestre una notificación sobre la adición exitosa de un usuario. Para hacer esto, en el doPost()método, después de agregar un nuevo usuario al modelo, podemos agregar este nombre de usuario a los atributos del objeto req y devolver el control a una vista ( add.jsp ). Y ahora agregaremos una sección con código Java, donde verificaremos si la solicitud tiene dicho atributo y, si lo tiene, mostraremos un mensaje que indica que el usuario se agregó correctamente. Después de estos cambios, el código completo de 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 doPost()método, creamos un atributo con el nombre del usuario que se agregó al modelo y luego llamamos al doGet()método, al que le pasamos la solicitud y la respuesta actuales. El doGet()método ahora transfiere el control a la vista, que también recibe el objeto de solicitud con el nombre del usuario agregado adjunto como atributo. Lo que nos queda por hacer es corregir add.jsp para que muestre la notificación si no existe tal atributo. Aquí está la versión final de add.jsp :

<%@ 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 lo siguiente:
  • un div con un encabezado;
  • un contenedor div para contenido, que incluye una verificación de si existe un atributo con un nombre de usuario;
  • un div con el formulario de usuario adicional;
  • y en la parte inferior, un pie de página con un botón para volver a la página de inicio.
Esto puede parecer demasiados divs, pero los usaremos más adelante cuando agreguemos estilos. Aquí está la versión final de list.jsp :

<%@ 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 guardar y agregar usuarios, y también mostrar una lista de sus nombres. Ahora solo tenemos que hacerlo bonito... :) Creando una aplicación web simple usando servlets y JSPs (parte 2) - 2

Adición de estilos. Usaremos el framework W3.CSS

Por el momento, nuestra aplicación funciona, pero se ve absolutamente escandalosa. Entonces, agreguemos un fondo, coloreemos el texto y los botones, agreguemos estilo a las listas, alineemos elementos, agreguemos sangrías, etc. Escribir estilos manualmente puede llevar mucho tiempo y poner a prueba nuestros nervios. Así que propongo usar el marco W3.CSS . Ya tiene clases listas para usar con estilos. Solo necesitamos organizar las clases de CSS que queremos usar en los lugares correctos. Para agregarlos a nuestras páginas, primero conectamos el archivo de estilo. Hay dos maneras de hacer esto:
  1. vaya a nuestras páginas e inserte el siguiente enlace directo al archivo de estilo en la sección de encabezado

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

    Esta opción es adecuada si tiene una conexión permanente a Internet. Cuando abra sus páginas en el servidor local, los estilos se extraerán de Internet.

  2. Pero si desea tener todos los estilos localmente y no depender de una conexión a Internet, descargue el archivo de estilo y colóquelo en algún lugar dentro de la carpeta web (por ejemplo, web/styles/w3.css ). Luego revise todas nuestras páginas ( index.html, add.jsp, list.jsp ) y agregue el siguiente enlace al archivo de estilo dentro de la sección principal :

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

    Después de eso, solo revise las etiquetas y agregue los estilos que desee. No me detendré en esto en detalle. En su lugar, solo proporcionaré versiones listas para usar de tres de mis archivos con clases de estilo ráster.

í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>
Y eso es. :) Si todavía tiene alguna pregunta o comentario, o si algo no funciona, por favor deje un comentario. Y adjuntaré un par de capturas de pantalla de cómo resultó todo.
Creando una aplicación web simple usando servlets y JSPs (parte 2) - 3
Creación de una aplicación web sencilla utilizando servlets y JSP (parte 2) - 4
Creación de una aplicación web sencilla utilizando servlets y JSP (parte 2) - 5
Y por último , si quieres practicar con este proyecto, puedes probar lo siguiente:
  • cree un servlet y JSP para eliminar un usuario y agregue otro par para editar un usuario existente. El resultado será una aplicación web CRUD genuina creada con servlets. ;)
  • reemplace la Lista 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