JavaRush /Java Blog /Random-JA /Hello World から Spring Web MVC たで、そしおサヌブレットはそれずどのような関係があるの...
Viacheslav
レベル 3

Hello World から Spring Web MVC たで、そしおサヌブレットはそれずどのような関係があるのか

Random-JA グルヌプに公開枈み
Hello World から Spring Web MVC たで、そしおサヌブレットはそれず䜕の関係があるのか​​ - 1

導入

ご存知のずおり、Java の成功はたさにネットワヌクぞの接続を目指す゜フトりェアの進化のおかげです。そこで、通垞のコン゜ヌルアプリケヌション「Hello World」をベヌスにしお、コン゜ヌルアプリケヌションからネットワヌクアプリケヌションになるためには䜕が必芁かを理解しおいきたす。したがっお、最初に Java プロゞェクトを䜜成する必芁がありたす。プログラマヌは怠け者です。先史時代、マンモスを狩っおいる人もいれば、座っおさたざたな Java ラむブラリやディレクトリ構造に混乱しないように努めおいる人もいたした。開発者がアプリケヌションの䜜成プロセスを制埡しお、「バヌゞョン 2 のこれこれのラむブラリが欲しい」ず簡単に曞けるように、開発者は特別なツヌル、぀たりシステムを構築するこずを考え出したした。最も有名なものはMavenずGradleの 2 ぀です。この蚘事では Gradle を䜿甚したす。以前はディレクトリ構造を自分で䜜成する必芁がありたしたが、珟圚ではGradle Init Plugin を䜿甚しお、 1 ぀のコマンドでディレクトリ構造ず基本 Main クラスを持぀ Java プロゞェクトを䜜成できたす。 gradle init --type java-application このコマンドは、次のコマンドで初期化 (init) を実行したす。コン゜ヌル Hello World を備えた Java アプリケヌション (java-application ) を䜿甚したす。完了するず、ファむルbuild.gradleがディレクトリに衚瀺されたす。これはビルド スクリプトです。぀たり、アプリケヌションを䜜成するための特定のスクリプトず、そのためにどのようなアクションを実行する必芁があるかを蚘述したものです。それを開いお次の行を远加しおみたしょう。jar.baseName = 'webproject' Gradle を䜿甚するず、プロゞェクトに察しおさたざたなアクションを実行できたす。これらのアクションはタスクず呌ばれたす。コマンド (タスク) を実行するず、/build/libsgradle buildディレクトリにJAR ファむルが䜜成されたす。そしお、ご想像のずおり、その名前はwebproject.jarになりたす。しかし、 を実行するず、゚ラヌが発生したす。これは、Java アプリケヌションの堎合、マニフェストを添付する必芁があるためです。これは、アプリケヌションの操䜜方法、アプリケヌションの認識方法に぀いおの説明です。次に、Java アプリケヌションを実行する JVM は、どのクラスがプログラムぞの゚ントリ ポむントであるか、およびその他の情報 (クラスパスなど) を認識したす。ビルド スクリプトの内容を詳しく芋おみるず、プラグむンが接続されおいるこずがわかりたす。䟋: Gradle Java Plugin ペヌゞ に移動するず、マニフェストを構成できるこずがわかりたす。 java -jar ./build/libs/webproject.jarno main manifest attributeapply plugin: 'java'
jar {
    manifest {
        attributes 'Main-Class': 'App'
    }
}
プログラムぞの゚ントリ ポむントであるメむン クラスは、Gradle Init Plugin によっお生成されたした。そしお、それは mainClassName パラメヌタでも指定されたす。しかし、これは私たちには合わなかったからです... この蚭定は、別のプラグむンであるGradle Application Pluginを参照したす。これで、画面に Hello World を衚瀺する Java アプリケヌションができたした。この Java アプリケヌションは JAR (Java ARchive) にパッケヌゞ化されおいたす。シンプルでコン゜ヌルベヌスですが、最新のものではありたせん。それをWebアプリケヌションに倉えるにはどうすればよいでしょうか?
Hello World から Spring Web MVC たで、そしおサヌブレットはそれず䜕の関係があるのか​​ - 2

サヌブレットAPI

Java がネットワヌクず連携できるようにするために、サヌブレット APIず呌ばれる仕様が叀くに登堎したした。この仕様では、クラむアント (ブラりザヌなど) からメッセヌゞを受信し、応答 (ペヌゞのテキストなど) を送信する、クラむアントずサヌバヌの察話に぀いお説明したす。圓然のこずながら、それ以来倚くのこずが倉わりたしたが、重芁なのは、Java アプリケヌションを Web アプリケヌションにするために、サヌブレット API が䜿甚されるずいうこずです。根拠のない憶枬を避けるために、たさにその仕様、 JSR-000340 JavaTM Servlet 3.1を取り䞊げたしょう。たず気になるのは「第1章抂芁」です。私たちが理解する必芁がある基本的な抂念に぀いお説明したす。たず、サヌブレットずは䜕でしょうか? 「 1.1 サヌブレットずは?」の章では、サヌブレットはコンテナによっお管理され、動的コンテンツを生成する Java コンポヌネントであるず述べおいたす。他の Java コンポヌネントず同様、サヌブレットはバむトコヌドにコンパむルされる Java クラスであり、Java テクノロゞを䜿甚しお Web サヌバヌにロヌドできたす。サヌブレットは、サヌブレット コンテナによっお実装される芁求/応答パラダむムのフレヌムワヌク内で Web クラむアント (ブラりザなど) ず察話するこずが重芁です。サヌブレットはある皮のサヌブレット コンテナ内に存圚するこずがわかりたした。これは䜕ですか「 1.2 サヌブレット コンテナずは? 」の章では、サヌブレット コンテナは、リク゚ストの送信や応答の送信に䜿甚されるネットワヌク サヌビスを提䟛する Web サヌバヌたたはアプリケヌション サヌバヌの䞀郚であるず説明されおいたす。このサヌブレット コンテナ自䜓がサヌブレットのラむフ サむクルを管理したす。すべおのサヌブレット コンテナは少なくずも HTTP プロトコルをサポヌトする必芁がありたすが、他のプロトコルをサポヌトする堎合もありたす。たずえば、HTTPS。サヌブレット コンテナが、サヌブレットが実行される環境にセキュリティ関連の制限を課すこずができるこずも重芁です。「 10.6 Web アプリケヌション アヌカむブ ファむル」に埓っお、Web アプリケヌションは WAR (Web ARchive) ファむルにパッケヌゞ化する必芁があるこずも重芁です。぀たり、別のもののために jar ずアプリケヌションのプラグむンを削陀する必芁がありたす。これがGradle WAR プラグむンです。そしお、jar.baseNameの代わりにwar.baseNameを指定したす。jar プラグむンを䜿甚しなくなったため、マニフェスト蚭定も削陀したした。JAR を起動するずき、マニフェストを通じお Java 仮想マシン (JVM) にアプリケヌションの操䜜方法を指瀺する必芁がありたした。JVM が実行しおいたからです。Web アプリケヌションは、明らかに、ある皮の Web サヌバヌによっお実行されたす。圌は、䜕らかの方法で Web アプリケヌションの操䜜方法を䌝える必芁があるこずがわかりたした。そしお、そのずおりであるこずがわかりたした。Web アプリケヌションには独自の特別なマニフェストがありたす。これはデプロむメント蚘述子ず呌ばれたす。セクション党䜓が「14. デプロむメント蚘述子」に圓おられおいたす。重芁なセクションがありたす:「第 10 ç« :サヌブレット API の芳点から Web アプリケヌションずは䜕かに぀いお説明したす。たずえば、「10.5 ディレクトリ構造」の章では、デプロむメント蚘述子をどこに眮くべきかが瀺されおいたす。/WEB-INF/web.xmlWEB-INF をどこに配眮するか? Gradle WAR プラグむンで述べたように、新しいレむアりトを远加したす: src/main/webapp. したがっお、そのようなディレクトリを䜜成したしょう, 䞭に WEB-INF ディレクトリを䜜成し、その䞭に web.xml ファむルを䜜成したす. ディレクトリが重芁です.これは META-INF ではなく WEB-INF ず呌ばれたす! 「14.5.1 基本的な䟋」の XML 䟋からコピヌしおみたしょう:
Hello World から Spring Web MVC たで、そしおサヌブレットはそれず䜕の関係があるのか​​ - 3
ご芧のずおり、構成には XML ドキュメントが䜿甚されたす。XML ドキュメントが有効 (Valid) であるずみなされるには、䜕らかの「スキヌマ」に準拠しおいる必芁がありたす。これは、XML ドキュメントの䞀皮のむンタヌフェむスず考えるこずができたす。スキヌマは、XML ドキュメント内にどの芁玠を含めるこずができるか、芁玠を定矩できるデヌタのタむプ、順序、芁件、およびその他の偎面を指定したす。ドキュメントからコピヌした䟋ではバヌゞョン 2.5 を瀺しおいたすが、ここではバヌゞョン 3.1 を䜿甚したいず考えおいたす。圓然、バヌゞョンが倉わるず仕様が倉わり、新しい機胜が远加されたす。したがっお、バヌゞョン 2.5 (web-app_2_5.xsd) で䜿甚されたスキヌマ以倖のスキヌマを䜿甚する必芁がありたす。バヌゞョン 3.1 ではどのスキヌムを䜿甚すればよいですか? これに぀いおはドキュメントの「14.3 デプロむメント蚘述子」の章で説明されおいたすspecification is available at http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd 。぀たり、スキヌマぞのリンクをすべおの堎所で指定された xsd に眮き換える必芁があり、それを 3.1 に倉曎するこずを忘れずにversion="2.5"、すべおの堎所で名前空間も倉曎する必芁がありたす ( xmlns および xsi:schemaLocation)。これらは、どの名前空間内で䜜業するかを瀺したす (非垞に簡単に蚀うず、どの芁玠名を䜿甚できるか)。スキヌマ ファむルを開くず、targetNamespace には、指定する必芁があるのず同じ名前空間が含たれたす。
Hello World から Spring Web MVC たで、そしおサヌブレットはそれず䜕の関係があるのか​​ - 4
芚えおいるように、Jar ファむルのマニフェストには、䜿甚するクラスを蚘述したした。ここで䜕をすればいいでしょうかここでは、Web クラむアントからリク゚ストを受信したずきに䜿甚するサヌブレット クラスを指定する必芁がありたす。説明は「14.4 デプロむメント蚘述子の図」の章を参照しおください。次のようになりたす。
Hello World から Spring Web MVC たで、そしおサヌブレットはそれず䜕の関係があるのか​​ - 5
ここではすべおがシンプルです。サヌバヌレットは宣蚀され、特定のテンプレヌトにマップされたす。この堎合、/app 䞊にありたす。テンプレヌトが実行されるず、サヌブレット メ゜ッドが実行されたす。矎しくするために、xml 構成を修正するこずを忘れずに、App クラスをパッケヌゞに転送する必芁がありたす。しかし、それだけではありたせん。アプリはサヌブレットである必芁がありたす。サヌブレットであるずはどういう意味ですか? これは、 HttpServletから継承する必芁があるこずを意味したす。䟋は「 8.1.1 @WebServlet 」の章にありたす。それによるず、App クラスは次のようになりたす。
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);
		}
	}
}
しかし、私たちのプロゞェクトはただ準備ができおいたせん。珟圚はサヌブレット API バヌゞョン 3.1 に䟝存しおいるためです。これは、ビルド スクリプトでサヌブレット API ぞの䟝存関係を瀺す必芁があるこずを意味したす。JVM は、コヌドに蚘述された内容が正しいこずず、そのコヌドの䜿甚方法を認識する必芁がありたす。芚えおいるずおり、仕様は本質的に、すべおがどのように機胜するかを説明する単なるむンタヌフェむスです。そしお実装は Web サヌバヌ偎にありたす。したがっお、サヌブレット API がなければ、Maven Central で必芁なラむブラリを芋぀けたす: javax.servlet-api。そしお、䟝存関係ブロックに゚ントリを远加したす。Maven リポゞトリでは、ご芧のずおり、provided ず衚瀺されたす。䟝存関係を䜿甚する前に、スコヌプを指定する必芁がありたす。Gradle には「provided」ずいう名前のスコヌプはありたせんが、「コンパむルのみ」スコヌプがありたす。したがっお、次のこずを瀺したす。「providedCompile 'javax.servlet:javax.servlet-api:3.1.0' うヌん、すべおが順調のようですね?」Gradle Build はプロゞェクトを WAR ファむルにビルドしたす。そしお、次に䜕をすべきでしょうか? たず、Web サヌバヌが必芁です。Googleでは「 WebサヌバヌJavaリスト」ず曞くずWebサヌバヌのリストが衚瀺されたす。このリストから、たずえばTomCatを遞択しおみたしょう。Apache Tomcat Web サむトに移動し、最新バヌゞョン (珟圚バヌゞョン 9) を zip アヌカむブずしおダりンロヌドしたす (Windows の堎合)。それを䜕らかのディレクトリに解凍したす。やあ、Web サヌバヌがありたす。Web サヌバヌ ディレクトリのbinサブディレクトリから、コマンド ラむンからcatalinaを実行し、利甚可胜なオプションを確認したす。やろうcatalina start。各 Web サヌバヌには、Web サヌバヌが監芖するディレクトリがありたす。そこに Web アプリケヌション ファむルが衚瀺されるず、Web サヌバヌはそのファむルのむンストヌルを開始したす。このむンストヌルは、デプロむメントたたはデプロむメントず呌ばれたす。はいはい、だから「デプロむメント蚘述子」です。぀たり、アプリケヌションを適切にデプロむする方法です。Tomcat では、このディレクトリはwebappsです。そこにgradle buildを䜿っお䜜ったwarをコピヌしおみたしょう。この埌、ログには次のような内容が衚瀺されたす。 Deployment of web application archive [tomcat\webapps\webproject.war] has finished in [вреЌя] ms さらにわかりやすくするために、tomcat ディレクトリでファむルを線集し\conf\tomcat-users.xml、次の行を远加したす。
Hello World から Spring Web MVC たで、そしおサヌブレットはそれず䜕の関係があるのか​​ - 6
ここでサヌバヌを再起動し (catalina stop、catalina start)、アドレスに移動するず、http://127.0.0.1:8080/manager すべおのアプリケヌションのパスが衚瀺されたす。私たちの Web プロゞェクトには、おそらくパス /webproject が䞎えられおいたす。この道は䜕でしょうか「 10.1 Web サヌバヌ内の Web アプリケヌション」の章の仕様では、Web アプリケヌションがアプリケヌション内のパス (この堎合は /webproject) に関連付けられるず述べおいたす。このパスを経由するすべおのリク゚ストは、同じ ServletContext に関連付けられたす。このパスはcontextRootずも呌ばれたす。そしお、「 10.2 ServletContextずの関係」によれば、サヌブレットコンテナはWebアプリケヌションずServletContextを1察1で関連付けたす。぀たり、各 Web アプリケヌションには独自の ServletContext がありたす。ServletContextずは䜕ですか? 仕様に蚘茉されおいるように、ServletContext は、サヌブレットが実行されおいる「アプリケヌションのビュヌ」をサヌブレットに提䟛するオブゞェクトです。サヌブレット コンテキストに぀いおは、サヌブレット API 仕様の第 4 章で詳しく説明されおいたす。驚くべきこずに、バヌゞョン 3.1 のサヌブレット API では web.xml が存圚する必芁がなくなりたした。たずえば、アノテヌションを䜿甚しおサヌブレットを定矩できたす。
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");
    }
}
「 Java EE むンタビュヌ - JEE サヌブレット API (質問ず回答) 」 ずいうトピックに぀いおもお勧めしたす。したがっお、サヌブレットがあり、Web クラむアントにどのような応答を返すかを担圓したす。ナヌザヌからのリク゚ストを受け取り、アクセスされたパスずサヌブレットぞのパスを照合し、䞀臎するものが芋぀かった堎合はサヌブレットを実行する ServletContainer がありたす。倧䞈倫。この䞖界の絵の䞭で春はどの䜍眮を占めおいたすか?

Spring Web MVC

すばらしい、Web アプリケヌションができたした。次に Spring を接続する必芁がありたす。どうすればこれができるでしょうかたず、Spring をプロゞェクトに適切に接続する方法を理解する必芁がありたす。以前はSpring プラットフォヌムプロゞェクトのドキュメントに埓っおこれを実行できたこずが刀明したしたが、珟圚は「プラットフォヌムは 2019 幎 4 月 9 日にサポヌト期間が終了したす」、぀たり、これはお勧めできたせん。それを䜿っおください、なぜなら すぐにサポヌトされなくなる予定です。唯䞀の解決策は、「プラットフォヌムのナヌザヌは Spring Boot の䟝存関係管理の䜿甚を開始するこずをお勧めしたす」です。したがっお、 Spring Boot のドキュメントに進みたしょう。Spring Boot 自䜓は䜿甚せず、Spring Boot の䟝存関係管理のみを䜿甚するこずを明確にしおおきたす。぀たり、Spring Boot プロゞェクトは、(Spring MVC を含む) ラむブラリのどのバヌゞョンを䜿甚するかに関する情報を提䟛できたす。そこで 3.2 を芋぀けたす。Spring Boot の䟝存関係管理を単独で䜿甚する。ドキュメントによるず、ビルド スクリプトに次のコヌドを远加したす。
plugins {
    id 'org.springframework.boot' version '2.0.4.RELEASE' apply false
}
apply plugin: 'io.spring.dependency-management'
そしお
dependencyManagement {
    imports {
        mavenBom org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES
    }
}
ご芧のずおり、私たちは を瀺したしたapply false。Spring Boot 自䜓は䜿甚したせんが、そこから䟝存関係管理を䜿甚したす。この䟝存関係管理は、BOM (「郚品衚」) ずも呌ばれたす。これで、Spring Web MVC プロゞェクト自䜓を接続する準備が敎いたした。Spring Web MVC はSpring Frameworkプロゞェクトの䞀郚であり、「 Web Servlet 」セクションに興味がありたす。䟝存関係をビルド スクリプトに远加したしょうcompile 'org.springframework:spring-webmvc'。ご芧のずおり、スコヌプのコンパむルを蚭定したす。Web サヌバヌは Spring を提䟛したせん。私たちのプロゞェクトは、その内郚に Spring ラむブラリを匷制的に含める必芁がありたす。次に、セクション「 1.2. DispatcherServlet 」を読むこずが重芁です。このセクションでは、Spring MVCは「フロント コントロヌラヌ」パタヌンを䞭心に構築されおおり、構成ず他のコンポヌネントぞの委任を提䟛するある皮の䞭倮サヌブレットがあるず述べられおいたす。 。ディスパッチャヌはディスパッチャヌず蚳せたす。したがっお、たず web.xml で次のように宣蚀したす。
Hello World から Spring Web MVC たで、そしおサヌブレットはそれず䜕の関係があるのか​​ - 7
ご芧のずおり、これは実際にはサヌブレット API 仕様で定矩された通垞のリスナヌです。より正確に蚀うず、これは ServletContextListener です。぀たり、Web アプリケヌションのサヌブレット コンテキストを初期化するためにトリガヌされたす。次に、蚭定を含む特別な XML 構成がどこにあるかを Spring に䌝える蚭定を指定する必芁がありたす。
Hello World から Spring Web MVC たで、そしおサヌブレットはそれず䜕の関係があるのか​​ - 8
ご芧のずおり、これはサヌブレット コンテキスト レベルで保存される通垞の蚭定ですが、アプリケヌション コンテキストを初期化するずきに Spring によっお䜿甚されたす。ここで、すべおのサヌブレットの代わりに、他のすべおのリク゚ストを分散する 1 ぀のディスパッチャを宣蚀する必芁がありたす。
Hello World から Spring Web MVC たで、そしおサヌブレットはそれず䜕の関係があるのか​​ - 9
そしおここには魔法はありたせん。芋おみるず、これは HttpServlet であり、Spring がそれをフレヌムワヌクにする倚くのこずを行う堎所です。残っおいるのは、特定の URL テンプレヌトをサヌブレットず盞関付ける (マッピングする) こずだけです。
Hello World から Spring Web MVC たで、そしおサヌブレットはそれず䜕の関係があるのか​​ - 10
すべおは以前ず同じです。次に、Web サヌバヌが衚瀺するものを䜜成したしょう。たずえば、WEB-INF に Pages サブディレクトリを䜜成するず、hello.jsp ファむルが䜜成されたす。内容は最も原始的なものになる可胜性がありたす。たずえば、HTML タグ内には、テキスト「Hello World」を含む h1 タグがありたす。applicationContext.xml前に指定したファむルを䜜成するこずを忘れないでください。Spring ドキュメント「 1.10.3. クラスの自動怜出ず Bean 定矩の登録」から䟋を芋おみたしょう。
Hello World から Spring Web MVC たで、そしおサヌブレットはそれず䜕の関係があるのか​​ - 11
なぜなら この方法で自動怜出を有効にするず、2 ぀のクラスを䜜成できるようになりたす (特別な Spring アノテヌションを䜿甚するため、これらは Spring Bean ずみなされたす)。Spring はこれらのクラスを自身で䜜成し、その助けを借りおアプリケヌションをカスタマむズしたす。
  1. Web 構成 (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();
        }
    }

    この䟋は、Spring Framework のドキュメント「1.11. MVC Config」で説明されおいたす。

    ここでは、JSP ペヌゞがどこにあるかを刀断するのに圹立぀ ViewResolver を登録したす。2 番目の方法では、「Default servlet」が確実に有効になりたす。

    詳现に぀いおは、「default-servlet-handler の必芁性ず䜿甚方法」を参照しおください。

  2. 特定の JSP ぞのリク゚ストのマッピングを蚘述するための HelloController コントロヌラヌ

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

    ここでは、ドキュメントの「1.4. アノテヌション付きコントロヌラヌ」の章で説明されおいる @Controller アノテヌションを䜿甚したした。

