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

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

在 Random-TW 群組發布
使用 servlet 和 jsp 創建一個簡單的 Web 應用程式(第 1 部分) 來理解本文所需的知識水平:您已經或多或少地了解了 Java Core,並且希望了解 JavaEE 技術和 Web 程式設計。如果您目前正在研究 Java Collections 任務,那麼它是最有意義的,它涵蓋了與本文接近的主題。
使用 servlet 和 jsp 建立簡單的 Web 應用程式(第 2 部分)- 1

建立實體

實體包中,我們將建立一個類別User,其中有兩個私有字串變數namepassword。讓我們建立建構函式(預設的和接受兩個值的建構子)、getters/setters、重寫toString()方法(以防萬一)以及equals()hashCode()方法。也就是說,我們將做一個合格的 Java 開發人員在創建類別時所做的一切。
public class User {
    private String name;
    private String password;

    public User() {
    }

    public User(String name, String password) {
        this.name = name;
        this.password = password;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", password='" + password + '\'' +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        User user = (User) o;

        if (name != null ? !name.equals(user.name) : user.name != null) return false;
        return password != null ? password.equals(user.password) : user.password == null;

    }

    @Override
    public int hashCode() {
        int result = name != null ? name.hashCode() : 0;
        result = 31 * result + (password != null ? password.hashCode() : 0);
        return result;
    }
}
現在我們可以開始建立使用者清單。我們將向其中添加用戶,並從那裡將他們顯示出來。然而,有一個問題。我們不創建 servlet 對象,Tomcat為我們做這件事。我們在其中重寫的方法也已經為我們定義好了,我們無法新增參數。那我們要如何建立一個對我們的兩個 servlet 都可見的共享清單呢?如果我們只是在每個 servlet 中建立自己的清單對象,那麼我們將把使用者加入到一個清單中,並使用ListServlet servlet 將使用者清單顯示到另一個清單中。事實證明,我們需要一個兩個 servlet 共用的物件。一般來說,我們需要一個對程式中所有類別都通用的物件;整個程序的唯一對象。我希望您聽說過一些有關設計模式的知識。也許,對於某些人來說,這是在他們的程式中使用單例模式的第一個真正需求。您可以變態並通過雙重檢查和同步創建一些很酷的單例(是的,我們有一個多線程應用程序,因為Tomcat 在不同的線程中運行servlet),但我將使用早期初始化的選項,因為它在這裡非常合適足夠了,它適合我們的目的。

創建模型

讓我們在模型包中建立一個類別(並在其中實作單例模式)並將其命名為不尋常的名稱。讓我們說模型。讓我們在類別中建立一個私人用戶列表對象,並實現兩個方法:第一個用於添加用戶,第二個用於返回字串(用戶名)列表。由於我們的使用者物件由名稱和密碼組成,並且我們不想「洩漏」使用者密碼,因此我們只有一個名稱清單。
public class Model {
    private static Model instance = new Model();

    private List<User> model;

    public static Model getInstance() {
        return instance;
    }

    private Model() {
        model = new ArrayList<>();
    }

    public void add(User user) {
        model.add(user);
    }

    public List<String> list() {
        return model.stream()
                .map(User::getName)
                .collect(Collectors.toList());
    }
}

關於mvc的一些知識

既然您聽說過singleton,那麼您可能也聽說過另一種設計模式 - MVC(模型-視圖-控制器,俄語中的模型-視圖-控制器,或者就像英語中的模型-視圖-控制器)。其本質是將業務邏輯與表示分開。也就是說,將決定要做什麼的程式碼與決定如何顯示的程式碼分開。視圖(視圖或簡稱視圖)負責某些資料的呈現形式。在我們的例子中,視圖是我們的 JSP 頁面。這就是為什麼我將它們放在一個名為“views”的資料夾中。 模型是程式運行時使用的實際數據。在我們的例子中,這些是用戶(用戶列表)。那麼,控制器就是它們之間的連接紐帶。它們從模型中獲取數據並將其傳遞給視圖(或從 Tomcat 接收一些數據,對其進行處理並將其傳遞給模型)。業務邏輯(程式到底應該做什麼)需要在其中描述,而不是在模型或視圖中。於是,每個人都做自己的事:
  • 模型儲存資料;
  • 視圖繪製了資料的漂亮表示;
  • 控制器負責資料處理。
這使得程式相當簡單且可維護,而不是一個類別中所有程式碼的巨大轉儲。 MVC不僅適用於 Web 編程,而且在這個領域中它的身影尤其頻繁(幾乎總是)。在我們的例子中,Servlet 將充當控制器。這是對該模式的非常膚淺和簡短的描述,但MVC不是本文的主要主題。誰想了解更多 - 谷歌來救援!建立用於新增使用者的表單 讓我們在add.jsp檔案中新增一個表單,該表單由兩個文字輸入字段(一個是常規輸入字段,另一個是密碼)和一個用於將資料傳送到伺服器的按鈕組成。
<form method="post">
    <label>Name:
        <input type="text" name="name"><br />
    </label>

    <label>Password:
        <input type="password" name="pass"><br />
    </label>
    <button type="submit">Submit</button>
</form>
這裡的表單有一個值為post 的method屬性。這意味著該表單中的資料將以 POST 請求的形式傳送到伺服器。未指定action屬性,這表示請求將發送到我們訪問此頁面的相同位址 ( /add )。因此,綁定到該位址的 servlet 在收到 GET 請求後,會傳回此 jsp 以及用於新增使用者的表單,如果它收到 POST 請求,則表示該表單已將其資料傳送到那裡(我們將從doPost() 值得注意的是,輸入字段有一個名稱參數(對於具有名稱的字段,它具有值 name ,對於具有密碼的字段,它具有值pass)。這是非常重要的一點。因為為了從請求(已經在 servlet 內部)獲取這些資料(將輸入的名稱和密碼),我們將準確使用這些名稱pass。但稍後會詳細介紹。用於發送資料的按鈕本身再次以按鈕的形式製作,而不是像通常習慣那樣作為輸出欄位。我不知道這個選項有多通用,但它對我有用(Chrome 瀏覽器)。

使用 servlet 處理 POST 請求

讓我們回到AddServlet servlet 。讓我提醒您:為了讓我們的 servlet 能夠「捕獲」GET 請求,我們重寫了HttpServlet類別中的doGet()方法。為了教導我們的 servlet 也捕捉 POST 請求,我們還需要重寫doPost()方法。它從Tomcat接收類似的請求和回應對象,我們將使用它。首先,讓我們從請求中提取名稱並傳遞表單發送的參數(如果您在表單中對它們進行了不同的命名,那麼這些就是您編寫的名稱)。之後,我們將使用接收到的資料建立使用者物件。然後我們將獲取模型物件並將創建的使用者新增至模型中。
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    String name = req.getParameter("name");
    String password = req.getParameter("pass");
    User user = new User(name, password);
    Model model = Model.getInstance();
    model.add(user);
}

傳遞資料以查看

讓我們繼續討論ListServlet servlet 。這裡已經實作了doGet()方法,它只是將控制權轉移到list.jsp視圖。如果您還沒有,請使用AddServlet servlet 中的相同方法進行類別推。現在,最好從模型中獲取使用者名稱清單並將它們傳遞給視圖,視圖將接收它們並很好地顯示它們。為此,我們將再次使用從Tomcat收到的請求物件。我們可以為這個物件添加一個屬性,給它一些名稱,事實上,我們想要將其傳輸到view 的物件本身。由於以下事實:當將執行程序從 servlet 轉移到視圖時,我們將 servlet 本身接收到的相同請求和響應對象傳遞給那裡,然後透過將名稱列表新增至請求對象,我們就可以從該請求視圖中的物件創建我們的用戶名列表並獲取。我們已經完成了ListServlet類,所以這裡是整個類別的程式碼:
package app.servlets;

import app.model.Model;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

public class ListServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Model model = Model.getInstance();
        List<String> names = model.list();
        req.setAttribute("userNames", names);

        RequestDispatcher requestDispatcher = req.getRequestDispatcher("views/list.jsp");
        requestDispatcher.forward(req, resp);
    }
}

執行jsp檔案中的java程式碼

現在是開始處理list.jsp檔案的時候了。只有當ListServlet經過這裡的執行流程時才會執行。此外,在該 servlet 中,我們已經從模型中準備了使用者名稱列表,並將其傳遞到請求物件中。由於我們有一個名稱列表,因此我們可以循環遍歷它列印每個名稱。正如我已經說過的,jsp 檔案可以執行 java 程式碼(這就是它們與靜態 html 頁面的不同之處)。為了執行一些程式碼,將以下結構放在我們需要的地方就足夠了:
<!-- html code -->
<%
    // java code
%>
<!-- html code -->
在這個構造中,我們可以存取幾個變數:
  • request是我們的請求對象,我們從 servlet 傳遞它,在這裡它被簡單地稱為req
  • responce - 回應對象,在 servlet 中稱為resp
  • out是JspWriter類型的物件(繼承自通常的Writer),借助它我們可以直接將某些內容「寫入」到 html 頁面本身。out.println("Hello world!")條目與System.out.println("Hello world!")條目非常相似,但不要混淆兩者!
    out.println() “寫入”html頁面,而System.out.println寫入系統輸出。如果您使用 Java 程式碼呼叫該部分內的jsp 方法 System.out.println() ,您將在Tomcat控制台中看到結果,而不是在頁面上。

您可以在此處 找到 jsp 中的其他可用物件。使用request對象,我們可以獲得從 servlet 傳遞的名稱列表(我們將相應的屬性附加到該對象),並且使用out對象,我們可以顯示這些名稱。讓我們這樣做(現在只是以 html 列表的形式):
<ul>
    <%
        List<String> names = (List<String>) request.getAttribute("userNames");

        if (names != null && !names.isEmpty()) {
            for (String s : names) {
                out.println("<li>" + s + "</li>");
            }
        }
    %>
</ul>
如果您需要僅在有用戶時顯示列表,否則顯示還沒有用戶的警告,我們可以稍微重寫此部分:
<%
    List<String> names = (List<String>) request.getAttribute("userNames");

    if (names != null && !names.isEmpty()) {
        out.println("<ui>");
        for (String s : names) {
            out.println("<li>" + s + "</li>");
        }
        out.println("</ui>");
    } else out.println("<p>There are no users yet!</p>");
%>
現在我們可以將資料從 servlet 傳遞到視圖,我們可以稍微改進AddServlet,以便在成功新增使用者時顯示通知。為此,在doPost()方法中,將新使用者新增至模型後,我們可以將該使用者的名稱新增至req物件的屬性中,並將控制權傳遞回add.jsp視圖。其中已經建立了一個包含 Java 程式碼的部分,其中檢查請求中是否存在這樣的屬性,如果存在,則輸出一則訊息,表示使用者已成功新增。經過這些變更後,完整的AddServlet servlet 程式碼將如下所示:
package app.servlets;

import app.entities.User;
import app.model.Model;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class AddServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        RequestDispatcher requestDispatcher = req.getRequestDispatcher("views/add.jsp");
        requestDispatcher.forward(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String name = req.getParameter("name");
        String password = req.getParameter("pass");
        User user = new User(name, password);
        Model model = Model.getInstance();
        model.add(user);

        req.setAttribute("userName", name);
        doGet(req, resp);
    }
}
在這裡,在doPost()方法 的末尾,我們設定一個屬性,其中包含新增到模型中的使用者名稱,然後呼叫 doGet ()方法,將目前請求和回應傳遞給該方法。doGet ()方法已將控制權轉移到視圖,並在其中傳送一個請求對象,其中新增的使用者名稱作為屬性附加。剩下的工作就是更正add.jsp,以便在存在此類屬性時顯示此類通知。最終的add.jsp 是
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <head>
        <title>Add new user</title>
    </head>

    <body>
        <div>
            <h1>Super app!</h1>
        </div>

        <div>
            <%
                if (request.getAttribute("userName") != null) {
                    out.println("<p>User '" + request.getAttribute("userName") + "' added!</p>");
                }
            %>
            <div>
                <div>
                    <h2>Add user</h2>
                </div>

                <form method="post">
                    <label>Name:
                        <input type="text" name="name"><br />
                    </label>
                    <label>Password:
                        <input type="password" name="pass"><br />
                    </label>
                    <button type="submit">Submit</button>
                </form>
            </div>
        </div>

        <div>
            <button onclick="location.href='/'">Back to main</button>
        </div>
    </body>
