JDBC连接Mysql数据库一实现登录注册功能


前言

JDBC是SUN公司制定的一套接口(interface)


1、需求

模拟用户登录功能的实现


2、业务描述

程序运行时,提供一个输入的入口,可以让用户输入用户名和密码。用户输入用户名和密码之后,提交信息,java程序收集到用户信息后,连接数据库验证用户名和密码是否合法。
合法:提示登陆成功
不合法:提示登陆失败


3、数据准备

在实际开发中,表的设计会使用专业的建模工具:power desiger来进行数据库表的设计。


4、编程步骤

1、初始化一个界面提供给用户输入,返回值是用户名和密码
2、验证用户名和密码


5、实现源码

public class Login01 {
    public static void main(String[] args) {

        /*初始化一个界面*/
        Map<String,String> loginIn = inintUI();
        /*验证用户名和密码*/
        boolean loginSuccess = Login(loginIn);
        System.out.println(loginSuccess == true ? "登陆成功" : "登陆失败");

    }

    /**
     * 用户登录
     * @param loginIn 用户登录
     * @return 返回true表示登陆成功,返回false表示登陆失败
     */
    private static boolean Login(Map<String, String> loginIn) {

        /*打标记*/
        boolean loginSuccess = false;

        /*获取配置文件*/
        ResourceBundle bundle = ResourceBundle.getBundle("jdbc");

        /*准备一个连接对象*/
        Connection connection = null;
        /*准备一个数据库操作对象*/
        Statement statement = null;
        /*准备一个结果集对象*/
        ResultSet resultSet = null;
        try {
            /*注册驱动*/
            Class.forName(bundle.getString("driver"));

            /*获取连接*/
            connection = DriverManager.getConnection(bundle.getString("url"),bundle.getString("user"),bundle.getString("password"));

            /*获取数据库操作对象*/
            statement = connection.createStatement();

            /*执行SQL*/
            String sql1 = "select loginName,loginPwd from t_user where loginName = '"+loginIn.get("loginName")+"' and loginPwd = '"+loginIn.get("loginPwd")+"'";
            resultSet = statement.executeQuery(sql1);

            /*处理结果集*/
            if (resultSet.next()) {
                /*登陆成功*/
                loginSuccess = true;
            }

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            /*释放资源*/
            if (resultSet != null) {
                try {
                    resultSet.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
            if (statement != null) {
                try {
                    statement.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
            if (connection != null) {
                try {
                    connection.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
        }
        return loginSuccess;
    }

    /**
     * 初始化用户界面
     * @return 返回用户登录的用户名和密码
     */
    private static Map<String, String> inintUI() {

        /*接受用户输入*/
        Scanner s = new Scanner(System.in);

        /*提醒输入*/
        System.out.println("请输入您的用户名: ");
        String uname = s.nextLine();

        System.out.println("请输入您的密码: ");
        String upassword = s.nextLine();

        /*将用户输入放入集合,返回用户输入给JVM*/
        Map<String,String> userlogin = new HashMap<>();
        userlogin.put("loginName",uname);
        userlogin.put("loginPwd",upassword);
            return userlogin;
    }
}

6、程序存在bug

用户名:fdsa
密码:fdsa’ or ‘1’='1
显示登陆成功,但数据库中并没有这些数据,这种现象被称作SQL注入。

(1)导致这种现象的原因是什么?

Debug查看sql语句:

select loginName,loginPwd from t_user where loginName = 'fdsa' and loginPwd = 'fdsa'or'1'='1

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

(2)解决SQL注入

只要用户提供的信息不参与SQL语句的编译过程,问题就解决了。即使用户提供的信息中含有SQL语句的关键字,但只要不参与编译,就不会起作用。要想用户信息不参与SQL语句的编译,那么必须使用java.sql.preparedstatement(预编译的数据库操作对象)

preparedstatement的原理:

预先对SQL语句的框架进行编译,然后再给SQL语句传入值。

preparedstatement的使用:

①先准备一个预编译的数据库操作对象

/*准备一个预编译的数据库操作对象*/
PreparedStatement prestatement = null;

②写出sql语句的框架;调用preparestatement方法传入sql
其中一个?是一个占位符,一个?表示将来接受一个值,注意:占位符不能使用单引号括起来

String sql1 = "select loginName,loginPwd from t_user where loginName = ? and loginPwd = ?";
prestatement =  connection.prepareStatement(sql1);

③给占位符传入值
第一个?下标是1,第二个?下标是2。JDBC中所有下标从1开始

//给占位符传入值
prestatement.setString(1,loginIn.get("loginName"));
prestatement.setString(2,loginIn.get("loginPwd"));
resultSet = prestatement.executeQuery();
(3)总结:

解决sql注入的关键是:即使用户传入了sql语句的关键字,只要让这些关键字不参与sql语句的编译,就不会存在sql注入。


7、对比一下statement和preparestatement:

①statement存在sql注入的问题,preparestatement解决了sql注入的问题;
②statement是编译一次执行一次,preparestatement是编译一次执行N次;
③preparestatement会在编译阶段进行类型的安全检查。

综上所述:preparestatement在大多情况下使用,只有极少数需要进行sql注入的情况下才会使用statement。

补充知识点:mysql在查询时,如果两次查询使用了相同的查询语句,第一次会进行编译,第二次就不会编译,会直接调用第一次的查询结果。

什么情况下必须使用statement呢?

业务方面要求必须支持sql注入的时候使用statement,statement支持sql注入,凡是业务方面要求是需要对sql语句进行拼接的,必须使用statement(例:升序降序排列时)。如果只需要传入值得到结果,就使用preparestatement。

例:用户输入desc就是降序,输入asc就是升序排列

public class JDBCTest08 {
    public static void main(String[] args) {

        /*接受用户输入*/
        List<String> inputList = input();
        /*执行排序*/
        Sorting(inputList);
    }

    private static void Sorting(List<String> inputList) {

        /*获取配置文件*/
        ResourceBundle bundle = ResourceBundle.getBundle("jdbc");

        /*准备连接对象*/
        Connection conn = null;
        /*准备数据库操作对象*/
        Statement statement = null;
        /*准备一个结果集对象*/
        ResultSet resultSet = null;
        try {
            /*注册驱动*/
            Class.forName(bundle.getString("driver"));

            /*建立连接*/
            conn = DriverManager.getConnection(bundle.getString("url"),bundle.getString("user"),bundle.getString("password"));

            /*获取操作对象*/
            statement = conn.createStatement();

            /*执行sql*/
            String sql1 = "select ename,sal from emp order by sal " + inputList.get(0);
            resultSet = statement.executeQuery(sql1);

            /*遍历结果集*/
            while (resultSet.next()) {
            String ename = resultSet.getString("ename");
            double sal = resultSet.getDouble("sal");
                System.out.println(ename + " " + sal);

            }


        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            /*释放资源*/
            if (resultSet != null) {
                try {
                    resultSet.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
            if (statement != null) {
                try {
                    statement.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
        }
    }

    private static List<String> input() {

        /*接收用户输入*/
        Scanner s = new Scanner(System.in);

        System.out.println("desc表示降序,asc表示升序");
        System.out.println("请输入desc或asc : ");

        String in = s.nextLine();

        List<String> userInput = new ArrayList<>();
        userInput.add(in);

    return userInput;
    }
}
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值