Java模拟用户名密码登录验证(JDBC)

0、示例程序说明

  • 演示登录验证,用户通过终端输入用户名与密码,程序连接数据库查询合法性;
  • 基本步骤:
    • 获取数据库连接对象
    • 获取SQL执行对象
    • 执行SQL获取结果对象
    • 处理结果
  • 执行SQL语句有两个类,Statement与PrepareStatement,后者是前者的子类,后者有防SQL流入的功能

1、封装工具类操作数据库

package com.yusian.utils;

import java.io.FileReader;
import java.io.IOException;
import java.net.URL;
import java.sql.*;
import java.util.Properties;

public class Utils {
    private static String url;  // 数据库连接url
    private static String user; // 数据库用户名
    private static String pass; // 数据库密码
    private static String driver;

    /**
     * 读取配置文件初始化参数值
     */
    static {
        // 通过ClassLoader获取配置文件的路径
        ClassLoader loader = Utils.class.getClassLoader();
        URL jdbc = loader.getResource("jdbc.properties");
        try {
            // 通过Properties类读取配置文件中的数据,赋值给静态变量
            Properties prop = new Properties();
            prop.load(new FileReader(jdbc.getPath()));
            url = prop.getProperty("url");
            user = prop.getProperty("user");
            pass = prop.getProperty("pass");
            driver = prop.getProperty("driver");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取数据库连接
     * @return 数据库连接对象Connection
     * @throws SQLException
     */
    public static Connection getConnection() throws SQLException {
        // 注册MySQL驱动类
        try {
            Class.forName(driver);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        // 获取MySQL连接对象
        return DriverManager.getConnection(url, user, pass);
    }

    /**
     * 释放更新类数据库操作对象
     * @param conn 数据库连接对象
     * @param stmt SQL语句执行对象
     */
    public static void releaseExcuteUpdate(Connection conn, Statement stmt) {
        releaseCloseableObject(stmt);
        releaseCloseableObject(conn);
    }

    /**
     * 释放查询类数据库操作对象
     * @param conn 数据库连接对象
     * @param stmt SQL执行对象
     * @param retSet 查询结果
     */
    public static void releaseExecuteQuery(Connection conn, Statement stmt, ResultSet retSet) {
        releaseCloseableObject(retSet);
        releaseExcuteUpdate(conn, stmt);
    }
    /**
     * 释放资源
     * @param object 需要释放的资源对象
     */
    private static void releaseCloseableObject(AutoCloseable object) {
        if (object == null) return;
        try {
            object.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

2、字符串拼接SQL语句的方式实现查询

/**
 * 数据库验证用户名及密码的正确性
 *
 * @param username 用户名
 * @param password 密码
 * @return 验证结果
 */
private static boolean login(String username, String password) {
    Connection conn = null;
    Statement stmt = null;
    ResultSet retSet = null;
    // 拼接查询语句SQL
    String sql = "select * from user where username = '" + username + "' and password = '" + password + "'";
    try {
        conn = Utils.getConnection();
        stmt = conn.createStatement();
        // 获取查询结果,有结果表明验证成功,无则失败
        retSet = stmt.executeQuery(sql);
        return retSet.next();
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        // 释放资源
        Utils.releaseExecuteQuery(conn, stmt, retSet);
    }
    return false;
}

3、防SQL注入的实现方式

/**
 * 数据库验证用户名密码的正确性,防SQL流入方法
 * @param username 用户名
 * @param password 密码
 * @return 验证结果
 */
private static boolean login2(String username, String password) {
    Connection conn = null;
    PreparedStatement pstmt = null;
    ResultSet retSet = null;
    try {
        conn = Utils.getConnection();
        // 这里是与Statement最本质的区别点,SQL中的变量用?占位,通过setXxxx方法赋值来规避SQL注入
        pstmt = conn.prepareStatement("select * from user where username = ? and password = ?");
        // 给SQL中占位符赋值,序号从1开始
        pstmt.setString(1, username);
        pstmt.setString(2, password);
        retSet = pstmt.executeQuery();
        return retSet.next();
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        Utils.releaseExecuteQuery(conn, pstmt, retSet);
    }
    return false;
}

Leave a Reply