给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

  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>
  
  
 
 

 
 
这样是不是很方便呢 ,呵呵 偷笑


 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
阅读更多 登录后自动展开

猜你喜欢

转载自blog.csdn.net/didi7696/article/details/82351167