使用“純”Servlet做一個單表的CRUD操作

每博一文案
莊子說:"獨往獨來,是謂獨有,獨有之人,是謂至貴",熱鬧是別人的狂歡,而孤獨是自己的自由,
相聚總是短暫,唯孤獨綿長,學會孤獨為伍,才能找到浮世清歡,
金庸曾筆下人物說:"天上的白云聚了又聚,散了又散,人生離合,亦復如斯," 人生一世,所有的人來人往,
聚散離合,都是緣分使然,緣來便聚,緣盡則散,聚是一團火,散是滿天星,往后余生,與孤獨和解,做自己的知音,
都說幸福的樣子千篇一律,不幸的人卻各有各的不幸,很多人都只能看到別人所擁有的,卻沒看到人所失去的,
沒有人的生活是真正的容易,當你站在橋上看風景的時候,可能自己亦是別人眼中的風景,
所以不必羨慕別人,珍惜現在所擁有的,過好自己的人生才最重要,
—————— 《一禪心靈廟語》
@
目錄- 使用“純”Servlet做一個單表的CRUD操作
- 每博一文案
- 1. 專案說明
- 2. 具體對應的功能的代碼實作
- 2.1 準備作業:
- 2.2 模塊目錄結構
- 2.3 工具類 DBUtil
- 2.4 功能一: index.html 該專案的歡迎頁面如下:
- 2.5 功能二:部門串列 DeptListServlet
- 2.6 功能三:查看部門詳情 DeptDetailServlet
- 2.7 功能四:洗掉部門 DeptDelServlet
- 2.8 功能五:新增部門 DeptSaveServlet
- 2.9 功能六:跳轉到修改部門的頁面 DepEditServlet
- 2.10 功能七:修改部門 DeptSaveServlet
- 3. 最后的 web.xml 配置資訊
- 4. 優化方案: @WebServlet 注解 + 模板方法
- 5. 總結:
- 6. 最后:
1. 專案說明
介紹: 這里我們使用 純粹 的 Servlet 完成單表【對部門的】的增刪改查操作,(B/S結構的,)
結構圖

初始的歡迎頁面

部門串列頁面

部門詳情

修改部門

洗掉部門:

新增部門:

2. 具體對應的功能的代碼實作
2.1 準備作業:
- 首先我們使用資料庫,存盤資料,這里我們使用的資料庫是 MYSQL ,
- 我們需要準備一個名為
dept的資料表,并插入一些資料,
create table dept (
depton int primary key,
dname varchar(255),
loc varchar(255)
);
insert into dept(depton,dname,loc) values(10,'xiaoShouBu','BEIJING');
insert into dept(depton,dname,loc) values(20,'YanFaBu','SHANGHAI');
insert into dept(depton,dname,loc) values(30,'JisShuBu','GUANGZHOU');
insert into dept(depton,dname,loc) values(40,'MeiTiBu','SHENZHEN');
select * from dept;
小技巧: MySQL 在 cmd 命令中,批量執行 sql陳述句的方法:如下,首先將撰寫好的 .sql 檔案存盤起來,如下圖所示,

再打開cmd 進入命令視窗,再進入到Mysql當中,輸入如下命令:
source 后接檔案路徑(要執行的批量的.sql檔案)

當前資料表 dept 的資訊內容如下:

- 為該模塊匯入 MYSQL的 JDBC 的
jar包,
注意: 因為我們是在 Tomcat 服務器當中部署專案的,所以我們需要在 WEB-INF 的目錄下,創建一個名為 lib 的目錄檔案夾,用來存放相關的 依賴jar 包,注意路徑位置不可以修改,目錄檔案必須為 lib 不然,當你啟動的Tocmat 服務器的時候,是無法找到該對應的 依賴jar 包的,具體如下,我們將 Mysql對應的 jdbc jar 包匯入其中,
- 創建一個webapp(給這個webapp添加servlet-api.jar和jsp-api.jar到classpath當中,)
- 向webapp中添加連接資料庫的jar包(mysql驅動)
- 必須在WEB-INF目錄下新建lib目錄,然后將mysql的驅動jar包拷貝到這個lib目錄下,這個目錄名必須叫做lib,全部小寫的,

2.2 模塊目錄結構

2.3 工具類 DBUtil
這里因為我們要連接資料庫,所以我們撰寫一個連接Mysql 資料庫的 工具類,這里我們名為一個 DBUtil 的工具類,
這里我們通過讀取配置jdbc.properties的組態檔的方式,注冊相對應的Mysql驅動 ,
如下是相關: jdbc.properties 的配置資訊
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/test
user=root
password=123
再撰寫好相關的:DBUtil 類 ,具體代碼的撰寫內容如下:
package com.RainbowSea.DBUtil;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ResourceBundle;
/**
* JDBC工具類
*/
public class DBUtil {
// 靜態變數,在類加載時執行
// 都是一些從 jdbc.properties 讀取到的組態檔的資訊
// 該方法僅僅只會讀取 “.properties" 的后綴的檔案,注意:默認是從src目錄開始的,有子目錄需要寫明子目錄
private static ResourceBundle bundle = ResourceBundle.getBundle("com/RainbowSea/resources/jdbc");
private static String driver = bundle.getString("driver"); // 根據properties中的name讀取對應的value值
private static String url = bundle.getString("url");
private static String user = bundle.getString("user");
private static String password = bundle.getString("password");
static {
// 注冊驅動(注冊驅動只需要注冊一次,放在靜態代碼當中,DBUtil類加載的時候執行)
// "com.mysql.jdbc.Driver"是連接資料庫的驅動,不能寫死,因為以后可能還會連接Oracle資料庫,
// OCP開閉原則: 對擴展開放,對修改關閉(什么是符合 OCP呢?在進行功能擴展的時候,不需要修改java源代碼)
// Class.forName("com.mysql.jdbc.Driver")
try {
Class.forName(driver); // 加載驅動
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
/**
* 獲取資料庫連接
* @return Connection
*/
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url,user,password);
}
/**
* 關閉連接
* @param connection
* @param statement
* @param resultSet
*/
public static void close(Connection connection, Statement statement, ResultSet resultSet) {
// 注意:分開try,最后使用的資源,優先關閉
if(resultSet != null) {
try {
resultSet.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
if(statement != null) {
try {
statement.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
if(connection != null) {
try {
connection.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
}
2.4 功能一: index.html 該專案的歡迎頁面如下:
默認在 web 當中,一個全域配置資訊當中,會將名為 index.html 的檔案,設定為該專案的歡迎頁面,相應的具體內容大家可以移步至 ?????? 關于Web的歡迎頁面的開發設定_ChinaRainbowSea的博客-CSDN博客
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>歡迎使用OA系統</title>
</head>
<body>
<!--注意:對應前端的資源獲取基本上都是要加專案名的,并且要"/"開始-->
<a href="https://www.cnblogs.com/servlet09/dept/list/">查看部門串列</a>
</body>
</html>
2.5 功能二:部門串列 DeptListServlet
注意:因為我們這里使用的是 純 Servlet 撰寫的一個專案,所以在后端想要將相關的 HTML 標簽相應到前端瀏覽器,被瀏覽器渲染的話,則需要特殊的方法:如下
// 設定將后端的字串的 html 標簽相應到瀏覽器端執行處理,并設定相應的字符集編碼
response.setContentType("text/html;charSet=UTF-8");
PrintWriter writer = response.getWriter();
思路:
- 在DeptListServlet類的doGet方法中連接資料庫,查詢所有的部門,動態的展示部門串列頁面.
-
分析 html 頁面中哪部分是固定死的,哪部分是需要動態展示的,
-
html頁面中的內容所有的雙引號要替換成單引號,因為out.print("")這里有一個雙引號,容易沖突,
-
現在寫完這個功能之后,你會有一種感覺,感覺開發很繁瑣,只使用servlet寫代碼太繁瑣了
- 我們需要連接資料庫,從資料庫中獲取到資料,顯示到前端瀏覽器當中,
- 注意我們這里上面的 index.html 中是通過超鏈接的方式,跳轉到該 部門串列頁面的,超鏈接是 doGet 請求,
package com.RainbowSea.servlet;
import com.RainbowSea.DBUtil.DBUtil;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* 部門串列
*/
public class DeptListServlet extends HttpServlet {
/*
說明:這里使用了doGet,和 goPost 的原因是,我們前端的 DeptSaveServlet 的新增部門,
的請求是doPost,從 doPost 請求 "轉發"出來的同樣是 doPost請求的,而 重定向就是doGet請求了,無論是doPost,doGet請求都是
所以這里為了,處理接受到 DeptSaveServlet 的新增部門的 "轉發"請求,寫了一個doPost 請求處理
*/
// 優化,將轉發,替換成了 重定向的機制,(重定向的機制)是自發到瀏覽器前端的地址欄上的,后自發的執行
// 地址欄上是 doGet 請求的,就不需要 doPost 請求了,
/* @Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException,
IOException {
doGet(request, response); // 呼叫本身這里的doGet()請求
}*/
/*
因為我們前端使用的是 <a>超鏈接,是goGet請求所以,
前后端的請求保持一致,
*/
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException,
IOException {
// 設定前端瀏覽器顯示的格式型別,以及編碼
response.setContentType("text/html;charSet=UTF-8");
PrintWriter writer = response.getWriter();
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
// 獲取到該webapp的專案根路徑:也就是在Tomcat 當中設定的訪問的專案路徑
// 注意的是: getContextPath()獲取回傳的路徑是帶有 "/專案名"的,所以不要多寫了 /
String contextPath = request.getContextPath();
int i = 0;
writer.println(" <!DOCTYPE html>");
writer.println("<html lang='en'>");
writer.println("<head>");
writer.println(" <meta charset='UTF-8'>");
writer.println(" <title>部門串列頁面</title>");
writer.println("</head>");
writer.println(" <script type = 'text/javascript' >");
writer.println(" function del(dno) {");
// 彈出確認框,用戶點擊確定,回傳true,點擊取消回傳false
writer.println(" var ok = window.confirm('親,刪了不可恢復哦!');");
writer.println(" if (ok) {");
// 發送請求進行洗掉資料的操作
// 在js代碼當中如何發送請求給服務
// document.location.href='https://www.cnblogs.com/TheMagicalRainbowSea/p/請求路徑
// document.location ='請求路徑'")
// window.location.hrefhttps://www.cnblogs.com/TheMagicalRainbowSea/p/= 'https://www.cnblogs.com/TheMagicalRainbowSea/p/請求路徑
// window.location ='請求路徑'
// 注意是根據所傳的部門編號洗掉資料的
writer.println(" document.location.hrefhttps://www.cnblogs.com/TheMagicalRainbowSea/p/= '" + contextPath + "/dept/delete?deptno=' + dno");
writer.println(" }");
writer.println(" }");
writer.println("</script >");
writer.println("<body>");
writer.println(" <h1 align='center'>部門串列</h1>");
writer.println(" <table border='1px' align='center' width='50%'>");
writer.println(" <tr>");
writer.println(" <th>序號</th>");
writer.println(" <th>部門編號</th>");
writer.println(" <th>部門名稱</th>");
writer.println(" </tr>");
try {
// 連接資料庫,查詢所有部門:
// 1. 注冊驅動,獲取連接
connection = DBUtil.getConnection();
// 2. 獲取操作資料庫物件,預編譯sql陳述句
String sql = "select depton as det,dname,loc from dept"; // 在mysql中測驗一下是否正確
preparedStatement = connection.prepareStatement(sql);
// 3. 執行sql陳述句
resultSet = preparedStatement.executeQuery();
// 4. 處理查詢結果集
while (resultSet.next()) {
String det = resultSet.getString("det"); // 有別名要使用別名
String dname = resultSet.getString("dname");
String loc = resultSet.getString("loc");
writer.print(" <tr>");
writer.print(" <td>" + (++i) + "</td>");
writer.print(" <td>" + det + "</td>");
writer.print(" <td>" + dname + "</td>");
writer.print(" <td>");
writer.print(" <a href='javascript:void(0)' onclick= 'del(" + det + ")'>洗掉</a>");
// 將部門編號傳過去,用戶資料庫查詢修改
writer.print(" <a href='"+contextPath+"/dept/edit?deptno="+det+"'>修改</a>");
//注意這里的是前端的資源,需要加專案名,但是這里的專案名我們通過 getContestPath()方法動態獲取
// 并且將部門名傳過去,再從資料庫當中查找出來對應的部門的詳細資訊:注意: ?(間隔) Http傳輸協議
writer.print(" <a href='" + contextPath + "/dept/detail?deptno=" + det + "'>詳情</a>");
writer.print(" </td>");
writer.print(" </tr>");
}
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
// 5. 關閉資源
DBUtil.close(connection, preparedStatement, resultSet);
}
writer.println("</table>");
writer.println("<hr>");
// 前端的資源路徑訪問需要加專案名
writer.println("<a href='" + contextPath + "/add.html'>新增部門</a>");
writer.println("</body>");
writer.println("</html>");
}
}
2.6 功能三:查看部門詳情 DeptDetailServlet
建議:從前端往后端一步一步實作,首先要考慮的是,用戶點擊的是什么?用戶點擊的東西在哪里?
一定要先找到用戶點的“詳情”在哪里,這里我們使用超鏈接的形式處理
<a href='https://www.cnblogs.com/TheMagicalRainbowSea/p/寫一個路徑'>詳情</a>
詳情 是需要連接資料庫的,所以這個超鏈接點擊之后也是需要執行一段java代碼的,所以要將這個超鏈接的路徑修改一下,
注意:修改路徑之后,這個路徑是需要加專案名的,"/servlet09/dept/detail"
技巧:
out.print("<a href='"+contextPath+"/dept/detail?deptno="+deptno+"'>詳情</a>");
重點:向服務器提交資料的格式:uri?name=value&name=value&name=value&name=value ,這里的問號,必須是英文的問號,不能中文的問號,
思路:
中文思路(思路來源于:你要做什么?目標:查看部門詳細資訊,)
第一步:獲取部門編號
第二步:根據部門編號查詢資料庫,獲取該部門編號對應的部門資訊,
第三步:將部門資訊回應到瀏覽器上,(顯示一個詳情,)
package com.RainbowSea.servlet;
import com.RainbowSea.DBUtil.DBUtil;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* 部門詳情
*/
public class DeptDetailServlet extends HttpServlet {
// 前端超連接是 doGet()請求
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException,
IOException {
// 設定前端瀏覽器格式型別和字符集編碼
response.setContentType("text/html;charSet=UTF-8");
PrintWriter writer = response.getWriter();
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
//中文思路(思路來源于:你要做什么?目標:查看部門詳細資訊,)
// 第一步:獲取部門編號
// 第二步:根據部門編號查詢資料庫,獲取該部門編號對應的部門資訊,
// 第三步:將部門資訊回應到瀏覽器上,(顯示一個詳情,)
// 1.
// http://127.0.0.1:8080/servlet09/dept/detail?deptno=40
String deptno = request.getParameter("deptno"); // 注意是我們前端提交的資料,建議復制name
try {
// 2. 連接資料庫,根據部門編號查詢資料庫
// 1.注冊驅動,連接資料庫
connection = DBUtil.getConnection();
// 2. 預編譯SQL陳述句,sql要測驗
String sql = "select dname,loc from dept where depton = ?"; // ? 占位符
preparedStatement = connection.prepareStatement(sql);
// 3. 填充占位符,真正執行sql陳述句
preparedStatement.setString(1, deptno);
resultSet = preparedStatement.executeQuery();
// 4. 處理查詢結果集
while (resultSet.next()) {
String dname = resultSet.getString("dname");
String loc = resultSet.getString("loc");
// 注意將 “雙引號轉換為單引號,因為在Java當中不可以嵌套多個雙引號,除非是字串的拼接
// 所以使用 '單引號
writer.println(" <body>");
writer.println(" <h1>部門詳情</h1>");
writer.println(" 部門編號: " + deptno + " <br>");
writer.println(" 部門名稱: " + dname + "<br>");
writer.println(" 部門位置: " + loc + "<br>");
writer.println(" <input type='button' value='https://www.cnblogs.com/TheMagicalRainbowSea/p/后退' onclick='window.history.back()' />");
}
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
// 5. 釋放資源
DBUtil.close(connection, preparedStatement, resultSet);
}
writer.println("</body>");
writer.println("</html>");
}
}
2.7 功能四:洗掉部門 DeptDelServlet
怎么開始?從哪里開始?從前端頁面開始,用戶點擊洗掉按鈕的時候,應該提示用戶是否洗掉,因為洗掉這個動作是比較危險的,任何系統在進行洗掉操作之前,是必須要提示用戶的,因為這個洗掉的動作有可能是用戶誤操作,(在前端頁面上寫JS代碼,來提示用戶是否洗掉,)
<a href="javascript:void(0)" onclick="del(30)" >洗掉</a>
<script type="text/javascript">
function del(dno){
if(window.confirm("親,刪了不可恢復哦!")){
document.location.href = "https://www.cnblogs.com/oa/dept/delete?deptno=" + dno;
}
}
</script>
以上的前端程式要寫到后端的java代碼當中:DeptListServlet類的doGet方法當中,使用out.print()方法,將以上的前端代碼輸出到瀏覽器上,
洗掉成功或者失敗的時候的一個處理(這里我們一開始使用的選擇的是轉發,后面優化使用的是重定向機制,)
洗掉成功:我們跳轉到部門串列當中,DeptListServlet
洗掉失敗:我們跳轉到一個失敗的頁面當中,這里我們將該失敗的頁面名為: error.html 頁面如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>error</title>
</head>
<body>
<h1> 操作失敗: </h1>
<a href='https://www.cnblogs.com/servlet09/dept/list/' onclick="window.history.back()">回傳</a>
</body>
</html>
具體的 Servlet 撰寫如下
package com.RainbowSea.servlet;
import com.RainbowSea.DBUtil.DBUtil;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
/**
* 洗掉部門
*/
public class DeptDelServlet extends HttpServlet {
/*
注意前端是超鏈接的方式:是get請求
*/
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException,
IOException {
response.setContentType("text/html;charSet=UTF-8");
PrintWriter writer = response.getWriter();
request.setCharacterEncoding("UTF-8");
// 思路:
/*
根據部門編號洗掉資訊,
洗掉成功,跳轉回原來的部門串列頁面
洗掉失敗,跳轉洗掉失敗的頁面
*/
Connection connection = null;
PreparedStatement preparedStatement = null;
// 記錄洗掉資料庫的行數
int count = 0;
// 獲取到前端提交的資料
String deptno = request.getParameter("deptno");
// 連接資料庫進行洗掉操作
try {
// 1.注冊驅動,連接資料庫
connection = DBUtil.getConnection();
// 開啟事務(取消自動提交機制),實作可回滾
connection.setAutoCommit(false);
// 2. 預編譯sql陳述句,sql測驗
String sql = "delete from dept where depton = ?"; // ? 占位符
preparedStatement = connection.prepareStatement(sql);
// 3. 填充占位符,真正的執行sql陳述句
preparedStatement.setString(1, deptno);
// 回傳影響資料庫的行數
count = preparedStatement.executeUpdate();
connection.commit(); // 手動提交資料
} catch (SQLException e) {
// 遇到例外回滾
if (connection != null) {
try {
// 事務的回滾
connection.rollback();
} catch (SQLException ex) {
throw new RuntimeException(ex);
}
}
throw new RuntimeException(e);
} finally {
// 4. 釋放資源
// 因為這里是洗掉資料,沒有查詢操作,所以 沒有 ResultSet 可以傳null
DBUtil.close(connection, preparedStatement, null);
}
if (count == 1) {
// 洗掉成功
// 仍然跳轉到部門串列頁面
// 部門串列頁面的顯示需要執行另外一個Servlet,怎么辦,可以使用跳轉,不過這里最后是使用重定向
// 注意:轉發是在服務器間的,所以不要加“專案名” 而是 / + web.xml 映射的路徑即可
//request.getRequestDispatcher("/dept/list/").forward(request,response);
// 優化:使用重定向機制 注意: 重定向是自發到前端的地址欄上的,前端所以需要指明專案名
// 注意: request.getContextPath() 回傳的根路徑是,包含了 "/" 的
response.sendRedirect(request.getContextPath() + "/dept/list/");
} else {
// 洗掉失敗
// web當中的 html資源,這里的 "/" 表示 web 目錄
//request.getRequestDispatcher("/error.html/").forward(request, response);
// 優化,使用重定向
response.sendRedirect(request.getContextPath() + "/error.html/");
}
}
}
2.8 功能五:新增部門 DeptSaveServlet
思路:
獲取到前端 form 表單提交的資料,這里我們 form 表單 中的 metod = post 設定為了 doPost 請求,
再連接資料庫,添加一條記錄,
添加成功:我們跳轉到部門串列當中,DeptListServlet
添加失敗:我們跳轉到一個失敗的頁面當中,這里我們將該失敗的頁面名為: error.html
注意點:
最后保存成功之后,跳轉到 /dept/list 的時候,如果你使用的是
轉發機制的話,這里因為你是從doPost請求轉發過去的(轉發是一次請求,之前是post,之后還是post,因為它是一次請求,),所以對應接收該 doPost 請求的也要是 doPost 方法處理該請求,不然會報405錯誤,而同時:這時候接收該
轉發的 /dept/list Servlet當中只有一個doGet方法,就會報405錯誤,怎么解決?兩種方案
- 第一種:在/dept/list Servlet中添加doPost方法,然后在doPost方法中呼叫doGet,
- 第二種:使用
重定向的方式,進行跳轉,重定向的機制是改變瀏覽器的請求路徑URL,讓瀏覽器重新發送跳轉之后的 URL 地址,該方式是從瀏覽器地址欄上跳轉的,所以是doGet請求,就不要撰寫doPost請求了,
具體代碼撰寫如下:
package com.RainbowSea.servlet;
import com.RainbowSea.DBUtil.DBUtil;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
/**
* 增加部門資料
*/
public class DeptSaveServlet extends HttpServlet {
// 前端是注冊資訊,是post 請求
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException,
IOException {
/*
思路:
獲取到前端的提交的資料,注意 編碼設定post 請求
連接資料庫: 進行添加資料
添加成功: 回傳部門串列頁面
添加失敗: 回傳失敗的頁面
*/
request.setCharacterEncoding("UTF-8");
// 獲取到前端的資料,建議 name 使用復制
String deptno = request.getParameter("deptno");
String dname = request.getParameter("dname");
String loc = request.getParameter("loc");
// 連接資料庫,添加資料
Connection connection = null;
PreparedStatement preparedStatement = null;
// 影響資料庫的行數
int count = 0;
try {
// 1. 注冊驅動,連接資料庫
connection = DBUtil.getConnection();
// 2. 獲取操作資料庫物件,預編譯sql陳述句,Sql測驗
String sql = "insert into dept(depton,dname,loc) values(?,?,?)";
preparedStatement = connection.prepareStatement(sql);
// 3. 填充占位符, 真正執行sql陳述句,
// 注意: 占位符的填充是從 1 開始的,基本上資料庫相關的起始下標索引都是從 1下標開始的
preparedStatement.setString(1, deptno);
preparedStatement.setString(2, dname);
preparedStatement.setString(3, loc);
// 回傳影響資料庫的行數
count = preparedStatement.executeUpdate();
// 5.釋放資源
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
DBUtil.close(connection, preparedStatement, null);
}
// 保存成功,回傳部門串列頁面
if (count == 1) {
// 這里應該使用,重定向
// 這里用的轉發,是服務器內部的,不要加專案名
//request.getRequestDispatcher("/dept/list/").forward(request, response);
// 重定向
response.sendRedirect(request.getContextPath() + "/dept/list/");
} else {
// 保存失敗
// web當中的 html資源,這里的 "/" 表示 web 目錄
//request.getRequestDispatcher("/error.html").forward(request, response);
response.sendRedirect(request.getContextPath() + "/error.html");
}
}
}
2.9 功能六:跳轉到修改部門的頁面 DepEditServlet
思路:
獲取到提交的過來的 部門編號
根據部門編號修改資訊,注意:部門編號是唯一的不要被修改了
連接資料庫,查詢到相關資訊顯示到瀏覽器頁面當中,方便用戶修改
具體的代碼撰寫如下
package com.RainbowSea.servlet;
import com.RainbowSea.DBUtil.DBUtil;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* 跳轉到修改部門的頁面
*/
public class DepEditServlet extends HttpServlet {
// 超鏈接是 doGet()請求
// http://127.0.0.1:8080/servlet09/dept/edit?deptno=10
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException,
IOException {
response.setContentType("text/html;charSet=UTF-8");
PrintWriter writer = response.getWriter();
writer.println(" <!DOCTYPE html>");
writer.println("<html lang='en'>");
writer.println("<head>");
writer.println(" <meta charset='UTF-8'>");
writer.println(" <title>部門串列頁面</title>");
writer.println("</head>");
writer.println("<body>");
writer.println(" <h1>修改部門</h1>");
writer.println(" <form action='"+request.getContextPath()+"/dept/modify' method='post'>");
/*
思路:
獲取到提交的過來的 部門編號
根據部門編號修改資訊,注意:部門編號是唯一的不要被修改了
連接資料庫,查詢到相關資訊顯示到瀏覽器頁面當中,方便用戶修改
*/
String deptno = request.getParameter("deptno");
// 連接資料庫
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
// 1. 注冊驅動,連接資料庫
connection = DBUtil.getConnection();
// 2. 獲取到操作資料庫物件,預編譯SQL陳述句,sql測驗
String sql = "select dname,loc from dept where depton = ?";
preparedStatement = connection.prepareStatement(sql);
// 3. 填充占位符,真正執行sql陳述句
preparedStatement.setString(1, deptno);
resultSet = preparedStatement.executeQuery();
// 4. 處理查詢結果集
while (resultSet.next()) {
String dname = resultSet.getString("dname"); // 查詢使用的別名,要用別名
String loc = resultSet.getString("loc");
// <!-- readonly 表示只讀,不可修改的作用
writer.println(" 部門編號: <input type='text' name='deptno' value='" + deptno + "' readonly /><br>");
writer.println(" 部門名稱: <input type='text' name='dname' value="https://www.cnblogs.com/TheMagicalRainbowSea/p/+ dname +" /><br>");
writer.println(" 部門位置: <input type='text' name='loc' value="https://www.cnblogs.com/TheMagicalRainbowSea/p/+ loc +" /><br>");
}
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
// 5.釋放資源,最后使用的優先關閉(因為如果是關閉優先使用的話,再最后面使用的可能需要前面的資源,才能執行)
DBUtil.close(connection, preparedStatement, resultSet);
}
writer.println(" <input type='submit' value='https://www.cnblogs.com/TheMagicalRainbowSea/p/修改' />");
writer.println(" </form>");
writer.println("</body>");
writer.println("</html>");
}
}
2.10 功能七:修改部門 DeptSaveServlet
思路:
獲取到前端的提交的資料,注意 編碼設定post 請求
連接資料庫: 進行添加資料
添加成功: 回傳部門串列頁面
添加失敗: 回傳失敗的頁面
具體的代碼撰寫如下:
package com.RainbowSea.servlet;
import com.RainbowSea.DBUtil.DBUtil;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
/**
* 增加部門資料
*/
public class DeptSaveServlet extends HttpServlet {
// 前端是注冊資訊,是post 請求
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException,
IOException {
/*
思路:
獲取到前端的提交的資料,注意 編碼設定post 請求
連接資料庫: 進行添加資料
添加成功: 回傳部門串列頁面
添加失敗: 回傳失敗的頁面
*/
request.setCharacterEncoding("UTF-8");
// 獲取到前端的資料,建議 name 使用復制
String deptno = request.getParameter("deptno");
String dname = request.getParameter("dname");
String loc = request.getParameter("loc");
// 連接資料庫,添加資料
Connection connection = null;
PreparedStatement preparedStatement = null;
// 影響資料庫的行數
int count = 0;
try {
// 1. 注冊驅動,連接資料庫
connection = DBUtil.getConnection();
// 2. 獲取操作資料庫物件,預編譯sql陳述句,Sql測驗
String sql = "insert into dept(depton,dname,loc) values(?,?,?)";
preparedStatement = connection.prepareStatement(sql);
// 3. 填充占位符, 真正執行sql陳述句,
// 注意: 占位符的填充是從 1 開始的,基本上資料庫相關的起始下標索引都是從 1下標開始的
preparedStatement.setString(1, deptno);
preparedStatement.setString(2, dname);
preparedStatement.setString(3, loc);
// 回傳影響資料庫的行數
count = preparedStatement.executeUpdate();
// 5.釋放資源
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
DBUtil.close(connection, preparedStatement, null);
}
// 保存成功,回傳部門串列頁面
if (count == 1) {
// 這里應該使用,重定向
// 這里用的轉發,是服務器內部的,不要加專案名
//request.getRequestDispatcher("/dept/list/").forward(request, response);
// 重定向
response.sendRedirect(request.getContextPath() + "/dept/list/");
} else {
// 保存失敗
// web當中的 html資源,這里的 "/" 表示 web 目錄
//request.getRequestDispatcher("/error.html").forward(request, response);
response.sendRedirect(request.getContextPath() + "/error.html");
}
}
}
3. 最后的 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_4_0.xsd"
version="4.0">
<!-- 查看部門串列-->
<servlet>
<!-- 注意: 兩個name值要保持一致-->
<servlet-name>list</servlet-name>
<servlet-class>com.RainbowSea.servlet.DeptListServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>list</servlet-name>
<!-- 注意是: / 開始-->
<url-pattern>/dept/list/</url-pattern>
</servlet-mapping>
<!-- 部門詳情-->
<servlet>
<servlet-name>detail</servlet-name>
<servlet-class>com.RainbowSea.servlet.DeptDetailServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>detail</servlet-name>
<url-pattern>/dept/detail</url-pattern>
</servlet-mapping>
<!-- 洗掉部門-->
<servlet>
<servlet-name>delete</servlet-name>
<servlet-class>com.RainbowSea.servlet.DeptDelServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>delete</servlet-name>
<!-- / 開始-->
<url-pattern>/dept/delete</url-pattern>
</servlet-mapping>
<!-- 新增部門-->
<servlet>
<servlet-name>save</servlet-name>
<servlet-class>com.RainbowSea.servlet.DeptSaveServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>save</servlet-name>
<url-pattern>/dept/save</url-pattern>
</servlet-mapping>
<!-- 跳轉到修改部門-->
<servlet>
<!-- 兩個 name 保持一致-->
<servlet-name>edit</servlet-name>
<servlet-class>com.RainbowSea.servlet.DepEditServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>edit</servlet-name>
<!-- "/" 開始-->
<url-pattern>/dept/edit</url-pattern>
</servlet-mapping>
<!-- 修改部門資訊-->
<servlet>
<servlet-name>modify</servlet-name>
<servlet-class>com.RainbowSea.servlet.DeptModifyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>modify</servlet-name>
<url-pattern>/dept/modify</url-pattern>
</servlet-mapping>
</web-app>

4. 優化方案: @WebServlet 注解 + 模板方法
由于設計到文章的篇幅過多,大家想要了解的可以移步至:?????? Servlet注解的使用,簡化配置 以及,使用模板方法設計模式優化oa專案_ChinaRainbowSea的博客-CSDN博客
5. 總結:
-
每次前端提交的資料都通過瀏覽器 F12 檢查的方式,查看我們提交的資料是否,是我們需要的,是否滿足條件,
-
每次后端從前端瀏覽器獲取到的資料,同樣都是需要列印或者除錯看看,我們獲取的資料是否存在錯誤,或者亂碼的情況,
-
如果對SQL陳述句不太熟練的話,建議無論是否是簡單的 SQL陳述句都,可以先在對應的資料庫中運行測驗看看,是否存在錯誤,
-
盡可能的做到,每實作一點功能就測驗一下,是否存在錯誤,而不是一頓操作下來,雖然所以代碼都撰寫完了,但是到最后測驗的時候,一堆 BUG ,
-
我們應該怎么去實作一個功能呢?
- 建議:你可以從后端往前端一步一步寫,也可以從前端一步一步往后端寫,都可以,但是千萬要記住不要想起來什么寫什么,你寫代碼的程序最好是程式的執行程序,也就是說:程式執行到哪里,你就寫哪里,這樣一個順序流下來之后,基本上不會出現什么錯誤、意外,
- 從哪里開始?
- 假設從前端開始,那么一定是從用戶點擊按鈕那里開始的
-
分析清楚哪里使用的是
doGet請求 ,哪里使用的是doPost請求, -
分析清楚哪里使用的是
服務器端的轉發,哪里使用的是重定向機制, -
注意: 在服務器當需要使用到的
jar包,必須在WEB-INF的目錄下,創建一個名為lib的目錄檔案夾,用來存放相關的 依賴jar包,注意路徑位置不可以修改,目錄檔案必須為lib不然,當你啟動的Tocmat 服務器的時候,是無法找到該對應的 依賴jar 包的,
6. 最后:
限于自身水平,其中存在的錯誤,希望大家,給予指教,韓信點兵——多多益善,謝謝大家,江湖再見,后會有期!!!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/549713.html
標籤:Java
上一篇:我們為什么需要分布式系統?
下一篇:我們為什么需要分布式系統?

