JavaRush /Blog Java /Random-ES /Aplicación web en Java
Viacheslav
Nivel 3

Aplicación web en Java

Publicado en el grupo Random-ES
Aplicación web en Java - 1

Introducción

Érase una vez, Java fortaleció su posición debido a que eligió las aplicaciones web como prioridad. Desde sus inicios, Java ha luchado por encontrar su camino. Primero, sugerí subprogramas. Esto ha brindado muchas oportunidades para que los desarrolladores creen contenido dinámico (contenido) en páginas HTML estáticas. Sin embargo, los applets no estuvieron a la altura de las expectativas por muchas razones: seguridad, gastos generales y otras. Luego, los desarrolladores del lenguaje Java propusieron una alternativa: Servlet API . Y resultó ser la decisión correcta. La API de Servlet es la especificación sobre la que se construye cualquier aplicación web Java, ya sea una aplicación basada en web o un servicio web que devuelve información según lo solicitado. Por lo tanto, el camino para comprender cómo funcionan las aplicaciones web Java comienza con la comprensión de la API de Servlet.
Aplicación web en Java - 2

API de servlet

Entonces, la API de Servlet es lo que los desarrolladores del lenguaje ofrecieron a los desarrolladores de Java. La API de Servlet es una especificación que debería responder a nuestras preguntas principales. Puede encontrarlo aquí: " JSR-000340 JavaTM Servlet 3.1 Versión final para evaluación ". El capítulo " 1.1 ¿Qué es un Servlet? " dice que un servlet es un componente web basado en tecnología Java que crea contenido dinámico (es decir, contenido). "Basado en Java" significa que un servlet es una clase Java compilada en código de bytes . Los servlets son administrados por un contenedor de servlets, a veces llamado motor de servlet. Un contenedor de servlets es una extensión de servidor web que proporciona funcionalidad de servlet. A su vez, los servlets proporcionan interacción con el cliente en el paradigma de solicitud/respuesta, que es implementado por el contenedor de servlets. En el capítulo " 1.2 ¿Qué es un contenedor de servlet? " se dice que un contenedor de servlet es parte de un servidor web o servidor de aplicaciones que proporciona servicios de red a través de los cuales se envían solicitudes y respuestas, se generan y procesan solicitudes y respuestas basadas en MIME. . Además, los contenedores de servlets gestionan el ciclo de vida de los servlets (es decir, deciden cuándo crearlos, eliminarlos, etc.). Todos los contenedores de servlets deben admitir el protocolo HTTP para recibir solicitudes y enviar respuestas. Aquí me gustaría agregar que MIME es un estándar, una especificación que indica cómo se debe codificar la información y formatear los mensajes para que puedan enviarse a través de Internet.
Aplicación web en Java - 3

Servidor web

Un servidor web es un servidor que acepta solicitudes HTTP de clientes y les proporciona respuestas HTTP (generalmente junto con una página HTML, imagen, archivo u otros datos). Los recursos solicitados se identifican mediante URL. Uno de los servidores web más populares con soporte para Servlet API es Apache Tomcat . La mayoría de los servidores web son máquinas complejas que se componen de varios componentes, cada uno de los cuales realiza funciones específicas. Por ejemplo:
Aplicación web en Java - 4

Conectores

— En la entrada tenemos Conectores (es decir, conectores) que aceptan solicitudes entrantes de los clientes. El conector HTTP en Tomcat se implementa mediante el componente "Coyote". Los conectores reciben datos del cliente y los pasan al motor Tomcat. Contenedor de servlets : Tomcat Engine, a su vez, procesa la solicitud recibida del cliente utilizando el componente "Catalina", que es un contenedor de servlets. Consulte la documentación de Tomcat: " Descripción general de la arquitectura " para obtener más detalles. Existen otros servidores web que admiten la especificación API de Servlet. Por ejemplo, " Embarcadero " o " Resaca ". Su arquitectura es similar, por lo que, al comprender el principio de trabajar con un contenedor de servlets, puede pasar a trabajar con otro.
Aplicación web en Java - 5

Aplicación web

Entonces, para que podamos ejecutar una aplicación web, necesitamos un servidor web que admita la API de Servlet (es decir, uno que tenga un componente de extensión que implemente la compatibilidad con la API de Servlet para el servidor web). Bien. ¿Qué es una aplicación web de todos modos? Según el capítulo " Diez aplicaciones web " de la especificación Servlet API, una aplicación web es una colección de servlets, páginas HTML, clases y otros recursos que conforman una aplicación final en un servidor web. Según el capítulo " 10.6 Archivo de almacenamiento de aplicaciones web ", una aplicación web se puede empaquetar en Web ARchive (un archivo con una extensión WAR). Como se indica en la página " Glosario-219 ":
Aplicación web en Java - 6
Es decir, se crea WAR en lugar de JAR para mostrar que se trata de una aplicación web. El siguiente hecho importante: debemos tener una determinada estructura de directorios en nuestro archivo WAR. En la especificación de Servlet API en el capítulo " 10.5 Estructura de directorios ". Este capítulo dice que hay un directorio especial llamado "WEB-INF". Este directorio es especial porque no es visible para el cliente y no se le muestra directamente, pero es accesible para el código del servlet. También dice lo que puede contener el directorio WEB-INF:
Aplicación web en Java - 7
De toda esta lista, ahora no conocemos ni entendemos el elemento sobre algún archivo web.xml llamado descriptor de implementación . ¿Qué es? El capítulo " 14. Descriptor de implementación " está dedicado al descriptor de implementación. En resumen, un descriptor de implementación es un archivo xml que describe cómo implementar (es decir, ejecutar) nuestra aplicación web en un servidor web. Por ejemplo, el descriptor de implementación indica qué URL se deben utilizar para acceder a nuestra aplicación, se indican las configuraciones de seguridad relacionadas con nuestra aplicación, etc. El capítulo " 14.2 Reglas para procesar la implementación " dice que el esquema de web.xml será validado antes de configurar e iniciar nuestra aplicación (es decir, se verificará que el contenido de web.xml esté escrito correctamente de acuerdo con el esquema). . Y en el capítulo " 14.3 Deployment Descriptor " se indica que el diagrama está aquí: http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd Si miramos el contenido del archivo, podemos ver:
Aplicación web en Java - 8
¿Qué esquema se utiliza para los archivos XML? Los esquemas indican cómo completar correctamente un documento XML: qué elementos se pueden utilizar, qué tipo de datos se pueden especificar en los elementos, en qué orden deben ir los elementos, qué elementos se requieren, etc. Puede comparar el esquema de un documento XML con una interfaz en Java, porque el esquema en Java también especifica cómo se deben escribir las clases que satisfacen una interfaz determinada (es decir, que implementan una interfaz determinada). Entonces, ¡estamos armados con conocimiento secreto y estamos listos para crear nuestra primera aplicación web!
Aplicación web en Java - 9

Creando una aplicación web

Es difícil imaginar trabajar con una aplicación Java moderna sin utilizar sistemas automáticos de creación de proyectos. Algunos de los sistemas más populares son Maven y Gradle . Usaremos Gradle para esta revisión. La instalación de Gradle se describe en el sitio web oficial . Para crear una nueva aplicación, necesitamos un complemento integrado en Gradle: " Build Init Plugin ". Para crear una aplicación Java es necesario ejecutar el siguiente comando: gradle init --type java-application
Aplicación web en Java - 10
Después de crear el proyecto, necesitaremos editar el archivo build.gradle . Este es el llamado Build Script (para más detalles, consulte la documentación de Gradle: " Escribir scripts de compilación "). Este archivo describe cómo ensamblar el proyecto y otros aspectos del trabajo con un proyecto Java. El bloque de complementos describe qué " complementos de Gradle " deben usarse para el proyecto Gradle actual. Los complementos amplían las capacidades de nuestro proyecto. Por ejemplo, el complemento predeterminado es " java ". Este complemento siempre se utiliza si necesitamos soporte para Java. Pero no necesitamos el complemento " aplicación ", porque... su descripción indica que se utiliza para crear una "aplicación JVM ejecutable", es decir. ejecutando aplicaciones JVM. Necesitamos crear una aplicación web en forma de archivo WAR. Y si buscamos la palabra WAR en la documentación de Gradle, encontraremos “ War Plugin ”. Por lo tanto, especificaremos los siguientes complementos:
plugins {
    id 'java'
    id 'war'
}
También en la " Configuración predeterminada del complemento de guerra " se dice que el directorio con todo el contenido de la aplicación web debe ser "src/main/webapp", debe haber el mismo directorio WEB-INF en el que debe estar web.xml. situado. Creemos un archivo de este tipo. Lo completaremos un poco más tarde, porque... Todavía no tenemos suficiente información para esto. En el bloque "dependencias" indicamos las dependencias de nuestro proyecto, es decir, aquellas librerías/frameworks sin las cuales nuestra aplicación no puede funcionar. En este caso, estamos escribiendo una aplicación web, lo que significa que no podemos trabajar sin la API de Servlet:
dependencies {
    providedCompile 'javax.servlet:javax.servlet-api:3.1.0'
    testCompile 'junit:junit:4.12'
}
provideCompile significa que no es necesario incluir la dependencia en nuestro archivo WAR de la aplicación web: solo es necesaria para la compilación. Y cuando se ejecute, esta dependencia será proporcionada por otra persona (es decir, el servidor web). Bueno, dejamos información en el script de compilación sobre qué repositorio de dependencias queremos usar; todas las dependencias especificadas se descargarán desde allí:
repositories {
    jcenter()
}
Eliminamos todo lo demás del archivo del script de compilación. Ahora editemos la clase src\main\java\App.java. Hagamos un servlet con eso. La especificación API de Servlet en el capítulo " CAPÍTULO 2. La interfaz de Servlet " establece que la interfaz de Servlet tiene una implementación básica de HttpServlet , que debería ser suficiente en la mayoría de los casos y los desarrolladores solo necesitan heredar de ella. Y en el capítulo " 2.1.1 Métodos de manejo de solicitudes específicas de HTTP " se indican los principales métodos que procesan las solicitudes entrantes. Por tanto, reescribamos la clase App.java:
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.io.IOException;

public class App extends HttpServlet {
    public String getGreeting() {
        return "Hello world.";
    }

    public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
 		// https://www.oracle.com/technetwork/java/servlet-142430.html
 		PrintWriter out = resp.getWriter();
 		out.println(this.getGreeting());
 		out.close();
 	}
}
Entonces, parece que tenemos todo listo. Todo lo que queda es escribir el descriptor de implementación correctamente. Del diagrama, copie el siguiente texto en web.xml:
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="..."
      version="3.1">
      ...
</web-app>
Y también la ruta al esquema que en él se indica: http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd Ahora veamos un ejemplo de cómo debería verse web.xml en la especificación API de Servlet. Este ejemplo se proporciona en el capítulo " 14.5.1 Un ejemplo básico ". Combinemos lo indicado en el diagrama con el ejemplo indicado en la especificación. Obtenemos lo siguiente:
<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">
      <display-name>A Simple Web Application</display-name>
      <servlet>
		<servlet-name>app</servlet-name>
		<servlet-class>App</servlet-class>
	  </servlet>
	  <servlet-mapping>
		<servlet-name>app</servlet-name>
		<url-pattern>/app</url-pattern>
	  </servlet-mapping>
</web-app>
Como puede ver, utilizamos el esquema y la ubicación del esquema que se especificaron anteriormente. Y la descripción de los elementos mismos se tomó del ejemplo del Capítulo 14.5.1. Si hicimos todo correctamente ejecutaremos la tarea de gradle war sin errores:
Aplicación web en Java - 11
Aplicación web en Java - 12

Lanzar una aplicación web

