同步釋出:http://www.yuanrengu.com/index.php/20170511.html
先簡單介紹下反射的概念:java反射機制是在執行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個物件,都能夠呼叫它的任意方法和屬性;這種動態獲取資訊以及動態呼叫物件方法的功能稱為java語言的反射機制。
反射是java中一種強大的工具,能夠使我們很方便的建立靈活的程式碼,這些程式碼可以在執行時裝配。在實際的業務中,可能會動態根據屬性去獲取值。
工具類如下:
package com.yaoguang.common.utils.field; import java.beans.BeanInfo; import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * 實體屬性操作工具類 * * @author heyonggang * @date 2017年5月10日下午5:56:59 */ public class ObjectFieldUtil { private static Logger log = LoggerFactory.getLogger(ObjectFieldUtil.class); /** * 根據屬性名獲取屬性值 * * @param fieldName 欄位名 * @param o 實體 * @return */ public static Object getFieldValueByName(String fieldName, Object o) { try { String firstLetter = fieldName.substring(0, 1).toUpperCase(); String getter = "get" + firstLetter + fieldName.substring(1); Method method = o.getClass().getMethod(getter, new Class[] {}); Object value = method.invoke(o, new Object[] {}); return value; } catch (Exception e) { log.error(e.getMessage(), e); return null; } } /** * 獲取屬性名陣列 * * @param o 實體 * @return */ public static String[] getFiledName(Object o) { Field[] fields = o.getClass().getDeclaredFields(); String[] fieldNames = new String[fields.length]; for (int i = 0; i < fields.length; i++) { System.out.println(fields[i].getType()); fieldNames[i] = fields[i].getName(); } return fieldNames; } /** * 獲取屬性型別(type),屬性名(name),屬性值(value)的map組成的list * * @param o 實體 * @return */ public static List<Map<String, Object>> getFiledsInfo(Object o) { Field[] fields = o.getClass().getDeclaredFields(); // String[] fieldNames = new String[fields.length]; List<Map<String, Object>> list = new ArrayList<>(); Map<String, Object> infoMap = null; for (int i = 0; i < fields.length; i++) { infoMap = new HashMap<String, Object>(); infoMap.put("type", fields[i].getType().toString()); infoMap.put("name", fields[i].getName()); infoMap.put("value", getFieldValueByName(fields[i].getName(), o)); list.add(infoMap); } return list; } /** * 獲取物件的所有屬性值,返回一個物件陣列 * * @param o 實體 * @return */ public static Object[] getFiledValues(Object o) { String[] fieldNames = getFiledName(o); Object[] value = new Object[fieldNames.length]; for (int i = 0; i < fieldNames.length; i++) { value[i] = getFieldValueByName(fieldNames[i], o); } return value; } /** * 根據物件屬性名設定屬性值 * * @param fieldName 欄位名 * @param value 欄位值 * @param o 實體 * @return */ public static void setFieldValueByName(String fieldName, Object o,Object value) { try { BeanInfo obj =Introspector.getBeanInfo(o.getClass(), Object.class); PropertyDescriptor[] pds = obj.getPropertyDescriptors(); for (PropertyDescriptor pd : pds) { if(pd.getName().equals(fieldName)){ pd.getWriteMethod().invoke(o, value); break; } } } catch (Exception e) { log.error(e.getMessage(), e); } } }
測試用例如下:
/** * 根據實體和屬性名獲取值 */ @Test public void testGetField(){ TruckBills truckBills = iTruckBillsService.geTruckBills("02cb5069b44f45dca578e5ada08bf513", "88"); String orderSn = (String) ObjectFieldUtil.getFieldValueByName("orderSn", truckBills); String shipper = (String) ObjectFieldUtil.getFieldValueByName("shipper", truckBills); String[] fieldNames = ObjectFieldUtil.getFiledName(truckBills); List<Map<String, Object>> listMap = ObjectFieldUtil.getFiledsInfo(truckBills); System.out.println("---------------------------"); System.out.println(orderSn); System.out.println(shipper); System.out.println(Arrays.toString(fieldNames)); for (Map<String, Object> map : listMap) { System.out.println("---------------------------"); Set<Entry<String, Object>> entrySet = map.entrySet(); for (Entry<String, Object> entry : entrySet) { System.out.println(entry.getKey() + "-----" + entry.getValue()); } System.out.println("---------------------------"); } }
還有一種將字串轉換成java程式碼並執行的方法:Java Expression Language (JEXL) 是一個表示式語言引擎,可以用來在應用或者框架中使用。
JEXL受Velocity和JSP 標籤庫 1.1 (JSTL) 的影響而產生的,需要注意的是,JEXL 並不時 JSTL 中的表示式語言的實現。
需要先新增jar包,maven配置如下:
<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-jexl</artifactId> <version>2.0</version> </dependency>
核心程式碼如下:
public class DyMethodUtil { /** * 將字串轉換成java程式碼並執行 * * @param jexlExp 需要轉換的字串 * @param map 引數集合 * @return 方法執行結果 * 如: * String jexlExp="testService.save(person)"; * map.put("testService",testService); * map.put("person",person); */ public static Object invokeMethod(String jexlExp, Map<String, Object> map) { JexlEngine jexl = new JexlEngine(); Expression e = jexl.createExpression(jexlExp); JexlContext jc = new MapContext(); for (String key : map.keySet()) { jc.set(key, map.get(key)); } if (null == e.evaluate(jc)) { return ""; } return e.evaluate(jc); } }
測試示例如下:
/** * 動態構建 */ @Test @Rollback(false) public void testTemple(){ //1.拿到結果集 //2.構建語言表示式 //3.動態構建 TruckBills truckBills = iTruckBillsService.geTruckBills("02cb5069b44f45dca578e5ada08bf513", "88"); List<TruckGoodsAddr> truckGoodsAddrs = truckBills.getTruckGoodsAddrs(); TruckOther truckOther = truckBills.getTruckOther(); Map<String, Object> map = new HashMap<>(); map.put("truckBills", truckBills); System.out.println("------------------------"); System.out.println(JsonBinder.buildNormalBinder().toJson(map)); System.out.println("------------------------"); String expression = "truckBills.getTruckGoodsAddrs().get(0).getBillsId()"; Object aa = DyMethodUtil.invokeMethod(expression, map); System.out.println("------------------------"); System.out.println(JsonBinder.buildNormalBinder().toJson(aa)); System.out.println("------------------------"); }