使用 servlet 和 jsp 創建一個簡單的 Web 應用程式(第 1 部分) 來理解本文所需的知識水平:您已經或多或少地了解了 Java Core,並且希望了解 JavaEE 技術和 Web 程式設計。如果您目前正在研究 Java Collections 任務,那麼它是最有意義的,它涵蓋了與本文接近的主題。
最後 ,如果你想練習這個項目,你可以嘗試:
建立實體
在實體包中,我們將建立一個類別User,其中有兩個私有字串變數name和password。讓我們建立建構函式(預設的和接受兩個值的建構子)、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 接收一些數據,對其進行處理並將其傳遞給模型)。業務邏輯(程式到底應該做什麼)需要在其中描述,而不是在模型或視圖中。於是,每個人都做自己的事:- 模型儲存資料;
- 視圖繪製了資料的漂亮表示;
- 控制器負責資料處理。
<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控制台中看到結果,而不是在頁面上。
<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 隨附用於新增使用者的表單;
- 最後有一個頁腳,帶有返回主頁的按鈕。
<%@ 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 類別放置在正確的位置。為了將它們添加到我們的頁面中,首先我們將包含一個帶有樣式的文件。這可以透過兩種方式完成:-
瀏覽我們的頁面,並在頭部插入帶有樣式的文件的直接鏈接
<link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
如果您有持續的互聯網連接,則此選項適合。然後,當您在本機伺服器上開啟頁面時,樣式將從 Internet 中提取。
-
如果您想在本地擁有所有樣式而不依賴 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 來刪除用戶,並製作幾個來更改/編輯現有用戶。您將獲得一個真正的 CrUD Web 應用程式 :) 在 servlet 上));
- 將清單(List)替換為使用資料庫,以便新增的使用者在重新啟動伺服器後不會消失:)
GO TO FULL VERSION