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 1)

Publicado en el grupo Random-ES
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 1) - 1Este material es una continuación lógica de mi artículo Creación de un proyecto web simple en IntelliJ Idea Enterprise . En él demostré cómo crear una plantilla de proyecto web funcional. Esta vez le mostraré cómo crear una aplicación web sencilla pero bonita utilizando las tecnologías Java Servlet API y JavaServer Pages API. Nuestra aplicación tendrá una página de inicio con dos enlaces:
  • a la página de adición de usuarios;
  • a la página de vista de lista de usuarios.
Seguiré usando IntelliJ Idea Enterprise Edition, Apache Maven (solo incluye algunas dependencias) y Apache Tomcat. Al final, “decoraremos” nuestra aplicación usando el framework W3.CSS . Supondremos que en estos momentos ya tienes un proyecto vacío, que desarrollaremos aquí. Si no, lee el primer artículo y hazlo. Sólo te llevará unos minutos :)

Un poco sobre la estructura de la futura aplicación.

Nuestra página principal ( / ) será la página HTML estática más común con un encabezado y dos enlaces/botones:
  • agregar un nuevo usuario (se enviará a /add );
  • ver la lista de usuarios (enviar a /list ).
Tomcat captará las solicitudes a estas direcciones y las enviará a uno de los dos servlets que crearemos (describiremos el mapeo en el archivo web.xml ). Y los servlets, a su vez, procesarán solicitudes, prepararán datos (o los guardarán si se agrega un usuario) y transferirán el control a los archivos jsp correspondientes, que ya "presentarán" el resultado. Almacenaremos los datos en la lista más común (List).

Creemos una página de inicio estática.

Si tiene index.jsp en su carpeta web , elimínelo. En su lugar, en esta carpeta crearemos un archivo html simple llamado index.html :
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>My super project!</title>
</head>
<body>
    <!-- header -->
    <div>
        <h1>Super app!<//h1>
    </div>

    <div>       <!-- content -->
        <div>    <!-- buttons holder -->
            <button onclick="location.href='/list'">List users<//button>
            <button onclick="location.href='/add'">Add user<//button>
        </div>
    </div>
</body>
</html>
Aquí no hay nada complicado. En título indicamos el título de nuestra página. En el cuerpo de la página tenemos dos divs principales: header (header) y content (contenido). En el contenido tenemos un soporte para nuestros botones y, en realidad, dos botones que, al hacer clic, se envían a las direcciones apropiadas. Puede ejecutar el proyecto y ver cómo se ve ahora. Si hace clic en los botones, se abren páginas con un error 404 porque aún no las tenemos. Pero esto sugiere que los botones funcionan. Permítame señalar que esta no es la opción más universal, porque si de repente desactiva JavaScript, estos botones no servirán de nada en el navegador. Pero asumiremos que nadie deshabilitó JavaScript :). Está claro que se podrían utilizar enlaces sencillos, pero yo prefiero botones. Haz lo que más te guste. Y no mires el hecho de que en mis ejemplos habrá muchos divs . Luego los llenaremos de estilos, y todo quedará más bonito :).

Crea archivos jsp para representar el resultado.

En el mismo directorio web crearemos una carpeta donde colocaremos nuestros archivos jsp . Lo llamé vistas y, nuevamente, puedes improvisar. En esta carpeta crearemos dos archivos jsp:
  • add.jsp : página para agregar usuarios;
  • list.jsp : página para mostrar una lista de usuarios.
Démosles los títulos de página apropiados. Algo así como “Agregar nuevo usuario” y “Lista de usuarios”, y lo dejaremos así por ahora.

Creemos dos servlets.

Los servlets aceptarán y procesarán las solicitudes que Tomcat les pasará. En la carpeta src/main/java crearemos un paquete de aplicación , que contendrá nuestras fuentes. Allí tendremos más paquetes diferentes. Por lo tanto, para que estos paquetes no se creen uno dentro del otro, creemos alguna clase en el paquete de la aplicación (luego eliminémosla). Ahora creemos tres paquetes diferentes en el paquete de la aplicación :
  • entidades : aquí es donde se ubicarán nuestras entidades (la clase misma, que describirá los objetos del usuario);
  • modelo : nuestro modelo estará aquí (más sobre esto más adelante);
  • servlets - bueno, aquí estarán nuestros servlets.
