1. 程式人生 > >給java物件動態的新增屬性

給java物件動態的新增屬性

抓狂、不知道大家有沒有遇到過這樣的需求 ,就java執行的時候 動態給你java物件新增屬性,最近在專案終於到了,想到了反射去實現,但是最終也沒有搞出來。。。哎。。


有的時候 比如你用的是hibernate或者Spring jdbc 來做dao層進行資料庫相關的操作的時候,若果是單表的操作的時候 還比較簡單 hibernate可直接返回(get,load)你的需要的po,spring3可以用rowmapper的實現類來處理這個操作,這些操作對於大家來說都是熟悉的不能在熟悉了。

疑問、問題:當進行多個表進行連線的操作時候,如:

select
p.id,p.name,ad.address,ad.post_code from person p join person_address ad on p.id = ad.person_id


現在有兩張表進行查詢 ,查詢出來是兩個表的欄位,hibernate中也許你會想建立一個含有這些欄位的vo就可以瞭解決了 (或者基於這個查詢建立以個檢視 ,然後基於這個檢視在用hibernate進行orm對映,),在spring3裡會用到org.springframework.jdbc.core.BeanPropertyRowMapper如:

this.jdbcTemplate.queryForObject(sql,BeanPropertyRowMapper.
newInstance(PersonAdressVo.class));//返回PersonAdressVo物件

是的這樣的確可以解決,想想如果你的好的查詢,而且結果都不一樣,連線的表也是很多,那麼你建立的vo或者是檢視肯定是氾濫的,整個專案就會臃腫起來,這是我們不想看到的。

大笑、現在說說解決方法:

你可以在進行查詢結果的時候,為你聯合查詢出來的Object 動態新增你查出來的屬性;

下面來說一下具體的程式碼:

此時需要你需要cglib-nodep-2.2.jar,自己google下載

DynamicBean.java


  
  1. package
    com.ajun.spring.orm;
  2. import java.util.Iterator;
  3. import java.util.Map;
  4. import java.util.Set;
  5. import net.sf.cglib.beans.BeanGenerator;
  6. import net.sf.cglib.beans.BeanMap;
  7. /**
  8. *
  9. * @author ajun
  10. *
  11. */
  12. public class DynamicBean {
  13. /**
  14. * 實體Object
  15. */
  16. private Object object = null;
  17. /**
  18. * 屬性map
  19. */
  20. private BeanMap beanMap = null;
  21. public DynamicBean() {
  22. super();
  23. }
  24. @SuppressWarnings( "unchecked")
  25. public DynamicBean(Map propertyMap) {
  26. this.object = generateBean(propertyMap);
  27. this.beanMap = BeanMap.create( this.object);
  28. }
  29. /**
  30. * 給bean屬性賦值
  31. * @param property 屬性名
  32. * @param value 值
  33. */
  34. public void setValue(String property, Object value) {
  35. beanMap.put(property, value);
  36. }
  37. /**
  38. * 通過屬性名得到屬性值
  39. * @param property 屬性名
  40. * @return
  41. */
  42. public Object getValue(String property) {
  43. return beanMap.get(property);
  44. }
  45. /**
  46. * 得到該實體bean物件
  47. * @return
  48. */
  49. public Object getObject() {
  50. return this.object;
  51. }
  52. /**
  53. * @param propertyMap
  54. * @return
  55. */
  56. @SuppressWarnings( "unchecked")
  57. private Object generateBean(Map propertyMap) {
  58. BeanGenerator generator = new BeanGenerator();
  59. Set keySet = propertyMap.keySet();
  60. for (Iterator i = keySet.iterator(); i.hasNext();) {
  61. String key = (String) i.next();
  62. generator.addProperty(key, (Class) propertyMap.get(key));
  63. }
  64. return generator.create();
  65. }
  66. }

