JDBC(二)用户登录业务介绍、配置idea

通过反射机制完成注册

观察源码,可以看出已经写了注册的方法,所以通过反射拿到class文件
在这里插入图片描述

package JDBCTEST;

import java.sql.*;


public class JDBCTest04 {
    public static void main(String[] args) {
        Connection connection = null;
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            System.out.println("register is ok");

            String url = "jdbc:mysql://localhost:3306/mysql";
            String user = "root";
            String password = "333";

            connection = DriverManager.getConnection(url, user, password);
            System.out.println("database connection object is " + connection);

        } catch (SQLException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

在这里插入图片描述

报错记录

想通过ResourceBundle来配置

package JDBCTEST;
import java.sql.*;
import java.util.ResourceBundle;

public class JDBCTEST05 {
    public static void main(String[] args) throws Exception {

        ResourceBundle resourceBundle = ResourceBundle.getBundle("JDBC_Test");
        String MyDriver = resourceBundle.getString("MyDriver");
        String url = resourceBundle.getString("url");
        String user = resourceBundle.getString("user");
        String password = resourceBundle.getString("password");
        Connection connection = null;
        try {
            Class.forName(MyDriver);
            System.out.println("register is ok");

            connection = DriverManager.getConnection(url, user, password);
            System.out.println("database connection object is " + connection);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

然后配置文件也放在同一个目录下的

MyDriver="com.mysql.cj.jdbc.Driver"
url="jdbc:mysql://localhost:3306/mysql";
user="root";
password="333";

但是始终报错
Exception in thread “main” java.util.MissingResourceException: Can’t find bundle for base name JDBC_Test

这个问题百度了还是找不到,所以先搁置一下吧

更新一下:又重新配置了一个空的Project,可以使用,之前这个添加jar包报了以下错误
在这里插入图片描述

处理查询结果集

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

public class JDBC20210330 {
    public static void main(String[] args) {
        Connection connection = null;
        Statement statement = null;
        ResultSet rs = null;
        try {
            //注册驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            //获取连接
            connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mysql", "root", "333");
            //获取数据库操作对象
            statement = connection.createStatement();
            //执行sql语句
            String sql = "select empno,ename,sal from emp";
            rs = statement.executeQuery(sql);
            //处理查询的结果集
            //rs一次取一行,判断下一行是否有数据
            boolean flag1;
            while (flag1 = rs.next()) {

                String empno = rs.getString(1);
                String ename = rs.getString(2);
                //或者直接写成字段名,查询结果后的字段名,如果as重命名后,用重命名的
                //除了String类型,还有其他类型
                double sal = rs.getDouble("sal");
                System.out.println(empno + "," + ename + "," + (100 + sal));
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
        }
    }
}

处理的时候rs.next(),仿佛回到了迭代器的日子

在这里插入图片描述

配置intellij

在module上,配置module
在这里插入图片描述
open module settings
library里面添加jar包
在这里插入图片描述

用户登录业务介绍

配置数据库

PowerDesign工具

在百度上随便搜一个下载一下
在这里插入图片描述
选择对应数据库的版本,新建一个model
从右侧拖一个table过来
在这里插入图片描述
双击表,给表设置各种属性
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
可以直接保存为一个sql文件

稍微修改一下刚刚的sql 文件

准备数据集

drop table if exists t_User;

/*==============================================================*/
/* Table: t_User                                                */
/*==============================================================*/
create table t_User
(
   id                   bigint auto_increment,
   loginName            varchar(255),
   loginPassword        varchar(255),
   realName             varchar(255),
   primary key (id)
);

insert into t_user(loginName,loginPassword,realName)values("ZS","123","Zhangsan");
insert into t_user(loginName,loginPassword,realName)values("LS","123","Lisi");
insert into t_user(loginName,loginPassword,realName)values("Wangwu","123","王五");
commit;
select * from t_user;

在这里插入图片描述

写JDBC语句

分布来拆解
写出主程序,各个子模块定义方法即可
初始化界面+输出情况写在主方法里面

//模拟用户登录
public class JDBCTest02 {
    public static void main(String[] args) {
        //初始化UI界面,尽量把所有的子功能写成单独的方法
        //用Map来存
        Map<String, String> userLoginInfo = Initiate_UI();
        //验证用户名和密码
        System.out.println(userLoginInfo);
        //登录成功或者失败,就两种情况,所以用boolean
        boolean loginSuccess = login(userLoginInfo);
        System.out.println(loginSuccess ? "登录成功" : "登录失败");

    }

定义Initiate_UI()方法
利用Map存放密码和用户
放进一个HashMap里面

//上面给了返回值,那么生成的方法也一定要有返回值
    private static Map<String, String> Initiate_UI() {
    
        Scanner scanner = new Scanner(System.in);
        System.out.println("用户名:");
        //一次接受一行
        String userName = scanner.nextLine();
        System.out.println("密码:");
        String passWord = scanner.nextLine();
        Map<String, String> user_info = new HashMap<>();
        user_info.put("userName", userName);
        user_info.put("passWord", passWord);
        return user_info;
    }

定义login方法

private static boolean login(Map<String, String> userLoginInfo) {
        //定义变量
        boolean loginSuccess = false;
        //来自之前的Map集合,用来读取里面的数据
        String loginName = userLoginInfo.get("userName");
        String loginPassword = userLoginInfo.get("passWord");

        //JDBC代码,按照JDBC六步走

        Statement statement = null;
        Connection connection = null;
        ResultSet resultSet = null;
        try {
            //注册驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            //建立数据库连接
            connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mysql", "root", "333");
            //获取数据库操作对象
            statement = connection.createStatement();

            //执行Sql语句
            //注意在sql语句中写变量,是两个双引号和两个加号拼起来
            String sql = "select * from t_user where loginName='" + loginName + "' and loginPassword='" + loginPassword + "'";
            resultSet = statement.executeQuery(sql);
            //处理结果集
            //因为对错与否都只有一个结果,所以不需要whiletrue,只需要简单的if
            if (resultSet.next()) {
                loginSuccess = true;
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //释放资源
            if (statement != null) {
                try {
                    statement.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (connection != null)
                try {
                    connection.close();

                } catch (SQLException e) {
                    e.printStackTrace();
                }
            if (resultSet != null)
                try {
                    resultSet.close();

                } catch (SQLException e) {
                    e.printStackTrace();
                }
        }

        return loginSuccess;
    }

数据库里有三条记录

+----+-----------+---------------+----------+
| id | loginName | loginPassword | realName |
+----+-----------+---------------+----------+
|  1 | ZS        | 123           | Zhangsan |
|  2 | LS        | 123           | Lisi     |
|  3 | Wangwu    | 123           | 鐜嬩簲     |
+----+-----------+---------------+----------+

执行以上代码

用户名:
ZS
密码:
123
{passWord=123, userName=ZS}
登录成功
用户名:
Zhangsan
密码:
234
{passWord=234, userName=Zhangsan}
登录失败

上述完整代码

package BUPT20210330;

import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

//模拟用户登录
public class JDBCTest02 {
    public static void main(String[] args) {
        //初始化UI界面,尽量把所有的子功能写成单独的方法
        //用Map来存
        Map<String, String> userLoginInfo = Initiate_UI();
        //验证用户名和密码
        System.out.println(userLoginInfo);
        //登录成功或者失败,就两种情况,所以用boolean
        boolean loginSuccess = login(userLoginInfo);
        System.out.println(loginSuccess ? "登录成功" : "登录失败");

    }

    private static boolean login(Map<String, String> userLoginInfo) {
        //定义变量
        boolean loginSuccess = false;
        String loginName = userLoginInfo.get("userName");
        String loginPassword = userLoginInfo.get("passWord");

        //JDBC代码,按照JDBC六步走

        Statement statement = null;
        Connection connection = null;
        ResultSet resultSet = null;
        try {
            //注册驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            //建立数据库连接
            connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mysql", "root", "333");
            //获取数据库操作对象
            statement = connection.createStatement();

            //执行Sql语句
            //注意在sql语句中写变量,是两个双引号和两个加号拼起来
            String sql = "select * from t_user where loginName='" + loginName + "' and loginPassword='" + loginPassword + "'";
            resultSet = statement.executeQuery(sql);
            //处理结果集
            //因为对错与否都只有一个结果,所以不需要whiletrue,只需要简单的if
            if (resultSet.next()) {
                loginSuccess = true;
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //释放资源
            if (statement != null) {
                try {
                    statement.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (connection != null)
                try {
                    connection.close();

                } catch (SQLException e) {
                    e.printStackTrace();
                }
            if (resultSet != null)
                try {
                    resultSet.close();

                } catch (SQLException e) {
                    e.printStackTrace();
                }
        }

        return loginSuccess;
    }

    //上面给了返回值,那么生成的方法也一定要有返回值
    private static Map<String, String> Initiate_UI() {
        Scanner scanner = new Scanner(System.in);
        System.out.println("用户名:");
        //一次接受一行
        String userName = scanner.nextLine();
        System.out.println("密码:");
        String passWord = scanner.nextLine();
        Map<String, String> user_info = new HashMap<>();
        user_info.put("userName", userName);
        user_info.put("passWord", passWord);
        return user_info;
    }
}

SQL注入现象

用户名:
jdh
密码:
jdh' or '1'='1
{passWord=jdh' or '1'='1, userName=fdsa}
登录成功

即使这个用户名和密码不在库中,还是进了系统

  • 导致SQL注入的根本原因是什么?
    用户输入的信息中含有sql语句的关键字,并且这些关键字参与sql语句的编译过程,导致sql语句的原意被扭曲,进而达到sql注入。

解决注入现象:使用预编译

主要调整的部分
先写sql再获取预编译的操作对象
给占位符传值而不再需要用单引号自己写到参与编译的statement对象中

//获取预编译的数据库操作对象
            //先写sql语句,再传递到对象中,用问号作为占位符,都用预编译的写法prepareXX
            String sql = "select * from t_user where loginName=? and loginPassword=?";
            preparedStatement = connection.prepareStatement(sql);
            //给占位符?传值,第一个问号下标是1,从1开始,
            //不要给问号加引号,set的类型自己就会判断加不加
            preparedStatement.setString(1, loginName);
            preparedStatement.setString(2, loginPassword);
            //执行Sql语句就不用传参了
            resultSet = preparedStatement.executeQuery();

能够解决该问题

用户名:
jdh
密码:
jdh' or '1'='1
{passWord=jdh' or '1'='1, userName=jdh}
登录失败

Process finished with exit code 0

完整代码

package BUPT20210330;

import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

//解决sql注入的问题
public class JDBCTest03 {
    public static void main(String[] args) {
        //初始化UI界面,尽量把所有的子功能写成单独的方法
        //用Map来存
        Map<String, String> userLoginInfo = Initiate_UI();
        //验证用户名和密码
        System.out.println(userLoginInfo);
        //登录成功或者失败,就两种情况,所以用boolean
        boolean loginSuccess = login(userLoginInfo);
        System.out.println(loginSuccess ? "登录成功" : "登录失败");
    }

    private static boolean login(Map<String, String> userLoginInfo) {
        //定义变量
        boolean loginSuccess = false;
        String loginName = userLoginInfo.get("userName");
        String loginPassword = userLoginInfo.get("passWord");
        
        //JDBC代码,按照JDBC六步走
        PreparedStatement preparedStatement = null;
        Connection connection = null;
        ResultSet resultSet = null;
        try {
            //注册驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            //建立数据库连接
            connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mysql", "root", "333");
            //获取预编译的数据库操作对象
            //先写sql语句,再传递到对象中,用问号作为占位符,都用预编译的写法prepareXX
            String sql = "select * from t_user where loginName=? and loginPassword=?";
            preparedStatement = connection.prepareStatement(sql);
            //给占位符?传值,第一个问号下标是1,从1开始,不要给问号加引号,set的类型自己就会判断加不加
            preparedStatement.setString(1, loginName);
            preparedStatement.setString(2, loginPassword);
            //执行Sql语句就不用传参了
            resultSet = preparedStatement.executeQuery();
            //处理结果集
            //因为对错与否都只有一个结果,所以不需要whiletrue,只需要简单的if
            if (resultSet.next()) {
                loginSuccess = true;
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //释放资源
            if (preparedStatement != null) {
                try {
                    preparedStatement.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (connection != null)
                try {
                    connection.close();

                } catch (SQLException e) {
                    e.printStackTrace();
                }
            if (resultSet != null)
                try {
                    resultSet.close();

                } catch (SQLException e) {
                    e.printStackTrace();
                }
        }

        return loginSuccess;
    }

    //上面给了返回值,那么生成的方法也一定要有返回值
    private static Map<String, String> Initiate_UI() {
        Scanner scanner = new Scanner(System.in);
        System.out.println("用户名:");
        //一次接受一行
        String userName = scanner.nextLine();
        System.out.println("密码:");
        String passWord = scanner.nextLine();
        Map<String, String> user_info = new HashMap<>();
        user_info.put("userName", userName);
        user_info.put("passWord", passWord);
        return user_info;
    }
}

比较Statement和PreparedStatement

对比一下statement和Preparedstatement

  • Statement存在sql注入问题,Preparedstatement解决了sql注入问题。
  • Statement是编译一次执行一次。Preparedstatement是编译一次,可执行n次。Preparedstatement效率较高一些。
  • Preparedstatement会在编译阶段做类型的安全检查。

若是业务要求必须支持Sql注入的时候,就只能用Statement

比如写sql语句中包含一个 asc/desc排序,那么不能用占位符,占位符给进去就是一个字符串,而我们不能传用引号括起来的字符串
必须拼接用statement,传值用preparedstatement
如果还写成preparedstatement形式,就要报错

asc升序,desc降序
desc
java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; 

所以得改回statement形式

package BUPT20210330;

import java.sql.*;
import java.util.Scanner;

public class JDBCTest04 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.println("asc升序,desc降序");
        String keyword = scanner.nextLine();
        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mysql", "root", "333");
            String sql = "select * from emp order by sal " + keyword;
            statement = connection.createStatement();
            resultSet = statement.executeQuery(sql);
            while (resultSet.next()) {
                System.out.println(resultSet.getString("sal"));
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (statement != null) {
                try {
                    statement.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (connection != null) {
                try {
                    connection.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (resultSet != null) {
                try {
                    resultSet.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值