¿Cómo se inicia una aplicación web? Abordemos primero la opción más compleja. Anteriormente dijimos que existe un servidor web Apache Tomcat que admite la API de Servlet. Esto significa que podemos implementar nuestro archivo de guerra recopilado (también dicen "implementar") en este servidor. En la página " Descargar Tomcat ", descargue desde la sección "Distribuciones binarias" el tipo de entrega "Core" en formato zip. Y descomprima el archivo descargado en algún directorio, por ejemplo en C:\apache-tomcat-9.0.14. Antes de iniciar el servidor, abramos el archivo para editarlo conf\tomcat-users.xmly agreguemos la siguiente línea: <user username="tomcat" password="tomcat" roles="tomcat,manager-gui,admin-gui"/> Ahora, en la línea de comando, vaya al directorio bin y ejecute catalina.bat start. De forma predeterminada, la consola del servidor estará disponible en http://localhost:8080/manager. El nombre de usuario y la contraseña son los mismos que especificamos en tomcat-users.xml. Tomcat tiene un directorio "webapps", que contiene aplicaciones web. Si queremos desplegar el nuestro, debemos copiar allí nuestro archivo de guerra. Cuando ejecutamos anteriormente el comando gradle war, \build\libs\se creó un archivo war en el directorio. Esto es lo que necesitamos copiar. Después de copiar, actualice la página http://localhost:8080/managery vea:
Aplicación web en Java - 13
Una vez completado http://localhost:8080/javaweb/app, pasaremos a nuestro servlet, porque Anteriormente "asignamos" (es decir, asignamos) la solicitud /app al servlet de la aplicación. Existe una forma más rápida de comprobar cómo funciona la aplicación. Y el sistema de montaje también nos ayuda en esto. En el script de compilación de nuestro proyecto Gradle, podemos agregar un nuevo complemento " Gretty " a la sección de complementos: id "org.gretty" version "2.3.1" Y ahora podemos realizar una tarea de Gradle para ejecutar nuestra aplicación:gradle appRun
Aplicación web en Java - 14
Consulte " Agregue el complemento gretty y ejecute la aplicación " para obtener más detalles.
Aplicación web en Java - 15

API de primavera y servlet

Los servlets son la base de todo. E incluso el ahora popular Spring Framework no es más que un complemento de la API de Servlet. Para empezar, Spring Framework es una nueva dependencia para nuestro proyecto. Por lo tanto, agreguémoslo al script de compilación en el bloque de dependencias: compile 'org.springframework:spring-webmvc:5.1.3.RELEASE' En la documentación de Spring Framework hay un capítulo " 1.1. DispatcherServlet ". Dice que Spring Framework se basa en el patrón de "controlador frontal"; esto es cuando hay un servlet central llamado " DispatcherServlet ". Todas las solicitudes llegan a este servlet y este delega las llamadas a los componentes necesarios. Verás, incluso aquí hay servlets. Debe agregar un oyente al descriptor de implementación:
<listener>
	&ltlistener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
Este es un detector de eventos de contexto de servlet. Es decir, cuando se inicia el contexto de servlet, también se inicia el contexto de Spring (WebApplicationContext). ¿Qué es el contexto de servlet? Se describe en la especificación de Servle API en el capítulo " CAPÍTULO 4. Contexto de Servlet ". Un contexto de servlet es una "vista" de un servlet de la aplicación web dentro de la cual se ejecutan los servlets. Cada aplicación web tiene su propio contexto de servlet. A continuación, para habilitar Spring Framework, debe especificar context-param, el parámetro de inicialización para el contexto del servlet.
<context-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>/WEB-INF/app-context.xml</param-value>
</context-param>
Y la definición de DispatcherServlet completa la configuración :
<servlet>
	<servlet-name>app</servlet-name>
	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
	<init-param>
		<param-name>contextConfigLocation</param-name>
 		<param-value></param-value>
	</init-param>
	<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
	<servlet-name>app</servlet-name>
	<url-pattern>/</url-pattern>
</servlet-mapping>
Y ahora solo necesitamos completar el archivo especificado en contextConfigLocation. Cómo hacer esto se describe en la documentación de Spring Framework en el capítulo "1.3.1. Declaración":
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <context:component-scan base-package="ru.javarush.javaweb"/>
    <mvc:annotation-driven/>