Después de esto, puedes eliminar de forma segura esa clase del paquete de la aplicación (si la creaste, por supuesto). En el paquete de servlets crearemos dos clases:
  • AddServlet : procesará las solicitudes recibidas en /add ;
  • ListServlet : procesará las solicitudes recibidas en /list .

Conectando dependencias en Maven

Tomcat versión 9.* implementa las especificaciones de Servlet versión 4.0 y JavaServer Pages versión 2.3. Esto está escrito en la documentación oficial de Tomcat 9 en el primer párrafo de la segunda línea. Esto significa que si usted, como yo, está utilizando esta versión de Tomcat, entonces el código que escribimos y enviamos para ejecutar utilizará exactamente las versiones especificadas. Pero nos gustaría tener estas especificaciones en nuestro proyecto, para que nuestro código que las utiliza al menos se compile correctamente. Y para ello necesitamos cargarlos en nuestro proyecto. Aquí es donde Maven viene al rescate.

La regla general es esta: si necesitas conectar algo a tu proyecto usando Maven:

  • vaya al sitio web del repositorio de Maven;
  • busque allí la biblioteca que necesita y la versión que necesita;
  • obtienes el código de dependencia que debe insertarse en tu pom.xml;
  • ¡insertar! :)
Vamos a empezar. Primero, preparemos un archivo pom . En algún lugar después de /version pero antes de /project , inserte lo siguiente:
<dependencies>

</dependencies>
Así, indicamos que dentro de estas etiquetas listaremos las dependencias que necesitamos. Ahora vaya a mvnrepository.com , habrá un campo de búsqueda en la parte superior. Primero, ingrese servlet en la búsqueda. Nos conviene el primer resultado, donde hay más de siete mil usos. Recordamos que necesitamos la versión 4.0 (para Tomcat 9; para otras versiones, pueden ser adecuadas implementaciones anteriores). Esta es una versión bastante reciente, por lo que no tiene muchos usos, pero es la que necesitamos. Se abrirá una página donde podrá obtener el código de esta dependencia para varios administradores de paquetes e incluso podrá descargarlo. Pero como queremos conectarlo usando Maven, seleccionamos el código en la pestaña Maven. Copiamos y pegamos en nuestro archivo pom dentro de la sección de dependencias. Si aparece una notificación en la esquina inferior derecha de IDEA preguntándonos si queremos habilitar la importación automática, estamos de acuerdo. Si se negó accidentalmente, vaya a "Configuración" y habilite la importación automática manualmente: Configuración (Ctrl + Alt + S) -> Compilación, Ejecución, Implementación -> Maven -> Importación Esto mantendrá el archivo pom y los archivos de configuración de IDEA para esto. proyecto en sincronía. Ahora, usando el mismo principio, buscaremos y conectaremos JavaServer Pages versión 2.3 (ingrese jsp en la búsqueda). Y como ya hemos adoptado Maven, digámosle inmediatamente que nuestras fuentes cumplen con la sintaxis de Java 8 y que deben compilarse en un código de bytes de la misma versión. Después de todas estas manipulaciones, nuestro pom.xml se verá así:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>ru.javarush.info.fatfaggy</groupId>
    <artifactId>my-super-project</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>1.8</maven.compile.source>
        <maven.compiler.target>1.8</maven.compile.target>
    </properties>

    <dependencies>
        <!-- Servlet API 4.0 for tomcat 9 -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.0</version>
            <scope>provided</scope>
        </dependency>

        <!-- JavaServer Pages API 2.3 for tomcat 9 -->
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>javax.servlet.jsp-api</artifactId>
            <version>2.3.1</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

</project>

Hacer que nuestros servlets sean servlets reales

En este punto, el par de servlets que hemos creado son en realidad sólo clases normales. No tienen ninguna funcionalidad. Pero ahora hemos conectado la API de Servlet a nuestro proyecto y, de ser así, podemos usar clases desde allí. Para que nuestros servlets sean “reales”, simplemente necesitamos heredarlos de la clase HttpServlet .

Mapeo o partición

Ahora sería bueno decirle de alguna manera a Tomcat que las solicitudes de /add sean manejadas por nuestro servlet AddServlet y, por lo tanto, las solicitudes de /list sean manejadas por el servlet ListServlet . Este proceso se llama mapeo . Esto se hace en el archivo web.xml según este principio:
  • primero describimos el servlet (le damos algún nombre e indicamos la ruta a la clase misma);
  • luego vinculamos este servlet a una dirección específica (indicamos el nombre del servlet que le acabamos de dar e indicamos la dirección desde donde se deben enviar las solicitudes a este servlet).
