首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java JDBC 連接 Oracle 實現用戶註冊登錄完整實戰(含 PreparedStatement 防注入)

     編輯:Java 相關知識

項目結構概覽

com.example.auth
├── entity
│   └── User.java              # 用戶實體類
├── dao
│   ├── UserDao.java           # 數據訪問接口
│   └── UserDaoImpl.java       # JDBC 實現
├── service
│   ├── AuthService.java       # 業務邏輯接口
│   └── AuthServiceImpl.java   # 註冊/登錄邏輯
└── Main.java                  # 控制台測試入口

1. 實體類 User

package com.example.auth.entity;

public class User {
    private String name;       // 顯示名
    private String loginName;  // 登錄賬號
    private String password;   // 密碼(實際應存儲加密摘要)

    // Getter/Setter/構造器/toString 省略
}

2. 數據庫表結構

CREATE TABLE USERINFO (
    NAME       VARCHAR2(50) NOT NULL,
    LOGINNAME  VARCHAR2(50) PRIMARY KEY,
    LOGINPSW   VARCHAR2(100) NOT NULL  -- 存儲 BCrypt 雜湊值
);

3. DAO 實現(核心 JDBC 代碼)

package com.example.auth.dao;

import com.example.auth.entity.User;
import java.sql.*;

public class UserDaoImpl implements UserDao {
    private static final String URL = "jdbc:oracle:thin:@localhost:1521:orcl";
    private static final String USER = "scott";
    private static final String PASS = "tiger";

    static {
        try { Class.forName("oracle.jdbc.driver.OracleDriver"); }
        catch (ClassNotFoundException e) { throw new RuntimeException("驅動加載失敗", e); }
    }

    private Connection getConn() throws SQLException {
        return DriverManager.getConnection(URL, USER, PASS);
    }

    /** 登錄驗證:返回 User 或 null */
    @Override
    public User findByLoginNameAndPassword(String loginName, String password) {
        String sql = "SELECT NAME FROM USERINFO WHERE LOGINNAME = ? AND LOGINPSW = ?";
        try (Connection conn = getConn();
             PreparedStatement ps = conn.prepareStatement(sql)) {
            ps.setString(1, loginName);
            ps.setString(2, password); // 實際應傳入加密後的密碼
            try (ResultSet rs = ps.executeQuery()) {
                if (rs.next()) {
                    User u = new User();
                    u.setLoginName(loginName);
                    u.setName(rs.getString("NAME"));
                    return u;
                }
            }
        } catch (SQLException e) {
            throw new RuntimeException("登錄查詢異常", e);
        }
        return null;
    }

    /** 註冊:檢查用戶名唯一性並插入 */
    @Override
    public boolean register(User user) {
        // 1. 檢查登錄名是否存在
        String checkSql = "SELECT 1 FROM USERINFO WHERE LOGINNAME = ?";
        try (Connection conn = getConn();
             PreparedStatement ps = conn.prepareStatement(checkSql)) {
            ps.setString(1, user.getLoginName());
            try (ResultSet rs = ps.executeQuery()) {
                if (rs.next()) return false; // 已存在
            }
        } catch (SQLException e) {
            throw new RuntimeException("檢查用戶名異常", e);
        }

        // 2. 插入新用戶
        String insertSql = "INSERT INTO USERINFO (NAME, LOGINNAME, LOGINPSW) VALUES (?, ?, ?)";
        try (Connection conn = getConn();
             PreparedStatement ps = conn.prepareStatement(insertSql)) {
            ps.setString(1, user.getName());
            ps.setString(2, user.getLoginName());
            ps.setString(3, user.getPassword()); // 必須是加密後的密碼
            return ps.executeUpdate() > 0;
        } catch (SQLException e) {
            throw new RuntimeException("註冊插入異常", e);
        }
    }
}

4. 服務層業務邏輯

package com.example.auth.service;

import com.example.auth.dao.UserDao;
import com.example.auth.dao.UserDaoImpl;
import com.example.auth.entity.User;

public class AuthServiceImpl implements AuthService {
    private final UserDao userDao = new UserDaoImpl();

    @Override
    public User login(String loginName, String rawPassword) {
        // 實際應對 rawPassword 進行 BCrypt 加密後再查詢
        String encrypted = BCrypt.hashpw(rawPassword, BCrypt.gensalt()); // 示例
        return userDao.findByLoginNameAndPassword(loginName, encrypted);
    }

    @Override
    public boolean register(String name, String loginName, String rawPassword) {
        if (name == null || loginName == null || rawPassword == null) return false;
        User user = new User();
        user.setName(name);
        user.setLoginName(loginName);
        user.setPassword(BCrypt.hashpw(rawPassword, BCrypt.gensalt())); // 加密存儲
        return userDao.register(user);
    }
}

5. 控制台測試入口

package com.example.auth;

import com.example.auth.entity.User;
import com.example.auth.service.AuthService;
import com.example.auth.service.AuthServiceImpl;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        AuthService auth = new AuthServiceImpl();
        Scanner sc = new Scanner(System.in);

        while (true) {
            System.out.println("\n=== 用戶系統 ===");
            System.out.println("1. 登錄");
            System.out.println("2. 註冊");
            System.out.println("3. 退出");
            System.out.print("請選擇: ");
            int choice = sc.nextInt();
            sc.nextLine(); // 消耗換行

            switch (choice) {
                case 1:
                    System.out.print("登錄名: "); String ln = sc.nextLine();
                    System.out.print("密碼: "); String pw = sc.nextLine();
                    User u = auth.login(ln, pw);
                    if (u != null) System.out.println("歡迎 " + u.getName() + " 登錄成功!");
                    else System.out.println("登錄失敗:賬號或密碼錯誤");
                    break;
                case 2:
                    System.out.print("顯示名: "); String name = sc.nextLine();
                    System.out.print("登錄名: "); String regLn = sc.nextLine();
                    System.out.print("密碼: "); String regPw = sc.nextLine();
                    if (auth.register(name, regLn, regPw))
                        System.out.println("註冊成功!");
                    else
                        System.out.println("註冊失敗:登錄名已存在");
                    break;
                case 3:
                    System.out.println("再見!");
                    return;
                default:
                    System.out.println("無效選項");
            }
        }
    }
}

關鍵最佳實踐總結

總結

本文提供了從實體、DAO、Service 到主程序的完整分層架構,採用 PreparedStatement 防注入、BCrypt 加密密碼、try-with-resources 管理資源,是 Java JDBC 連接 Oracle 實現用戶註冊登錄的生產級參考模板。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
要點做法原因
防 SQL 注入全程使用 PreparedStatement + 參數綁定預編譯 SQL,參數不參與語法解析
密碼安全存儲 BCrypt/SCrypt/Argon2 雜湊值,絕不存明文防止數據洩露後被撞庫、彩虹表破解
資源管理try-with-resources 自動關閉 Connection/Statement/ResultSet避免連接洩漏導致連接池耗盡
異常處理捕獲 SQLException 轉為運行時異常上拋,由上層統一處理保持代碼整潔,避免業務邏輯被 try-catch 污染
連接池生產環境必須使用 HikariCP / Druid 等連接池頻繁創建銷毀連接性能極差