文章目录
【Mysql】JDBC从放弃到入门(上)
【Mysql】JDBC从放弃到入门(中)
【Mysql】JDBC从放弃到入门(下)
1.项目的业务需求
程序运行的时候,提供一个输入的入口,可以让用户输入用户名的密码,用户输入用户名和密码的时候,提交信息,Java程序收集用户信息,Java程序连接数据库验证用户名和密码是否合法。合法,显示登录成功,不合法,显示登录失败。
2.数据库设计
我们使用powerDesigner来设计数据库。
2.1填写Table Properties
生成用户表:
2.2生成sql语句
2.3保存项目和sql语句
保存项目后缀名为 pdm,保存sql语句后缀名为 sql。
2.4执行sql语句
我们在开始启动项目的时候,会得到一个后缀名为.sql文件,我们需要将sql语句导入数据库中。我们可以使用:
source + sql语句地址
于是得到:
3.实现
3.1用户界面初始化
package com.sdnu;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
/**
* @author Beyong
* @Description JdbcTest5
* @date 2021/07/19 12:52
*/
public class JdbcTest5 {
public static void main(String[] args) {
Map<String, String> userLoginInfo = initUI();
}
private static Map<String, String> initUI(){
Scanner user = new Scanner(System.in);
System.out.println("Please input userName: ");
String userName = user.next();
System.out.println("Please input password: ");
String passWord = user.next();
Map<String, String> userLoginInfo = new HashMap<>();
userLoginInfo.put("userName", userName);
userLoginInfo.put("passWord", passWord);
return userLoginInfo;
}
}
3.2登录方法实现
package com.sdnu;
import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
/**
* @author Beyong
* @Description JdbcTest5
* @date 2021/07/19 12:52
*/
public class JdbcTest5 {
public static void main(String[] args) {
Map<String, String> userLoginInfo = initUI();
boolean loginSucceed = login(userLoginInfo);
System.out.println(loginSucceed ? "登录成功" : "登录失败");
}
private static boolean login(Map<String, String> userLoginInfo) {
boolean loginSucceed = false;
Connection conn;
Statement stmt = null;
ResultSet rs = null;
try{
//1.注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2.获取连接
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydatabase?" +
"useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&" +
"allowMultiQueries=true&serverTimezone=Asia/Shanghai","root",
"123");
//3.获取数据库操作对象
stmt = conn.createStatement();
//4.执行sql语句
String sql = "SELECT * FROM t_user WHERE loginName = '"+userLoginInfo.get("userName")+"' AND loginPwd = '"+userLoginInfo.get("passWord")+"'";
rs = stmt.executeQuery(sql);
//5.处理查询结果
if(rs.next()){
loginSucceed = true;
}
return loginSucceed;
}catch(ClassNotFoundException e){
e.printStackTrace();
}catch(SQLException e){
e.printStackTrace();
}finally{
//6.释放资源
if( rs != null ){
try{
rs.close();
}catch(SQLException e) {
e.printStackTrace();
}
}
if( stmt != null){
try{
stmt.close();
}catch(SQLException e){
e.printStackTrace();
}
}
}
return loginSucceed;
}
private static Map<String, String> initUI(){
Scanner user = new Scanner(System.in);
System.out.println("Please input userName: ");
String userName = user.next();
System.out.println("Please input password: ");
String passWord = user.next();
Map<String, String> userLoginInfo = new HashMap<>();
userLoginInfo.put("userName", userName);
userLoginInfo.put("passWord", passWord);
return userLoginInfo;
}
}
先在数据库中写入一些信息,然后测试。
4.sql注入
4.1sql注入问题
我随便写了一段话(当然不是太随便的),没想到还通过了,其实,这就是注入,这是黑客攻击使用的一种手段。
我们通过设立断点+debug来查找原因:
仔细观察下面的sql语句:
发现语句的意思改变了,后面加上了or ‘1’ = ‘1’,这当然永远为真。
来看一段简书上的解释:
4.2解决sql注入问题
解决思路:用户提供的信息不参与sql语句的编译。
使用java.sql.PreparedStatement
PreparedStatement接口继承java.sql.Statement
PreparedStatement是预编译对象。
PreparedStatement的原理是:先对sql语句的框架进行编译,然后再给sql语句传值。
package com.sdnu;
import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
/**
* @author Beyong
* @Description 解决注入问题
* @date 2021/07/19 18:56
*/
public class JdbcTest6 {
public static void main(String[] args) {
Map<String, String> userLoginInfo = initUI();
boolean loginSucceed = login(userLoginInfo);
System.out.println(loginSucceed ? "登录成功" : "登录失败");
}
private static boolean login(Map<String, String> userLoginInfo) {
boolean loginSucceed = false;
Connection conn;
PreparedStatement ps = null;
ResultSet rs = null;
String loginName = userLoginInfo.get("userName");
String loginPwd = userLoginInfo.get("passWord");
try{
//1.注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2.获取连接
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydatabase?" +
"useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&" +
"allowMultiQueries=true&serverTimezone=Asia/Shanghai","root",
"123");
//3.获取数据库操作对象
//其中一个?表示一个占位符,一个?将来只能传一个值,?不能使用引号引起来。
String sql = "SELECT * FROM t_user WHERE loginName = ? AND loginPwd = ? ";
//程序执行下面一条语句会将sql语句传给DBMS,然后DBMS对sql语句进行编译。
ps = conn.prepareStatement(sql);
//给占位符传值,jdbc的值下标从1开始。
ps.setString(1,loginName);
ps.setString(2,loginPwd);
//4.执行sql语句
rs = ps.executeQuery();
//5.处理查询结果
if(rs.next()){
loginSucceed = true;
}
return loginSucceed;
}catch(ClassNotFoundException e){
e.printStackTrace();
}catch(SQLException e){
e.printStackTrace();
}finally{
//6.释放资源
if( rs != null ){
try{
rs.close();
}catch(SQLException e) {
e.printStackTrace();
}
}
if( ps != null){
try{
ps.close();
}catch(SQLException e){
e.printStackTrace();
}
}
}
return loginSucceed;
}
private static Map<String, String> initUI(){
Scanner user = new Scanner(System.in);
System.out.println("Please input userName: ");
String userName = user.next();
System.out.println("Please input password: ");
String passWord = user.next();
Map<String, String> userLoginInfo = new HashMap<>();
userLoginInfo.put("userName", userName);
userLoginInfo.put("passWord", passWord);
return userLoginInfo;
}
}
4.3Statement和PreparedStatement的使用
PreparedStatement使用不需要注入的地方,Statement使用在需要注入的地方,比如我们使用淘宝网站的时候,有一个升序和降序按钮,它就需要注入。
作者:Beyong
出处:Beyong博客
github地址:https://github.com/beyong2019
本博客中未标明转载的文章归作者Beyong有,欢迎转载,但未经作者同意必须保留此段声明,且在文章明显位置给出原文连接,否则保留追究法律责任的权利。