iT邦幫忙

0

工作中自學至獨立完成系統項目(Eclipse Servlet) - 5

  • 分享至 

  • xImage
  •  

技術內容

在資料傳輸前,有些相關的文件及當中的欄位、邏輯Annotation之類的必須要有,才能運作程式
因此要先確認這些事情有沒有做

1. 在Servlet文件中,透過@WebServlet(" "),在" "內打上要映射的url後,就可以在javaScript使用

例如圖片這樣
https://ithelp.ithome.com.tw/upload/images/20240529/201564385rSy02qRP8.png
htmljsp formaction那邊好像也可以用,但我還不確定,而且這個系統沒用到,因此等確定之後再補上來/images/emoticon/emoticon01.gif

2. 在javaScript使用 fetch API

※ login 是 url,GBS 則是你的專案名稱,也就是訪問專案底下的 login這個位址
在設置 @WebServlet(” ”) ,會自動在對應的web.xml寫入,所以這部份似乎不用太擔心
但是如果你設置好後一直訪問不到,甚至導致你整個程式連運作都無法運作的話,就要找到你專案底下的 web.xml
將那一個url相關的一些資料都刪除,然後再重新開啟 eclipse 開發環境即可。

  • 訪問後端url
  fetch("/GBS/login", {
  
        })
  • 確定 http 方法及傳輸格式及內容
    這邊用的 http 方法是 POST,常見來說有 POST、GET,但還有很多其他的,例如:PUT、DELETE 等等
    詳細請參考這裡還有這裡

在設置表頭(headers)的時候,由於這邊是訪問後端,因此這邊是 Request header
然後內容類型 (Content-Type) 為 "application/x-www-form-urlencoded"
為什麼是這個呢?請參考這篇文章

寫這樣算是為了登入表單的資料格式,因為我登入確實是用提交表單的方法
這個系統的開發也有 application/json也就是JSON數據格式,這個部份後面會在說明
至於 body 的部分和 (Content-Type) 一樣,因為是 HTTP請求的"表單"(form data)
這樣我在後端才可以用 request.getParameter("")來取到值
request.getParameter("")的部分之後會在說明

再來是 encodeURIComponent這個方法則是為了確保我前端輸入的值能夠正確的格式化
詳細文章內容請參考這裡

   fetch("/GBS/login", {
            method: "POST",
            headers: {
                "Content-Type": "application/x-www-form-urlencoded"
            },
            body: `empCode=${encodeURIComponent(empCode)}&password=${encodeURIComponent(password)}`
        })

要注意的地方是,這個訪問後端的邏輯是在按了前端html的登入按鍵後才執行的,也就是我有為這個按件設定監聽器,而要怎麼在javaScript知道那個按鈕是哪一個按鈕?或是那個表單是哪一個表單?
則需要透過document.getElementById("")這一個方法,如下:

 // 獲取登錄表單元素
    const loginForm = document.getElementById("login-form");
  // 添加表單提交事件監聽器
    loginForm.addEventListener("submit", function(event) {
      
    });

而這個login-form Id 就是在html表單的 id

 <form id="login-form">
     <label class="input" for="empCode">編號:</label>
     <input type="text" id="empCode" name="empCode" required placeholder="Your empCode..."><br><br>
     <label class="input" for="password">密碼:</label>
     <input type="password" id="password" name="password" required placeholder="Your password..."><br><br>
      <input type="submit" value="Login">
 </form>

如果沒有設置監聽器的話,則會在開啟或導向某一個頁面的時候,在引入javaScript的同時,就執行訪問後端位址的動作

到這裡基本的一個資料流感覺就有了/images/emoticon/emoticon07.gif

3. 後端接值與資料庫互動

在HTTP中,request.getParameter 是用來獲取從客戶端發送到伺服器的 HTTP 請求中的參數的方法。
這些參數通常來自於以下兩種情況:

  • GET 請求的 URL 查詢參數:例如,/login.html?empCode=123&password=abc。
  • POST 請求的表單數據:例如使用 application/x-www-form-urlencoded 或 multipart/form-data 類型的表單數據。

這也是為什麼在後端會用request.getParameter()這個方法來接值,當然不只有接表單值的情況,這邊先講接表單的這一個部分

String empCode = request.getParameter("empCode");
String password = request.getParameter("password");

宣告變數存值之後,進行與資料庫的連線,此部分以 SQL server 為例
這是一個用於連接到 Microsoft SQL Server 資料庫的 JDBC 連接字串 (connection string)。
每一部分都有特定的用途,用來告訴 JDBC 驅動程式如何連接到特定的資料庫。

※IP地址、資料庫名稱、登入的使用者名稱及密碼都要依據實務情況來做調整

String url = "jdbc:sqlserver://11.11.11.11:1433;databaseName=testdatabase;trustServerCertificate=true;";
String dbUsername = "";
String dbPassword = "";

以下是該連接字串的詳細解析:

  • jdbc:sqlserver://:這是告訴 JDBC 使用哪種驅動程式協議。jdbc 表示 JDBC 連接,而 sqlserver 表示連接到 Microsoft SQL Server。
  • 11.11.11.11:這是 SQL Server 資料庫所在伺服器的 IP 地址。如果伺服器位於本地,可以使用 localhost 或 127.0.0.1。
  • 1433:這是 SQL Server 的預設連接埠號。SQL Server 通常在這個連接埠上運行。
  • databaseName=testdatabase:這個參數指定要連接的資料庫名稱。在這個例子中,資料庫名稱是 testdatabase。
  • trustServerCertificate=true:這個參數告訴驅動程式信任伺服器的 SSL 憑證。這在使用自簽名憑證時特別有用,因為自簽名憑證可能不在客戶端的受信任憑證列表中。

加載 JDBC 驅動程序並建立與資料庫連接

// 加載JDBC驅動程序
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
// 建立與資料庫的連接
Connection connection = DriverManager.getConnection(url, dbUsername, dbPassword);

準備SQL 語句,防止 SQL 注入

使用 PreparedStatement 可以防止 SQL 注入的原因在於,這種方式將 SQL 語句與參數分開處理。
具體來說,PreparedStatement 提供了一個方法來安全地插入變數,而不會將變數的內容解釋為 SQL 語句的一部分。以下是詳細解釋:
什麼是 SQL 注入?
SQL 注入是一種攻擊技術,攻擊者可以通過在輸入中插入惡意 SQL 代碼來操控應用程序的 SQL 查詢,從而未經授權地訪問或修改數據庫。通常是由於將未經處理的用戶輸入直接嵌入到 SQL 查詢中。
使用 PreparedStatement 防止 SQL 注入
當你使用 PreparedStatement 準備 SQL 語句時,語句中的參數使用佔位符 (?) 表示,而不是將變數直接插入到語句中。然後,使用 setXXX 方法來設置這些佔位符的值。PreparedStatement 會自動地將這些值作為數據處理,而不是 SQL 語句的一部分。這樣,即使參數包含惡意 SQL 代碼,也不會被解釋為 SQL 語句的一部分。

// 使用PreparedStatement準備SQL語句
String sql = "SELECT * FROM users WHERE emp_code=? AND password=?";
PreparedStatement statement = connection.prepareStatement(sql);
statement.setString(1, empCode);
statement.setString(2, password);

執行SQL,JDBC 驅動會將查詢模板與設置好的參數值一起發送到資料庫伺服器
資料庫伺服器會使用這些參數來執行查詢,並返回查詢結果,並透過ResultSet來存
而 ResultSet 是 Java 中用來處理 SQL 查詢結果的一個介面

// 執行查詢
ResultSet resultSet = statement.executeQuery();

檢查結果集中是否有符合的資料,如果是第一次調用的話會移到第一行,
如果有更多的行存在,則 next() 方法返回 true,否則返回 false

if (resultSet.next()) {

}

在當中可以做其他的的邏輯,如果想要取值的話,則可以依照資料類型,使用不同的方法
像是:
resultSet.getString("role")、resultSet.getInt("id")
roleid 則是資料庫的欄位名稱,必須要一模一樣,不然存不到值

接著就可以創建對應用變數存值

String role = resultSet.getString("role");
int id = resultSet.getString("id");

4.將狀態或資料庫的值回傳 javaScript

在我撰寫的過程中,狀態的部分可以分為自己寫的或後端的方法兩種,現在的我是覺得原本就有的後端的方法比較好...因為自己寫的會有意想不到的問題,總之先來看看自己寫的這個部份。

  • 創建JSONObject物件 (回傳狀態)
JSONObject jsonResponse = new JSONObject();

//如果成功則給"success"鍵true值
sonResponse.put("success", true);

//失敗則給"success"鍵false值,要根據撰寫時的邏輯來決定
sonResponse.put("success", false);
// 設置回應的 Content-Type 為 application/json,這個前面有講述過了,應該沒問題
response.setContentType("application/json");

// 獲取 PrintWriter,用於寫入回應
PrintWriter是用來將字串寫入Response的一個類別

PrintWriter out = response.getWriter();
// 將 JSON 轉換字串後寫入回應
out.print(jsonResponse.toString());
// 刷新 PrintWriter ,確保資料能正確地回傳
out.flush();

接下來的部分,繼續看到

 fetch("/GBS/login", {
            method: "POST",
            headers: {
                "Content-Type": "application/x-www-form-urlencoded"
            },
          body:`empCode=${encodeURIComponent(empCode)}&password=${encodeURIComponent(password)}`
        })
        .then(response => response.json()) // 解析 JSON 格式的回應

如何確認fetch是否成功這個網頁中可以看到
確認fetch()是否成功的正確方式, 應包含檢查 promise resolved, 以及檢查Response.ok的屬性是否為 true.
這也是比較正確的做法,但這邊做的不是這樣

.then(response => response.json())下方,寫了這段,用來處理解析後的 JSON 資料。
還記得在後端有將 名 success 鍵的值放入 json 物件中嗎?
因此,在javaScript解析後的json 資料中,根據後端的放入的值,會有一個這樣子
{success: true}或這樣子{success: false}的資料

所以當我們用 console.log(data) 在瀏覽器上印出 data 的時候,就會看到
{success: true}{success: false}

而當我們寫 data.success 則是取到 data 當中 success 這一個鍵值
這一個值不是 true 就是 false,接下來 就會根據我們寫的條件來運作程式了/images/emoticon/emoticon12.gif

同時,我在後端也有多放入一個名為 role 的值,這個值是我從資料庫取出來後回傳的,目的是做判斷
根據不同的角色,導向不同的頁面

至於錯誤訊息顯示的部分,這邊就不多贅述了,有需要的話可以留言,我可以再補充
不過就這樣把文章閱讀下來,我想大家一定也知道這是在做什麼/images/emoticon/emoticon01.gif

 .then(data => {
            // 檢查登錄結果
            if (data.success) {
				if(data.role==="帥哥"){
					// 登錄成功,導向 帥哥 用戶列表頁面
					window.location.href = "XXXXXX.jsp";
				}else if (data.role==="像我一樣的宅宅"){
					// 登錄成功,導向 像我一樣的宅宅 用戶列表頁面
					window.location.href = "XXX.jsp";
				}
               
            } else {
                // 登錄失敗,顯示錯誤訊息
                const errorMessage = document.getElementById('error-message');
                errorMessage.innerText = data.error_message;
            }

如果想要回傳的是資料庫的值,則也是用同樣的方法來做,就可以將資料庫的值回傳到javaScript囉!

  • 透過設定狀態來回覆

與前面success類似,當我們正確地在後端訪問資料庫,並且將值存完或是做其他邏輯處理後,依據實務情況
要給前端一個回覆,前端才會知道後端把事情做完了,可以做下一步事情
success 是透過一個鍵然後寫入 true 或 false 的值後,放入 json 物件 ,然後在 javaScript 解析後
,依據當中的 boolean值的真假來做判斷

而這邊則是直接在後端設置 http 狀態碼,將其設置為 200 OK
response.setStatus(HttpServletResponse.SC_OK);

這個簡單許多,不過要注意設置的地方就是了,不能說程式執行錯誤,還回傳 200 OK

接著再回到 javaScript
透過 response.ok作為要執行哪一部份程式的判斷

.then(response => {
	if (response.ok) {
	    // 如果成功處理了回應,可以在這裡進行任何需要的處理
	    console.log('資料已成功傳遞到後端');
					
	} else {
		console.error('發生錯誤');
	}
})
.catch(error => {
	console.error('錯誤:', error);
});
  1. javaScript 與 html 互動

再回頭看看這一部份的程式碼,在後端的部分,如果登錄失敗,會寫入一些文字

// 登錄失敗,將錯誤訊息放入 JSON 中
jsonResponse.put("success", false);
jsonResponse.put("error_message", "員工編號或密碼輸入錯誤");

javaScript則與前面的程式碼一樣

 .then(data => {
            // 檢查登錄結果
            if (data.success) {
				if(data.role==="帥哥"){
					// 登錄成功,導向 帥哥 用戶列表頁面
					window.location.href = "XXXXXX.jsp";
				}else if (data.role==="像我一樣的宅宅"){
					// 登錄成功,導向 像我一樣的宅宅 用戶列表頁面
					window.location.href = "XXX.jsp";
				}
               
            } else {
                // 登錄失敗,顯示錯誤訊息
                const errorMessage = document.getElementById('error-message');
                errorMessage.innerText = data.error_message;
            }

如果登錄失敗的話要將後端寫的錯誤訊息,回傳給 javaScript 這一部份已經完成了
那麼該怎麼寫到前端的 html 呢? ,然後在 javaScript 中要取到

首先要有 <div> 區塊或是 需要的某一個元素,在這邊使用的是 <div>區塊
然後給予這個區塊 id 名稱
<div id="error-message" style="color: red;"></div>

然後在javaScript 中 透過變數來取到 html 這個 id 的元素後,將後端的值寫入

//取到 html id 為 "error-message" 這個區塊
const errorMessage = document.getElementById('error-message');

//為這個區塊寫入後端錯誤訊息的文字
errorMessage.innerText = data.error_message;

目前想到且整理過的技術部分大致就這樣
關於如何分上下區塊產生特定資訊及動態表格的部分,由於內容繁多,需要再整理一下/images/emoticon/emoticon07.gif

上一篇,工作中自學至獨立完成系統項目(Eclipse Servlet) - 4

暫時空缺的下一篇

  1. 留著給未來可能要補充的內容

圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言