1. 程式人生 > >jdbc篇第8課:進一步封裝jdbc

jdbc篇第8課:進一步封裝jdbc

  這節課我們來進一步封裝jdbc

 

  首先來分析下,jdbc的使用:

jdbc使用:
     1. 建立好表對應的類(我們稱為bean),要求每一列對應一個屬性,且資料型別對應上
     2. 建立連線,獲取Connection物件
     3. 使用Connection物件獲取Statement或PreparedStatement物件
     4. 寫好sql
     5. 使用Statement或PreparedStatement執行查詢語句,如果是select語句,獲取ResultSet物件,並執行6和7
     6. 建一個或多個bean物件
     7. 獲取ResultSet裡儲存的值,並封裝到bean物件中
     8. 關閉連線

 

第1步的封裝以後講,這個可以算是另一個小專案了

第2、3步我們已經封裝好了,就是dbc

 

接下來就是封裝4、5、6、7

 

程式碼:

package com.tool;



import com.bean.Employee;

import com.util.ClassUtil;

import com.util.ObjectUtil;

import com.util.StringUtil;



import java.io.IOException;

import java.lang.reflect.Field;

import 
java.lang.reflect.InvocationTargetException; import java.sql.*; import java.util.ArrayList; import java.util.List; import java.util.Map; /**  *  * @param <E> bean的型別  * 一個bean對應一個表,且bean的類名用駝峰式命名,表的命名用下劃線全小寫命名  * 這個類是一個抽象類,必須有子類繼承並且給定E的型別  */ public abstract class
Mapper<E> {     private Connection connection;     public Mapper(Connection connection)     {         this.connection = connection;     }     public Mapper(String dbcPropertiesPath) throws SQLException, IOException, ClassNotFoundException {         this.connection = Dbc.getConnection(dbcPropertiesPath);     }     /**      * 將value轉換成合適的型別插入到合適的位置      */     private void castToSuitType(PreparedStatement preparedStatement,int index, Object value) throws SQLException {         Class<?> valueClass = value.getClass();         if (valueClass == String.class)         {             preparedStatement.setString(index, String.valueOf(value));         }         else if(valueClass == Integer.class || valueClass == int.class)         {             preparedStatement.setInt(index,(Integer)value);         }         else if (valueClass == Float.class || valueClass == float.class)         {             preparedStatement.setFloat(index,(Float) value);         }         else if (valueClass == Double.class || valueClass == double.class)         {             preparedStatement.setDouble(index,(Double) value);         }         else if (valueClass == Short.class || valueClass == short.class)         {             preparedStatement.setShort(index,(Short)value);         }         else         {             preparedStatement.setString(index, String.valueOf(value));         }     }     private <T> T castToSuitType(ResultSet resultSet,int index, Class<T> fieldClass) throws SQLException     {         Object value;         if (fieldClass == String.class)         {             value = resultSet.getString(index);         }         else if(fieldClass == Integer.class || fieldClass == int.class)         {             value = resultSet.getInt(index);         }         else if (fieldClass == Float.class || fieldClass == float.class)         {             value = resultSet.getFloat(index);         }         else if (fieldClass == Double.class || fieldClass == double.class)         {             value = resultSet.getDouble(index);         }         else if (fieldClass == Short.class || fieldClass == short.class)         {             value = resultSet.getShort(index);         }         else         {             value = resultSet.getString(index);         }         return (T)value;     }     /**      * 首先,我們要獲取所有的類列      * 每一列對應bean的類的一個屬性      * 列名用全小寫下劃線式      * 屬性名用首字母小寫的駝峰式      *      * 接下來我們需要幾個一個工具類來處理字串      * 當然,要用的工具類我都提前寫好了      */     /**      * 獲取泛型E的Class物件,即bean的型別的Class物件      * @return      */     public Class<E> getBeanClass()     {         return ClassUtil.getSuperClassGenricType(this.getClass());     }     /**      * 獲取表名      * @param      */     public String getTableName()     {         Class<E> beanClass = getBeanClass();         String className = beanClass.getName();         className = className.substring(className.lastIndexOf(".") +1);         String tableName = StringUtil.castCamelCaseToUnderline(className);         //保險起見首字母轉下小寫         tableName = StringUtil.firstLetterToLowerCase(tableName);         return tableName;     }     /**      * 獲取列名      * @return      */     public List<String>  getColumnNames()     {         Class<E> beanClass = getBeanClass();         Field[] fields = beanClass.getDeclaredFields();         List<String> columnNames = new ArrayList<String>(fields.length);         for (Field field : fields) {             String columnName = StringUtil.castCamelCaseToUnderline(field.getName());             //保險起見首字母轉下小寫             columnName = StringUtil.firstLetterToLowerCase(columnName);             columnNames.add(columnName);         }         return columnNames;     }     //接下來封裝增刪改查操作     public void insert(E e) throws SQLException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {         //String sql = "insert into tbl_employee (id,last_name,email,gender,d_id) values (?,?,?,?,?)";         String sql = "insert into ";         sql += getTableName() + " (";         List<String> columnNames = getColumnNames();         for (String columnName : columnNames) {             sql += columnName + ",";         }         //刪除最後一個逗號         sql = StringUtil.deleteLastChildString(sql,1);         sql += ") values (";         //說了含金量高的,索性寫複雜點         List<Object> valueList = ObjectUtil.getAllFieldValue(e);         for (Object value : valueList) {             //用?當佔位符             sql += "?,";         }         //刪除最後一個逗號         sql = StringUtil.deleteLastChildString(sql,1);         sql += ");";         PreparedStatement preparedStatement = connection.prepareStatement(sql);         for (int i = 0; i < valueList.size(); i++) {             //這個也是從1開始             castToSuitType(preparedStatement,i + 1,valueList.get(i));         }         preparedStatement.executeUpdate();         //總算把insert寫完了,後面的都差不多,我快點寫,就不寫註釋了     }     public void delete(int id) throws SQLException {         //String sql = "delete from tbl_employee where id = ?";         String sql = "delete from ";         sql += getTableName() + " ";         sql += "where ";         Class<E> beanClass = getBeanClass();         //注意,在寫bean類的時候必須將主鍵寫在最前面,否則,這個程式碼要寫的更加複雜,因為涉及到註解         String primaryKeyName = beanClass.getDeclaredFields()[0].getName();         sql += primaryKeyName + "= ?;";         PreparedStatement preparedStatement = connection.prepareStatement(sql);         preparedStatement.setInt(1,id);         preparedStatement.executeUpdate();     }     public void update(E e) throws SQLException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {         //String sql = "update tbl_employee set last_name = ?,email = ?,gender = ?, d_id = ? where id = ?";         String sql = "update " + getTableName() + " set ";         List<String> columnNames = getColumnNames();         String primaryKeyName = columnNames.remove(0);         for (String columnName : columnNames) {             sql += columnName + "=?,";         }         sql = StringUtil.deleteLastChildString(sql,1);         sql += " where " + primaryKeyName + "=?";         PreparedStatement preparedStatement = connection.prepareStatement(sql);         List<Object> valueList = ObjectUtil.getAllFieldValue(e);         Object primaryKeyValue = valueList.remove(0);         //主鍵被挪到了最後,在where那裡         valueList.add(primaryKeyValue);         for (int i = 0; i < valueList.size(); i++) {             castToSuitType(preparedStatement,i + 1,valueList.get(i));         }         preparedStatement.executeUpdate();     }     public E selectByPrimaryKey(Object primaryKey) throws SQLException, IllegalAccessException, InstantiationException, NoSuchMethodException, NoSuchFieldException, InvocationTargetException {         Class<E> beanClass = getBeanClass();         //以前說過,java bean必須有空建構函式,其實就是為了方便通過反射構造物件         E e = null;         //String sql = "select * from tbl_employee where id = ?";         String sql = "select ";         List<String> columnNames = getColumnNames();         for (String columnName : columnNames) {             sql += columnName + ",";         }         sql = StringUtil.deleteLastChildString(sql,1);         sql += " from " + getTableName() + " where ";                 //獲取主鍵名稱         String primaryKeyName = beanClass.getDeclaredFields()[0].getName();         sql += primaryKeyName + "= ?;";         PreparedStatement preparedStatement = connection.prepareStatement(sql);         castToSuitType(preparedStatement,1,primaryKey);         ResultSet resultSet = preparedStatement.executeQuery();         if (resultSet.next())         {             //查得到資料才new,否則返回null             e = getBeanFromResultSet(resultSet, beanClass);         }         return e;     }     /**      *      * @param conditionMap 鍵是列名,值是要匹配的值      * @return      */     public List<E> selectByExample(Map<String,Object> conditionMap) throws SQLException, IllegalAccessException, InstantiationException, NoSuchMethodException, NoSuchFieldException, InvocationTargetException {         List<E> resultList = new ArrayList<E>();         int size = conditionMap.keySet().size();         String[] keyArr = new String[size];         Object[] valueArr = conditionMap.values().toArray();         conditionMap.keySet().toArray(keyArr);         //String sql = "select * from tbl_employee where ";         String sql = "select ";         List<String> columnNames = getColumnNames();         for (String columnName : columnNames) {             sql += columnName + ",";         }         sql = StringUtil.deleteLastChildString(sql,1);         sql += " from " + getTableName() + " where ";         for (int i = 0; i < size; i++) {             sql += keyArr[i] + "=? and "; //and前後要加空格         }         //末尾多了一個and,去掉         sql = sql.substring(0,sql.lastIndexOf("and") - 1);         PreparedStatement preparedStatement = connection.prepareStatement(sql);         for (int i = 0; i < valueArr.length; i++) {             castToSuitType(preparedStatement,i + 1,valueArr[i]);         }         ResultSet resultSet = preparedStatement.executeQuery();         Class<E> beanClass = getBeanClass();         while (resultSet.next())         {             E e = getBeanFromResultSet(resultSet, beanClass);             resultList.add(e);         }         return resultList;     }     //提取點公共程式碼     public E getBeanFromResultSet(ResultSet resultSet,Class<E> beanClass) throws IllegalAccessException, InstantiationException, SQLException, NoSuchMethodException, NoSuchFieldException, InvocationTargetException {         E e = beanClass.newInstance();         Field[] fields = beanClass.getDeclaredFields();         for (int i = 0; i < fields.length; i++) {             //列數從1開始             Object value = castToSuitType(resultSet, i + 1, fields[i].getType());             ObjectUtil.setFieldValue(e,fields[i],value);         }         return e;     } }

 

使用:

public class EmployeeMapper extends Mapper<Employee> {





    public EmployeeMapper(Connection connection) {

        super(connection);

    }



    public EmployeeMapper(String dbcPropertiesPath) throws SQLException, IOException, ClassNotFoundException {

        super(dbcPropertiesPath);

    }

}

 

測試:

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



    //測一下,我也不確定我能不能一次寫對

    EmployeeMapper mapper = new EmployeeMapper("src/com/resource/dbc.properties");



    //通過

    Employee employee = mapper.selectByPrimaryKey(3);

    System.out.println(employee);



    //通過

    mapper.delete(100);



    //通過

    employee = new Employee(13,"mahuateng","[email protected]","1",1004);

    mapper.update(employee);



    //通過

    employee = new Employee(100,"xiaowang","[email protected]","0",1002);

    mapper.insert(employee);



    //通過

    Map<String,Object > map = new HashMap<String, Object>();

    map.put("gender","1");

    map.put("d_id",1002);

    List<Employee> employees = mapper.selectByExample(map);



    for (Employee employee1 : employees) {

        System.out.println(employee1);

    }

}

 

工具類:

package com.util;



//字串工具類

//這個工具類裡的所有方法要求看懂並且可以自己寫出來

//這個裡的所有方法全是我自己手寫出來的,要求你們也要可以手寫出來

public class StringUtil {



    /**

     * 將字串首字母轉換成大寫

     *

     * @param str 要轉換的字串

     * @return 返回str首字母大寫後的字串

     */

    public static String firstLetterToUpperCase(String str)

    {

        //這裡只替換第一個

        return str.replaceFirst(String.valueOf(str.charAt(0)),String.valueOf(str.charAt(0)).toUpperCase());

    }



    /**

     * 將字串首字母轉換成小寫

     *

     * @param str 要轉換的字串

     * @return 返回str首字母瞎寫寫後的字串

     */

    public static String firstLetterToLowerCase(String str)

    {

        //這裡只替換第一個

        return str.replaceFirst(String.valueOf(str.charAt(0)),String.valueOf(str.charAt(0)).toLowerCase());

    }



    /**

     * 駝峰轉下劃線

     *     解釋下什麼叫駝峰式,就是每個單詞的首字母大寫,其餘字母都小寫

     *     java推薦所有變數、方法、類都使用駝峰式命名

     *     類名一般第一個單詞的首字母也要大寫

     *     變數、方法第一個單詞的首字母小寫

     *     下劃線式是指全字母小寫或全字母大寫,單詞之間用下劃線分割,如cast_camel_case_to_underline

     *     常量採用全字母大寫加下劃線式

     */





    /**

     * 將駝峰式字串轉換成下劃線式

     *

     * @param str 駝峰式字串

     * @return 下劃線式字串

     */

    public static String castCamelCaseToUnderline(String str)

    {

        char[] chars = str.toCharArray();

        String result = "";

        for (char i : chars)

        {

            if (i >= 'A' && i <= 'Z')

            {

                result += "_" + String.valueOf(i).toLowerCase();

            }

            else

            {

                result += i;

            }

        }

        if (result.startsWith("_"))

        {

            result = result.substring(1);

        }

        return result;

    }



    /**

     * 將下劃線字串轉換成駝峰式

     *

     * @param str 下劃線式字串

     * @return 駝峰式字串

     */

    public static String castUnderlineToCamelCase(String str)

    {

        String[] split = str.split("_");

        String result = "";

        for (String s : split)

        {

            result += firstLetterToUpperCase(s);

        }

        return firstLetterToLowerCase(result);

    }



    /**

     * 刪除下劃線最後length位字元

     *

     * @param str 要處理的字串

     * @param length 要刪除字串最後多少位字元

     * @return 刪除str字串最後length位字元後的新字串

     */

    public static String deleteLastChildString(String str,int length)

    {

        return str.substring(0,str.length() - length);

    }

}

 

package com.util;



import java.io.File;

import java.lang.reflect.Field;

import java.lang.reflect.InvocationTargetException;

import java.lang.reflect.Method;

import java.util.ArrayList;

import java.util.List;



public class ObjectUtil {



    /**

     * 獲取object的屬性值

     * @param object 要獲取屬性值的鍍錫

     * @param fieldName 屬性名

     * @return object的filedName對應的屬性值

     */

    public static Object getFieldValue(Object object,String fieldName) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {

        String getterMethodName = "get" + StringUtil.firstLetterToUpperCase(fieldName);



        //只要public的getter方法

        Method getterMethod = object.getClass().getMethod(getterMethodName);

        if (getterMethod != null)

        {

            Object value = getterMethod.invoke(object);

            return value;

        }

        return null;

    }



    /**

     * 獲取object的屬性值

     * @param object 要獲取屬性值的鍍錫

     * @param field 屬性

     * @return object的filed對應的屬性值

     */

    public static Object getFieldValue(Object object,Field field) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {

        return getFieldValue(object,field.getName());

    }



    /**

     * 獲取object的所有屬性值

     * @param object 要獲取屬性值的鍍錫

     * @return object的所有屬性值組成的List集合

     */

    public static List<Object> getAllFieldValue(Object object) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {

        Field[] declaredFields = object.getClass().getDeclaredFields();

        List<Object> valueList = new ArrayList<Object>(declaredFields.length);

        for (Field field : declaredFields) {

            valueList.add(getFieldValue(object,field));

        }

        return valueList;

    }



    /**

     * 設定object的屬性值

     * @param object 要獲取屬性值的鍍錫

     * @param fieldName 屬性名

     * @param value 要設定的屬性值

     * @return object的filedName對應的屬性值

     */

    public static void setFieldValue(Object object,String fieldName,Object value) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, NoSuchFieldException {

        String setterMethodName = "set" + StringUtil.firstLetterToUpperCase(fieldName);

        Class<?> fieldClass = object.getClass().getDeclaredField(fieldName).getType();



        //只要public的getter方法

        Method setterMethod = object.getClass().getMethod(setterMethodName,fieldClass);

        if (setterMethod != null)

        {

            setterMethod.invoke(object,value);

        }

    }



    /**

     * 設定object的屬性值

     * @param object 要獲取屬性值的鍍錫

     * @param field 屬性

     * @param value 要設定的屬性值

     * @return object的filedName對應的屬性值

     */

    public static void setFieldValue(Object object, Field field, Object value) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, NoSuchFieldException {

        setFieldValue(object,field.getName(),value);

    }

}

 

package com.util;



import java.lang.reflect.ParameterizedType;

import java.lang.reflect.Type;



//這個工具類的所有方法會用就行,以後需要就直接複製貼上

//反正這個玩意我也是百度的

public class ClassUtil {



    /**

     * 獲取父類的泛型的型別

     * @param clazz 子類

     * @return 父類的泛型的Class物件

     */

    public static Class getSuperClassGenricType(Class clazz) {

        return getSuperClassGenricType(clazz, 0);

    }



    /**

     * 通過反射,獲得定義Class時宣告的父類的範型引數的型別. 如public BookManager extends GenricManager<Book>

     *

     * @param clazz clazz The class to introspect

     * @param index the Index of the generic ddeclaration,start from 0.

     */

    public static Class getSuperClassGenricType(Class clazz, int index)

            throws IndexOutOfBoundsException {

        Type genType = clazz.getGenericSuperclass();

        if (!(genType instanceof ParameterizedType)) {

            return Object.class;

        }

        Type[] params = ((ParameterizedType) genType).getActualTypeArguments();

        if (index >= params.length || index < 0) {

            return Object.class;

        }

        if (!(params[index] instanceof Class)) {

            return Object.class;

        }

        return (Class) params[index];

    }





}