数据库实践——模拟用户登录功能的实现
假设用户数据库如下:
代码实现:
import javax.swing.plaf.nimbus.State;
import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.Scanner;
public class UserLogin {
public static void main(String[] args) {
//初始化一个用户登录界面
Map<String,String> userinfo=iniUI();
//验证登录名和登录密码
boolean loginSucess=login(userinfo);
System.out.println((loginSucess? "登录成功!":"登录失败!"));
}
/**
* 用户登录
* @param userinfo 用户登录信息
* @return true表示登录成功,false表示登录失败
*/
private static boolean login(Map<String, String> userinfo) {
//使用资源绑定器绑定资源配置文件
ResourceBundle bundle=ResourceBundle.getBundle("jdbc");
String driver=bundle.getString("driver");
String url=bundle.getString("url");
String user=bundle.getString("user");
String password=bundle.getString("password");
//JDBC编程
Connection cnn=null;
Statement stmt=null;
ResultSet res=null;
//登录成功标记
boolean logSucess=false;
try {
//第一步:注册驱动(在配置文件里面直接读取)
Class.forName(driver);
//第二步:获取连接
cnn=DriverManager.getConnection(url,user,password);
//第三步:获取数据库操作对象
stmt=cnn.createStatement();
//第四步:执行sql语句
//单独定义变量名
String loginName=userinfo.get("loginName");
String loginPwd=userinfo.get("loginPwd");
String sql="select * from t_user where logname='"+loginName+"'and logpwd='"+loginPwd+"'";
//注意:以下这个是不对的,因为sql是一个字符串,整个selcet语句是一个字符串,,需要将这表达这个意思的真个句子拼接起来
//String sql="select * from t_user where logname='loginName'and logpwd='loginPwd'";
//断开理解:
//String sql="select * from t_user where logname=' " +loginName+ " 'and logpwd=' "+loginPwd+ "'";
res=stmt.executeQuery(sql);
//第五步:处理查询结果集
//z合理不用while,因为不用循环,每次只能查一个用户
if(res.next()){//如果有数据,表示登陆成功
logSucess=true;
return logSucess;
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
//第六步:关闭资源
if (res != null) {
try {
res.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (stmt!= null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (cnn != null) {
try {
cnn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return logSucess;
}
/**
* 用户登录界面
* @return返回用户的登录信息
*/
private static Map<String, String> iniUI() {
Scanner s=new Scanner(System.in);
System.out.print("登录名:");
String loginName=s.nextLine();//读取一行
System.out.print("登录密码:");
String loginPwd=s.nextLine();
//将登录名和登录密码以键值对的方式存入map集合
Map<String ,String> userloginfo=new HashMap<>();
userloginfo.put("loginName",loginName);
userloginfo.put("loginPwd",loginPwd);
return userloginfo;
}
}
以上代码实现了:当输入的用户信息和数据库中的内容一致时,可以成功登陆。
但是以上代码存在以下bug (sql注入问题) :存在安全隐患
**分析发生sql注入的根本原因: 用户输入的信息中含有SQL语句的关键字,并且这些关键字参与SQL语句的编译,导致SQL语句的原意被扭曲,进而达到SQL注入。
**改进: 只要用户提供的信息不参与SQL语句的编译(采用java.sql.PreparedStatement预先对SQL语句的框架进行编译,然后再给SQL语句传“值”),即使用户提供的信息含有SQL的关键字,也不起作用。
代码改进:
import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.Scanner;
public class UserLogin2 {
public static void main(String[] args) {
//初始化一个登陆界面
Map<String,String> userinfo=iniUI();
//验证信息
Boolean logsucess=logSucess(userinfo);
System.out.println(logsucess? "登录成功!":"登录失败!");
}
private static Boolean logSucess(Map<String, String> userinfo) {
//使用资源绑定器绑定资源配置文件
ResourceBundle bundle=ResourceBundle.getBundle("jdbc");
String driver=bundle.getString("driver");
String url=bundle.getString("url");
String user=bundle.getString("user");
String password=bundle.getString("password");
//JDBC编程六步
Connection cnn=null;
PreparedStatement stmt=null;
ResultSet res=null;
boolean logsucess=false;
String logName=userinfo.get("logName");
String logPwd=userinfo.get("logPwd");
try {
//第一步:注册驱动
Class.forName(driver);
//第二步:获取连接
cnn= DriverManager.getConnection(url,user,password);
//第三步:获取预编译的数据库操作对象
//SQL语句,一个?代表一个占位符,一个?将来接受一个值,但是?不能用单引号扩起来
String sql="select * from t_user where logname= ? and logpwd= ? ";
//查询执行到此处,会把SQL语句发送给DBMS,DBMS预编译SQL 语句
stmt=cnn.prepareStatement(sql);
//给占位符?传值(预编译之后传值,即用户输入的信息不参与编译,会解决SQL注入问题),
// 第一个?下标是1,第二个问好下标是2.JDBC的下标是从1开始的
stmt.setString(1,logName);
stmt.setString(2,logPwd);
//第四步:执行SQL语句
res=stmt.executeQuery();
//第五步:处理 查询结果集
if(res.next()){//有数据
logsucess=true;
return logsucess;
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}finally {
//第六步:释放资源
if (res != null) {
try {
res.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (cnn != null) {
try {
cnn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return logsucess;
}
/**
* 初始化一个登陆界面
* @return返回用户的登录信息
*/
private static Map<String, String> iniUI() {
Map<String,String> userinfo=new HashMap<>();
Scanner s=new Scanner(System.in);
System.out.print("登录名:");
String loginName=s.nextLine();
System.out.print("登录密码:");
String loginPwd=s.nextLine();
userinfo.put("logName",loginName);
userinfo.put("logPwd",loginPwd);
return userinfo;
}
}
对于Statement和PreparedStatement还需要了解的,可以在查看:Statement和PreparedStatement的对比