1. 程式人生 > >如何實現一個增強版本的BeanUtil 工具類

如何實現一個增強版本的BeanUtil 工具類

背景:面對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);  
                    }  
                }  
            }  
        }  
    }  
}