JavaRush /Java Blog /Random-TW /使用 servlet 和 jsp 建立簡單的 Web 應用程式(第 1 部分)
Стас Пасинков
等級 26
Киев

使用 servlet 和 jsp 建立簡單的 Web 應用程式(第 1 部分)

在 Random-TW 群組發布
理解本文所需的知識水平:您已經或多或少地了解了 Java Core,並且想了解 JavaEE 技術和 Web 程式設計。如果您目前正在研究 Java Collections 任務,那麼它是最有意義的,它涵蓋了與本文接近的主題。 本資料是我的文章在 IntelliJ Idea Enterprise 中建立簡單的 Web 專案使用 servlet 和 jsp 建立簡單的 Web 應用程式(第 1 部分)- 1的邏輯延續。在其中我示範如何建立一個可用的 Web 專案範本。這次我將向您展示如何使用 Java Servlet API 和 JavaServer Pages API 技術來建立一個簡單但漂亮的 Web 應用程式。我們的應用程式將有一個帶有兩個連結的主頁:
  • 到使用者新增頁面;
  • 進入使用者清單查看頁面。
我仍將使用 IntelliJ Idea Enterprise Edition、Apache Maven(僅包含一些依賴項)和 Apache Tomcat。最後,我們將使用W3.CSS框架「裝飾」我們的應用程式。我們假設目前您已經有一個空項目,我們將在這裡開發該項目。如果沒有,請閱讀第一篇文章並完成它。只需幾分鐘:)

關於未來應用程式的結構的一些信息

我們的主頁 ( / ) 將是最普通的靜態 html 頁面,帶有標題和兩個連結/按鈕:
  • 新增用戶(將發送到/add);
  • 查看使用者清單(傳送到/list)。
Tomcat 將捕獲對這些地址的請求並將它們發送到我們將創建的兩個 servlet 之一(我們將在web.xml檔案中描述映射)。Servlet 依序處理請求、準備資料(或在新增使用者時儲存資料),並將控制權轉移到相應的 jsp 文件,這些文件已「呈現」結果。我們將資料儲存在最常見的清單(List)中。

讓我們建立一個靜態主頁

如果您的 Web 資料夾中有index.jsp,請將其刪除。相反,在此資料夾中,我們將建立一個名為index.html的簡單 html 檔案:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>My super project!</title>
</head>
<body>
    <!-- header -->
    <div>
        <h1>Super app!<//h1>
    </div>

    <div>       <!-- content -->
        <div>    <!-- buttons holder -->
            <button onclick="location.href='/list'">List users<//button>
            <button onclick="location.href='/add'">Add user<//button>
        </div>
    </div>
</body>
</html>
這裡沒有什麼複雜的。在標題中,我們表示頁面的標題。在頁面正文中我們有兩個主要的div:標題(header)和內容(content)。在內容中,我們有一個按鈕支架,實際上有兩個按鈕,當單擊時,它們會被發送到適當的位址。您可以運行該專案並查看它現在的樣子。如果您按一下這些按鈕,則會開啟帶有 404 錯誤的頁面,因為我們還沒有這些頁面。但這表明按鈕可以工作。請注意,這不是最通用的選項,因為如果您突然停用 JavaScript,這些按鈕將在瀏覽器中毫無用處。但我們假設沒有人禁用 JavaScript :)。顯然可以使用簡單的鏈接,但我更喜歡按鈕。你做你最喜歡的事。別看我的例子中會有很多div。然後我們會給它們填充樣式,一切都會看起來更漂亮:)。

建立jsp檔案來渲染結果

在同一個Web目錄中,我們將建立一個資料夾來放置jsp 檔案。我將其稱為視圖,同樣,您可以即興創作。在此資料夾中我們將建立兩個 jsp 檔案:
  • add.jsp — 新增使用者的頁面;
  • list.jsp - 用於顯示使用者清單的頁面。
讓我們為他們提供適當的頁面標題。像是「新增使用者」和「使用者清單」之類的東西,我們暫時保留這種狀態。

讓我們建立兩個 servlet

Servlet 將接受並處理 Tomcat 傳遞給它們的請求。在src/main/java資料夾中,我們將建立一個應用程式包,其中包含我們的原始程式碼。在那裡我們將有更多不同的包。因此,為了使這些套件不會在彼此內部創建,讓我們在應用程式包中創建一些類別(然後將其刪除)。現在讓我們在應用程式包中建立三個不同的套件 :
  • 實體- 這是我們的實體所在的位置(類別本身,它將描述使用者物件);
  • model - 我們的模型將在這裡(稍後會詳細介紹);
  • servlet - 好吧,這就是我們的 servlet。
之後,您可以安全地從應用程式包中刪除該類別(當然,如果您創建了它)。在servlets套件中,我們將建立兩個類別:
  • AddServlet - 將處理在/add收到的請求;
  • ListServlet - 將處理在/list收到的請求。

連接 Maven 中的依賴項

Tomcat 版本 9.* 實作了 Servlet 版本 4.0 和 JavaServer Pages 版本 2.3 規格。這是Tomcat 9官方文件中第二行第一段中寫的。這意味著,如果您像我一樣正在使用此版本的 Tomcat,那麼我們編寫並發送運行的程式碼將完全使用指定的版本。但我們希望在我們的專案中擁有這些規範,以便使用它們的程式碼至少能夠成功編譯。為此,我們需要將它們載入到我們的專案中。這就是 Maven 發揮作用的地方。

一般規則是這樣的:如果您需要使用 Maven 將某些內容連接到您的專案:

  • 前往 Maven 儲存庫網站;
  • 在那裡查找您需要的庫和版本;
  • 您獲得需要插入到 pom.xml 中的依賴項程式碼;
  • 插入!:)
那麼就讓我們開始吧。首先,我們準備一個pom檔在/version之後但/project之前的某個位置,插入以下內容:
<dependencies>

</dependencies>
因此,我們表明在這些標籤內我們將列出我們需要的依賴項。現在造訪mvnrepository.com,頂部會有一個搜尋欄位。首先,在搜尋中輸入 servlet。第一個結果有七千多種用途,很適合我們。我們記得我們需要 4.0 版本(對於 Tomcat 9;對於其他版本,舊的實作可能適合)。這是一個相當新的版本,所以沒有太多用途,但它是我們需要的。將打開一個頁面,您可以在其中獲取各種套件管理器的此依賴項的程式碼,您甚至可以直接下載它。但由於我們想使用 Maven 連接它,因此我們選擇 Maven 選項卡上的代碼。我們複製並貼上到 pom 檔案的依賴項部分。如果 IDEA 右下角出現通知詢問我們是否要啟用自動導入,我們同意。如果您不小心拒絕,請前往「設定」並手動啟用自動匯入:設定 (Ctrl + Alt + S) -> 建置、執行、部署 -> Maven -> 匯入 這將保留pom 檔案和 IDEA 設定檔專案同步。現在,使用相同的原理,我們將找到並連接 JavaServer Pages 版本 2.3(在搜尋中輸入 jsp)。既然我們已經使用了 Maven,那麼我們立即告訴它我們的原始程式碼符合 Java 8 語法,並且它們需要編譯成相同版本的字節碼。經過所有這些操作後,我們的pom.xml將如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>ru.javarush.info.fatfaggy</groupId>
    <artifactId>my-super-project</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>1.8</maven.compile.source>
        <maven.compiler.target>1.8</maven.compile.target>
    </properties>

    <dependencies>
        <!-- Servlet API 4.0 for tomcat 9 -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.0</version>
            <scope>provided</scope>
        </dependency>

        <!-- JavaServer Pages API 2.3 for tomcat 9 -->
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>javax.servlet.jsp-api</artifactId>
            <version>2.3.1</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

</project>

讓我們的 servlet 成為真正的 servlet

此時,我們創建的幾個 servlet 實際上只是常規類別。它們沒有任何功能。但現在我們已經將 Servlet API 連接到我們的項目,如果是這樣,我們可以使用那裡的類別。為了讓我們的 servlet 成為「真正的」servlet,我們只需從HttpServlet類別繼承它們即可。

映射或分區

現在,最好以某種方式告訴 Tomcat,以便來自/add的請求由我們的AddServlet servlet處理,因此來自/list 的請求由ListServlet servlet處理。這個過程稱為映射。這是根據以下原則 在web.xml檔案中完成的:
  • 首先我們描述 servlet(我們給出一些名稱並指出類別本身的路徑);
  • 然後我們將此 servlet 綁定到特定位址(我們指示我們剛剛提供的 servlet 的名稱,並指示應將請求發送到此 servlet 的位址)。
讓我們來描述一下 Servlet:
<servlet>
    <servlet-name>add</servlet-name>
    <servlet-class>app.servlets.AddServlet</servlet-class>
</servlet>
現在我們將它綁定到位址:
<servlet-mapping>
    <servlet-name>add</servlet-name>
    <url-pattern>/add</url-pattern>
</servlet-mapping>
正如您所看到的,兩種情況下的servlet-name是相同的。因此,Tomcat 知道如果請求到達/add位址,則需要將其傳遞給app.servlets.AddServlet servlet 。我們對第二個 servlet 執行同樣的操作。結果,我們的web.xml大約有以下內容:
<?xml version="1.0" encoding="UTF-8"?>
<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">

    <!-- add servlet -->
    <servlet>
        <servlet-name>add</servlet-name>
        <servlet-class>app.servlets.AddServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>add</servlet-name>
        <url-pattern>/add</url-pattern>
    </servlet-mapping>

    <!-- list servlet -->
    <servlet>
        <servlet-name>list</servlet-name>
        <servlet-class>app.servlets.ListServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>list</servlet-name>
        <url-pattern>/list</url-pattern>
    </servlet-mapping>
</web-app>
順便說一句,我們沒有為此處的主頁(位於/)建立標記。事實是,在這種情況下我們不需要它。我們的主頁是一個簡單的html 文件,只顯示兩個按鈕。沒有動態內容,因此我們為它創建一個單獨的 servlet 是沒有意義的,來自地址/的請求將被發送到該 servlet,並且除了將執行轉移到某些jsp之外什麼也不做(這也必須是創建),如果我們有兩個按鈕,它就會繪製。我們不需要這個;我們對靜態資源很滿意。當Tomcat收到一個請求時,它會檢查這個地址是否沒有一個servlet可以處理該請求,然後它會發現這個地址實際上有一個現成的html文件,它會成功發送該文件。我們可以再次運行我們的應用程式(根據需要重新啟動伺服器或重新部署)並確保主頁已呈現,沒有任何損壞,當我們單擊按鈕時,會發生轉換,但現在也會出現錯誤書面。順便說一句,如果之前有 404 錯誤,現在有 405 錯誤。這意味著映射有效,找到了 servlet,但它們只是沒有任何合適的方法來處理請求。如果在這個階段你仍然得到 404 錯誤,儘管一切都完成了,也許你應該更正 idea 中的部署配置。為此,您需要轉到“編輯配置”(位於頂部靠近“開始”按鈕的位置),轉到視窗右側的“部署”選項卡,並確保在“應用程式”上下文中簡單地指示/

簡短的抒情題外話:「幕後」正在發生什麼事?

您可能已經想知道我們的應用程式在 Tomcat 中如何運作?那裡發生了什麼事?main()方法在哪裡?一旦您在瀏覽器中輸入localhost:8080並造訪該位址,瀏覽器就會透過http協定向該位址傳送請求。我希望您已經意識到請求可以有不同的“類型”,最受歡迎的是GETPOST。每個請求都必須有一個答案。GET 請求期望在回應中給出現成的html 代碼,該代碼將返回瀏覽器,瀏覽器將漂亮地用各種字母、按鈕和表單替換代碼。POST 請求更有趣一些,因為它也攜帶一些資訊。例如,在使用者註冊或授權表單中,您輸入了資料並點擊「傳送」。此時,一個 POST 請求已傳送到伺服器,其中包含您的個人資訊。伺服器接受此訊息,對其進行處理並返回某種回應(例如,包含您的個人資料的html 頁面)。它們之間的根本區別在於,GET 請求僅用於從伺服器接收數據,而POST 請求則攜帶一些信息,並且伺服器上的數據可能會發生變化(例如,當您將照片上傳到伺服器時,它會更改)。會飛入POST請求,伺服器會將其添加到資料庫中,即會發生一些變化,現在我們回到Tomcat,當它收到客戶端的一些請求時,它會查看該位址,搜尋其資料查看是否有合適的servlet,它可以處理對這樣的地址的請求(或可以立即返回的現成資源)。如果沒有找到任何可返回的內容,則它不會以html 頁面響應,而是以帶有404 響應。如果它找到一個合適的servlet,「位於」該位址,它會查看收到的請求類型(GET、POST 或其他),然後詢問servlet 是否有一個方法可以處理這種類型的請求。如果servlet 說它不能處理這種類型,Tomcat 就會用程式碼405 回應客戶端。這就是我們剛剛發生的情況。但是如果找到了合適的servlet,並且它有合適的方法,Tomcat就會創建這個servlet的對象,在一個新的線程(thread)中運行它,這允許servlet在單獨的線程中工作,並且Tomcat繼續進一步工作本身,接收和發送請求。此外,Tomcat 還建立了兩個物件:一個是HttpServletRequest類型(我將在以後簡稱為請求),第二個是HttpServletResponse類型(我將其稱為答案)。在第一個物件中,它放置了從客戶端請求中接收到的所有數據,因此可以從此物件中提取所有資料。好吧,完成這一切之後,它將這兩個物件傳遞給在單獨執行緒中運行的 servlet 的適當方法。一旦 Servlet 完成其工作並準備好發送給客戶端的回應,它就會向 Tomcat 舉起一個標誌,說:“我完成了,一切都準備好了。” Tomcat 接受回應並將其傳送給客戶端。這使得 Tomcat 可以不間斷地接受請求並發送回應,而所有工作都是由在單獨執行緒中執行的 servlet 完成的。因此,當我們編寫 servlet 程式碼時,我們定義了將要執行的工作。是的,您可以將main()方法視為 Tomcat 本身中的方法(是的,它是用 Java 編寫的),當我們「啟動」Tomcat 時,main().

我們使用 servlet 捕獲 GET 方法並發送簡單的回應

目前,我們的 servlet 沒有合適的方法 (GET),因此 Tomcat 會傳回 405 錯誤。讓我們來製作它們吧!我們繼承 servlet 的HttpServlet類別定義了不同的方法。為了給方法設定一些程式碼,我們只需重寫它們即可。在這種情況下,我們需要重寫兩個 servlet 中的doGet()方法。
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

}
如你所看到的,這個方法接受兩個物件:req(請求)和resp(回應)。這些正是 Tomcat 在呼叫此 servlet 中的適當方法時將為我們建立和填充的物件。首先,我們來做最簡單的回答。為此,請取得resp物件並從中取得PrintWriter對象,該物件可用於撰寫回應。好吧,使用它我們將打印一些簡單的字串。
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    PrintWriter writer = resp.getWriter();
    writer.println("Method GET from AddServlet");
}
我們將在ListServlet servlet 中執行類似的操作,然後再次啟動伺服器。如您所見,一切正常!當您單擊按鈕時,頁面將打開,其中包含我們用 PrintWriter “記錄”的文字。只是我們為產生帶有答案的頁面而準備的jsp沒有以任何方式使用。這是因為執行根本沒有到達他們手中。現在,Serverlet 本身會產生回應並完成其工作,向 Tomcat 發出訊號,表示它已為客戶端準備好回應。Tomcat 只是接受此回應並將其發送回客戶端。我們將控制權從 servlet 轉移到jsp。 讓我們這樣更改方法的程式碼:
  • 我們從請求對像中取得一個請求管理器對象,在其中傳遞我們想要將控制權轉移到的頁面的jsp位址;
  • 使用接收到的對象,我們將控制權轉移到指定的jsp頁面,並且不要忘記附加我們從 Tomcat 接收的請求和回應對象。
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    RequestDispatcher requestDispatcher = req.getRequestDispatcher("views/add.jsp");
    requestDispatcher.forward(req, resp);
}
在jsp頁面 的body中(body標籤內)我們可以寫一些東西,這樣我們就可以清楚地看到正在顯示的是哪個頁面。之後,我們重新啟動伺服器並檢查。按下主頁上的按鈕,打開頁面,這意味著請求被傳送到 servlet,之後控制權被轉移到已經呈現的 jsp 頁面。就這樣。在本文的下一部分中,我們將討論應用程式的功能。

還有什麼要讀的:

在 IntelliJ Idea Enterprise 中建立一個簡單的 Web 專案。一步步來,有圖


我的聊天記錄
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION