在實際開發時,許多業務接口的入參非常復雜,比如會有多級的 JSON 嵌套或者混雜着各種數組。
這種時候如果我們將接口參數的拼裝邏輯雜亂的寫在 Controller 層,代碼的可讀性會非常差,后續接手的人員需要一個參數一個參數的比對着接口文檔來推演參數的拼裝邏輯。
在這種情況下,將接口調用參數封裝為數據傳輸對象 dto ,配合自定義注解可大大的提高程序的可讀性。
我們自定義一個注解來標識我們 dto 中的入參:
@Retention(RetentionPolicy.RUNTIME) @Target(value = ElementType.FIELD) public @interface ParamAnnotation { //是否必須參數 public boolean isRequired() default false; //參數名稱 public String name(); }
注解包含兩個屬性,參數名稱 和 是否必須參數。
這樣,我們的代碼由:
變為了:
明顯的提高了可讀性,同時我們可以將相關賦值邏輯封裝在 dto 的構造函數中。
在每次進行接口調用前,我們可以通過反射遍歷檢查 dto 中的必傳參數是否完整:
/** * @Author Nxy * @Date 2020/3/24 19:49 * @Param obj:需要驗證的參數對象 * @Return * @Exception * @Description 判斷參數中必填項是否都已填寫 */ public boolean isComplete(T obj) throws IllegalAccessException, NoSuchFieldException { Class objClass = obj.getClass(); Field fields[] = objClass.getDeclaredFields(); for (Field field : fields) { if (field.isAnnotationPresent(ParamAnnotation.class)) { field.setAccessible(true); ParamAnnotation paramAnnotation = field.getAnnotation(ParamAnnotation.class); //如果是必填項 if (paramAnnotation.isRequired()) { Object value = field.get(obj); if (null == value) { Object paraName = paramAnnotation.name(); //缺失項回寫 Field deletion = objClass.getDeclaredField("deletion"); deletion.setAccessible(true); deletion.set(obj, paraName); return false; } } } } return true; }
這樣我們的外層邏輯由幾十行代碼變成了:
由 vo 得到 dto 參數,校驗參數完整性。讓 controller 只去關注調用邏輯,其余零碎的轉換和校驗模塊化。
雖然反射降低了運行效率,但對於對性能要求不是特別高的場景,用這些代價換取代碼的可讀性是值得的。