Describamos el servlet:
<servlet>
    <servlet-name>add</servlet-name>
    <servlet-class>app.servlets.AddServlet</servlet-class>
</servlet>
Ahora lo vinculamos a la dirección:
<servlet-mapping>
    <servlet-name>add</servlet-name>
    <url-pattern>/add</url-pattern>
</servlet-mapping>
Como puede ver, el nombre del servlet es el mismo en ambos casos. Gracias a esto, Tomcat sabe que si llega una solicitud a la dirección /add , debe pasarse al servlet app.servlets.AddServlet . Hacemos lo mismo con el segundo servlet. Como resultado, nuestro web.xml tiene aproximadamente el siguiente contenido:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">

    <!-- add servlet -->
    <servlet>
        <servlet-name>add</servlet-name>
        <servlet-class>app.servlets.AddServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>add</servlet-name>
        <url-pattern>/add</url-pattern>
    </servlet-mapping>

    <!-- list servlet -->
    <servlet>
        <servlet-name>list</servlet-name>
        <servlet-class>app.servlets.ListServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>list</servlet-name>
        <url-pattern>/list</url-pattern>
    </servlet-mapping>
</web-app>
Por cierto, no creamos etiquetas para la página principal aquí (en / ). El caso es que en este caso no lo necesitamos. Nuestra página de inicio es un archivo html simple que simplemente muestra dos botones. No hay contenido dinámico, por lo que no tiene sentido para nosotros crear un servlet separado al que se enviarán las solicitudes desde la dirección / y que no hará nada más que transferir la ejecución a algún jsp (que también tendría que ser creado), que dibujaría si solo tuviéramos dos botones. No necesitamos esto; estamos contentos con un recurso estático. Cuando Tomcat recibe una solicitud, comprobará que no hay un solo servlet que pueda procesar la solicitud en dicha dirección, y luego verá que en esta dirección hay en realidad un archivo html listo para usar , que enviará con éxito. . Podemos ejecutar nuestra aplicación nuevamente (reiniciar el servidor o volver a implementarlo, como desee) y asegurarnos de que la página principal se muestre, que no haya nada roto, cuando hacemos clic en los botones, se producen transiciones, pero por ahora también hay un error. escrito. Por cierto, si antes teníamos un error 404, ahora tenemos un 405. Esto significa que el mapeo funcionó, se encontraron los servlets, pero simplemente no tenían ningún método adecuado para procesar la solicitud. Si en esta etapa todavía aparece el error 404, 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 esté indicado /

Una breve digresión lírica: ¿qué está pasando “bajo el capó”?

