1. 程式人生 > >BenUtils組件和DbUtils組件

BenUtils組件和DbUtils組件

內部 println 編碼 dstat dex 都是 ati ner 根據

[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。

BenUtils組件和DbUtils組件