zoukankan      html  css  js  c++  java
  • BenUtils组件和DbUtils组件

     

    [TOC]

    1.BenUtils组件

    1.1.简介

    程序中对javabean的操作很频繁,所有Apache提供了一套开源api,方便javabean的操作!即BeanUtils组件
    BeanUtils组件的作用就是简化javabean的操作

    使用BeanUtils组件

    1. 引入commons-beanutils-1.8.3.jar核心包
    2. 引入日志支持包: commons-logging-1.1.3.jar
      即使用BeanUtils必须导入两个包才可以

    1.2.基本用法,对象属性,对象,map的拷贝

    BeanUtils中有个常用的方法来拷贝数据:
    1.对象属性的拷贝

    BeanUtils.conProperty(admin,"name","jack");
    BeanUtils.setProperty(admin,"psw","123456");
    上面的两个方法作用是一样的,

    2.对象的拷贝

    BeanUtils.copyProperties(newAdmin,admin);

    3.Map数据拷贝到javabean中

    BeanUtils.populate(adminMap,map);
    注意:map中的key要与javabean的属性名称一样

    代码示例:

    
    /**
     * 测试BeanUtils
     * Created by cenyu on 16-12-17.
     */
    public class BeanUtilsDemo {
    
        //1.对javabean的基本操作
        @Test
        public void test1() throws InvocationTargetException, IllegalAccessException {
            //1.基本操作
            Admin admin = new Admin();
    //        admin.setName("jack");
    //        admin.setPsw("123456");
    
            //2.BeanUtils组件实现对象属性的拷贝
            BeanUtils.copyProperty(admin,"name","juerry");
            BeanUtils.copyProperty(admin,"psw","123456");
            //总结1:对于基本数据类型,会自动进行类型转换!
    
            //3.对象的拷贝
            //把admin对象拷贝到一个新的对象。
            Admin newAdmin = new Admin();
            //第一个参数是新对象,第二个参数是要拷贝的对象
            BeanUtils.copyProperties(newAdmin,admin);
    
            //4.map数据,拷贝到对象中
            //定义一个新的Admin对象,此时name和psw的值都是空的
            Admin adminMap = new Admin();
            //创建一个Map对象,并放进去两个值
            Map<String,Object> map = new HashMap<String,Object>();
            map.put("name","Tom");
            map.put("psw","32453");
            //注意:map中的key要与javabean的属性名称一致
            BeanUtils.populate(adminMap,map);
    
            
            //测试
            System.out.println(adminMap.getName());
            System.out.println(admin.getPsw());
        }
    }

    1.3.日期类的拷贝

    由于表单进来的数据都是String类型,也就是说表单填写一个日期类型,但是在实体要存放的是日期类型,这个时候就要对接收到的数据进行转换格式,常用的转换格式有两种:
    一种是使用自定义方法,重写转换方法
    另外一种是使用BeanUtils提供的日期类型转换工具,但是这种转换工具有一个问题就是可以为null,但是不能为空,为空的化报错
    示例代码如下:

        //2.自定义日期类型转换器
        //需求:从表单接受过来的数据都是字符串,如果中间有时间,就要把字符串转换成日期类型
        @Test
        public void test2() throws InvocationTargetException, IllegalAccessException {
            //模拟表单数据
            String name = "jack";
            String age = "20";
            String birth = "1999-03-24";
    
            //对象
            Admin admin=new Admin();
    
            //注册日期类型转换器
            //1.自定义的方式
    //        ConvertUtils.register(new Converter() {
    //            //转换器的内部实现方法,需要重写
    //            @Override
    //            public Object convert(Class type, Object value) {
    //                //判断
    //                if (type != Date.class){
    //                    return  null;
    //                }
    //                if (value == null || "".equals(value.toString().trim())){
    //                    return null;
    //                }
    //
    //                try {
    //                    //字符串转换为日期
    //                    SimpleDateFormat sdf = new SimpleDateFormat("yyy-MM-dd");
    //                    return sdf.parse(value.toString());
    //                } catch (ParseException e) {
    //                    e.printStackTrace();
    //                    throw new RuntimeException(e);
    //                }
    //            
    //        }, Date.class);
    
            //日期类型转发方式2:
            //使用提供的日期类型转换工具类
            ConvertUtils.register(new DateLocaleConverter(),Date.class);
    
    
            //把表单提交的数据,封装到对象中
            BeanUtils.copyProperty(admin,"name",name);
            BeanUtils.copyProperty(admin,"age",age);
            BeanUtils.copyProperty(admin,"birth",birth);
    
    
            //测试
            System.out.println(admin);
    
        }

    ```

    1.4.封装表单数据到实体

    在servlet中,我们接收jsp传递过来的表单参数,之前的做法是通过request的方法来获取参数值,然后保存早实体对象中,但是这样做是写死的,修改起来会很麻烦,现在将这个过程重新优化封装一下:
    常用的抽象方式有两种,第一种可以使用手写的方法,第一种通过使用BeanUtils工具类,由于两种方法都是抽取出来的抽象方法,所以这个方法是通用的,我们把该方法单独抽取出来,然后在Servlet中调用该方法

    用代码分别展示如何在Servlet中接收jsp表单的数据然后封装到实体对象中:
    方法在单独一个类中的封装:

    /**
     * 封装从jsp表单中获取参数保存到实体的过程
     * Created by cenyu on 16-12-17.
     */
    
    public class WebUtil {
    
    
        @Deprecated
        public static <T> T copyToBean_old(HttpServletRequest request, Class<T> clazz) {
            try {
                // 创建对象
                T t = clazz.newInstance();
    
                // 获取所有的表单元素的名称
                //getParameterNames();将请求页面中的form表单里所欲具有name属性的表单对象获取,返回一个Enumeration
                Enumeration<String> enums = request.getParameterNames();
                // 遍历
                while (enums.hasMoreElements()) {
                    // 获取表单元素的名称:<input type="password" name="pwd"/>
                    String name = enums.nextElement();  // pwd
                    // 获取名称对应的值
                    String value = request.getParameter(name);
                    // 把指定属性名称对应的值进行拷贝
                    BeanUtils.copyProperty(t, name, value);
                }
    
                return t;
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    
        /**
         * 处理请求数据的封装
         */
        public static <T> T copyToBean(HttpServletRequest request, Class<T> clazz) {
            try {
                // (注册日期类型转换器)
                // 创建对象
                T t = clazz.newInstance();
                BeanUtils.populate(t, request.getParameterMap());
                return t;
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

    调用疯转的结果:
    在Servlet的doGet()方法里面进行方法调用:

    /**
     * 调用jsp表单参数保存到实体对象方法的封装
     * Created by cenyu on 16-12-17.
     */
    public class copyServlet extends javax.servlet.http.HttpServlet {
        protected void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {
            this.doGet(request,response);
        }
        protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {
    
            //使用WebUtil组件处理请求数据的封装
            WebUtil.copyToBean(request, Admin.class);
            
            //已经把表单参数封装到实体,可以进行其他操作了
    
        }
    }

    2.BeanUtils组件优化DAO更新和查询数据库方法

    2.1.对元数据的操作

    此处的元数据是指数据库的定义数据,例如:数据库,表,列的定义信息。使用jdbc来获取这些信息就会使用到元数据
    在jdbc中可以使用:数据元数据,参数元数据,结果集元数据
    常用方法代码:

    /**
     * Created by cenyu on 16-12-17.
     * 测试元数据
     */
    public class metaDataDemo {
        //1.数据库元数据
        @Test
        public void testDB() throws Exception{
            //获取连接
            Connection conn = JdbcUtils.getConnection();
            //创建数据库元数据对象
            DatabaseMetaData metaData=conn.getMetaData();
            //数据库元数据的方法
            //getURL():返回一个String类对象,代表数据库的URL。
            System.out.println(metaData.getURL());
            //getUserName():返回连接当前数据库管理系统的用户名。
            System.out.println(metaData.getUserName());
            //getDatabaseProductName():返回数据库的产品名称。
            System.out.println(metaData.getDatabaseProductName());
        }
    
        //2.参数元数据
        @Test
        public void testParams() throws Exception{
            //获取连接
            Connection conn = JdbcUtils.getConnection();
            //SQL
            String sql = "select * form student where id = ? and name = ?";
            PreparedStatement pstmt = conn.prepareStatement(sql);
            //获取参数元数据
            ParameterMetaData p_metaDate = pstmt.getParameterMetaData();
            //获取参数的个数
            int count = p_metaDate.getParameterCount();
    
            //测试
            System.out.println(count);
        }
    
        //3.结果集元数据
        @Test
        public void testRs() throws Exception{
            String sql = "select * from student";
            //获取连接
            Connection conn = JdbcUtils.getConnection();
            PreparedStatement pstmt = conn.prepareStatement(sql);
            ResultSet rs = pstmt.executeQuery();
            //得到结果集元数据(目标:通过结果集元数据,得到列的名称)
            ResultSetMetaData rs_metaData = rs.getMetaData();
    
            //迭代每一行结果
            while (rs.next()){
                //1.获取列的个数
                int count = rs_metaData.getColumnCount();
                //2.遍历,后去每一列的列名称
                for (int i = 0; i < count ; i++) {
                    //得到列的名称
                    String columnName=rs_metaData.getColumnClassName(i+1);
                    //获取每一行的每一列的值
                    Object columnValue = rs.getObject(columnName);
                    //测试
                    System.out.println(columnName+"="+columnValue);
                }
                System.out.println();
            }
        }
    }

    2.2.抽取DAO的更新和查询方法

    在DAO中要经常使用对数据库的更新和查询操作,使用频繁且重复代码跟高,这个时候,我们把DAO中根据对数据库的操作不同,抽取出两个通用方法分别为插入,更改,删除的更新方法update方法和查询的query方法。通用方法接收一个sql语句,一个参数列表,一个操作对象。
    1.现在假设数据库Admin有userName和password这两个字段,实体Admin也只有这个这两个方法,首先,我们在DAO中写出一个BaseDao类用来存放抽取出来的update和query方法
    代码示例如下:

    /**
     * Created by cenyu on 16-12-17.
     * 调用的dao,自己写的所有的dao都继承此类
     * 此类定义了两个通用的方法
     * 1.更新(插入,修改,删除)
     * 2.查询(select语句)
     */
    public class BaseDao {
        //初始化参数
        private Connection conn;
        private PreparedStatement pstmt;
        private ResultSet rs;
    
        //插入,更改,删除通用方法
        public void update(String sql, Object[] patamsValue){
    
    
            try {
                //获取连接
                conn=JdbcUtils.getConnection();
                //创建执行命令的stmt对象
                pstmt=conn.prepareStatement(sql);
                //参数元数据,得到占位符参数的个数
                int count = pstmt.getParameterMetaData().getParameterCount();
                //设置占位符参数的值
                if (patamsValue != null && patamsValue.length>0){
                    //循环给参数赋值
                    for (int i = 0; i < count; i++) {
                        pstmt.setObject(i+1,patamsValue[i]);
                    }
                    //执行更新
                    pstmt.executeUpdate();
                }
            } catch (SQLException e) {
                e.printStackTrace();
                throw new RuntimeException(e);
            }finally {
                JdbcUtils.closeAll(conn,pstmt,null);
            }
        }
    
    
        //查询通用方法
        public <T> List<T> query(String sql,Object[] paramsValue,Class<T> clazz){
    
            try {
                //返回的集合
                List<T> list = new ArrayList<T>();
                //对象
                T t = null;
                //1.获取连接
                conn=JdbcUtils.getConnection();
                //2.创建爱女stmt对象
                pstmt = conn.prepareStatement(sql);
                //3.获取占位符参数的个数,并设置每个参数的值
                int count = pstmt.getParameterMetaData().getParameterCount();
                if (paramsValue != null && paramsValue.length>0){
                    for (int i = 0; i < paramsValue.length; i++) {
                        pstmt.setObject(i+1,paramsValue[i]);
                    }
                }
                //4.执行查询
                rs = pstmt.executeQuery();
                //5.获取结果集元数据
                ResultSetMetaData rsmd = rs.getMetaData();
                //获取列的个数
                int coiumnCount = rsmd.getColumnCount();
                //6.遍历结果集(rs)
                while (rs.next()) {
                    //要封装的对象
                    t = clazz.newInstance();
                    //7.遍历每一行的每一列,封装到数据
                    for (int i = 0; i < coiumnCount ; i++) {
                        //获取每一列的列名称
                        String columnName = rsmd.getColumnName(i+1);
                        //获取每一列的列名称,对应的值
                        Object value = rs.getObject(columnName);
                        //封装,设置到t对象的属性中
                        BeanUtils.copyProperty(t,columnName,value);
                    }
                    //把封装完毕的对象,添加到集合中
                    list.add(t);
                }
                return list;
            }catch (Exception e){
                throw new RuntimeException(e);
            }finally {
                JdbcUtils.closeAll(conn,pstmt,null);
            }
        }
    }

    2.通用方法写完之后,我们写具体的DAO方法,通过继承BaseDao类,只需要写参数,然后调用父类中的方法就可以了
    示例代码如下:

    /**
     * Created by cenyu on 16-12-18.
     * 继承BaseDao,实现具体的数据库操作方法
     */
    public class AdminDao extends BaseDao{
    
        //删除
        public void delete(int id){
            String sql = "delete from Admin where id =? ";
            Object[] paramsValue = {id};
            super.update(sql,paramsValue);
        }
        //插入
        public void save(Admin admin){
            String sql = "insert into Admin (userName,password) values (?,?)";
            Object[] paramsValue = {admin.getUserName(),admin.getPassword()};
            super.update(sql,paramsValue);
        }
    
    
        //查询
        public List<Admin> getAll(){
            String sql = "select * from Admin";
            List<Admin> list = super.query(sql,null,Admin.class);
            return list;
        }
    
        //根据条件查询(主键)
        public Admin findById(int id){
            String sql = "select * from admin where id=?";
            List<Admin> list = super.query(sql,new Object[]{id},Admin.class);
            return (list!=null&&list.size()>0) ? list.get(0) : null;
        }
    }

    3.Dao方法已经写好,这个时候我们可以在其他地方调用Dao里面的方法对数据进行操作了。
    测试类代码如下:

    /**
     * Created by cenyu on 16-12-18.s
     * 测试继承自BaseDao的Dao方法
     */
    public class AdminDaoTest {
    
    
        //测试删除id=8
        @Test
        public void testdelete(){
            AdminDao adminDao = new AdminDao();
            adminDao.delete(6);
        }
    
        //插入测试
        @Test
        public void testInsert(){
            AdminDao adminDao = new AdminDao();
            Admin admin = new Admin();
            admin.setUserName("cenyu");
            admin.setPassword("cenyu");
            adminDao.save(admin);
        }
    
        //测试查询
        @Test
        public void testquery() throws Exception{
            AdminDao adminDao = new AdminDao();
    
            List<Admin> list = adminDao.getAll();
            System.out.println(list);
        }
    }

    3.DbUtils组件

    3.1.DBUtils组件简介

    commons-dbutils是Apache组织提供的一个开源JDBC工具类库,他是对JDBC的简单封装,学习成本极地,并且使用dbutils能极简化jdbc编码的工作量,同时也不会影响程序的性能
    使用方法:
    引入jar文件:commons-dbutils-1.6.jar

    组件常用API介绍:

    • org.apache.commons.dbutils.QueryRunner
      数据库查询的类库,主要是CURD操作

    • org.apache.commons.dbutils.ResultSetHandler
      处理ResultSet,将查询结果的数据按要求转换为另一种形式
      工具类:
      org.apache.commons.dbutils.DbUtils
      dbutils关闭资源,加载驱动

    3.2.QueryRunner类使用方法

    QueryRunner类简化了SQL的查询工作,与ResultSetHandle组合在一起使用可以完成大部分的数据库操作,能够大大减少编码量
    1.QueryRunner类提供了两个构造方法

    • 默认构造方法
    • 需要一个javax.sql.DataSource来做参数的构造方法

    2.QueryRunner类的主要方法
    public Object query(Connection conn, String sql, Object[] params, ResultSetHandler rsh) :

    执行一个查询操作,在这个查询中,对象数组中的每个元素值被用来作为查询语句的置换参数。该方法会自行处理 PreparedStatement 和 ResultSet 的创建和关闭。

    public Object query(String sql, Object[] params, ResultSetHandler rsh) : 

    几乎与第一种方法一样;唯一的不同在于它不将数据库连接提供给方法,并且它是从提供给构造方法的数据源(DataSource) 或使用的setDataSource 方法中重新获得 Connection。

    public Object query(Connection conn, String sql, ResultSetHandler rsh):

    执行一个不需要置换参数的查询操作。

    public int update(Connection conn, String sql, Object[] params):

    用来执行一个更新(插入、更新或删除)操作。

    public int update(Connection conn, String sql) :

    用来执行一个不需要置换参数的更新操作。

    代码示例:

    /**
     * 使用dbutils组件的QueryRunner类完成CURD,以及批处理
     * Created by cenyu on 16-12-18.
     */
    public class bdutilsUpdate {
        private Connection conn;
    
        //1.删除
        @Test
        public void testDelete() throws SQLException {
            String sql = "delete from Admin where id=?";
            //连接对象
            conn = JdbcUtils.getConnection();
            //创建DBUtils核心工具类对象
            QueryRunner qr=new QueryRunner();
            qr.update(conn,sql,3);//一个参数
            //关闭
            DbUtils.close(conn);
        }
    
        //2.插入
        @Test
        public void testInsert() throws SQLException {
            String sql = "INSERT INTO Admin(userName,password) VALUES (?,?)";
            //连接对象
            conn = JdbcUtils.getConnection();
            //创建DBUtils核心工具类对象
            QueryRunner qr=new QueryRunner();
            qr.update(conn,sql,"a111","a111");//两个参数
            //关闭
            DbUtils.close(conn);
        }
    
    
        //3.更改
        @Test
        public void testUpdate() throws SQLException {
            String sql = "UPDATE Admin SET userName=? WHERE id=?;";
            //连接对象
            conn = JdbcUtils.getConnection();
            //创建DBUtils核心工具类对象
            QueryRunner qr=new QueryRunner();
            qr.update(conn,sql,"Juerry",5);//两个参数
            //关闭
            DbUtils.close(conn);
        }
    
    
        //4.查询
        @Test
        public void testFind() throws SQLException {
            String sql = "select * from Admin where id=?";
            //连接对象
            conn = JdbcUtils.getConnection();
            //创建DBUtils核心工具类对象
            QueryRunner qr=new QueryRunner();
            Admin admin=qr.query(conn,sql,new BeanHandler<Admin>(Admin.class),5);
            //关闭
            System.out.println(admin);
            DbUtils.close(conn);
        }
    
        //5.批处理
        @Test
        public void testBatch() throws SQLException {
            String sql = "insert into Admin (userName, password) values(?,?)";
            conn = JdbcUtils.getConnection();
            QueryRunner qr = new QueryRunner();
            //批量处理
            qr.batch(conn,sql,new Object[][]{{"jack1","888"},{"jack","999"}});
            //关闭
            conn.close();
        }
    }

    3.3.ResultSetHandler接口使用方法

    ResultSetHandler接口用于处理java.sql.ResultSet,将数据按要求转换为另一种形式
    ResultSetHandler接口的实现类
    BeanHandler:将结果集中的第一行数据封装到一个对应的JavaBean实例中。
    BeanListHandler:将结果集中的每一行数据都封装到一个对应的JavaBean实例中,存放到List里。
    ArrayHandler:把结果集中的第一行数据转成对象数组。
    ArrayListHandler:把结果集中的每一行数据都转成一个数组,再存放到List中。
    ScalarHandler 查询返回结果记录的第一行的第一列 (在聚合函数统计的时候用)
    MapHandler 查询返回结果的第一条记录封装为map

    代码示例:

    /**
     * 测试ResultSetHandler对查询结构的封装类
     * Created by cenyu on 16-12-18.
     */
    public class bdutilsQuery {
        private Connection conn;
    
        // 一、查询, 自定义结果集封装数据
        @Test
        public void testQuery() throws Exception {
            String sql = "select * from admin where id=?";
            // 获取连接
            conn = JdbcUtils.getConnection();
            // 创建DbUtils核心工具类对象
            QueryRunner qr = new QueryRunner();
            // 查询
            Admin admin = qr.query(conn, sql, new ResultSetHandler<Admin>() {
    
                // 如何封装一个Admin对象
                public Admin handle(ResultSet rs) throws SQLException {
                    if (rs.next()) {
                        Admin admin = new Admin();
                        admin.setUserName(rs.getString("userName"));
                        admin.setPassword(rs.getString("password"));
                        return admin;
                    }
                    return null;
                }
    
            }, 29);
    
            // 测试
            System.out.println(admin);
            // 关闭
            conn.close();
    
        }
    
        // 二、查询, 使用组件提供的结果集对象封装数据
    
        // 1)BeanHandler: 查询返回单个对象
        @Test
        public void testQueryOne() throws Exception {
            String sql = "select * from admin where id=?";
            // 获取连接
            conn = JdbcUtils.getConnection();
            // 创建DbUtils核心工具类对象
            QueryRunner qr = new QueryRunner();
            // 查询返回单个对象
            Admin admin =  qr.query(conn, sql, new BeanHandler<Admin>(Admin.class), 29);
    
            System.out.println(admin);
            conn.close();
        }
    
        // 2)BeanListHandler: 查询返回list集合,集合元素是指定的对象
        @Test
        public void testQueryMany() throws Exception {
            String sql = "select * from admin";
            conn = JdbcUtils.getConnection();
            QueryRunner qr = new QueryRunner();
            // 查询全部数据
            List<Admin> list = qr.query(conn, sql, new BeanListHandler<Admin>(Admin.class));
    
            System.out.println(list);
            conn.close();
        }
        @Test
    //  3) ArrayHandler, 查询返回结果记录的第一行,封装对对象数组, 即返回:Object[]
    //  4) ArrayListHandler, 把查询的每一行都封装为对象数组,再添加到list集合中
    //  5) ScalarHandler 查询返回结果记录的第一行的第一列  (在聚合函数统计的时候用)
    //  6) MapHandler  查询返回结果的第一条记录封装为map
        public void testArray() throws Exception {
            String sql = "select * from admin";
            conn = JdbcUtils.getConnection();
            QueryRunner qr = new QueryRunner();
            // 查询
            //Object[] obj = qr.query(conn, sql, new ArrayHandler());
            //List<Object[]> list = qr.query(conn, sql, new ArrayListHandler());
            //Long num = qr.query(conn, sql, new ScalarHandler<Long>());
            Map<String, Object> map = qr.query(conn,sql, new MapHandler());
    
            conn.close();
        }
    }

    3.4.DbUtils工具类使用

     DbUtils :提供如关闭连接、装载JDBC驱动程序等常规工作的工具类,里面的所有方法都是静态的。主要方法如下:
    public static void close(…) throws java.sql.SQLException:

    DbUtils类提供了三个重载的关闭方法。这些方法检查所提供的参数是不是NULL,如果不是的话,它们就关闭Connection、Statement和ResultSet。

    public static void closeQuietly(…):

    这一类方法不仅能在Connection、Statement和ResultSet为NULL情况下避免关闭,还能隐藏一些在程序中抛出的SQLEeception。

    public static void commitAndCloseQuietly(Connection conn):

    用来提交连接,然后关闭连接,并且在关闭连接时不抛出SQL异常。

    public static boolean loadDriver(java.lang.String driverClassName):

    这一方装载并注册JDBC驱动程序,如果成功就返回true。使用该方法,你不需要捕捉这个异常ClassNotFoundException。

  • 相关阅读:
    电路维修 (广搜变形-双端队列bfs)
    靶形数独 (dfs+预处理+状态压缩)
    埃及分数问题(带乐观估计函数的迭代加深搜索算法-IDA*)
    weight (搜索对象的选取)
    Codeforces Round #506 (Div. 3)
    生日蛋糕 (poj1190) (dfs剪枝)
    校内模拟赛题面
    NOIP2013 D1T3 货车运输 zz耻辱记
    NOIP2011 D2T3 观光公交 做题笔记
    ARC 103
  • 原文地址:https://www.cnblogs.com/justuntil/p/7615674.html
Copyright © 2011-2022 走看看