上一篇文章已經詳細介紹了框架與RTTI的關係,RTTI與反射之間的關係。尤爲是對反射作了詳細說明,不少培訓機構也將其做爲高級教程來說解。前端
其實,我工做年限也不長,大概八九個月吧。但我見過不少技術人員,而我喜歡與別人討論技術。於是,我從中也知道了,不少公司沒有實現數據過濾。java
什麼是數據過濾?好比客戶端向服務器端發送展現項目圖片的請求,服務端接收到前端的請求並從數據庫中拿到項目圖片的對象,咱們只要返回圖片在服務端的地址和名稱便可,不必將整個圖片對象返回給客戶端。由於,那樣將會形成數據的冗餘。於是,咱們這時須要過濾數據(對象),如代碼所示:算法
/** * 經常使用的把圖片轉成 {id: 1, path: "xxx"}結構 */ public static JSONObject img2Json(Picture picture) { if (isNotNull(picture)) { String[] PICTURE_JSON = {"id", "remoteRelativeUrl:path"}; JSONObject jsonObject = propsFilter(picture, PICTURE_JSON); return jsonObject; } else { return null; } }
如上訴代碼的轉換,公司使用的是commons-beanutils這個框架。咱們只要在項目中農添加其maven配置便可:數據庫
<dependency> <groupId>commons-beanutils</groupId> <artifactId>commons-beanutils</artifactId> <version>1.9.2</version> </dependency>
我我的比較喜歡研究源碼,因而,仿照這個框架寫了本身的框架,下面,就是介紹我我的的框架。json
框架使用的算法或技術segmentfault
若是javabean的對象屬性類型不是用戶自定義的類型,咱們根據反射調用get方法拿到屬性的值
若是javabean的對象屬性類型是用戶自定義的類型,咱們利用遞歸從新調用改方法,直到出現碰見上面的條件數組
/** * Created By zby on 20:28 2019/2/13 * * @param bean 實體對象 * @param props 屬性名稱 */ public static Object getProperty(Object bean, String props) { if (bean == null) throw new RuntimeException("實例化對象不存在bean=" + bean); if (StringHelper.isBlank(props)) throw new RuntimeException("屬性名稱不存在props=" + props); Class<?> clazz = null; String methodName = null; String fieldName = null; String typeName = null; try { clazz = bean.getClass(); if (props.indexOf(".") != -1) { methodName = MethodHelper.propsToGetMethod(props.substring(0, props.indexOf("."))); Method method = clazz.getDeclaredMethod(methodName); Object obj = method.invoke(bean); return getProperty(obj, props.substring(props.indexOf(".") + 1)); } Field field = clazz.getDeclaredField(props); typeName = field.getType().getName(); if (typeName.equalsIgnoreCase("boolean")) { field.setAccessible(true); return field.getBoolean(bean); } methodName = MethodHelper.propsToGetMethod(props); Method method = clazz.getDeclaredMethod(methodName); return method.invoke(bean); } catch (NoSuchMethodException e) { logger.error(clazz + "類型沒有" + methodName + "方法"); e.printStackTrace(); } catch (NoSuchFieldException e) { logger.error(clazz + "類型沒有" + fieldName + "屬性"); e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } return null; }
咱們既然是經過屬性名稱來獲取屬性對象。咱們能夠設計一個算法,算法該算法有兩個參數,一個是當前對象,一個是對象的屬性數組。屬性數組還能夠有別名。服務器
爲何須要別名?好比當前對象採用組合關係,使用自定義的類。好比說訂單類使用用戶類(User)的對象做爲屬性,咱們在訂單中但願看到用戶姓名,咱們能夠這樣調用user.name,以該字段傳給客戶端,但客戶端須要轉換才能拿到用戶名,於是,咱們須要一個別名,前端不用轉換,就能夠拿到用戶名,好比:user.name:username。框架
固然,咱們須要將對象轉化爲json格式的框架, 這裏使用的阿里巴巴的fastjson框架,咱們能夠在項目中配置maven:maven
<dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.28</version> </dependency>
所示,算法設計爲:
/** * Created By zby on 9:40 2019/2/13 * 模擬框架中的數據 * * @param object 參數對象 * @param props String類型的變長數組,好比{"id:projectId", "mobile",...} * 前半部分是javabean的屬性名,後半部分是返回到給客戶端的參數名 */ public static JSONObject propsFilter(Object object, String... props) { //【1】判斷對象和變長數組的是否爲空,以及變長數組的長度是否爲0 boolean isNull = object == null || (null == props && props.length == 0); if (isNull) { logger.warn("參數爲空object=" + object + "props=" + props); return null; } JSONObject jsonObject = new JSONObject(); for (String prop : props) { //【2】再判斷對象不爲空,或者長度不爲0 if (prop == null && prop.length() == 0) { logger.warn("參數爲空prop= " + prop); throw new RuntimeException("參數爲空prop=" + prop); } Object o = null; String[] namePair = StringUtils.split(prop, ":"); try { o = PropertyUtil.getProperty(object, namePair[0]); } catch (Exception e) { logger.warn("類" + object.getClass() + ",屬性" + namePair[0] + "不存在"); } String key = namePair.length <= 1 ? namePair[0] : namePair[1]; if (o instanceof Date) jsonObject.put(key, DateUtil.simpleFormate((Date) o)); else if (o instanceof BigDecimal) jsonObject.put(key, CommonUtil.toFiexd((BigDecimal) o, 2)); else if (o instanceof TitleEnum) jsonObject.put(key, CommonUtil.builderEnum((TitleEnum) o)); else jsonObject.put(key, o); } return jsonObject; }
咱們既然寫好了這個框,也使用了這個框架,於是,咱們能夠使用Junit來測試:
@Test public void test(){ Address address = new Address(); address.setAddressTag(AddressTagEnum.ADDRESS_TAG_COMPANY); address.setArea("杭州市...."); address.setConsignee("zby"); User user = new User(); user.setHobby(HobbyEnum.HOBBY_DANCING); user.setGender("男"); user.setUserName("蔣三"); OrderSnapshot orderSnapshot = new OrderSnapshot(); orderSnapshot.setAddress(address); orderSnapshot.setId(1L); orderSnapshot.setName("復讀機"); orderSnapshot.setOrderNo(Long.valueOf(System.currentTimeMillis()).toString() + "1L"); orderSnapshot.setUser(user); String[] json = {"address.consignee:consignee","user.hobby:hobby", "address.addressTag:addressTag", "address.area:area" ,"address.consignee:consignee","user.userName:userName"}; System.out.println(JsonUtil.propsFilter(orderSnapshot, json));
測試結果爲:
可見,咱們算法時成功的。
咱們仍是要時常看源碼,由於,你的目的不是寫出框架,而是看別人寫框架的思想。畢竟,思想主導一切行爲,行爲成就一個的將來。致努力的本身。