如何實現一個增強版本的BeanUtil 工具類
阿新 • • 發佈:2019-01-01
背景:面對B端系統的開發,會涉及到很對後臺頁面的管理功能,如果一個頁面上有很多欄位需要落入資料庫,那麼在寫業務邏輯的時候,需要寫很多模型轉換的程式碼,因此寫一個簡單的框架讓模型轉換自動完成,是架構師需要考慮的一個問題。
解決方案:
(1)約定大於硬編碼,可以使用org.springframework.beans.BeanUtils類的copyProperties,將一個物件的屬性的值賦值給另外一個物件,這個方法只是一個簡單的實現,實現是基於反射實現,很消耗效能。
(2)在方案一的基礎上可以使用asm實現在系統第一次啟動的時候,動態實現二進位制位元組碼,然後快取起來,從第二次開始都從快取讀取二進位制位元組碼。如果模型轉換欄位改變,系統重新啟動會重新生成,這樣效率會大大的提高。
---如何對一個物件賦值,可以重寫其中的copyProperties,不允許NULL欄位賦值
在MVC的開發模式中經常需要將model與pojo的資料繫結,apache和spring的工具包中都有BeanUtils,使用其中的copyProperties方法可以非常方便的進行這些工作,但在實際應用中發現,對於null的處理不太符合個人的需要,例如在進行修改操作中只需要對model中某一項進行修改,那麼一般我們在頁面上只提交model的ID及需要修改項的值,這個時候使用BeanUtils.copyProperties會將其他的null繫結到pojo中去。為解決這個問題我重寫了部分spring BeanUtils的程式碼如下spring: 3.2.12,其他幾個copyProperties方法最終都是呼叫的這個,
spring的比apache的的多一個帶ignoreProperties的
Java程式碼
private static void copyProperties(Object source, Object target, Class<?> editable, String... ignoreProperties) throws BeansException { Assert.notNull(source, "Source must not be null"); Assert.notNull(target, "Target must not be null"); Class<?> actualEditable = target.getClass(); if (editable != null) { if (!editable.isInstance(target)) { throw new IllegalArgumentException("Target class [" + target.getClass().getName() + "] not assignable to Editable class [" + editable.getName() + "]"); } actualEditable = editable; } PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable); List<String> ignoreList = (ignoreProperties != null) ? Arrays.asList(ignoreProperties) : null; for (PropertyDescriptor targetPd : targetPds) { Method writeMethod = targetPd.getWriteMethod(); if (writeMethod != null && (ignoreProperties == null || (!ignoreList.contains(targetPd.getName())))) { PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName()); if (sourcePd != null) { Method readMethod = sourcePd.getReadMethod(); if (readMethod != null && ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType())) { try { if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) { readMethod.setAccessible(true); } Object value = readMethod.invoke(source); if(value != null){ //只拷貝不為null的屬性 by zhao if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) { writeMethod.setAccessible(true); } writeMethod.invoke(target, value); } } catch (Throwable ex) { throw new FatalBeanException( "Could not copy property '" + targetPd.getName() + "' from source to target", ex); } } } } } }