Probablemente ya te hayas preguntado ¿cómo funciona nuestra aplicación en Tomcat? ¿Que esta pasando ahí? ¿Y dónde está el método main() ? Tan pronto como escribe localhost:8080 en su navegador y va a esta dirección, el navegador envía una solicitud a esta dirección a través del protocolo http . Espero que ya sepas que las solicitudes pueden ser de diferentes “tipos”, siendo las más populares GET y POST . Cada solicitud debe tener una respuesta. Una solicitud GET espera que en respuesta se le proporcione un código html listo para usar , que se devolverá al navegador, y el navegador reemplazará maravillosamente este código con todo tipo de letras, botones y formularios. La solicitud POST es un poco más interesante, ya que también lleva consigo cierta información. Por ejemplo, en el formulario de registro o autorización de usuario, ingresaste tus datos y hiciste clic en “enviar”. En ese momento, se envió una solicitud POST al servidor con su información personal dentro. El servidor aceptó esta información, la procesó y devolvió algún tipo de respuesta (por ejemplo, una página html con su perfil). La diferencia fundamental entre ellas es que las solicitudes GET están destinadas únicamente a recibir datos del servidor, mientras que las solicitudes POST llevan consigo cierta información y los datos en el servidor pueden cambiar (por ejemplo, cuando carga su foto en el servidor, volará en la solicitud POST y el servidor la agregará a la base de datos, es decir, se producirá algún cambio. Ahora volvamos a Tomcat. Cuando recibe alguna solicitud del cliente, mira la dirección. Busca sus datos para vea si hay un servlet adecuado que procese las solicitudes a dicha dirección (o un recurso listo para usar que pueda devolverse de inmediato). Si no encuentra nada que devolver, no responde con una página html, sino con una respuesta 404. Si encuentra un servlet adecuado, que "se encuentra" en esta dirección, mira qué tipo de solicitud recibió (GET, POST o alguna otra) y luego le pregunta al servlet si tiene un método que podría manejar este tipo de solicitud. Si el servlet dice que no puede procesar este tipo, Tomcat responde al cliente con el código 405. Esto es lo que nos acaba de pasar. Pero si se encuentra un servlet adecuado y tiene un método adecuado, Tomcat crea un objeto de este servlet, lo ejecuta en un nuevo hilo ( hilo ), lo que permite que el servlet funcione en un hilo separado, y Tomcat continúa trabajando. por su cuenta, recibiendo y enviando solicitudes. Además, Tomcat crea dos objetos más: uno de tipo HttpServletRequest (lo llamaré brevemente solicitud en el futuro) y el segundo de tipo HttpServletResponse .(Lo llamaré la respuesta). En el primer objeto coloca todos los datos que recibió en una solicitud del cliente, por lo que todos esos datos se pueden extraer de este objeto. Bueno, después de todo esto, pasa estos dos objetos al método apropiado del servlet que se ejecuta en un hilo separado. Tan pronto como el servlet termina su trabajo y tiene una respuesta lista para enviar al cliente, envía una bandera a Tomcat, diciendo: "Ya terminé, todo está listo". Tomcat acepta la respuesta y la envía al cliente. Esto permite a Tomcat aceptar solicitudes y enviar respuestas sin interrupción, mientras que todo el trabajo lo realizan servlets que se ejecutan en subprocesos separados. En consecuencia, cuando escribimos código de servlet, definimos el trabajo que se realizará. Y sí, puedes pensar que el método main() está en el propio Tomcat (sí, está escrito en Java), y cuando "iniciamos" Tomcat, el archivo main().

Captamos métodos GET con servlets y enviamos respuestas simples

Por el momento nuestros servlets no tienen métodos adecuados (GET), por lo que Tomcat nos devuelve un error 405. ¡Hagámoslos! La clase HttpServlet , de la que heredamos nuestros servlets, define diferentes métodos. Para establecer algún código para los métodos, simplemente los anulamos. En este caso, necesitamos anular el método doGet() en ambos servlets.
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

}
Como puede ver, este método acepta dos objetos: req (solicitud) y resp (respuesta). Estos son los mismos objetos que Tomcat creará y completará cuando llame al método apropiado en este servlet. Primero, hagamos las respuestas más simples. Para hacer esto, tome el objeto resp y obtenga de él un objeto PrintWriter , que puede usarse para redactar respuestas. Bueno, usándolo imprimiremos una cadena simple.
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    PrintWriter writer = resp.getWriter();
    writer.println("Method GET from AddServlet");
}
Haremos algo similar en el servlet ListServlet , después de lo cual iniciaremos nuestro servidor nuevamente. Como puedes ver, ¡todo funciona! Al hacer clic en los botones, se abren páginas con el texto que “grabamos” con PrintWriter . Es solo que nuestro jsp que preparamos para generar páginas con respuestas no se usa de ninguna manera. Esto se debe a que la ejecución simplemente no les llega. El propio servidor ahora genera una respuesta y finaliza su trabajo, indicando a Tomcat que tiene una respuesta lista para el cliente. Tomcat simplemente toma esta respuesta y la envía de vuelta al cliente. Transferimos el control de los servlets a jsp, cambiemos el código de nuestros métodos de esta manera:
  • obtenemos del objeto de solicitud un objeto de administrador de solicitudes, donde pasamos la dirección jsp de la página a la que queremos transferir el control;
  • Usando el objeto recibido, transferimos el control a la página jsp especificada y no olvidemos adjuntar allí los objetos de solicitud y respuesta que recibimos de Tomcat.
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    RequestDispatcher requestDispatcher = req.getRequestDispatcher("views/add.jsp");
    requestDispatcher.forward(req, resp);
}
En el cuerpo de las páginas jsp (dentro de la etiqueta del cuerpo) podemos escribir algo para que podamos ver claramente qué página se muestra. Después de eso, reiniciamos el servidor y verificamos. Se presionan los botones en la página principal, se abren las páginas, lo que significa que las solicitudes se envían a los servlets, después de lo cual el control se transfiere a las páginas jsp, que ya están representadas. Eso es todo. En la siguiente parte del artículo nos ocuparemos de la funcionalidad de nuestra aplicación.

Qué más leer:

Creación de un proyecto web simple en IntelliJ Idea Enterprise. Paso a paso, con fotos.


mi charla
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION