首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計疑難解答

Java Web 實作:將 JSP 註冊頁面資料寫入 MySQL 資料庫完整教學

     編輯:程式設計疑難解答

前言

在開發 Java Web 應用程式時,使用者註冊功能是最基礎也最重要的模組之一。本文將完整示範如何從 JSP 註冊頁面接收使用者輸入的資料,透過 Servlet 處理業務邏輯,最後使用 JDBC 將資料安全地寫入 MySQL 資料庫的用戶表中。

完整實作流程

1. 建立資料庫與用戶表

首先在 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;

2. 設計 JSP 註冊頁面 (register.jsp)

建立一個簡單的 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>

3. 建立資料庫連線工具類 (DBUtil.java)

封裝資料庫連線邏輯,方便複用並統一管理連線參數:

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) {}
            }
        }
    }
}

4. 實作註冊 Servlet (RegisterServlet.java)

核心業務邏輯:接收參數、驗證資料、密碼加密、預處理語句防止 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);
        }
    }
}

關鍵技術點總結

  • PreparedStatement:使用預處理語句完全杜絕 SQL 注入風險
  • 密碼加密:絕不可明文儲存密碼,生產環境建議使用 BCrypt 或 Argon2
  • 事務控制:確保資料一致性,失敗時自動回滾
  • 資源釋放:在 finally 區塊關閉 Connection、Statement、ResultSet
  • 編碼統一:資料庫、連線字串、JSP、Servlet 全部統一 UTF-8

進階優化建議

  1. 導入連線池 (HikariCP / Druid) 提升效能
  2. 使用 BCrypt 加鹽雜湊替代簡單 SHA-256
  3. 加入前端驗證 (JavaScript) 與後端雙重驗證
  4. 實作郵件驗證機制確保郵箱真實性
  5. 記錄稽核日誌追蹤註冊操作

完整範例碼可參考:CSDN 相關教學

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved