使用 servlet 和 JSP 創建一個簡單的 Web 應用程序(第 1 部分) 理解本文所需的知識:您已經或多或少地了解了 Java Core,並希望了解 JavaEE 技術和 Web 編程。對您來說,目前正在研究 Java Collections 任務是最有意義的,它處理的主題與本文很接近。
最後,如果你想練習這個項目,你可以嘗試以下方法:
創建實體
在entities包中,我們將創建一個User
具有兩個私有字符串變量的類:name和password。創建構造函數(默認構造函數和接受兩個值的構造函數)和 getter/setter,並重寫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 共享的對象。一般來說,我們需要一個由我們程序中的所有類共享的對象:一個對像用於整個程序。我希望你聽說過一些關於設計模式的事情。對於某些人來說,這可能是他們程序中第一次真正需要單例模式。您可以瘋狂地製作一些帶有雙重檢查和同步的甜蜜單例(是的,我們的應用程序是多線程的,因為 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中獲取一些數據,對其進行處理,並將其傳遞給模型)。您在其中定義您的業務邏輯(程序應該做什麼),而不是在模型或視圖中。因此,每個部分處理自己的業務:- 模型存儲數據;
- 視圖呈現數據的漂亮表示;
- 控制器處理數據處理。
<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>
這裡的表單有一個method屬性,其值為post。這表示此表單中的數據將作為POST 請求發送到服務器。未指定action屬性,這意味著請求將發送到我們訪問此頁面的相同地址 ( / add )。因此,在收到GET 請求後,綁定到該地址的 servlet 會返回帶有添加用戶表單的JSP 。如果它收到一個POST 請求,那麼我們就知道表單在這裡發送了它的數據(我們從doPost()
方法、過程,並傳遞給模型進行保存)。值得注意的是,輸入字段有一個名為name的參數(用於用戶名,或pass用於密碼)。這是非常重要的一點。因此,要從請求(在 servlet 內)接收此數據(將輸入的用戶名和密碼),我們將使用這些名稱和傳遞字段。但稍後會詳細介紹。我用於發送數據的按鈕再次被製作為按鈕,而不是通常的輸出字段。我不知道這種方法的採用有多廣泛,但它適用於我(Chrome 瀏覽器)。
POST 請求的 Servlet 處理
讓我們回到AddServlet。我提醒您,為了讓我們的 servlet 能夠“捕獲” GET 請求,我們覆蓋了HttpServletdoGet()
類中的方法。為了讓我們的 servlet 也能捕獲POST 請求,我們還必須覆蓋該方法。Tomcat向它傳遞我們將使用的類似請求和響應對象。首先,提取請求的名稱並傳遞表單發送的參數(如果您在表單中指定了不同的名稱,則使用這些名稱)。之後,使用接收到的數據創建一個用戶對象。然後我們獲取模型對象並將創建的用戶添加到模型中。 doPost()
@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。該doGet()
方法已經實施。它只是將控制轉移到視圖 ( list.jsp )。如果您還沒有這個,則類比 AddServlet 中的方法創建它。現在最好從模型中獲取用戶名列表並將它們傳遞給視圖,視圖將接收它們並漂亮地顯示它們。為此,我們將再次使用從Tomcat收到的請求對象。我們可以給這個對象添加一個屬性,給它起一個名字。其實我們可以把我們要傳遞的對象添加到視圖中. 由於在將控制從 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 中的模型準備了用戶名列表,並將其傳遞到請求對像中。由於我們有姓名列表,我們可以使用循環對其進行迭代for
並顯示每個姓名。正如我之前所說,JSP 文件可以執行Java 代碼(這就是它們與靜態 HTML 頁面的不同之處)。要執行一些代碼,我們需要做的就是將以下結構放在適當的位置:
<!-- html code -->
<%
// Java code
%>
<!-- html code -->
在這個結構中,我們可以訪問幾個變量:
- request — 我們的請求對象,我們從 servlet 傳遞過來的,它被簡稱為req;
- response — 響應對象(在 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控制台中看到結果,而不是在頁面上。
<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的完整代碼將如下所示:
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;
- 內容的 div 容器,其中包括檢查是否存在具有用戶名的屬性;
- 帶有添加用戶表單的 div;
- 在底部,一個帶有返回主頁按鈕的頁腳。
<%@ 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 類安排在正確的位置即可。要將它們添加到我們的頁面,我們首先連接樣式文件。有兩種方法可以做到這一點:-
瀏覽我們的頁面並在標題部分插入以下樣式文件的直接鏈接
<link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
如果您有永久的 Internet 連接,則此選項適用。當您在本地服務器上打開您的頁面時,樣式將從 Internet 中提取。
-
但是如果你想在本地擁有所有樣式而不依賴於 Internet 連接,請下載樣式文件並將其放在 web文件夾中的某個位置(例如web/styles/w3.css)。然後瀏覽我們所有的頁面(index.html、add.jsp、list.jsp)並將以下鏈接添加到head部分內的樣式文件:
<link rel="stylesheet" href="styles/w3.css">
之後,只需瀏覽標籤並添加您喜歡的樣式即可。這個我就不詳細說了。相反,我將只提供三個帶有光柵樣式類的文件的即用型版本。
<!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>
就是這樣。:) 如果您還有任何問題或意見,或者有什麼不對,請發表評論。我將附上幾張截圖,說明結果如何。
- 製作一個 servlet 和 JSP 來刪除用戶,並添加另一對來編輯現有用戶。結果將是使用 servlet 構建的真正的 CRUD Web 應用程序。;)
- 將List替換為數據庫,這樣添加的用戶不會在服務器重啟後消失。:)
GO TO FULL VERSION