9.30JavaWeb之PreparedStatement获取任意一个对象的属性值

9.30JavaWeb之PreparedStatement获取任意一个对象的属性值

获取一个对象的属性值

关键点:

  • 使用泛型方法来获取

    • 通过泛型的模式获取运行时类

    /*通过反射获取运行是要建立的类的引用*/
   /**
    * 建立泛型参数、泛型方法
    * <T>表示泛型方法
    * 方法名前面的T表示返回值类型
    * Class<T>当中的T表示对应的运行时类
    * @param clazz
    * @param sql
    * @param args
    * @param <T>
    * @return
    */
   public <T> T getInstance(Class<T> clazz, String sql, Object ...args) {
       Connection conn = null;
       PreparedStatement ps = null;
       ResultSet rs = null;
       try {
           //获取数据库连接
           conn = JDBCUtils.getConnection();
           //预编译sql
           ps = conn.prepareStatement(sql);
           //填充占位符
           for (int i=0; i<args.length; i++) {
               ps.setObject(i+1, args[i]);
          }
           //执行sql保存为结果集对象
           rs = ps.executeQuery();

           //获取结果集元数据
           ResultSetMetaData rsmd = rs.getMetaData();
           //获取列数
           int columnCount = rsmd.getColumnCount();
           //获取结果集
           if (rs.next()) {
               //通过反射获取运行时加载类建立对象的引用--->反射+泛型
               T t = clazz.newInstance(); //--->任何一个类在提供一个JavaBean对象的时候要提供一个空参的public权限的构造器,在这里使用
               /*
               方法当中返回一个t
               t由当前类决定的
                */
               //动态的获取列,列的数量为列数
               for (int j=0; j<columnCount; j++) {
                   //动态的获取列值--->结果集当中获取列值
                   Object columnValue = rs.getObject(j+1);
                   //获取每列的列名
                   String columnLabel = rsmd.getColumnLabel(j+1);
                   //动态获取加载的类的属性--->获取到域(T类型的)
                   Field field = clazz.getField(columnLabel);
                   //设置私有属性可访问
                   field.setAccessible(true);
                   //将对象属性设置成列值
                   field.set(t, columnValue);
              }
               return t;
          }
      }catch (Exception e) {
           e.printStackTrace();
      }
       return null;
  }

获取集合对象(多个对象)的属性值

查询结果集返回多条数据--->多个对象

新语法糖:--->list.forEach(System.out::println)

由于占位符的使用所以解决了SQL注入的问题

    /**
    * 查询一条sql语句返回多个结果集对象
    * 使用List进行封装然后再集中展示
    * @since JDK 1.8
    * @date 2021/09/30
    * @author Lucifer
    */
   public <T> List<T> getForList(Class<T> clazz, String sql, Object ...args) {
       Connection conn = null;
       PreparedStatement ps = null;
       ResultSet rs = null;
       try {
           //获取数据库连接
           conn = JDBCUtils.getConnection();
           //预编译sql
           ps = conn.prepareStatement(sql);
           //填充占位符
           for (int i=0; i<args.length; i++) {
               ps.setObject(i+1, args[i]);
          }
           //执行sql保存为结果集对象
           rs = ps.executeQuery();

           //获取结果集元数据
           ResultSetMetaData rsmd = rs.getMetaData();
           //获取列数
           int columnCount = rsmd.getColumnCount();
           //创建集合对象--->用于存储查询出的结果集对象
           ArrayList<T> list = new ArrayList<T>();
           //查询多条语句使用循环进行查询
           while (rs.next()) {
               T t = clazz.newInstance();
               //处理结果集每一行数据的每一列
               for (int j=0; j<columnCount; j++) {
                   //获取列值
                   Object columnValue = rs.getObject(j+1);

                   //获取列名
                   String columnLabel = rsmd.getColumnLabel(j+1);
                   //动态获取运行类
                   Field field = clazz.getDeclaredField(columnLabel);
                   field.setAccessible(true);
                   field.set(t, columnValue);
              }
               //将t对象添加进入集合数组
               list.add(t);
               /*
               查询未找到
               1、抛异常了
               2、没有数据了
                */
          }
           return list;
      }catch (Exception e) {
           e.printStackTrace();
      }
       return null;
  }

注意:

  • 占位符的目的是为了解决SQL注入问题

  • 避免拼串的发生

    /**
    * 针对所有得运行时类进行表的查询操作
    * @since JDK 1.8
    * @date 2021/09/30
    * @author Lucifer
    */
   public <T> T getInstanceSQL(Class<T> clazz, String sql, Object ...args) {
       Connection conn = null;
       PreparedStatement ps = null;
       ResultSet rs = null;
       try {
           //建立连接
           conn = JDBCUtils.getConnection();
           //预编译sql
           ps = conn.prepareStatement(sql);
           //填充占位符
           for (int i=0; i<args.length; i++) {
               ps.setObject(i+1, args[i]);
          }
           //执行查询操作
           rs = ps.executeQuery();

           //获取结果集元数据
           ResultSetMetaData rsmd = rs.getMetaData();
           //通过结果集元数据获取列数
           int columnCount = rsmd.getColumnCount();

           //查询表中第一行数据
           while (rs.next()) {
               //通过反射获取运行时加载类建立对象的引用--->反射+泛型
               T t = clazz.newInstance();
               //循环获取列值
               for (int j=0; j<columnCount; j++) {
                   //动态的获取列值--->结果集当中获取列值
                   Object columnValue = rs.getObject(j+1);
                   //获取每列的列名
                   String columnLabel = rsmd.getColumnLabel(j+1);
                   //动态获取加载的类的属性--->获取到域(T类型的)
                   Field field = clazz.getField(columnLabel);
                   //设置私有属性可访问
                   field.setAccessible(true);
                   //将对象属性设置成列值
                   field.set(t, columnValue);
              }
               return t;
          }
      }catch (Exception e) {
           e.printStackTrace();
      }
       return null;
  }

测试方法:

    @Test
   public void testLoginNo1() {
       //获取控制台内容
       Scanner scan = new Scanner(System.in);
       System.out.println("UserName:");
       String user = scan.next();

       System.out.println("PassWord:");
       String password = scan.next();

       //提供一个sql语句
       String sql = "select `name`, `password` from users where Name = ? and Password = ?";
       /*
       上诉的写法称为拼串,需要拼写sql语句。--->不是一个完整的sql语句,存在sql注入的风险
        */

       User returnUser = getInstanceSQL(User.class, sql, user, password);

       if (returnUser!=null){
           System.out.println("Successfully!");
      }else {
           System.out.println("UserName or PassWord Error!!!");
      }
  }

Preparestatement预编译sql语句--->预编译期间已经判断了sql的逻辑关系

Preparestatement可以传流文件,拼串不可以。

Preparestatement可以更高效的插入--->预编译期间只需要检验一次,后续的添加只需要填充占位符即可

Statement因为没有预编译,所以在拼串的时候可以改变其逻辑关系,由且变成或等

小结

  • 面向接口编程的思想

  • ORM思想


只需要面向JDBC接口编程

原则:

  • 不出现第三方的API

  • 将第三方API与代码解耦,第三方API封装到XML或者配置文件中,全程操作使用Driver对象进行操作--->多态的一种形式

一个JavaBean类对应到数据库当中的一张表

原则:

  • Java操作的任何东西都是以对象的方式进行呈现

    • getColumnCount

    • getColumnLabel

使用反射获取到运行时类进行加载获取属性

                    //动态获取加载的类的属性--->获取到域(T类型的)
                   Field field = clazz.getField(columnLabel);
                   //设置私有属性可访问
                   field.setAccessible(true);
                   //将对象属性设置成列值
                   field.set(t, columnValue);

 

It's a lonely road!!!
原文地址:https://www.cnblogs.com/JunkingBoy/p/15369371.html