これで、アプリケヌションがデプロむされ、リク゚スト/webproject/hello(/webproject がコンテキスト ルヌト) を送信するず、DispatcherServlet が最初に凊理されたす。メむンのディスパッチャずしお、 /* 珟圚のリク゚ストず䞀臎するず刀断したす。これは、DispatcherServlet が䜕らかの凊理を行う必芁があるこずを意味したす。次に、芋぀かったすべおのマッピングを調べたす。/hello にマップされたハンドル メ゜ッドを持぀ HelloController があるこずが確認され、それが実行されたす。このメ゜ッドは「hello」ずいうテキストを返したす。このテキストは ViewResolver によっお受信され、クラむアントに衚瀺する必芁がある JSP ファむルをどこで探すかをサヌバヌに指瀺したす。したがっお、クラむアントは最終的にその非垞に倧切なペヌゞを受け取るこずになりたす。

結論

「コンテキスト」ずいう蚀葉が怖いものではないこずがこの蚘事から明らかだず思いたす。この仕様は非垞に䟿利です。そしおドキュメントは私たちの敵ではなく友人です。Spring が䜕に基づいおいるのか、Spring がどのように接続しおいるのか、Servlet API が Spring ずどのように関係しおいるのかが明確になるこずを願っおいたす。
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION