JavaRush /Java Blog /Random-TW /Java 中的 Web 應用程式
Viacheslav
等級 3

Java 中的 Web 應用程式

在 Random-TW 群組發布
Java 中的 Web 應用程式 - 1

介紹

曾幾何時,Java 由於選擇 Web 應用程式作為優先事項而鞏固了自己的地位。從早期開始,Java 就一直在努力尋找自己的出路。首先,我建議使用小程式。這為開發人員在靜態 HTML 頁面上建立動態內容提供了許多機會。然而,由於安全、開銷等多種原因,小程式並沒有達到預期。於是Java語言的開發者提出了一個替代方案-Servlet API。事實證明這是一個正確的決定。 Servlet API是建立任何 Java Web 應用程式的規範,無論是基於 Web 的應用程式還是根據請求傳回資訊的 Web 服務。因此,了解 Java Web 應用程式如何運作的途徑始於了解 Servlet API。
Java 中的 Web 應用程式 - 2

服務程式介面

因此,Servlet API是語言開發人員提供給 Java 開發人員的。Servlet API 是一個應該回答我們主要問題的規格。您可以在這裡找到它:「JSR-000340 JavaTM Servlet 3.1 Final Release for Assessment」。「 1.1 什麼是Servlet? 」一章說Servlet是基於Java技術的創建動態內容(即內容)的Web元件。「基於Java」意味著servlet 是編譯成字節碼的Java 類別。Servlet 由 servlet 容器(有時稱為 Servlet 引擎)管理。servlet 容器是提供 servlet 功能的Web 伺服器擴充。反過來,servlet 在請求/回應範例中提供與客戶端的交互,這是由 servlet 容器實現的。在「 1.2 什麼是 Servlet 容器? 」一章中提到Servlet 容器是 Web 伺服器或應用程式伺服器的一部分,它提供網路服務,透過它發送請求和回應,產生和處理基於 MIME 的請求和回應。此外,servlet 容器管理 servlet 的生命週期(即決定何時建立它們、刪除它們等)。所有servlet容器都必須支援HTTP協定來接收請求和發送回應。在這裡我想補充一點,MIME是一個標準,一個規範,它告訴我們如何對資訊進行編碼和格式化訊息,以便它們可以透過網路發送。
Java 中的 Web 應用程式 - 3

網路伺服器

Web 伺服器是接受來自客戶端的 HTTP 請求並向其提供 HTTP 回應(通常連同 HTML 頁面、圖像、檔案或其他資料)的伺服器。請求的資源由 URL 標識。Apache Tomcat是最受歡迎的支援 Servlet API 的 Web 伺服器之一。大多數網路伺服器都是由各種元件組成的複雜機器,每個元件執行特定的功能。例如:
Java 中的 Web 應用程式 - 4

連接器

— 在輸入處,我們有連接器(即連接器),用於接受來自客戶端的傳入請求。Tomcat 中的 HTTP 連接器是使用「Coyote」元件實現的。連接器從客戶端接收資料並將其傳遞到 Tomcat 引擎。 Servlet 容器- Tomcat 引擎反過來使用「Catalina」元件(一個 Servlet 容器)處理從客戶端接收到的請求。更多詳細資訊請參閱 Tomcat 文件:「架構概述」。還有其他支援 Servlet API 規範的 Web 伺服器。例如,「Jetty」或「Undertow」。它們的架構相似,因此在了解使用一個 servlet 容器的原理後,您可以切換到使用另一個容器。
Java 中的 Web 應用程式 - 5

Web應用程式

因此,為了讓我們運行一個 Web 應用程序,我們需要一個支援 Servlet API 的 Web 伺服器(即具有為 Web 伺服器實作 Servlet API 支援的擴充元件)。美好的。到底什麼是網頁應用程式? 根據Servlet API 規範的「 10 Web 應用程式」一章, Web 應用程式是 servlet、HTML 頁面、類別和其他資源的集合,它們構成 Web 伺服器上的最終應用程式。根據「10.6 Web應用程式存檔檔案」一章,可以將Web應用程式打包在Web ARchive(帶有WAR副檔名的檔案)中。如「 Glossary-219 」頁所述:
Java 中的 Web 應用程式 - 6
也就是說,製作WAR而不是JAR來表明這是一個Web應用程式。下一個重要事實:我們的 WAR 檔案中必須有一定的目錄結構。在Servlet API規格中的「10.5目錄結構」一章中。本章說有一個特別的目錄叫做「WEB-INF」。該目錄的特殊之處在於它對客戶端不可見,也​​不會直接顯示給客戶端,但 servlet 程式碼可以存取它。它也說明了 WEB-INF 目錄可以包含哪些內容:
Java 中的 Web 應用程式 - 7
從整個清單中,我們現在不知道也不理解有關某些稱為部署描述符的web.xml檔案的項目。它是什麼?「 14.部署描述符」一章專門介紹部署描述符。簡而言之,部署描述符是一個 xml 文件,描述如何在 Web 伺服器上部署(即運行)我們的 Web 應用程式。例如,部署描述符指示應使用哪些 URL 來存取我們的應用程式、指示與我們的應用程式相關的安全設定等。「 14.2 處理部署的規則」一章說,在配置和啟動我們的應用程式之前,web.xml 將進行模式驗證(即,將根據模式檢查 web.xml 的內容是否正確寫入) 。在「 14.3 部署描述符」一章中指出該圖在這裡: 如果我們查看文件的內容,我們可以看到: http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd
Java 中的 Web 應用程式 - 8
XML 檔案使用什麼架構?模式指示如何正確填寫 XML 文件:可以使用哪些元素、可以在元素中指定哪種類型的資料、元素應按什麼順序排列、需要哪些元素等。您可以將 XML 文件的模式與 Java 中的介面進行比較,因為 Java 中的模式也指定應如何編寫滿足給定介面(即實作給定介面)的類別。因此,我們已經掌握了秘密知識,並準備好創建我們的第一個 Web 應用程式!
Java 中的 Web 應用程式 - 9

建立 Web 應用程式

很難想像在不使用自動專案建置系統的情況下使用現代 Java 應用程式。一些最受歡迎的系統是Maven 和 Gradle。我們將使用 Gradle 進行本次審查。Gradle的安裝在官方網站上有描述。要建立一個新應用程序,我們需要一個內建於 Gradle 中的插件:「Build Init Plugin」。要建立 Java 應用程序,您需要執行以下命令: gradle init --type java-application
Java 中的 Web 應用程式 - 10
建立專案後,我們需要編輯build.gradle檔案。這就是所謂的Build Script(更多詳細信息,請參見Gradle文件:“編寫構建腳本”)。該文件描述如何組裝專案以及使用 Java 專案的其他方面。插件塊描述了目前 Gradle 專案應該使用哪些「 Gradle 插件」。插件擴展了我們專案的功能。例如,預設插件是“ java ”。如果我們需要 Java 支持,總是會使用這個外掛。但我們不需要「應用程式」插件,因為...... 它的描述表明它用於創建“可執行的 JVM 應用程式”,即 運行 JVM 應用程式。我們需要以 WAR 存檔的形式建立一個 Web 應用程式。如果我們在 Gradle 文件中尋找 WAR 一詞,我們會找到「War Plugin」。因此,我們將指定以下插件:
plugins {
    id 'java'
    id 'war'
}
另外,在“ War Plugin Default Settings ”中,表示包含Web應用程式所有內容的目錄應該是“src/main/webapp”,應該有與web.xml相同的WEB-INF目錄位於。讓我們建立一個這樣的檔案。我們稍後會填寫它,因為...... 我們對此還沒有足夠的資訊。在「依賴項」區塊中,我們指示專案的依賴項,也就是我們的應用程式無法運行的程式庫/框架。在本例中,我們正在編寫一個 Web 應用程序,這意味著沒有 Servlet API 就無法運作:
dependencies {
    providedCompile 'javax.servlet:javax.servlet-api:3.1.0'
    testCompile 'junit:junit:4.12'
}
providedCompile 意味著依賴項不需要包含在我們的 Web 應用程式的 WAR 檔案中:僅在編譯時需要它。而執行時,這個依賴將由其他人(即Web伺服器)提供。好吧,我們在建置腳本中留下有關我們要使用哪個依賴項儲存庫的資訊 - 所有指定的依賴項都將從它下載:
repositories {
    jcenter()
}
我們從建置腳本檔案中刪除其他所有內容。現在讓我們編輯類別 src\main\java\App.java。讓我們用它來創建一個 servlet。「第 2 章 Servlet 介面」一章中的 Servlet API 規範指出,Servlet 介面有一個HttpServlet 的基本實現,這在大多數情況下應該足夠了,開發人員只需要繼承它。在「 2.1.1 HTTP 特定請求處理方法」一章中指出了處理傳入請求的主要方法。因此,讓我們重寫 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();
 	}
}
所以,我們似乎已經萬事俱備了。剩下的就是正確編寫部署描述符。從圖中,將以下文字複製到 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>
還有其中所指示的架構路徑: http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd 現在讓我們來看一個範例,說明 web.xml 在 Servlet API 規格中應該是什麼樣子。此範例在「 14.5.1 基本範例」一章中給出。讓我們將圖中所示的內容與規範中所示的範例結合。我們得到以下資訊:
<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>
如您所見,我們使用了先前指定的 schema 和 schemaLocation。元素本身的描述取自第 14.5.1 章的範例。如果一切正確,我們將正確執行 gradle war 任務:
Java 中的 Web 應用程式 - 11
Java 中的 Web 應用程式 - 12

啟動網路應用程式

Web 應用程式如何啟動?讓我們先處理更複雜的選項。我們之前說過有一個支援 Servlet API 的 Apache Tomcat Web 伺服器。這意味著我們可以在該伺服器上部署我們收集的戰爭檔案(他們也說「部署」)。在「下載 Tomcat」頁面上,從「二進位發行版」部分下載 zip 格式的交付類型「Core」。並將下載的檔案解壓縮到某個目錄,例如 C:\apache-tomcat-9.0.14。在啟動伺服器之前,讓我們打開文件進行編輯conf\tomcat-users.xml並向其中添加以下行: <user username="tomcat" password="tomcat" roles="tomcat,manager-gui,admin-gui"/> 現在,在命令行上,轉到 bin 目錄並執行catalina.bat start. 預設情況下,伺服器控制台將在 處可用http://localhost:8080/manager。登入名稱和密碼與我們在 tomcat-users.xml 中指定的相同。Tomcat 有一個「webapps」目錄,其中包含Web 應用程式。如果我們想部署我們自己的,我們必須將我們的戰爭檔案複製到那裡。當我們之前執行 gradle war 指令時,\build\libs\會在目錄中建立一個 war 存檔。這就是我們需要複製的。複製完成後刷新頁面http://localhost:8080/manager即可看到:
Java 中的 Web 應用程式 - 13
完成後http://localhost:8080/javaweb/app,我們將轉向我們的 servlet,因為 我們之前將 /app 請求「映射」(即映射)到 App servlet。有一種更快的方法來檢查應用程式的工作情況。裝配系統再次幫助我們解決了這個問題。在 Gradle 專案的建置腳本中,我們可以將一個新插件「Gretty」新增到插件部分: id "org.gretty" version "2.3.1" 現在我們可以執行 gradle 任務來執行我們的應用程式:gradle appRun
Java 中的 Web 應用程式 - 14
詳細資訊 請參閱「新增 gretty 外掛程式並執行應用程式」。
Java 中的 Web 應用程式 - 15

Spring 和 Servlet API

Servlet 是一切的基礎。即使是現在流行的 Spring 框架也只不過是 Servlet API 的附加元件。首先,Spring 框架是我們專案的新相依性。因此,讓我們將其新增至相依性區塊中的建置腳本: compile 'org.springframework:spring-webmvc:5.1.3.RELEASE' 在 Spring 框架文件中有一章「1.1.DispatcherServlet」。它說 Spring 框架是建立在「前端控制器」模式之上的 - 這是當有一個名為「DispatcherServlet」的中央 servlet 時。所有請求都到達此 servlet,並將呼叫委託給必要的元件。您看,即使這裡也有 servlet。您需要將偵聽器新增至部署描述符:
<listener>
	&ltlistener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
這是一個 servlet 上下文事件監聽器。也就是說,當Servlet Context啟動時,Spring上下文(WebApplicationContext)也會啟動。什麼是 Servlet 上下文?它在 Servle API 規範的「第 4 章 Servlet 上下文」一章中進行了描述。Servlet 上下文是 Servlet 運行的 Web 應用程式的「視圖」。每個 Web 應用程式都有自己的 Servlet 上下文。接下來,要啟用 Spring 框架,您需要指定 context-param - servlet 上下文的初始化參數。
<context-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>/WEB-INF/app-context.xml</param-value>
</context-param>
DispatcherServlet定義完成設定:
<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>
現在我們只需填寫 contextConfigLocation 中指定的檔案。Spring框架文件的「1.3.1.聲明」一章描述如何做到這一點:
<?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>
這裡重要的是不僅要指示要掃描哪個包,而且我們要註解驅動,即控制 Spring 將如何運作的註解。剩下的就是建立 ru.javarush.javaweb 套件並將 Spring 控制器類別放入其中:
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.";
    }
}
現在運行 gradle appRun 並轉到該地址,http://127.0.0.1:8080/javaweb/app我們將得到相同的 Hello World。正如您所看到的,Spring 框架與 Servlet API 緊密相連,並使用它在其之上工作。
Java 中的 Web 應用程式 - 16

註解

正如我們所見,註釋很方便。我們並不是唯一這麼想的人。因此,在Servlet API規格中,從3.0版本開始,出現了「CHAPTER 8 Annotations and Pluggability」一章,規定Servlet容器必須支援透過註解來指定先前在Deployment Descriptor中指定的內容的能力。這樣,web.xml就可以從專案中完全刪除,並且在servlet類別之上您可以指定@WebServlet註解並指示將servlet對應到哪個路徑。這裡一切似乎都很清楚。但如果我們把Spring連接到專案中,需要更複雜的設定呢?這裡一切都有點複雜。首先,Spring 文件說要在沒有 web.xml 的情況下配置 Spring,您需要使用自己的類別來實作 WebApplicationInitializer。更多詳細信息,請參見“ 1.1.DispatcherServlet ”章節。原來這是一個Spring類。那麼這裡的Servlet API是如何使用的呢?事實上,ServletContainerInitializer已新增至 Servlet API 3.0 中。使用 Java 中的特殊機制(稱為SPI),Spring 指定了名為 的 servlet 容器初始值設定項SpringServletContainerInitializer。反過來,它已經查找 WebApplicationInitializer 的實作並呼叫必要的方法並執行必要的設定。有關更多詳細信息,請參閱“ servlet 容器如何查找 WebApplicationInitializer 實作”。上述設定可以這樣完成:
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);
    }
}
現在,使用“基於 Java 的配置”,我們將指示要掃描哪個套件+啟用註解:
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 {
}
而SpringController本身被移到了ru.javarush.javaweb.controllers,這樣在掃描的時候,配置就不會找到它自己,而只會尋找控制器。
Java 中的 Web 應用程式 - 17

總結

我希望這篇概述能讓您對 Web 應用程式如何在 Java 中運作有所了解。這只是冰山一角,但如果不了解基礎知識,就很難理解基於此基礎的技術是如何運作的。Servlet API 是任何 Java Web 應用程式的核心部分,我們已經研究了其他框架如何融入其中。要繼續,您可以查看以下材料: #維亞切斯拉夫
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION