Computación Web (2025/26)

Práctica 5: Desarrollo de una aplicación Web con Spring MVC (I)

Preparación de tu entorno de desarrollo

El entorno de desarrollo recomendado para este laboratorio y los siguientes son los ordenadores de los laboratorios del Departamento de Ingeniería Telemática, a los que puedes acceder directamente en un laboratorio o de forma remota desde un navegador Web a través del servicio de laboratorio virtual en https://aulavirtual.lab.it.uc3m.es/. En ellos usaremos un sistema GNU/Debian Linux.

Cuando te conectes al servicio de laboratorio virtual, selecciona siempre que sea posible "DPTO-TELEM-VIRTUAL-4", ya que sus máquinas virtuales están siempre disponibles para acceso libre, mientras que las otras podrían estar reservadas para clases de otras asignaturas.

No obstante, puedes usar tu propio ordenador Linux, Windows o MacOS si lo prefieres. En ese caso, deberás instalar tú mismo un servidor de bases de datos MySQL o MariaDB (no debería ser demasiado complicado) así como un JDK de Java 17 o superior (por ejemplo, OpenJDK u Oracle JDK). Puedes usar Visual Studio Code o tu entorno de desarrollo preferido para Java. Por favor, ten en cuenta que es imposible para los profesores proporcionar soporte técnico para la instalación en tu propio ordenador de las herramientas necesarias u otros problemas relacionados.

Para tu comodidad, cada ejercicio proporcionará tanto los comandos Linux como los de Windows cuando sea apropiado. Los comandos Linux están adaptados para la instalación en el laboratorio, aunque probablemente funcionarán en otros sistemas Linux e incluso MacOS. De nuevo, ten en cuenta que no podemos garantizar que estos comandos funcionen correctamente si no estás usando los ordenadores del Departamento de Ingeniería Telemática en el laboratorio o los virtuales.

Despliegue de la base del proyecto

La aplicación que desarrollarás en el proyecto funcionará sobre el entorno Spring Boot, el cual facilitará considerablemente la tarea de desplegar un servidor Web en que ejecutar tu aplicación. Este entorno proporciona un sistema llamado Spring Initializr que permite crear el esqueleto inicial de una aplicación Spring Boot. Cuando quieras comenzar a desarrollar una aplicación Spring desde cero, resultará práctico utilizar este servicio.

Sin embargo, en vez de utilizar Initializr, comenzaremos este proyecto sobre la base de código que se proporciona a continuación. Crea un directorio de trabajo para el código del proyecto y, en él, descarga y descomprime el fichero microblog-app.tgz.

Antes de hacer nada más, puedes comprobar que el código base funcione entrando en el directorio microblog-app que se acaba de descomprimir y ejecutando el comando:

./gradlew bootRun

Si estás en Windows, ejecuta en su lugar:

gradlew bootRun

Tras cerca de un minuto (a partir de la segunda vez tardará bastante menos), la aplicación Web estará lista. Cuando dejen de actualizarse los mensajes y veas el texto "Started MicroblogApplication in X seconds", aunque no te indique un porcentaje del 100%, podrás acceder a la aplicación abriendo en un navegador el URL http://localhost:8080/. Deberías ver una página muy simple que solo muestra dos publicaciones de prueba.

Gradle es un sistema que automatiza la obtención de dependencias, compilación y despliegue de aplicaciones. En este caso, se encarga de descargar todas las bibliotecas de código que tu aplicación necesita, compilar el código fuente de la aplicación y lanzar un servidor Web a través del cual podrás acceder a la misma.

Puedes parar este servidor en cualquier momento introduciendo en el terminal la combinación de teclas Ctrl+C en el terminal en que estés ejecutando Gradle. En general, cada vez que cambies el código y desees probar los cambios, pararás el servidor y lo volverás iniciar, para que se compile y despliegue la nueva versión de la aplicación.

Análisis de la aplicación desplegada

Abre el directorio microblog-app desde tu entorno de desarrollo preferido. Por ejemplo, si usas Visual Studio Code, entra en el directorio y ejecuta (o, simplemente, ejecuta Visual Studio Code y selecciona el menú File / Open Folder):

code .

Este primer inicio le puede llevar unos minutos hasta que todo esté listo. A partir de la segunda vez debería iniciar más rápidamente.

Antes de nada, instala las siguientes extensiones de Visual Studio Code, que facilitarán el desarrollo de aplicaciones Spring Boot en Java: Spring Boot Extension Pack y Java Extension Pack. Puedes instalarlas en el menú de extensiones de VS Code, buscándolas por nombre y presionando en el botón de instalación.

Encontrarás el código fuente Java de la aplicación Web bajo el directorio src/main/java. El primer fichero de la aplicación en el cual te puedes fijar es el código fuente de la clase que define la aplicación, MicroblogApplication en el paquete es.uc3m.microblog:

@SpringBootApplication
public class MicroblogApplication {

    public static void main(String[] args) {
        SpringApplication.run(MicroblogApplication.class, args);
    }
}
Configura esta clase como la clase principal de la aplicación Spring Boot. Activa la configuración automática de Spring Boot y localiza los componentes de la aplicación.
Inicia la aplicación Spring Boot a partir de la clase MicroblogApplication.

Esta clase arranca el entorno de autoconfiguración que Spring Boot proporciona para la aplicación.

Cuando pides el recurso principal (URL /) de la aplicación, se ejecuta el método mainView del controlador MainController en el paquete es.uc3m.microblog.controllers:

@Controller
@RequestMapping(path = "/")
public class MainController {

    @GetMapping(path = "/")
    public String mainView(Model model) {
        List<Message> messages = new ArrayList<Message>();
        User user = new User();
        user.setId(1);
        user.setEmail("mary@example.com");
        user.setName("mary");
        Message message = new Message();
        message.setId(1);
        message.setUser(user);
        message.setText("Test post");
        message.setTimestamp(new Date());
        messages.add(message);
        message = new Message();
        message.setId(2);
        message.setUser(user);
        message.setText("Another post");
        message.setTimestamp(new Date());
        messages.add(message);
        model.addAttribute("messages", messages);
        return "main_view";
    }
}
Configura esta clase como un controlador de la aplicación.
Configura esta clase para que se encargue de manejar las peticiones a la ruta raíz de la aplicación (URL /). Servirá de prefijo implícito para las rutas de los métodos de esta clase.
Configura este método para que se encargue de manejar las peticiones a la ruta raíz de la aplicación (URL /).
El objeto de la clase Model se usa para almacenar atributos que luego serán accesibles desde las plantillas de código que se usen para generar las vistas de la aplicación. Por el hecho de declarar este objeto como parámetro del método, el entorno de Spring Boot se encargará de proporcionarlo automáticamente cada vez que se ejecute el método.
El valor de retorno de este método es una cadena de texto que indica el nombre de la plantilla de código que se usará para generar la vista que se devolverá al cliente (main_view.html en este caso).

Este controlador crea, a modo de demostración porque la aplicación todavía no está conectada con una base de datos, un usuario y dos publicaciones en la red social (observa el código de las clases User y Message en el paquete es.uc3m.microblog.model). A continuación, el programa añade una lista con las dos publicaciones creadas como atributo del objeto de la clase Model. Finalmente, devuelve la cadena de texto "main_view".

El hecho de devolver esta cadena de texto le indica al entorno que debe devolver al cliente la salida proporcionada por la plantilla de código src/main/resources/templates/main_view.html. El objeto Model será accesible a esta plantilla, lo cual le permitirá acceder a los objetos de ambos mensajes y, por tanto, mostrar su contenido. Observa el contenido de esta plantilla:

<!DOCTYPE html>
<html xmlns:th="https://www.thymeleaf.org">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Microblogging app</title>
        <link rel="stylesheet" href="public/microblog.css">
    </head>
    <body>
        <header>
            <h1>Microblogging</h1>
            <a href="/">Home</a>
        </header>
        <section class="content">
            <form th:action="@{/post}" method="post">
                <textarea name="text" placeholder="Type a new post here"></textarea>
                <input type="submit" value="Post!">
            </form>
            <h2>Latest posts from the people you follow</h2>
            <div class="messages">
                <div class="message" th:each="message : ${messages}">
                    <div class="text" th:text="${message.getText()}">
                        Text of the post
                    </div>
                    <div class="metadata">
                        <span class="author" th:text="${message.getUser().getName()}">Author's name</span>
                        <span class="date" th:text="${message.getTimestamp()}">Timestamp</span>
                    </div>
                </div>
            </div>
        </section>
    </body>
</html>
Cada vez que se nombre un elemento o atributo con el prefijo th:, se estará usando una instrucción del lenguaje de plantillas Thymeleaf. Por ejemplo, el atributo th:each hace referencia a un atributo llamado each definido por Thymeleaf, y no a un atributo HTML estándar.
Se generará un atributo action con el valor /post. El prefijo @ se usa para indicar que el valor de este atributo es una URL relativa a la raíz de la aplicación.
Se generará este elemento div tantas veces como publicaciones se incluyan en la variable messages. La variable message irá tomando como valor, en cada iteración, el mensaje de la lista messages que corresponda con dicha iteración.
Se accede al atributo messages que el controlador ha incluido previamente en el objeto Model.
El contenido de este elemento div será reemplazado por el resultado de evaluar la expresión ${message.getText()}, esto es, el resultado de invocar el método getText() del objeto message.
Este texto no se mostrará, dado que será reemplazado por el resultado de evaluar la expresión del atributo th:text. Sin embargo, lo incluimos para que, si se abre la plantilla directamente en un navegador sin pasar por el sistema de plantillas Thymeleaf, se muestre un texto de ejemplo en vez de un elemento vacío. Esto hace más ágil diseñar y modificar la plantilla.

Esta plantilla se basa en el lenguaje de plantillas Thymeleaf. Este lenguaje te permite escribir código HTML estático para las vistas de tu aplicación, y añadirle instrucciones para inyectar en las plantillas datos provenientes de la aplicación. En este caso, se está accediendo al atributo messages que el controlador almacenó anteriormente en el objeto Model.

El elemento div de la clase message se generará tantas veces como publicaciones se incluyan en el atributo messages recibido. La variable llamada message irá tomando como valor cada uno de dichos mensajes y, por tanto, se irá mostrando el texto de los mensajes uno a uno a partir de la plantilla que se proporciona para este elemento div.

Modifica el controlador para que cree e incluya en la lista una nueva publicación. Para que tomen efecto las modificaciones que acabas de realizar, para la aplicación presionando Control+C en el terminal donde la estés ejecutando e iníciala de nuevo a continuación. Recarga la página en el navegador y comprueba que ahora se muestre también el mensaje que acabas de crear.

Plantilla de la vista principal

Integra la vista principal que creaste en el laboratorio de HTML y CSS, junto con su hoja de estilos CSS, con las plantillas del ejercicio anterior, de forma que se presenten los mismos tres mensajes con el aspecto que tendrán en tu aplicación.

Guarda los ficheros estáticos, como tus hojas de estilos CSS o imágenes, bajo el directorio src/main/resources/static/public en el árbol de directorios de tu código fuente. Su ruta URL comenzará por /public (observa, por ejemplo, cómo ya se está incluyendo una hoja de estilos CSS en main_view.html).

Vista del perfil público de un usuario

De forma análoga a lo hecho en la vista principal, crea un método controlador y una plantilla para la vista que muestra el perfil público de un usuario.

En primer lugar, debes crear un nuevo método en la clase MainController que cree un usuario de prueba, así como una lista con algunos mensajes de dicho usuario. Debes además asignarle una ruta distinta a la de la vista principal como, por ejemplo, /user.

A continuación, debes crear una nueva plantilla Thymeleaf que reciba el objeto usuario y los mensajes, y los muestre, reutilizando el diseño de esta vista que creaste en el laboratorio de HTML y CSS. Recuerda que el método del controlador debe devolver el nombre de esta nueva plantilla para que esta se aplique.

Plantilla de la vista de mensaje

De forma similar a la vista principal y a la vista del perfil público de un usuario, crea el controlador y la plantilla para la vista que muestra un mensaje concreto junto con las respuestas al mismo.

Primero, añade un nuevo método a la clase MainController que cree un mensaje de prueba, así como una lista con algunas respuestas (también de prueba) a dicho mensaje. Asígnale una ruta, como /message.

A continuación, debes crear una nueva plantilla Thymeleaf que muestre dichos objetos, con un diseño que sea consistente con las otras dos vistas que ya tienes.