一.实现功能:
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.cnblogs.com/Burning-youth/p/15755229.html
图文来源于网络,如有侵权请联系删除。