JDBC--利用反射處理查詢到的結(jié)果集

版權(quán)聲明:本文為小斑馬偉原創(chuàng)文章,轉(zhuǎn)載請注明出處!
通用的查詢方法:可以根據(jù)傳入的 SQL、Class 對象返回 SQL 對應(yīng)的記錄的對象。
查詢(要求:列的別名要和 Class 對應(yīng)的類的屬性名相同)锨络,得到 ResultSet 對象,得到 ResultSetMetaData 對象:可以知道 SQL 語句中查詢了哪些列狼牺,以及列的別名都是什么羡儿,反射創(chuàng)建Class 對應(yīng)的類對象,為對應(yīng)的屬性賦值是钥。
實(shí)現(xiàn)查詢到的數(shù)據(jù)列表信息與DAO對象綁定

主要步驟
1.先利用 SQL 進(jìn)行查詢掠归,得到結(jié)果集
2.利用反射創(chuàng)建實(shí)體類的對象:創(chuàng)建 Student 對象
3.獲取結(jié)果集的列的別名:idCard、studentName
4.再獲取結(jié)果集的每一列的值悄泥, 結(jié)合 3 得到一個 Map虏冻,鍵:列的別名,值:列的值:{flowId:5, type:6, idCard: xxx ……}
5.再利用反射為 2 的對應(yīng)的屬性賦值:屬性即為 Map 的鍵弹囚,值即為 Map 的值
/**
 * 通用的查詢方法:可以根據(jù)傳入的 SQL厨相、Class 對象返回 SQL 對應(yīng)的記錄的對象
 * @param clazz: 描述對象的類型
 * @param sql: SQL 語句∨葛模可能帶占位符
 * @param args: 填充占位符的可變參數(shù)蛮穿。
 * @return
 */
public <T> T get(Class<T> clazz, String sql, Object... args) {
    T entity = null;

    Connection connection = null;
    PreparedStatement preparedStatement = null;
    ResultSet resultSet = null;

    try {
        //1. 得到 ResultSet 對象
        connection = JDBCTools.getConnection();
        preparedStatement = connection.prepareStatement(sql);
        for (int i = 0; i < args.length; i++) {
            preparedStatement.setObject(i + 1, args[i]);
        }
        resultSet = preparedStatement.executeQuery();

        //2. 得到 ResultSetMetaData 對象
        ResultSetMetaData rsmd = resultSet.getMetaData();
        
        //3. 創(chuàng)建一個 Map<String, Object> 對象, 鍵: SQL 查詢的列的別名, 
        //值: 列的值
        Map<String, Object> values = new HashMap<>();
        
        //4. 處理結(jié)果集. 利用 ResultSetMetaData 填充 3 對應(yīng)的 Map 對象
        if(resultSet.next()){
            for(int i = 0; i < rsmd.getColumnCount(); i++){
                String columnLabel = rsmd.getColumnLabel(i + 1);
                Object columnValue = resultSet.getObject(i + 1);
                
                values.put(columnLabel, columnValue);
            }
        }
        
        //5. 若 Map 不為空集, 利用反射創(chuàng)建 clazz 對應(yīng)的對象
        if(values.size() > 0){
            entity = clazz.newInstance();
            
            //5. 遍歷 Map 對象, 利用反射為 Class 對象的對應(yīng)的屬性賦值. 
            for(Map.Entry<String, Object> entry: values.entrySet()){
                String fieldName = entry.getKey();
                Object value = entry.getValue();
                ReflectionUtils.setFieldValue(entity, fieldName, value);
            }
        }
        

    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        JDBCTools.releaseDB(resultSet, preparedStatement, connection);
    }

    return entity;
}
@Test
public void testGet() {
    String sql = "SELECT id, name, email, birth "
            + "FROM customers WHERE id = ?";


    Customer customer = get(Customer.class, sql, 5);
    System.out.println(customer);

    sql = "SELECT flow_id flowId, type, id_card idCard, "
            + "exam_card examCard, student_name studentName, "
            + "location, grade " + "FROM examstudent WHERE flow_id = ?";

    Student stu = get(Student.class, sql, 5);
    System.out.println(stu);
}

反射的 Utils 函數(shù)集合 提供訪問私有變量, 獲取泛型類型 Class, 提取集合中元素屬性等 Utils 函數(shù)。

/**
 * 反射的 Utils 函數(shù)集合
 * 提供訪問私有變量, 獲取泛型類型 Class, 提取集合中元素屬性等 Utils 函數(shù)
 * @author weiwei
 *
 */
 public class ReflectionUtils {


/**
 * 通過反射, 獲得定義 Class 時聲明的父類的泛型參數(shù)的類型
 * 如: public EmployeeDao extends BaseDao<Employee, String>
 * @param clazz
 * @param index
 * @return
 */
@SuppressWarnings("unchecked")
public static Class getSuperClassGenricType(Class clazz, int index){
    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];
}

/**
 * 通過反射, 獲得 Class 定義中聲明的父類的泛型參數(shù)類型
 * 如: public EmployeeDao extends BaseDao<Employee, String>
 * @param <T>
 * @param clazz
 * @return
 */
@SuppressWarnings("unchecked")
public static<T> Class<T> getSuperGenericType(Class clazz){
    return getSuperClassGenricType(clazz, 0);
}

/**
 * 循環(huán)向上轉(zhuǎn)型, 獲取對象的 DeclaredMethod
 * @param object
 * @param methodName
 * @param parameterTypes
 * @return
 */
public static Method getDeclaredMethod(Object object, String methodName, Class<?>[] parameterTypes){
    
    for(Class<?> superClass = object.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()){
        try {
            //superClass.getMethod(methodName, parameterTypes);
            return superClass.getDeclaredMethod(methodName, parameterTypes);
        } catch (NoSuchMethodException e) {
            //Method 不在當(dāng)前類定義, 繼續(xù)向上轉(zhuǎn)型
        }
        //..
    }
    
    return null;
}

/**
 * 使 filed 變?yōu)榭稍L問
 * @param field
 */
public static void makeAccessible(Field field){
    if(!Modifier.isPublic(field.getModifiers())){
        field.setAccessible(true);
    }
}

/**
 * 循環(huán)向上轉(zhuǎn)型, 獲取對象的 DeclaredField
 * @param object
 * @param filedName
 * @return
 */
public static Field getDeclaredField(Object object, String filedName){
    
    for(Class<?> superClass = object.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()){
        try {
            return superClass.getDeclaredField(filedName);
        } catch (NoSuchFieldException e) {
            //Field 不在當(dāng)前類定義, 繼續(xù)向上轉(zhuǎn)型
        }
    }
    return null;
}

/**
 * 直接調(diào)用對象方法, 而忽略修飾符(private, protected)
 * @param object
 * @param methodName
 * @param parameterTypes
 * @param parameters
 * @return
 * @throws InvocationTargetException 
 * @throws IllegalArgumentException 
 */
public static Object invokeMethod(Object object, String methodName, Class<?> [] parameterTypes,
        Object [] parameters) throws InvocationTargetException{
    
    Method method = getDeclaredMethod(object, methodName, parameterTypes);
    
    if(method == null){
        throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + object + "]");
    }
    
    method.setAccessible(true);
    
    try {
        return method.invoke(object, parameters);
    } catch(IllegalAccessException e) {
        System.out.println("不可能拋出的異常");
    } 
    
    return null;
}

/**
 * 直接設(shè)置對象屬性值, 忽略 private/protected 修飾符, 也不經(jīng)過 setter
 * @param object
 * @param fieldName
 * @param value
 */
public static void setFieldValue(Object object, String fieldName, Object value){
    Field field = getDeclaredField(object, fieldName);
    
    if (field == null)
        throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + object + "]");
    
    makeAccessible(field);
    
    try {
        field.set(object, value);
    } catch (IllegalAccessException e) {
        System.out.println("不可能拋出的異常");
    }
}

/**
 * 直接讀取對象的屬性值, 忽略 private/protected 修飾符, 也不經(jīng)過 getter
 * @param object
 * @param fieldName
 * @return
 */
public static Object getFieldValue(Object object, String fieldName){
    Field field = getDeclaredField(object, fieldName);
    
    if (field == null)
        throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + object + "]");
    
    makeAccessible(field);
    
    Object result = null;
    
    try {
        result = field.get(object);
    } catch (IllegalAccessException e) {
        System.out.println("不可能拋出的異常");
    }
    
    return result;
}
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末毁渗,一起剝皮案震驚了整個濱河市践磅,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌灸异,老刑警劉巖音诈,帶你破解...
    沈念sama閱讀 218,546評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異绎狭,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)褥傍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評論 3 395
  • 文/潘曉璐 我一進(jìn)店門儡嘶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人恍风,你說我怎么就攤上這事蹦狂∈睦椋” “怎么了?”我有些...
    開封第一講書人閱讀 164,911評論 0 354
  • 文/不壞的土叔 我叫張陵凯楔,是天一觀的道長窜骄。 經(jīng)常有香客問我,道長摆屯,這世上最難降的妖魔是什么邻遏? 我笑而不...
    開封第一講書人閱讀 58,737評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮虐骑,結(jié)果婚禮上准验,老公的妹妹穿的比我還像新娘。我一直安慰自己廷没,他們只是感情好糊饱,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,753評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著颠黎,像睡著了一般另锋。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上狭归,一...
    開封第一講書人閱讀 51,598評論 1 305
  • 那天夭坪,我揣著相機(jī)與錄音,去河邊找鬼唉铜。 笑死台舱,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的潭流。 我是一名探鬼主播竞惋,決...
    沈念sama閱讀 40,338評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼灰嫉!你這毒婦竟也來了拆宛?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,249評論 0 276
  • 序言:老撾萬榮一對情侶失蹤讼撒,失蹤者是張志新(化名)和其女友劉穎浑厚,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體根盒,經(jīng)...
    沈念sama閱讀 45,696評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡钳幅,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,888評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了炎滞。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片敢艰。...
    茶點(diǎn)故事閱讀 40,013評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖册赛,靈堂內(nèi)的尸體忽然破棺而出钠导,到底是詐尸還是另有隱情震嫉,我是刑警寧澤,帶...
    沈念sama閱讀 35,731評論 5 346
  • 正文 年R本政府宣布牡属,位于F島的核電站票堵,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏逮栅。R本人自食惡果不足惜悴势,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,348評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望证芭。 院中可真熱鬧瞳浦,春花似錦、人聲如沸废士。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽官硝。三九已至矗蕊,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間氢架,已是汗流浹背傻咖。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留岖研,地道東北人卿操。 一個月前我還...
    沈念sama閱讀 48,203評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像孙援,于是被迫代替她去往敵國和親害淤。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,960評論 2 355

推薦閱讀更多精彩內(nèi)容