JavaRush /Java Blog /Random-IT /Applicazione Web in Java
Viacheslav
Livello 3

Applicazione Web in Java

Pubblicato nel gruppo Random-IT
Applicazione Web in Java - 1

introduzione

C'era una volta Java che rafforzava la sua posizione perché sceglieva le applicazioni web come priorità. Sin dai suoi albori, Java ha faticato a trovare la sua strada. Per prima cosa ho suggerito le applet. Ciò ha fornito molte opportunità agli sviluppatori di creare contenuto dinamico (contenuto) su pagine HTML statiche. Tuttavia, le applet non sono state all'altezza delle aspettative per molte ragioni: sicurezza, spese generali e altre. Quindi gli sviluppatori del linguaggio Java hanno proposto un'alternativa: l'API Servlet . E si è rivelata la decisione giusta. L'API Servlet è la specifica su cui è costruita qualsiasi applicazione Web Java, sia essa un'applicazione basata sul Web o un servizio Web che restituisce le informazioni come richiesto. Pertanto, il percorso per comprendere il funzionamento delle applicazioni Web Java inizia con la comprensione dell'API Servlet.
Applicazione Web in Java - 2

API servlet

Quindi, l'API Servlet è ciò che gli sviluppatori del linguaggio hanno offerto agli sviluppatori Java. L'API Servlet è una specifica che dovrebbe rispondere alle nostre domande principali. Puoi trovarlo qui: " JSR-000340 JavaTM Servlet 3.1 Versione finale per la valutazione ". Il capitolo " 1.1 Cos'è una servlet? " dice che una servlet è un componente web basato sulla tecnologia Java che crea contenuto dinamico (cioè contenuto). "Basato su Java" significa che una servlet è una classe Java compilata in bytecode . Le servlet sono gestite da un contenitore servlet, talvolta chiamato motore servlet. Un contenitore servlet è un'estensione del server Web che fornisce funzionalità servlet. A loro volta, le servlet forniscono l'interazione con il client nel paradigma richiesta/risposta, che è implementato dal contenitore servlet. Nel capitolo " 1.2 Cos'è un servlet container? " si dice che un servlet container è parte di un server web o server applicativo che fornisce servizi di rete attraverso i quali vengono inviate richieste e risposte, generate ed elaborate richieste e risposte basate su MIME . Inoltre, i contenitori servlet gestiscono il ciclo di vita delle servlet (cioè decidono quando crearle, eliminarle, ecc.). Tutti i contenitori servlet devono supportare il protocollo HTTP per ricevere richieste e inviare risposte. Qui vorrei aggiungere che MIME è uno standard, una specifica che indica come le informazioni dovrebbero essere codificate e i messaggi formattati in modo che possano essere inviati su Internet.
Applicazione Web in Java - 3

Server web