測試類:


  
  1. public static void main(String[] args) throws ClassNotFoundException {
  2. // 設定類成員屬性
  3. HashMap propertyMap = new HashMap();
  4. propertyMap.put( "id", Class.forName( "java.lang.Integer"));
  5. propertyMap.put( "name", Class.forName( "java.lang.String"));
  6. propertyMap.put( "address", Class.forName( "java.lang.String"));
  7. // 生成動態 Bean
  8. DynamicBean bean = new DynamicBean(propertyMap);
  9. // 給 Bean 設定值
  10. bean.setValue( "id", new Integer( 123));
  11. bean.setValue( "name", "454");
  12. bean.setValue( "address", "789");
  13. // 從 Bean 中獲取值,當然了獲得值的型別是 Object
  14. System.out.println( " >> id = " + bean.getValue( "id"));
  15. System.out.println( " >> name = " + bean.getValue( "name"));
  16. System.out.println( " >> address = " + bean.getValue( "address"));
  17. // 獲得bean的實體
  18. Object object = bean.getObject();
  19. // 通過反射檢視所有方法名
  20. Class clazz = object.getClass();
  21. Method[] methods = clazz.getDeclaredMethods();
  22. for ( int i = 0; i < methods.length; i++) {
  23. System.out.println(methods[i].getName());
  24. }
  25. }

在這裡在舉一個spring jdbc中查詢多個表 ,返回一個動態bean的例子:
首先是你在用spring3 jdbc進行查詢的時候 這時候你想返回一個物件 此時你一般的做法是:


  
  1. String sql= "select p.id,p.name,ad.address,ad.post_code from person p join person_address ad on p.id = ad.person_id"; //此時你返回是多個表的結果
  2. this.jdbcTemplate.queryForObject(sql,BeanPropertyRowMapper.newInstance(PersonAddressVO.class), id); //返回一個含有多個表的屬性的vo:PersonAddressVO
隨著你的業務的複雜也許你vo會很多 ,為了減少你vo的數量 ,應該動態返回一個bean 此時bean含有你想要的的屬性。

我們在用spring jdbc 進行查詢 就行orm對映的時候 都要是首先實現org.springframework.jdbc.core.RowMapper,因為spring jdbc查詢的時候你要進行orm要求一個引數必須為org.springframework.jdbc.core.RowMapper,所以此時我要實現org.springframework.jdbc.core.RowMapper裡的public Object mapRow(ResultSet rs, int rowNum) f。


  

裡面我們會用前面的DynamicBean.java

[java] view plain copy print ?
  1. <code class="language-java">package com.ajun.spring.orm;  
  2.   
  3. import java.sql.ResultSet;  
  4. import java.sql.ResultSetMetaData;  
  5. import java.sql.SQLException;  
  6. import java.util.HashMap;  
  7.   
  8. import org.springframework.jdbc.core.RowMapper;  
  9. import org.springframework.jdbc.support.JdbcUtils;  
  10.   
  11.   
  12.   
  13. /** 
  14.  ********************************************************************************* 
  15.  * 例子:資料庫:person_id <----->po:personId 請寫好駝峰表示風格 
  16.  ********************************************************************************* 
  17.  * @author ajun 
  18.  */  
  19. @SuppressWarnings("unchecked")  
  20. public class CustomRowMapper implements RowMapper {  
  21.   
  22.       
  23.     @Override  
  24.     public Object mapRow(ResultSet rs, int rowNum) throws SQLException {  
  25.             return this.toDynamicObject(rs, rowNum);  
  26.     }  
  27.       
  28.     private  Object toDynamicObject(ResultSet rs, int rowNum) throws SQLException{  
  29.         DynamicBean dyBean  =null;  
  30.         ResultSetMetaData rsmd = rs.getMetaData();  
  31.         if(rsmd!=null){  
  32.             int columnCount = rsmd.getColumnCount();  
  33.             HashMap propertyMap = new HashMap();  
  34.             for (int index = 1; index <= columnCount; index++){//JdbcUtils自己查spring API  
  35.                 String column = JdbcUtils.lookupColumnName(rsmd, index);  
  36.                 String propertyName = JdbcUtils.convertUnderscoreNameToPropertyName(column);  
  37.                 propertyMap.put(propertyName, Object.class);//新增動態屬性 此時person_address ==>personAddress  
  38.             }  
  39.             dyBean = new DynamicBean(propertyMap);  
  40.             for (int index = 1; index <= columnCount; index++){  
  41.                 String column = JdbcUtils.lookupColumnName(rsmd, index);  
  42.                 String propertyName = JdbcUtils.convertUnderscoreNameToPropertyName(column);  
  43.                 Object value = JdbcUtils.getResultSetValue(rs, index);  
  44.                 dyBean.setValue(propertyName, value);//設定值  
  45.             }  
  46.         }  
  47.         return dyBean.getObject();  
  48.     }  
  49.       
  50.       
  51.     public static  CopyOfCustomRowMapper newInstance() {  
  52.         CopyOfCustomRowMapper newInstance = new CopyOfCustomRowMapper();  
  53.         return newInstance;  
  54.     }  
  55.   
  56. }  
  57. </code>  

   
  1. package com.ajun.spring.orm;
  2. import java.sql.ResultSet;
  3. import java.sql.ResultSetMetaData;
  4. import java.sql.SQLException;
  5. import java.util.HashMap;
  6. import org.springframework.jdbc.core.RowMapper;
  7. import org.springframework.jdbc.support.JdbcUtils;
  8. /**
  9. *********************************************************************************
  10. * 例子:資料庫:person_id <----->po:personId 請寫好駝峰表示風格
  11. *********************************************************************************
  12. * @author ajun
  13. */
  14. @SuppressWarnings( "unchecked")
  15. public class CustomRowMapper implements RowMapper {
  16. @Override
  17. public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
  18. return this.toDynamicObject(rs, rowNum);
  19. }
  20. private Object toDynamicObject(ResultSet rs, int rowNum) throws SQLException{
  21. DynamicBean dyBean = null;
  22. ResultSetMetaData rsmd = rs.getMetaData();
  23. if(rsmd!= null){
  24. int columnCount = rsmd.getColumnCount();
  25. HashMap propertyMap = new HashMap();
  26. for ( int index = 1; index <= columnCount; index++){ //JdbcUtils自己查spring API
  27. String column = JdbcUtils.lookupColumnName(rsmd, index);
  28. String propertyName = JdbcUtils.convertUnderscoreNameToPropertyName(column);
  29. propertyMap.put(propertyName, Object.class); //新增動態屬性 此時person_address ==>personAddress
  30. }
  31. dyBean = new DynamicBean(propertyMap);
  32. for ( int index = 1; index <= columnCount; index++){
  33. String column = JdbcUtils.lookupColumnName(rsmd, index);
  34. String propertyName = JdbcUtils.convertUnderscoreNameToPropertyName(column);
  35. Object value = JdbcUtils.getResultSetValue(rs, index);
  36. dyBean.setValue(propertyName, value); //設定值
  37. }
  38. }
  39. return dyBean.getObject();
  40. }
  41. public static CopyOfCustomRowMapper newInstance() {
  42. CopyOfCustomRowMapper newInstance = new CopyOfCustomRowMapper();
  43. return newInstance;
  44. }
  45. }
呼叫的時候:


  
  1. String sql= "select p.id,p.name,ad.address,ad.post_code from person p join person_address ad on p.id = ad.person_id"; //此時你返回是多個表的結果
  2. List<Object> list = this.jdbcTemplate.query(sql, BeanPropertyRowMapper.newInstance()); //返回一個含有多個表的屬性的動態bean

在頁面上你就可以用el表示式這樣去出來:


  
  1. <c:forEach items="${list}" var="p">
  2. <tr>
  3. <td>${p.id} </td>
  4. <td>${p.name} </td>
  5. <td>${p.address} </td>
                        <td>${p.postCode}</td>
  
</tr> </c:forEach>
  
 
 

 
 
這樣是不是很方便呢 ,呵呵 偷笑


 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
  
  閱讀更多 
  登入後自動展開