</html>
頁面正文包括:
  • div-a 附標題;
  • div 內容容器,它會檢查是否存在帶有使用者名稱的屬性;
  • div 隨附用於新增使用者的表單;
  • 最後有一個頁腳,帶有返回主頁的按鈕。
看起來好像div太多了,但是我們稍後添加樣式時會用到它們。最終的list.jsp是:
<%@ page import="java.util.List" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <head>
        <title>Users</title>
    </head>

    <body>
        <div>
            <h1>Super app!</h1>
        </div>

        <div>
            <div>
                <div>
                    <h2>Users</h2>
                </div>
                <%
                    List<String> names = (List<String>) request.getAttribute("userNames");

                    if (names != null && !names.isEmpty()) {
                        out.println("<ui>");
                        for (String s : names) {
                            out.println("<li>" + s + "</li>");
                        }
                        out.println("</ui>");
                    } else out.println("<p>There are no users yet!</p>");
                %>
            </div>
        </div>

        <div>
            <button onclick="location.href='/'">Back to main</button>
        </div>
    </body>
</html>
因此,我們有一個完全運行的 Web 應用程序,可以儲存和添加用戶,以及顯示他們的姓名列表。剩下的就是修飾它......:)

新增樣式。我們使用W3.CSS框架

目前我們的應用程式正在運行,但絕對瘋狂。因此,我們將新增背景、文字和按鈕的顏色、樣式清單、對齊、新增縮排等。如果您手動編寫樣式,可能會花費大量時間和精力。因此,我建議使用W3.CSS CSS框架。它已經有了帶有樣式的現成類別;剩下的就是將我們想要應用的 CSS 類別放置在正確的位置。為了將它們添加到我們的頁面中,首先我們將包含一個帶有樣式的文件。這可以透過兩種方式完成:
  1. 瀏覽我們的頁面,並在頭部插入帶有樣式的文件的直接鏈接

    <link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">

    如果您有持續的互聯網連接,則此選項適合。然後,當您在本機伺服器上開啟頁面時,樣式將從 Internet 中提取。


  2. 如果您想在本地擁有所有樣式而不依賴 Internet 連接,請下載帶有樣式的檔案並將其放置在 web資料夾中的某個位置(例如web/styles/w3.css),然後瀏覽我們的所有樣式頁面(index.html、add.jsp、list.jsp)並輸入指向此文件的鏈接,並在head部分中使用樣式

    <link rel="stylesheet" href="styles/w3.css">

    之後,只需瀏覽標籤並添加您喜歡的樣式即可。我不會詳細討論這一點,但會立即提供我的三個文件的現成版本以及已安排的樣式類別。

索引.html

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Super app!</title>
        <link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
    </head>

    <body class="w3-light-grey">
        <div class="w3-container w3-blue-grey w3-opacity w3-right-align">
            <h1>Super app!</h1>
        </div>

        <div class="w3-container w3-center">
            <div class="w3-bar w3-padding-large w3-padding-24">
                <button class="w3-btn w3-hover-light-blue w3-round-large" onclick="location.href='/list'">List users</button>
                <button class="w3-btn w3-hover-green w3-round-large" onclick="location.href='/add'">Add user</button>
            </div>
        </div>
    </body>
</html>

添加.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <head>
        <title>Add new user</title>
        <link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
    </head>

    <body class="w3-light-grey">
        <div class="w3-container w3-blue-grey w3-opacity w3-right-align">
            <h1>Super app!</h1>
        </div>

        <div class="w3-container w3-padding">
            <%
                if (request.getAttribute("userName") != null) {
                    out.println("<div class=\"w3-panel w3-green w3-display-container w3-card-4 w3-round\">\n" +
                            "   <span onclick=\"this.parentElement.style.display='none'\"\n" +
                            "   class=\"w3-button w3-margin-right w3-display-right w3-round-large w3-hover-green w3-border w3-border-green w3-hover-border-grey\">×</span>\n" +
                            "   <h5>User '" + request.getAttribute("userName") + "' added!</h5>\n" +
                            "</div>");
                }
            %>
            <div class="w3-card-4">
                <div class="w3-container w3-center w3-green">
                    <h2>Add user</h2>
                </div>
                <form method="post" class="w3-selection w3-light-grey w3-padding">
                    <label>Name:
                        <input type="text" name="name" class="w3-input w3-animate-input w3-border w3-round-large" style="width: 30%"><br />
                    </label>
                    <label>Password:
                        <input type="password" name="pass" class="w3-input w3-animate-input w3-border w3-round-large" style="width: 30%"><br />
                    </label>
                    <button type="submit" class="w3-btn w3-green w3-round-large w3-margin-bottom">Submit</button>
                </form>
            </div>
        </div>

        <div class="w3-container w3-grey w3-opacity w3-right-align w3-padding">
            <button class="w3-btn w3-round-large" onclick="location.href='/'">Back to main</button>
        </div>
    </body>
</html>

列表.jsp

<%@ page import="java.util.List" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <head>
        <title>Users list</title>
        <link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
    </head>

    <body class="w3-light-grey">
        <div class="w3-container w3-blue-grey w3-opacity w3-right-align">
            <h1>Super app!</h1>
        </div>

        <div class="w3-container w3-center w3-margin-bottom w3-padding">
            <div class="w3-card-4">
                <div class="w3-container w3-light-blue">
                    <h2>Users</h2>
                </div>
                <%
                    List<String> names = (List<String>) request.getAttribute("userNames");

                    if (names != null && !names.isEmpty()) {
                        out.println("<ul class=\"w3-ul\">");
                        for (String s : names) {
                            out.println("<li class=\"w3-hover-sand\">" + s + "</li>");
                        }
                        out.println("</ul>");

                    } else out.println("<div class=\"w3-panel w3-red w3-display-container w3-card-4 w3-round\">\n"
+
                            "   <span onclick=\"this.parentElement.style.display='none'\"\n" +
                            "   class=\"w3-button w3-margin-right w3-display-right w3-round-large w3-hover-red w3-border w3-border-red w3-hover-border-grey\">×</span>\n" +
                            "   <h5>There are no users yet!</h5>\n" +
                            "</div>");
                %>
            </div>
        </div>

        <div class="w3-container w3-grey w3-opacity w3-right-align w3-padding">
            <button class="w3-btn w3-round-large" onclick="location.href='/'">Back to main</button>
        </div>
    </body>
</html>
僅此而已 :) 如果您仍有任何問題或有任何意見,或者相反,有些事情沒有解決 - 請發表評論。UPD:如果您在單擊按鈕時遇到 404 錯誤的問題,儘管一切都已正確完成,也許您應該更正 idea 中的部署配置。為此,您需要轉到“編輯配置”(位於頂部靠近“開始”按鈕的位置),轉到視窗右側的“部署”選項卡,並確保在“應用程式”上下文中簡單地指示它/嗯,我'我會附上幾張截圖來說明這一切的結果。
使用 servlet 和 jsp 建立簡單的 Web 應用程式(第 2 部分)- 2
使用 servlet 和 jsp 建立簡單的 Web 應用程式(第 2 部分)- 3
使用 servlet 和 jsp 建立簡單的 Web 應用程式(第 2 部分)- 4
最後 ,如果你想練習這個項目,你可以嘗試:
  • 製作一個 servlet 和 jsp 來刪除用戶,並製作幾個來更改/編輯現有用戶。您將獲得一個真正的 CrUD Web 應用程式 :) 在 servlet 上));
  • 將清單(List)替換為使用資料庫,以便新增的使用者在重新啟動伺服器後不會消失:)
祝你好運!
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION