在開發 Java Web 應用程式時,使用者註冊功能是最基礎也最重要的模組之一。本文將完整示範如何從 JSP 註冊頁面接收使用者輸入的資料,透過 Servlet 處理業務邏輯,最後使用 JDBC 將資料安全地寫入 MySQL 資料庫的用戶表中。
首先在 MySQL 中建立資料庫與對應的用戶表:
CREATE DATABASE IF NOT EXISTS user_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE user_db;
CREATE TABLE IF NOT EXISTS users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL UNIQUE,
password VARCHAR(255) NOT NULL,
email VARCHAR(100) NOT NULL UNIQUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
建立一個簡單的 HTML 表單,採用 POST 方法提交至 Servlet:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html>
<head>
<title>使用者註冊</title>
<meta charset="UTF-8">
</head>
<body>
<h2>使用者註冊</h2>
<form action="RegisterServlet" method="post">
<div>
<label>使用者名稱:</label>
<input type="text" name="username" required>
</div>
<div>
<label>電子郵件:</label>
<input type="email" name="email" required>
</div>
<div>
<label>密碼:</label>
<input type="password" name="password" required>
</div>
<div>
<label>確認密碼:</label>
<input type="password" name="confirmPassword" required>
</div>
<button type="submit">註冊</button>
</form>
</body>
</html>
封裝資料庫連線邏輯,方便複用並統一管理連線參數:
package com.example.util;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class DBUtil {
private static final String URL = "jdbc:mysql://localhost:3306/user_db?useSSL=false&serverTimezone=UTC&characterEncoding=UTF-8";
private static final String USER = "root";
private static final String PASSWORD = "your_password";
static {
try {
Class.forName("com.mysql.cj.jdbc.Driver");
} catch (ClassNotFoundException e) {
throw new ExceptionInInitializerError("MySQL 驅動載入失敗: " + e.getMessage());
}
}
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(URL, USER, PASSWORD);
}
public static void close(AutoCloseable... resources) {
for (AutoCloseable res : resources) {
if (res != null) {
try {
res.close();
} catch (Exception ignored) {}
}
}
}
}
核心業務邏輯:接收參數、驗證資料、密碼加密、預處理語句防止 SQL 注入、事務處理:
package com.example.servlet;
import com.example.util.DBUtil;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.*;
import java.io.IOException;
import java.sql.*;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
@WebServlet("/RegisterServlet")
public class RegisterServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=UTF-8");
String username = req.getParameter("username").trim();
String email = req.getParameter("email").trim();
String password = req.getParameter("password");
String confirmPassword = req.getParameter("confirmPassword");
// 基本驗證
if (username.isEmpty() || email.isEmpty() || password.isEmpty()) {
req.setAttribute("error", "所有欄位皆為必填");
req.getRequestDispatcher("/register.jsp").forward(req, resp);
return;
}
if (!password.equals(confirmPassword)) {
req.setAttribute("error", "兩次輸入密碼不一致");
req.getRequestDispatcher("/register.jsp").forward(req, resp);
return;
}
// 密碼加密 (SHA-256 + Salt 更佳,此處示範基本雜湊)
String hashedPassword = hashPassword(password);
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
conn = DBUtil.getConnection();
conn.setAutoCommit(false); // 開啟事務
// 檢查使用者名稱或郵箱是否已存在
String checkSql = "SELECT id FROM users WHERE username = ? OR email = ?";
pstmt = conn.prepareStatement(checkSql);
pstmt.setString(1, username);
pstmt.setString(2, email);
rs = pstmt.executeQuery();
if (rs.next()) {
req.setAttribute("error", "使用者名稱或電子郵件已被註冊");
req.getRequestDispatcher("/register.jsp").forward(req, resp);
return;
}
// 插入新用戶
String insertSql = "INSERT INTO users (username, password, email) VALUES (?, ?, ?)";
pstmt = conn.prepareStatement(insertSql, Statement.RETURN_GENERATED_KEYS);
pstmt.setString(1, username);
pstmt.setString(2, hashedPassword);
pstmt.setString(3, email);
int affectedRows = pstmt.executeUpdate();
if (affectedRows > 0) {
conn.commit();
req.setAttribute("success", "註冊成功!請登入");
} else {
conn.rollback();
req.setAttribute("error", "註冊失敗,請稍後再試");
}
} catch (SQLException e) {
try { if (conn != null) conn.rollback(); } catch (SQLException ignored) {}
e.printStackTrace();
req.setAttribute("error", "系統錯誤: " + e.getMessage());
req.getRequestDispatcher("/register.jsp").forward(req, resp);
} finally {
DBUtil.close(rs, pstmt, conn);
}
req.getRequestDispatcher("/register.jsp").forward(req, resp);
}
private String hashPassword(String password) {
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] hash = md.digest(password.getBytes());
StringBuilder hex = new StringBuilder();
for (byte b : hash) {
hex.append(String.format("%02x", b));
}
return hex.toString();
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("密碼加密失敗", e);
}
}
}
完整範例碼可參考:CSDN 相關教學