一、為什麼表單需要驗證?
在前面的文章中,我們已經完成病患資料的新增、查詢、修改、刪除與搜尋。
但我們還沒有認真處理一個問題:
如果使用者輸入錯誤的資料,系統該怎麼辦?
例如:
如果系統沒有檢查,就可能把錯誤資料寫入資料庫。
因此,今天要學習表單驗證,讓系統在儲存資料之前先確認輸入是否符合基本規則。
二、表單驗證分成兩個部分
常見的表單驗證可以分成兩種。
前端驗證是在瀏覽器中進行的,例如 HTML 的 required、type="date" 和 maxlength。
這些屬性可以協助使用者在送出表單前發現部分錯誤。
但前端驗證可以被繞過,因此不能只靠它保護資料庫。
後端驗證是在 Servlet 或其他伺服器端程式中進行。
例如:
String name = request.getParameter("name");
if (name == null || name.isBlank()) {
// 拒絕儲存
}
即使使用者繞過前端表單,伺服器仍然會再次檢查輸入。
因此,前端驗證主要是改善使用體驗,後端驗證才是資料儲存前不可省略的檢查。
三、先建立有驗證功能的表單
我們先建立 patient-form.jsp:
<%@ page contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" %>
這裡使用 required 要求姓名與生日不可空白,也使用 pattern 對電話輸入進行基本格式限制。
不過,不同地區的電話格式可能不同,因此這個範例只是教學用途,並不是完整的國際電話驗證規則。
四、在 Servlet 進行後端驗證
接下來建立 PatientRegisterServlet.java。
這個範例會接收表單資料、驗證姓名和生日,再將合法資料寫入 MySQL。
package servlet;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.time.LocalDate;
import java.time.format.DateTimeParseException;
import java.util.regex.Pattern;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import util.DBConnection;
@WebServlet("/patient/register")
public class PatientRegisterServlet extends HttpServlet {
private static final Pattern PHONE_PATTERN =
Pattern.compile("[0-9+\- ]{6,20}");
@Override
protected void doPost(
HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
String name = request.getParameter("name");
String gender = request.getParameter("gender");
String birthdayText = request.getParameter("birthday");
String phone = request.getParameter("phone");
name = name == null ? "" : name.trim();
gender = gender == null ? "" : gender.trim();
birthdayText = birthdayText == null
? "" : birthdayText.trim();
phone = phone == null ? "" : phone.trim();
String error = null;
LocalDate birthday = null;
if (name.isBlank()) {
error = "姓名不可為空白。";
} else if (name.length() > 100) {
error = "姓名長度不可超過 100 個字元。";
}
if (error == null) {
try {
birthday = LocalDate.parse(birthdayText);
if (birthday.isAfter(LocalDate.now())) {
error = "生日不可晚於今天。";
}
} catch (DateTimeParseException e) {
error = "生日格式不正確。";
}
}
if (error == null && !phone.isEmpty()
&& !PHONE_PATTERN.matcher(phone).matches()) {
error = "電話格式不正確。";
}
if (error != null) {
request.setAttribute("error", error);
request.getRequestDispatcher("/patient-error.jsp")
.forward(request, response);
return;
}
String sql = "INSERT INTO patient "
+ "(name, gender, birthday, phone) "
+ "VALUES (?, ?, ?, ?)";
try (
Connection conn = DBConnection.getConnection();
PreparedStatement ps = conn.prepareStatement(sql)
) {
ps.setString(1, name);
ps.setString(2, gender);
ps.setDate(
3,
java.sql.Date.valueOf(birthday)
);
if (phone.isEmpty()) {
ps.setNull(4, java.sql.Types.VARCHAR);
} else {
ps.setString(4, phone);
}
ps.executeUpdate();
response.sendRedirect(
request.getContextPath() + "/patients"
);
} catch (SQLException e) {
throw new ServletException("新增病患資料失敗", e);
}
}
}
這裡的驗證規則包含:
請注意,這份範例以先前的 patient 資料表為基礎。若你的資料表欄位、長度或必填規則不同,應同步調整程式。
五、顯示錯誤訊息
當輸入資料不符合規則時,Servlet 會將錯誤訊息傳給 JSP。
建立 patient-error.jsp:
<%@ page contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" %>
<%@ taglib prefix="c"
uri="jakarta.tags.core" %>
這樣一來,使用者就能知道是哪個欄位出了問題,而不是只看到一個沒有說明的錯誤畫面。
這個版本會在驗證失敗後顯示錯誤訊息,返回表單時需要重新輸入。如果想進一步改善體驗,可以把原本輸入的內容也保留下來。
六、如何測試驗證功能?
啟動 Tomcat 後,開啟新增病患表單。
可以依序測試以下情況:
測試內容 預期結果
姓名留空 阻止送出或顯示錯誤
生日格式不正確 顯示日期格式錯誤
生日設定為未來日期 顯示生日不可晚於今天
電話輸入不符合規則的內容 顯示電話格式錯誤
輸入符合規則的測試資料 新增成功並回到清單
除了透過瀏覽器測試,也可以思考:如果有人不使用這個 HTML 表單,而是直接發送請求,後端是否仍然能拒絕不合法的資料?
這就是後端驗證的價值。
七、驗證不只是檢查有沒有填寫
實際的醫療資訊系統可能還需要考慮:
不同欄位應該有不同的驗證規則,不能只用一個 required 解決所有問題。
今日小結
今天我們完成了基本的表單驗證機制,學會:
Day 24 完成!
現在我們的系統除了能管理病患資料,也開始具備基本的輸入檢查。接下來可以繼續完成登入功能與權限管理,讓系統逐步接近一個完整的醫療資訊小系統。
參考資料:Jakarta Servlet 官方文件