</beans>
Aquí es importante no solo indicar qué paquete escanear, sino también que queremos que esté basado en anotaciones, es decir, controlar las anotaciones sobre cómo funcionará Spring. Todo lo que queda es crear el paquete ru.javarush.javaweb y colocar la clase de controlador Spring en él:
package ru.javarush.javaweb;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class SpringController {

    @GetMapping("/app")
    @ResponseBody
    public String getGreeting() {
        return "Hello world.";
    }
}
Ahora ejecutando gradle appRun y ​​yendo a la dirección, http://127.0.0.1:8080/javaweb/appobtendremos el mismo Hello World. Como puede ver, Spring Framework está estrechamente entrelazado con la API de Servlet y la utiliza para trabajar sobre ella.
Aplicación web en Java - 16

Anotaciones

Como hemos visto, las anotaciones son convenientes. Y no éramos los únicos que pensábamos eso. Por lo tanto, en la especificación API de Servlet, a partir de la versión 3.0, apareció el capítulo “ CAPÍTULO 8 Anotaciones y conectabilidad ”, que especifica que los contenedores de servlet deben soportar la capacidad de especificar lo previamente especificado en el Descriptor de Implementación a través de anotaciones. Por lo tanto, web.xml se puede eliminar completamente del proyecto y, encima de la clase de servlet, puede especificar la anotación @WebServlet e indicar a qué ruta asignar el servlet. Aquí todo parece claro. Pero, ¿qué pasa si conectamos Spring al proyecto, que requiere configuraciones más complejas? Aquí todo es un poco más complicado. Primero, la documentación de Spring dice que para configurar Spring sin web.xml, necesita usar su propia clase que implementará WebApplicationInitializer. Para obtener más detalles, consulte el capítulo " 1.1. DispatcherServlet ". Resulta que esta es una clase de primavera. ¿Cómo se utiliza entonces la API de Servlet aquí? De hecho, ServletContainerInitializer se agregó a Servlet API 3.0 . Utilizando un mecanismo especial en Java (llamado SPI ), Spring especifica su inicializador de contenedor de servlet llamado SpringServletContainerInitializer. A su vez, ya busca implementaciones de WebApplicationInitializer, llama a los métodos necesarios y realiza las configuraciones necesarias. Consulte " Cómo el contenedor de servlets encuentra implementaciones de WebApplicationInitializer " para obtener más detalles. La configuración anterior se puede hacer así:
package ru.javarush.javaweb.config;

import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;

public class AppInitializer implements WebApplicationInitializer {
    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
        // регистрируем конфигурацию созданую высше
        ctx.register(AppConfig.class);
        // добавляем в контекст слушателя с нашей конфигурацией
        servletContext.addListener(new ContextLoaderListener(ctx));

        ctx.setServletContext(servletContext);

        // настраиваем маппинг Dispatcher Servlet-а
        ServletRegistration.Dynamic servlet =
                servletContext.addServlet("dispatcher", new DispatcherServlet(ctx));
        servlet.addMapping("/");
        servlet.setLoadOnStartup(1);
    }
}
Ahora, usando " Configuración basada en Java " indicaremos qué paquete escanear + habilitar anotaciones:
package ru.javarush.javaweb.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "ru.javarush.javaweb.controllers")
public class AppConfig {
}
Y el SpringController en sí se movió a ru.javarush.javaweb.controllers, para que al escanear, la configuración no se encontrara a sí misma, sino que solo buscara controladores.
Aplicación web en Java - 17

resumiendo

Espero que esta descripción general haya arrojado algo de luz sobre cómo funcionan las aplicaciones web en Java. Esto es sólo la punta del iceberg, pero sin entender los conceptos básicos, es difícil entender cómo funcionan las tecnologías basadas en esta base. La API de Servlet es la parte central de cualquier aplicación web Java y hemos visto cómo encajan otros marcos en ella. Para continuar, puedes ver los siguientes materiales: #viacheslav
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION