一.實作功能:
1.解決“應用Statement的登錄系統”存在的SQL注入問題
2.用戶資訊表
+----+-----------+----------+----------+
| id | loginName | loginPwd | realName |
+----+-----------+----------+----------+
| 1 | abc | 123 | 張三 |
| 2 | wwe | 456 | 李四 |
+----+-----------+----------+----------+
二.代碼實作:
import java.sql.*;
import java.util.*;
public class JDBCTest02 {
public static void main(String[] args) {
//初始化界面(用戶輸入賬號和密碼)
Map<String,String> userLoginInfo = initUI();
//驗證用戶名和密碼(JDBC)
boolean loginSuccess = login(userLoginInfo);
//顯示結果:
System.out.println(loginSuccess==true?"登錄成功":"登錄失敗");
}
/**
* 驗證用戶登錄資訊是否正確
* @param userLoginInfo 用戶登錄資訊
* @return false 表示登錄失敗,true 表示登錄成功
*/
private static boolean login(Map<String, String> userLoginInfo) {
//打標記(登錄結果)
boolean loginSuccess = false;
Connection connection = null;
PreparedStatement ps = null;
ResultSet resultSet = null;
try {
//1、注冊驅動
Class.forName("com.mysql.cj.jdbc.Driver");
//2、獲取連接
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode",
"root","888");
//3、獲取預編譯的資料庫操作物件
//一個?代表一個占位符,一個?接受一個“值”
String sql = "select * from t_user where loginName = ? and loginPwd = ? ";
//程式執行到此處,會發送sql陳述句框子給DBMS,然后DBMS進行sql的編譯
ps = connection.prepareStatement(sql);
//給占位符傳值(第一個?下標是1,第二個?下標是2,JDBC的的下標從1開始)
ps.setString(1,userLoginInfo.get("loginName"));
ps.setString(2,userLoginInfo.get("loginPwd"));
//4、執行sql
resultSet = ps.executeQuery();
//5、處理結果集
//不需要while結果集,因為查詢結果不是 無 就是 1條記錄
if (resultSet.next()){
loginSuccess = true;
}
} catch (Exception e) {
e.printStackTrace();
}finally {
//從小到大分別關閉三個資源
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (ps != null) {
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
//最后回傳 登錄結果(boolean)
return loginSuccess;
}
/**
* 初始化用戶界面
* @return 用戶的用戶名和密碼(Map)
*/
private static Map<String, String> initUI() {
Scanner s=new Scanner(System.in);
System.out.println("用戶名:");
String loginName = s.nextLine();
System.out.println("密碼:");
String loginPwd = s.nextLine();
//用 HashMap(鍵值對的方式)存盤用戶輸入的 賬號和密碼
Map<String,String> userLoginInfo = new HashMap<>();
userLoginInfo.put("loginName",loginName);
userLoginInfo.put("loginPwd",loginPwd);
return userLoginInfo;
}
}
三.效果展示:
1.使用 PreparedStatement 解決了SQL注入問題:
用戶名:
yyds
密碼:
yyds' or '1'='1
登錄失敗
Process finished with exit code 0
2.注意:
1)JDBC代碼部分的第三步 --- 獲取預編譯的資料庫操作物件(不同于Statement):
先寫好sql陳述句模型:
String sql = "select * from t_user where loginName = ? and loginPwd = ? ";
發送sql陳述句框子給DBMS,然后DBMS準備進行sql的編譯:
ps = connection.prepareStatement(sql);
給占位符傳值:?的值為String就setString,?的值為int就setInt ...
ps.setString(1,userLoginInfo.get("loginName"));
ps.setString(2,userLoginInfo.get("loginPwd"));
四.Statement 與 PreparedStatement 對比:
1.Statement 編譯一次執行一次,PreparedStatement 編譯一次,可執行n次,所以 PreparedStatement 效率較高;
2.PreparedStatement 比 Statement 更加安全;
3.Statement 可以完成根據用戶的意愿,通過輸入sql陳述句來實作相應的功能,比如:升序(asc)/降序(desc):
1)假設使用 PreparedStatement:
用戶想通過按“賬號首字母”升序的方式看到用戶的資訊,所以向?傳入“asc”,但這樣運行是會報錯的,因為實際執行的sql陳述句是:
select * from t_user order by loginName 'asc' //那這倆單引號是什么鬼嘛,執行肯定報錯啊,所以這時只能選擇 Statement
String sql = "select * from t_user order by loginName ?";
ps = connection.prepareStatement(sql);
ps.setString(1,"asc");
resultSet = ps.executeQuery();
2)假設使用 Statement:
statement = connection.createStatement();
String sql = "select * from t_user order by loginName asc";
resultSet = statement.executeQuery(sql);
while (resultSet.next()) {
System.out.println(resultSet.getString("loginName"));
}
這樣就可以根據 loginName 首字母大小升序的方式來輸出 loginName:
abc
wwe
Process finished with exit code 0
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/400327.html
標籤:MySQL
上一篇:使用vue.js和axios對資料和API的回應不一致
下一篇:【JDBC】筆記(3)--- 提高用戶登錄功能的安全性 (javaSE+MySQL+JDBC)[ 應用 PreparedStatement ]
