給java物件動態的新增屬性
阿新 • • 發佈:2018-11-25
、不知道大家有沒有遇到過這樣的需求 ,就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
this.jdbcTemplate.queryForObject(sql,BeanPropertyRowMapper. newInstance(PersonAdressVo.class));//返回PersonAdressVo物件
是的這樣的確可以解決,想想如果你的好的查詢,而且結果都不一樣,連線的表也是很多,那麼你建立的vo或者是檢視肯定是氾濫的,整個專案就會臃腫起來,這是我們不想看到的。
、現在說說解決方法:
你可以在進行查詢結果的時候,為你聯合查詢出來的Object 動態新增你查出來的屬性;
下面來說一下具體的程式碼:
此時需要你需要cglib-nodep-2.2.jar,自己google下載
DynamicBean.java
-
package
com.ajun.spring.orm;
-
-
import java.util.Iterator;
-
import java.util.Map;
-
import java.util.Set;
-
-
import net.sf.cglib.beans.BeanGenerator;
-
import net.sf.cglib.beans.BeanMap;
-
-
/**
-
*
-
* @author ajun
-
*
-
*/
-
public
class DynamicBean {
-
-
/**
-
* 實體Object
-
*/
-
private Object object =
null;
-
-
/**
-
* 屬性map
-
*/
-
private BeanMap beanMap =
null;
-
-
public DynamicBean() {
-
super();
-
}
-
-
@SuppressWarnings(
"unchecked")
-
public DynamicBean(Map propertyMap) {
-
this.object = generateBean(propertyMap);
-
this.beanMap = BeanMap.create(
this.object);
-
}
-
-
/**
-
* 給bean屬性賦值
-
* @param property 屬性名
-
* @param value 值
-
*/
-
public void setValue(String property, Object value) {
-
beanMap.put(property, value);
-
}
-
-
/**
-
* 通過屬性名得到屬性值
-
* @param property 屬性名
-
* @return 值
-
*/
-
public Object getValue(String property) {
-
return beanMap.get(property);
-
}
-
-
/**
-
* 得到該實體bean物件
-
* @return
-
*/
-
public Object getObject() {
-
return
this.object;
-
}
-
-
/**
-
* @param propertyMap
-
* @return
-
*/
-
@SuppressWarnings(
"unchecked")
-
private Object generateBean(Map propertyMap) {
-
BeanGenerator generator =
new BeanGenerator();
-
Set keySet = propertyMap.keySet();
-
for (Iterator i = keySet.iterator(); i.hasNext();) {
-
String key = (String) i.next();
-
generator.addProperty(key, (Class) propertyMap.get(key));
-
}
-
return generator.create();
-
}
-
-
}
測試類:
-
public static void main(String[] args) throws ClassNotFoundException {
-
-
// 設定類成員屬性
-
HashMap propertyMap =
new HashMap();
-
-
propertyMap.put(
"id", Class.forName(
"java.lang.Integer"));
-
-
propertyMap.put(
"name", Class.forName(
"java.lang.String"));
-
-
propertyMap.put(
"address", Class.forName(
"java.lang.String"));
-
-
// 生成動態 Bean
-
DynamicBean bean =
new DynamicBean(propertyMap);
-
-
// 給 Bean 設定值
-
bean.setValue(
"id",
new Integer(
123));
-
-
bean.setValue(
"name",
"454");
-
-
bean.setValue(
"address",
"789");
-
-
// 從 Bean 中獲取值,當然了獲得值的型別是 Object
-
-
System.out.println(
" >> id = " + bean.getValue(
"id"));
-
-
System.out.println(
" >> name = " + bean.getValue(
"name"));
-
-
System.out.println(
" >> address = " + bean.getValue(
"address"));
-
-
// 獲得bean的實體
-
Object object = bean.getObject();
-
-
// 通過反射檢視所有方法名
-
Class clazz = object.getClass();
-
Method[] methods = clazz.getDeclaredMethods();
-
for (
int i =
0; i < methods.length; i++) {
-
System.out.println(methods[i].getName());
-
}
-
}
在這裡在舉一個spring jdbc中查詢多個表 ,返回一個動態bean的例子:
首先是你在用spring3 jdbc進行查詢的時候 這時候你想返回一個物件 此時你一般的做法是:
-
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";
//此時你返回是多個表的結果
-
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
- <code class="language-java">package com.ajun.spring.orm;
- import java.sql.ResultSet;
- import java.sql.ResultSetMetaData;
- import java.sql.SQLException;
- import java.util.HashMap;
- import org.springframework.jdbc.core.RowMapper;
- import org.springframework.jdbc.support.JdbcUtils;
- /**
- *********************************************************************************
- * 例子:資料庫:person_id <----->po:personId 請寫好駝峰表示風格
- *********************************************************************************
- * @author ajun
- */
- @SuppressWarnings("unchecked")
- public class CustomRowMapper implements RowMapper {
- @Override
- public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
- return this.toDynamicObject(rs, rowNum);
- }
- private Object toDynamicObject(ResultSet rs, int rowNum) throws SQLException{
- DynamicBean dyBean =null;
- ResultSetMetaData rsmd = rs.getMetaData();
- if(rsmd!=null){
- int columnCount = rsmd.getColumnCount();
- HashMap propertyMap = new HashMap();
- for (int index = 1; index <= columnCount; index++){//JdbcUtils自己查spring API
- String column = JdbcUtils.lookupColumnName(rsmd, index);
- String propertyName = JdbcUtils.convertUnderscoreNameToPropertyName(column);
- propertyMap.put(propertyName, Object.class);//新增動態屬性 此時person_address ==>personAddress
- }
- dyBean = new DynamicBean(propertyMap);
- for (int index = 1; index <= columnCount; index++){
- String column = JdbcUtils.lookupColumnName(rsmd, index);
- String propertyName = JdbcUtils.convertUnderscoreNameToPropertyName(column);
- Object value = JdbcUtils.getResultSetValue(rs, index);
- dyBean.setValue(propertyName, value);//設定值
- }
- }
- return dyBean.getObject();
- }
- public static CopyOfCustomRowMapper newInstance() {
- CopyOfCustomRowMapper newInstance = new CopyOfCustomRowMapper();
- return newInstance;
- }
- }
- </code>
-
package com.ajun.spring.orm;
-
-
import java.sql.ResultSet;
-
import java.sql.ResultSetMetaData;
-
import java.sql.SQLException;
-
import java.util.HashMap;
-
-
import org.springframework.jdbc.core.RowMapper;
-
import org.springframework.jdbc.support.JdbcUtils;
-
-
-
-
/**
-
*********************************************************************************
-
* 例子:資料庫:person_id <----->po:personId 請寫好駝峰表示風格
-
*********************************************************************************
-
* @author ajun
-
*/
-
@SuppressWarnings(
"unchecked")
-
public
class CustomRowMapper implements RowMapper {
-
-
-
@Override
-
public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
-
return
this.toDynamicObject(rs, rowNum);
-
}
-
-
private Object toDynamicObject(ResultSet rs, int rowNum) throws SQLException{
-
DynamicBean dyBean =
null;
-
ResultSetMetaData rsmd = rs.getMetaData();
-
if(rsmd!=
null){
-
int columnCount = rsmd.getColumnCount();
-
HashMap propertyMap =
new HashMap();
-
for (
int index =
1; index <= columnCount; index++){
//JdbcUtils自己查spring API
-
String column = JdbcUtils.lookupColumnName(rsmd, index);
-
String propertyName = JdbcUtils.convertUnderscoreNameToPropertyName(column);
-
propertyMap.put(propertyName, Object.class);
//新增動態屬性 此時person_address ==>personAddress
-
}
-
dyBean =
new DynamicBean(propertyMap);
-
for (
int index =
1; index <= columnCount; index++){
-
String column = JdbcUtils.lookupColumnName(rsmd, index);
-
String propertyName = JdbcUtils.convertUnderscoreNameToPropertyName(column);
-
Object value = JdbcUtils.getResultSetValue(rs, index);
-
dyBean.setValue(propertyName, value);
//設定值
-
}
-
}
-
return dyBean.getObject();
-
}
-
-
-
public static CopyOfCustomRowMapper newInstance() {
-
CopyOfCustomRowMapper newInstance =
new CopyOfCustomRowMapper();
-
return newInstance;
-
}
-
-
}
呼叫的時候:
-
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";
//此時你返回是多個表的結果
-
List<Object> list =
this.jdbcTemplate.query(sql, BeanPropertyRowMapper.newInstance());
//返回一個含有多個表的屬性的動態bean
在頁面上你就可以用el表示式這樣去出來:
-
<c:forEach items="${list}" var="p">
-
<tr>
-
<td>${p.id}
</td>
-
<td>${p.name}
</td>
-
<td>${p.address}
</td>
<td>${p.postCode}</td>
</tr> </c:forEach>
這樣是不是很方便呢 ,呵呵