Un server Web è un server che accetta richieste HTTP dai client e fornisce loro risposte HTTP (solitamente insieme a una pagina HTML, un'immagine, un file o altri dati). Le risorse richieste sono identificate da URL. Uno dei server Web più popolari con supporto API Servlet è Apache Tomcat . La maggior parte dei server web sono macchine complesse composte da vari componenti, ognuno dei quali svolge funzioni specifiche. Per esempio:
Applicazione Web in Java - 4

Connettori

— All'input abbiamo i connettori (cioè i connettori) che accettano le richieste in arrivo dai client. Il connettore HTTP in Tomcat è implementato utilizzando il componente "Coyote". I connettori ricevono i dati dal client e li trasmettono al Tomcat Engine. Servlet Container - Tomcat Engine, a sua volta, elabora la richiesta ricevuta dal client utilizzando il componente "Catalina", che è un servlet container. Consulta la documentazione di Tomcat: " Panoramica dell'architettura " per ulteriori dettagli. Esistono altri server Web che supportano la specifica API Servlet. Ad esempio, " Jetty " o " Undertow ". La loro architettura è simile, quindi comprendendo il principio di lavorare con un contenitore servlet, puoi passare a lavorare con un altro.
Applicazione Web in Java - 5

Applicazione web

Quindi, per poter eseguire un'applicazione web, abbiamo bisogno di un server web che supporti l'API Servlet (ovvero, uno che abbia un componente di estensione che implementa il supporto dell'API Servlet per il server web). Bene. Cos'è comunque un'applicazione web? Secondo il capitolo " 10 Applicazioni Web " delle specifiche API Servlet, un'applicazione Web è una raccolta di servlet, pagine HTML, classi e altre risorse che costituiscono un'applicazione finale su un server Web. Secondo il capitolo " 10.6 File di archivio dell'applicazione Web ", un'applicazione Web può essere impacchettata in Web ARchive (un archivio con estensione WAR). Come indicato nella pagina " Glossario-219 ":
Applicazione Web in Java - 6
Cioè, viene creato WAR invece di JAR per dimostrare che si tratta di un'applicazione web. Il prossimo fatto importante: dobbiamo avere una certa struttura di directory nel nostro archivio WAR. Nella specifica API Servlet nel capitolo " 10.5 Struttura delle directory ". Questo capitolo dice che esiste una directory speciale chiamata "WEB-INF". Questa directory è speciale in quanto non è visibile al client e non gli viene mostrata direttamente, ma è accessibile al codice servlet. Dice anche cosa può contenere la directory WEB-INF:
Applicazione Web in Java - 7
Di tutto questo elenco, ora non sappiamo e non comprendiamo l'elemento relativo ad alcuni file web.xml chiamati descrittore di distribuzione . Che cos'è? Il capitolo " 14. Deployment Descriptor " è dedicato al deploy descriptor. In breve, un descrittore di distribuzione è un file xml che descrive come distribuire (ovvero eseguire) la nostra applicazione web su un server web. Ad esempio, il descrittore di distribuzione indica quali URL devono essere utilizzati per accedere alla nostra applicazione, vengono indicate le impostazioni di sicurezza relative alla nostra applicazione, ecc. Il capitolo " 14.2 Regole per l'elaborazione del Deployment " dice che lo schema web.xml verrà convalidato prima che la nostra applicazione venga configurata e lanciata (ovvero verrà effettuato un controllo che i contenuti di web.xml siano scritti correttamente secondo lo schema) . E nel capitolo " 14.3 Deployment Descriptor " è indicato che il diagramma è qui: http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd Se guardiamo il contenuto del file, possiamo vedere:
Applicazione Web in Java - 8
Qual è lo schema utilizzato per i file XML? Gli schemi indicano come compilare correttamente un documento XML: quali elementi possono essere utilizzati, che tipo di dati possono essere specificati negli elementi, in quale ordine devono essere posizionati gli elementi, quali elementi sono richiesti, ecc. È possibile confrontare lo schema di un documento XML con un'interfaccia in Java, poiché lo schema in Java specifica anche come dovrebbero essere scritte le classi che soddisfano una determinata interfaccia (ovvero, che implementano una determinata interfaccia). Quindi, siamo armati di conoscenze segrete e siamo pronti a creare la nostra prima applicazione web!
Applicazione Web in Java - 9

Creazione di un'applicazione Web

È difficile immaginare di lavorare con una moderna applicazione Java senza utilizzare sistemi di creazione automatica del progetto. Alcuni dei sistemi più popolari sono Maven e Gradle . Utilizzeremo Gradle per questa recensione. L'installazione di Gradle è descritta sul sito ufficiale . Per creare una nuova applicazione, abbiamo bisogno di un plugin integrato in Gradle: " Build Init Plugin ". Per creare un'applicazione Java è necessario eseguire il seguente comando: gradle init --type java-application
Applicazione Web in Java - 10
Dopo aver creato il progetto, dovremo modificare il file build.gradle . Questo è il cosiddetto Build Script (per maggiori dettagli consultare la documentazione di Gradle: " Writing Build Scripts "). Questo file descrive come assemblare il progetto e altri aspetti del lavoro con un progetto Java. Il blocco plugin descrive quali " plugin Gradle " dovrebbero essere utilizzati per l'attuale progetto Gradle. I plugin espandono le capacità del nostro progetto. Ad esempio, il plugin predefinito è " java ". Questo plugin viene sempre utilizzato se abbiamo bisogno del supporto Java. Ma non abbiamo bisogno del plugin “ applicazione ”, perché... la sua descrizione afferma che viene utilizzato per creare una "applicazione JVM eseguibile", ovvero eseguire applicazioni JVM. Dobbiamo creare un'applicazione Web sotto forma di archivio WAR. E se cerchiamo la parola WAR nella documentazione di Gradle, troveremo “ War Plugin ”. Pertanto specificheremo i seguenti plugin:
plugins {
    id 'java'
    id 'war'
}
Anche nelle " Impostazioni predefinite del plugin di guerra " si dice che la directory con tutto il contenuto dell'applicazione web dovrebbe essere "src/main/webapp", dovrebbe esserci la stessa directory WEB-INF in cui dovrebbe essere web.xml situato. Creiamo un file di questo tipo. Lo compileremo un po' più tardi, perché... non abbiamo ancora abbastanza informazioni per questo. Nel blocco "dipendenze" indichiamo le dipendenze del nostro progetto, cioè quelle librerie/framework senza le quali la nostra applicazione non può funzionare. In questo caso stiamo scrivendo un'applicazione web, il che significa che non possiamo lavorare senza l'API Servlet:
dependencies {
    providedCompile 'javax.servlet:javax.servlet-api:3.1.0'
    testCompile 'junit:junit:4.12'
}
fornitoCompile significa che non è necessario che la dipendenza sia inclusa nel nostro archivio WAR dell'applicazione web: è necessaria solo per la compilazione. E una volta eseguita, questa dipendenza verrà fornita da qualcun altro (ovvero dal server web). Bene, lasciamo le informazioni nello script di build su quale repository di dipendenze vogliamo utilizzare: tutte le dipendenze specificate verranno scaricate da esso:
repositories {
    jcenter()
}
Rimuoviamo tutto il resto dal file dello script di build. Ora modifichiamo la classe src\main\java\App.java. Facciamone un servlet. La specifica dell'API Servlet nel capitolo " CAPITOLO 2. L'interfaccia Servlet " afferma che l'interfaccia Servlet ha un'implementazione di base di HttpServlet , che dovrebbe essere sufficiente nella maggior parte dei casi e gli sviluppatori devono semplicemente ereditarla. E nel capitolo " 2.1.1 Metodi di gestione delle richieste specifiche HTTP " sono indicati i principali metodi che elaborano le richieste in entrata. Quindi, riscriviamo la classe 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();
 	}
}
Quindi, sembra che abbiamo tutto pronto. Tutto ciò che resta è scrivere correttamente il descrittore di distribuzione. Dal diagramma, copia il seguente testo in 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>
E anche il percorso dello schema indicato in esso: http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd ora vediamo un esempio di come dovrebbe apparire web.xml nella specifica API Servlet. Questo esempio è riportato nel capitolo " 14.5.1 Un esempio di base ". Combiniamo quanto indicato nello schema con l'esempio indicato nella specifica. Otteniamo quanto segue:
<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>
Come puoi vedere, abbiamo utilizzato lo schema e lo schemaLocation specificati in precedenza. E la descrizione degli elementi stessi è stata presa dall'esempio del capitolo 14.5.1. Se abbiamo fatto tutto correttamente, eseguiremo il compito di gradle war senza errori:
Applicazione Web in Java - 11
Applicazione Web in Java - 12

Avvio di un'applicazione web

Come si avvia un'applicazione web? Affrontiamo prima l'opzione più complessa. Abbiamo detto in precedenza che esiste un server web Apache Tomcat che supporta l'API Servlet. Ciò significa che possiamo distribuire il nostro archivio di guerra raccolto (dicono anche "distribuisci") su questo server. Nella pagina " Download Tomcat ", scaricare dalla sezione "Distribuzioni binarie" la tipologia di consegna "Core" in formato zip. E scompatta l'archivio scaricato in qualche directory, ad esempio in C:\apache-tomcat-9.0.14. Prima di avviare il server, apriamo il file per la modifica conf\tomcat-users.xmle aggiungiamo la seguente riga: <user username="tomcat" password="tomcat" roles="tomcat,manager-gui,admin-gui"/> Ora, sulla riga di comando, andiamo alla directory bin ed eseguiamo catalina.bat start. Per impostazione predefinita, la console del server sarà disponibile all'indirizzo http://localhost:8080/manager. Il login e la password sono gli stessi specificati in tomcat-users.xml. Tomcat dispone di una directory "webapps" che contiene applicazioni Web. Se vogliamo schierare il nostro, dobbiamo copiare lì il nostro archivio di guerra. Quando in precedenza abbiamo eseguito il comando gradle war, \build\libs\nella directory è stato creato un archivio war. Questo è ciò che dobbiamo copiare. Dopo la copia, aggiorna la pagina http://localhost:8080/managere vedi:
Applicazione Web in Java - 13
Dopo aver completato http://localhost:8080/javaweb/app, passeremo al nostro servlet, perché In precedenza abbiamo "mappato" (ovvero mappato) la richiesta /app alla servlet dell'app. Esiste un modo più veloce per verificare come funziona l'applicazione. E anche in questo il sistema di assemblaggio ci aiuta. Nello script di build del nostro progetto Gradle, possiamo aggiungere un nuovo plugin " Gretty " alla sezione plugin: id "org.gretty" version "2.3.1" E ora possiamo eseguire un'attività gradle per eseguire la nostra applicazione:gradle appRun
Applicazione Web in Java - 14
Vedi " Aggiungi il plugin gretty ed esegui l'app " per i dettagli.
Applicazione Web in Java - 15

API Spring e servlet

Le servlet sono la base di tutto. E anche l'ormai popolare Spring Framework non è altro che un componente aggiuntivo dell'API Servlet. Per cominciare, Spring Framework è una nuova dipendenza per il nostro progetto. Aggiungiamolo quindi allo script di build nel blocco delle dipendenze: compile 'org.springframework:spring-webmvc:5.1.3.RELEASE' Nella documentazione di Spring Framework c'è un capitolo " 1.1. DispatcherServlet ". Dice che Spring Framework è costruito sul modello "front controller" - questo è quando c'è un servlet centrale chiamato " DispatcherServlet ". Tutte le richieste arrivano a questo servlet e delega le chiamate ai componenti necessari. Vedi, anche qui ci sono le servlet. È necessario aggiungere un ascoltatore al descrittore di distribuzione:
<listener>
	&ltlistener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
Questo è un ascoltatore di eventi del contesto servlet. Cioè, quando si avvia il Servlet Context, si avvia anche il contesto Spring (WebApplicationContext). Cos'è il contesto servlet? È descritto nella specifica Servle API nel capitolo " CAPITOLO 4. Contesto servlet ". Un contesto servlet è la "vista" di un servlet dell'applicazione web all'interno della quale i servlet sono in esecuzione. Ogni applicazione web ha il proprio contesto servlet. Successivamente, per abilitare Spring Framework, è necessario specificare context-param, il parametro di inizializzazione per il contesto servlet.
<context-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>/WEB-INF/app-context.xml</param-value>
</context-param>
E la definizione DispatcherServlet completa la configurazione :
<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>
E ora non ci resta che compilare il file specificato in contextConfigLocation. Come farlo è descritto nella documentazione di Spring Framework nel capitolo "1.3.1. Dichiarazione":
<?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>
È importante qui non solo indicare quale pacchetto scansionare, ma anche che lo vogliamo annotation-driven, cioè controllare le annotazioni su come funzionerà Spring. Non resta che creare il pacchetto ru.javarush.javaweb e inserirvi la classe Spring controller:
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.";
    }
}
Ora eseguendo gradle appRun e andando all'indirizzo, http://127.0.0.1:8080/javaweb/appotterremo lo stesso Hello World. Come puoi vedere, Spring Framework è strettamente intrecciato con l'API Servlet e la utilizza per lavorare su di essa.
Applicazione Web in Java - 16

Annotazioni

Come abbiamo visto, le annotazioni sono convenienti. E non eravamo gli unici a pensarla così. Pertanto, nella specifica delle Servlet API, a partire dalla versione 3.0, è apparso il capitolo “ CAPITOLO 8 Annotazioni e pluggability ”, in cui si specifica che i contenitori servlet devono supportare la capacità di specificare quanto precedentemente specificato nel Deployment Descriptor tramite annotazioni. Pertanto, web.xml può essere completamente rimosso dal progetto e sopra la classe servlet è possibile specificare l' annotazione @WebServlet e indicare a quale percorso mappare il servlet. Qui sembra tutto chiaro. Ma cosa succederebbe se collegassimo Spring al progetto, che richiede ambientazioni più complesse? Qui tutto è un po’ più complicato. Innanzitutto, la documentazione di Spring afferma che per configurare Spring senza web.xml, è necessario utilizzare la propria classe che implementerà WebApplicationInitializer. Per maggiori dettagli consultare il capitolo " 1.1. DispatcherServlet ". Si scopre che questa è una lezione primaverile. Come viene quindi utilizzata l'API Servlet qui? In effetti, ServletContainerInitializer è stato aggiunto alla Servlet API 3.0 . Utilizzando un meccanismo speciale in Java (chiamato SPI ), Spring specifica il suo inizializzatore del contenitore servlet chiamato SpringServletContainerInitializer. A sua volta, cerca già le implementazioni di WebApplicationInitializer, richiama i metodi necessari ed esegue le impostazioni necessarie. Per ulteriori dettagli, vedere " Come il contenitore servlet trova le implementazioni di WebApplicationInitializer ". Le impostazioni di cui sopra possono essere eseguite in questo modo:
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);
    }
}
Ora, utilizzando la " configurazione basata su Java " indicheremo quale pacchetto scansionare + abiliteremo le annotazioni:
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 {
}
E lo stesso SpringController è stato spostato in ru.javarush.javaweb.controllers, in modo che durante la scansione la configurazione non trovasse se stessa, ma cercasse solo i controller.
Applicazione Web in Java - 17

Riassumendo

Spero che questa panoramica abbia fatto luce su come funzionano le applicazioni web in Java. Questa è solo la punta dell’iceberg, ma senza comprenderne le basi è difficile capire come funzionano le tecnologie basate su queste basi. L'API Servlet è la parte centrale di qualsiasi applicazione Web Java e abbiamo esaminato come si inseriscono altri framework. Per proseguire è possibile visionare i seguenti materiali: #Viacheslav
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION