JavaRush /Java Blog /Random-IT /Da Hello World a Spring Web MVC e cosa c'entrano i servle...
Viacheslav
Livello 3

Da Hello World a Spring Web MVC e cosa c'entrano i servlet

Pubblicato nel gruppo Random-IT
Da Hello World a Spring Web MVC e cosa c'entrano i servlet - 1

introduzione

Come sappiamo, il successo di Java è arrivato proprio grazie all'evoluzione del software che punta a connettersi alla rete. Pertanto, prenderemo come base la solita applicazione console " Hello World " e capiremo di cosa ha bisogno per diventare un'applicazione di rete da un'applicazione console. Quindi, prima devi creare un progetto Java. I programmatori sono persone pigre. In epoca preistorica, quando alcuni cacciavano i mammut, altri si sedevano e cercavano di non confondersi nell'intera varietà di librerie Java e strutture di directory. Affinché lo sviluppatore possa controllare il processo di creazione di un'applicazione, in modo che possa semplicemente scrivere "Voglio una libreria di questa o quella versione 2", hanno inventato strumenti speciali: costruire sistemi. I due più famosi sono Maven e Gradle . Per questo articolo utilizzeremo Gradle. Se prima avremmo dovuto creare da soli la struttura delle directory, ora Gradle, utilizzando il plugin Gradle Init, ci consente di creare un progetto Java con una struttura di directory e una classe Main di base in un comando: gradle init --type java-application questo comando esegue l'inizializzazione (init) per us un'applicazione Java (java-application) con console Hello World. Al termine, verrà visualizzato un file nella directory - build.gradle . Questo è il nostro script di build , ovvero un determinato script per creare un'applicazione con una descrizione di quali azioni devono essere eseguite a tal fine. Apriamolo e aggiungiamo la riga: jar.baseName = 'webproject' Gradle ti consente di eseguire varie azioni su un progetto e queste azioni sono chiamate attività . Eseguendo un comando (task) verrà creato un file JAR gradle buildnella directory /build/libs . E, come hai intuito, il suo nome ora sarà webproject.jar . Ma se eseguiamo java -jar ./build/libs/webproject.jar, otterremo un errore: no main manifest attribute. Questo perché per un'applicazione Java è necessario allegare un manifest: questa è una descrizione di come lavorare con l'applicazione, come percepirla. Quindi la JVM, che eseguirà l'applicazione Java, saprà quale classe è il punto di ingresso al programma e altre informazioni (ad esempio, classpath). Se diamo un'occhiata più da vicino al contenuto dello script di build, vedremo i plugin collegati. Ad esempio: apply plugin: 'java' se andiamo alla pagina Gradle Java Plugin , possiamo vedere che possiamo configurare il manifest:
jar {
    manifest {
        attributes 'Main-Class': 'App'
    }
}
La classe principale, il punto di ingresso al programma, è stata generata per noi dal Gradle Init Plugin. Ed è anche specificato nel parametro mainClassName. Ma questo non ci andava bene, perché... questa impostazione si riferisce a un altro plugin, Gradle Application Plugin . Quindi, abbiamo un'applicazione Java che visualizza Hello World sullo schermo. Questa applicazione Java è confezionata in un JAR (Java ARchive). È semplice, basato su console, non aggiornato. Come trasformarlo in un'applicazione web?
Da Hello World a Spring Web MVC e cosa c'entrano i servlet - 2

API servlet

Affinché Java potesse funzionare con la rete, nei tempi antichi è apparsa una specifica chiamata Servlet API . È questa specifica che descrive l'interazione client-server, ricevendo un messaggio da un client (ad esempio, un browser) e inviando una risposta (ad esempio, con il testo di una pagina). Naturalmente da allora molto è cambiato, ma il punto è che affinché un'applicazione Java diventi un'applicazione web, viene utilizzata l'API Servlet. Per non fare speculazioni infondate, prendiamo proprio questa specifica: JSR-000340 JavaTM Servlet 3.1 . Innanzitutto ci interessa il " Capitolo 1: Panoramica ". Descrive i concetti di base che dobbiamo comprendere. Innanzitutto, cos'è un servlet? Il capitolo " 1.1 Cos'è una Servlet? " dice che una Servlet è un componente Java gestito da un contenitore e che genera contenuto dinamico. Come altri componenti Java, una servlet è una classe Java che viene compilata in bytecode e può essere caricata in un server web utilizzando la tecnologia Java. È importante che le servlet interagiscano con un client Web (ad esempio un browser) nell'ambito del paradigma richiesta/risposta implementato dal Servlet Container. Si scopre che i servlet vivono in una sorta di contenitore servlet. Cos'è questo? Nel capitolo " 1.2 Cos'è un Servlet Container? " si dice che un Servlet Container è una parte di un server Web o di un server di applicazioni che fornisce servizi di rete attraverso i quali vengono inviate le richieste e le risposte. Questo stesso contenitore Servlet gestisce il ciclo di vita dei servlet. Tutti i contenitori servlet devono supportare almeno il protocollo HTTP, ma possono supportarne altri. Ad esempio, HTTPS. È anche importante che il contenitore servlet possa imporre qualsiasi restrizione relativa alla sicurezza sull'ambiente in cui vengono eseguiti i servlet. È anche importante che, secondo “ 10.6 File di archivio dell'applicazione Web ”, l'applicazione Web deve essere impacchettata in un file WAR (Web ARchive). Cioè, ora dobbiamo rimuovere il nostro jar e i plugin dell'applicazione per qualcos'altro. E questo è il plugin Gradle WAR . E invece di jar.baseName specifica war.baseName Why Poiché non utilizziamo più il plug-in jar, abbiamo rimosso anche le impostazioni del manifest. Quando abbiamo lanciato il JAR, è stato necessario indicare alla Java Virtual Machine (JVM) attraverso il manifest come lavorare con la nostra applicazione. Perché la JVM lo stava eseguendo. L'applicazione web, a quanto pare, viene eseguita da una sorta di server web. Si scopre che ha bisogno di dirgli in qualche modo come lavorare con la nostra applicazione web? E si scopre che sì. Le applicazioni web hanno il loro manifesto speciale. Si chiama Descrittore di distribuzione . Ad esso è dedicata un’intera sezione: “ 14. Deployment Descriptor ”. C'è una sezione importante: " Capitolo 10:". Parla di cos'è un'applicazione web dal punto di vista dell'API Servlet. Ad esempio, nel capitolo " 10.5 Struttura delle directory " è indicato dove dovrebbe essere il Deployment Descriptor: /WEB-INF/web.xml. Dove posizionare il WEB-INF? Come indicato nel plugin Gradle WAR, aggiunge un nuovo layout : src/main/webapp. Pertanto, creiamo una directory di questo tipo, all'interno creeremo una directory WEB-INF e all'interno creeremo un file web.xml. È importante che la directory si chiama WEB-INF e non META-INF! Copiamolo dall'esempio XML " 14.5.1 A Basic Esempio ":
Da Hello World a Spring Web MVC e cosa c'entrano i servlet - 3
Come possiamo vedere, per la configurazione viene utilizzato un documento XML. Un documento XML, per essere considerato valido (Valid), deve essere conforme ad alcuni “schemi”. Puoi considerarlo come una sorta di interfaccia per un documento XML. Lo schema specifica quali elementi possono essere presenti in un documento XML, quale tipo di dati può definire l'elemento, l'ordine, il requisito e altri aspetti. L'esempio copiato dalla documentazione indica la versione 2.5, ma noi vogliamo utilizzare la versione 3.1. Naturalmente, le specifiche sono cambiate con il variare delle versioni e sono state aggiunte nuove funzionalità. Pertanto è necessario utilizzare uno schema diverso da quello utilizzato per la versione 2.5 (web-app_2_5.xsd). Quale schema dovrei usare per la versione 3.1? La documentazione ci aiuterà in questo, il capitolo “ 14.3 Deployment Descriptor ”, che afferma specification is available at http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd Cioè, dobbiamo sostituire ovunque il collegamento allo schema con l'xsd specificato, senza dimenticare di cambiarlo version="2.5"in 3.1, e anche cambiare lo spazio dei nomi ovunque ( xmlns e in xsi:schemaLocation). Indicano all'interno di quale spazio dei nomi lavoreremo (per dirla molto semplicemente, quali nomi di elementi possiamo usare). Se apri il file di schema, targetNamespace conterrà lo stesso spazio dei nomi che dovremmo specificare:
Da Hello World a Spring Web MVC e cosa c'entrano i servlet - 4
Come ricordiamo, nel file Manifest del Jar abbiamo scritto quale classe vogliamo utilizzare. Cosa fare qui? Qui dobbiamo specificare quale classe servlet vogliamo utilizzare quando riceviamo una richiesta da un client web. La descrizione può essere letta nel capitolo " 14.4 Deployment Descriptor Diagram ". Apparirà così:
Da Hello World a Spring Web MVC e cosa c'entrano i servlet - 5
Tutto è semplice qui. Il serverlet viene dichiarato e quindi mappato su un determinato modello. In questo caso, su /app. Quando il modello viene eseguito, verrà eseguito il metodo servlet. Per bellezza, la classe App andrebbe trasferita nel pacchetto, senza dimenticare di correggere la configurazione xml. Ma non è tutto. L'app deve essere una servlet. Cosa significa essere un servlet? Ciò significa che dobbiamo ereditare da HttpServlet . Un esempio può essere visto nel capitolo " 8.1.1 @WebServlet ". In base ad esso, la nostra classe App sarà simile a questa:
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

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

	public void doGet(HttpServletRequest request, HttpServletResponse response) {
		response.setContentType("text/html");
		try {
			response.getWriter().println(getGreeting());
		} catch (IOException e) {
			throw new IllegalStateException(e);
		}
	}
}
Ma il nostro progetto non è ancora pronto. Perché ora dipendiamo dalla versione API Servlet 3.1. Ciò significa che nel nostro script di build dobbiamo indicare una dipendenza dall'API Servlet. La JVM deve sapere che ciò che hai scritto nel codice è corretto e come usarlo. Come ricordiamo, le specifiche sono essenzialmente solo interfacce che descrivono come dovrebbe funzionare il tutto. E le implementazioni si trovano sul lato del server web. Pertanto, senza l'API Servlet ci sarà Trova la libreria richiesta su Maven Central: javax.servlet-api . E aggiungi una voce al blocco delle dipendenze . Nel repository Maven, come hai visto, c'è scritto fornito. Prima di utilizzare una dipendenza, è necessario specificare l'ambito. Gradle non ha un ambito denominato "fornito", ma ha un ambito " solo compilazione ". Pertanto indicheremo: providedCompile 'javax.servlet:javax.servlet-api:3.1.0' Uffa, sembra che vada tutto bene? Gradle Build costruirà il nostro progetto in un file WAR. E cosa dovremmo fare dopo? Innanzitutto, abbiamo bisogno di un server Web. In Google scriviamo “ web server java list ” e vediamo un elenco di server web. Scegliamo da questo elenco, ad esempio, TomCat . Vai al sito web Apache Tomcat , scarica l'ultima versione (attualmente la versione 9) come archivio zip (se per Windows). Scompattatelo in qualche directory. Evviva, abbiamo un server web. Dalla directory del server web nella sottodirectory bin , eseguiamo catalina dalla riga di comando e vediamo le opzioni disponibili. Facciamo: catalina start. Ogni server Web dispone di una directory monitorata dal server Web. Se lì viene visualizzato un file di un'applicazione Web, il server Web inizia a installarlo. Questa installazione è chiamata distribuzione o distribuzione . Sì sì, ecco perché " descrittore di distribuzione ". Cioè, come distribuire correttamente l'applicazione. In Tomcat questa directory è webapps . Copiamo lì la guerra che abbiamo realizzato utilizzando Gradle build. Dopodiché, nel log vedremo qualcosa del tipo: Deployment of web application archive [tomcat\webapps\webproject.war] has finished in [время] ms Per capire ancora meglio, nella directory tomcat modificheremo il file \conf\tomcat-users.xml, aggiungendo le seguenti righe:
Da Hello World a Spring Web MVC e cosa c'entrano i servlet - 6
Ora riavviamo il server (catalina stop, catalina start) e andiamo all'indirizzo, http://127.0.0.1:8080/manager qui vedremo i percorsi di tutte le applicazioni. Molto probabilmente al nostro progetto web è stato assegnato il percorso /webproject. Qual è questo percorso? La specifica nel capitolo " 10.1 Applicazioni Web all'interno dei server Web " afferma che un'applicazione Web è associata a un percorso all'interno dell'applicazione (in questo caso, /webproject). Tutte le richieste attraverso questo percorso verranno associate allo stesso ServletContext. Questo percorso è anche chiamato contextRoot . E secondo " 10.2 Relazione con ServletContext ", il contenitore servlet mette in relazione l'applicazione web e il ServletContext uno a uno. Cioè, ogni applicazione web ha il proprio ServletContext. Cos'è un ServletContext ? Come afferma la specifica, un ServletContext è un oggetto che fornisce ai servlet una "vista dell'applicazione " in cui sono in esecuzione. Il contesto servlet è descritto più dettagliatamente nel capitolo 4 della specifica API servlet. Sorprendentemente, l'API Servlet nella versione 3.1 non richiede più la presenza di web.xml. Ad esempio, puoi definire un servlet utilizzando le annotazioni:
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/app2")
public class App2 extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        response.setContentType("text/html");
        response.getWriter().println("app2");
    }
}
Consigliato anche sull'argomento: " Intervista Java EE - JEE Servlet API (domande e risposte) ". Quindi, abbiamo un Servlet: è responsabile della risposta da dare al client web. Abbiamo un ServletContainer che riceve richieste dall'utente, abbina il percorso a cui è stato effettuato l'accesso con il percorso del servlet e, se viene trovata una corrispondenza, esegue il Servlet. Bene. Che posto occupa la primavera in questa immagine del mondo ?

Primavera Web MVC

Ottimo, abbiamo un'applicazione web. Ora dobbiamo connettere Spring. Come possiamo farlo? Innanzitutto, devi capire come collegare correttamente Spring al tuo progetto. Si scopre che prima era possibile farlo in conformità con la documentazione del progetto della piattaforma Spring , ma ora " La piattaforma raggiungerà la fine della sua vita supportata il 9 aprile 2019 ", cioè non è consigliabile usarlo, perché presto non sarà più supportato. L'unica via d'uscita è " Gli utenti della piattaforma sono incoraggiati a iniziare a utilizzare la gestione delle dipendenze di Spring Boot ". Passiamo quindi alla documentazione di Spring Boot . Vorrei chiarire che non utilizziamo Spring Boot stesso, ma solo la gestione delle dipendenze di Spring Boot. Cioè, il progetto Spring Boot può fornire informazioni su quali versioni delle librerie utilizzare (incluso Spring MVC). Lì troveremo 3.2. Utilizzo della gestione delle dipendenze di Spring Boot in modo isolato . Secondo la documentazione, aggiungi quanto segue allo script di build:
plugins {
    id 'org.springframework.boot' version '2.0.4.RELEASE' apply false
}
apply plugin: 'io.spring.dependency-management'
E
dependencyManagement {
    imports {
        mavenBom org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES
    }
}
Come puoi vedere, abbiamo indicato apply false, cioè Non utilizziamo Spring Boot in sé, ma utilizziamo la gestione delle dipendenze da lì. Questa gestione delle dipendenze è anche chiamata BOM - " Bill Of Materials ". Ora siamo pronti per connettere il progetto Spring Web MVC stesso. Spring Web MVC fa parte del progetto Spring Framework e a noi interessa la sezione " Web Servlet ". Aggiungiamo la dipendenza allo script di build: compile 'org.springframework:spring-webmvc'. Come possiamo vedere, impostiamo scope compile, why il server web non ci fornisce Spring. Il nostro progetto è costretto a includere al suo interno la libreria Spring. Successivamente, è importante leggere la sezione " 1.2. DispatcherServlet ", dove si dice che Spring MVC è costruito attorno al modello " Front controller ", dove esiste una sorta di servlet centrale che fornisce configurazione e delega ad altri componenti . Dispatcher può essere tradotto come dispatcher. Quindi, prima di tutto, nel web.xml dichiariamo:
Da Hello World a Spring Web MVC e cosa c'entrano i servlet - 7
Come possiamo vedere, questo è in realtà un normale Listener definito nella specifica API Servlet. Per essere più precisi si tratta di un ServletContextListener, ovvero viene attivato per inizializzare il Servlet Context per la nostra applicazione web. Successivamente, devi specificare un'impostazione che indicherà a Spring dove si trova la sua speciale configurazione xml con le impostazioni:
Da Hello World a Spring Web MVC e cosa c'entrano i servlet - 8
Come puoi vedere, questa è solo un'impostazione normale memorizzata a livello del contesto servlet, ma che verrà utilizzata da Spring durante l'inizializzazione del contesto dell'applicazione. Ora devi dichiarare, invece di tutte le servlet, un unico dispatcher che distribuisca tutte le altre richieste.
Da Hello World a Spring Web MVC e cosa c'entrano i servlet - 9
E non c'è magia qui. Se guardiamo, è un HttpServlet, proprio dove Spring fa molte cose che lo rendono un framework. Non resta che correlare (mappare) uno specifico template URL con la servlet:
Da Hello World a Spring Web MVC e cosa c'entrano i servlet - 10
Tutto è come prima. Ora creiamo qualcosa che il nostro server web dovrebbe visualizzare. Ad esempio, creiamo una sottodirectory di pagine nel nostro WEB-INF e ci sarà un file hello.jsp. Il contenuto può essere il più primitivo. Ad esempio, all'interno dei tag html c'è un tag h1 con il testo " Hello World ". E non dimenticare di creare il file applicationContext.xmlche abbiamo specificato in precedenza. Prendiamo un esempio dalla documentazione di Spring: " 1.10.3. Rilevamento automatico delle classi e registrazione delle definizioni dei bean ".
Da Hello World a Spring Web MVC e cosa c'entrano i servlet - 11
Perché abilitiamo il rilevamento automatico in questo modo, ora possiamo creare 2 classi (saranno considerate Spring Beans a causa dell'utilizzo di speciali annotazioni Spring), che Spring ora creerà da sola e personalizzerà la nostra applicazione con il loro aiuto:
  1. Configurazione Web, ad esempio configurazione in stile Java:

    @Configuration
    @EnableWebMvc
    public class WebConfig implements WebMvcConfigurer {
        @Override
        public void configureViewResolvers(ViewResolverRegistry registry) {
            registry.jsp("/WEB-INF/pages/", ".jsp");
        }
        @Override
        public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
            configurer.enable();
        }
    }

    Questo esempio è descritto nella documentazione di Spring Framework: " 1.11. MVC Config ".

    Qui registriamo un ViewResolver, che aiuterà a determinare dove si trovano le pagine jsp. Il secondo metodo garantisce che il " servlet predefinito " sia abilitato.

    Puoi leggere ulteriori informazioni al riguardo qui: " Qual è la necessità e l'uso del gestore servlet predefinito ".

  2. Controller HelloController per descrivere la mappatura delle richieste a uno specifico JSP

    @Controller
    public class HelloController {
        @GetMapping("/hello")
        public String handle(Model model) {
            return "hello";
        }
    }

    Qui abbiamo utilizzato l'annotazione @Controller descritta nella documentazione nel capitolo " 1.4. Controller annotati ".

Ora, quando la nostra applicazione viene distribuita, quando inviamo una richiesta /webproject/hello(dove /webproject è la root del contesto), il DispatcherServlet verrà elaborato per primo. Lui, in qualità di dispatcher principale, determinerà che we /* corrisponde alla richiesta corrente, il che significa che il DispatcherServlet deve fare qualcosa. Quindi esaminerà tutte le mappature trovate. Vedrà che esiste un HelloController con un metodo handle mappato su /hello e lo eseguirà. Questo metodo restituirà il testo "ciao". Questo testo verrà ricevuto da ViewResolver, che dirà al server dove cercare i file jsp che devono essere visualizzati al client. Pertanto, il cliente alla fine riceverà quella pagina molto cara.

Conclusione

Spero che dall'articolo risulti chiaro che la parola "contesto" non fa paura. Queste specifiche si rivelano molto utili. E la documentazione è nostra amica, non nostra nemica. Spero che sia chiaro su cosa si basa Spring, come si connette e cosa c'entra l'API Servlet.
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION