在日常項目開發中,不免都會用到一些數據字典的信息,以及前端展示的時候通常也需要把這些數據字典值轉換成具體字典文本信息。遇到這種場景通常都是后端把字典的文本轉換好一起返回給前端,前端只需要直接展示即可。一般情況下后端可能需要單獨給返回對象創建一個字段來存儲對應的字典文本值,然后進行手動的處理,這種方式通常比較繁瑣,在字段多的時候會增加更多的工作量。
所以我們這次目的是利用java反射機制跟自定義注解功能實現了這一自動轉換過程,不需要在對象中定義存放字典文本的字段,只需要在字段上使用特定的注解配置,通過調用方法來完成轉換工作。
一、首先我們先創建一個注解
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface AutoEnum { /** * 需要翻譯說明的枚舉路徑 * @return */ String path() default ""; /** * 對應翻譯后返回字段的名稱 * @return */ String fieldName() default ""; }
二、然后在實體類里對應需要翻譯的屬性上寫上我們定義的注解如下
@Data @EqualsAndHashCode(callSuper = false) @Accessors(chain = true) public class ServiceOrgAreasExamine implements Serializable { private static final long serialVersionUID = 1L; private Integer id; @AutoEnum(path = "com.aspect.enums.ActivitiesAttributeEnum",fieldName = "areasId") private Integer organId; private String organIdV; @AutoEnum(path = "com.aspect.enums.ExamineStatusEnum") private Integer examineStatus; private String examineStatusV;
上面的注解中的path是我們需要翻譯的枚舉類的路徑,fieldName是我們翻譯后用哪個字段來回顯。如果不填寫默認本字段來顯示翻譯。
三 需要翻譯的枚舉類如下
/** * 活動類型枚舉類 */ @Getter @AllArgsConstructor public enum ActivitiesAttributeEnum { OFFLINE("1", "線下活動"), CONSULT("2", "活動咨詢"); private final String code; private final String desc; }
/** * 服務區域審核狀態枚舉類 */ @Getter @AllArgsConstructor public enum ExamineStatusEnum { PENDING_REVIEW(0, "待審核"), REFUSE(1, "已拒絕"), SERVING(2, "服務中"), DISMISSAL(3, "解除服務"); private final Integer code; private final String desc; }
四、以上准備工作完成。最重要的就是如何通過反射進行賦值了。
import com.aspect.annotation.AutoEnum; import java.io.Serializable; import java.lang.reflect.Field; import java.util.List; import java.util.Map; /** * @Author: cq * @Description * @Date Create in 2:44 PM 2021/12/27. */ public class InterprectChineseUtils<T extends Serializable> { /** * 通過注解將傳入的實體翻譯成中文的說明 實體中對應注解@AutoEnum * @param t 需要將枚舉翻譯成中文說明的實體 */ public void reflexEnum(T t) { Class clas = t.getClass(); for (Field f : t.getClass().getDeclaredFields()) { Object value = null; try { //對於private的屬性,如果不解鎖,那么將無法訪問,會報錯 f.setAccessible(true); //通過反射的字段獲取實體中的值 value = f.get(t); } catch (IllegalAccessException e) { e.printStackTrace(); } //獲取注解的信息 AutoEnum anno2 = f.getAnnotation(AutoEnum.class); if(anno2!=null&&value!=null) { //注解的path String path = anno2.path(); //注解的fieldName String fieldName = anno2.fieldName(); //通過value過去枚舉中對應的中文說明 String enumValues = InterprectChineseUtils.enumExplain(path, value.toString()); try { //通過注解中寫的fieldName,給需要賦值的字段賦值 Field fv = null; if(!"".equals(fieldName)) { fv = clas.getDeclaredField(fieldName); } else { fv = f; } //對於private的屬性,如果不解鎖,那么將無法訪問,會報錯 fv.setAccessible(true); fv.set(t,enumValues); } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } } } /** * 通過枚舉路徑跟值獲取對應的中文說明 * @param name 枚舉的class路徑 * @param code 對應的枚舉值 * @return */ public static String enumExplain(String name, String code) { try { Class clazz = Class.forName(name); List<Map<String, Object>> list = EnumUtils.toMapList(clazz); for (Map map : list) { if (map.get("code").toString().equals(code)) { return map.get("desc").toString(); } } } catch (ClassNotFoundException e) { e.printStackTrace(); } return ""; } }
五、另外附上EnumUtils類用於將枚舉類轉換成list方便遍歷出想要的desc說明內容。
/** * @Author: cq * @Description 枚舉工具類 * @Date Create in 3:43 PM 2020/4/26. */ public class EnumUtils { private static final String DEFAULT_ENUM_NAME = "name"; /** * 首字母轉大寫 * * @param s 需要操作的字符串 * @return 轉換后結果 */ private static String toUpperCaseFirstOne(String s) { if (Character.isUpperCase(s.charAt(0))) { return s; } else { return Character.toUpperCase(s.charAt(0)) + s.substring(1); } } /** * 枚舉轉List格式 * * @param targetEnumClazz 目標枚舉Clazz * @return 裝換結果 */ public static List<Map<String, Object>> toMapList(Class targetEnumClazz) { return toList(targetEnumClazz, DEFAULT_ENUM_NAME); } /** * 枚舉轉List格式 * * @param targetEnumClazz 目標枚舉Clazz * @param enumName 返回JSON中枚舉名稱對應的Key * @return 轉換結果 */ public static List<Map<String, Object>> toList(Class targetEnumClazz, String enumName) { try { //獲取方法 Method[] methods = targetEnumClazz.getMethods(); Field[] fields = targetEnumClazz.getDeclaredFields(); List<Field> fieldList = new ArrayList(); for (Method method : methods) { for (Field field : fields) { if (method.getName().endsWith(toUpperCaseFirstOne(field.getName()))) { fieldList.add(field); } } } List<Map<String, Object>> resultList = new ArrayList(); //獲取值 Enum[] enums = (Enum[]) targetEnumClazz.getEnumConstants(); for (Enum e : enums) { Map<String, Object> eMap = new HashMap(); String enumNameValue = e.name(); for (Field field : fieldList) { field.setAccessible(true); if (field.getName().equals(enumName)) { enumNameValue = enumNameValue + ";" + field.get(e); } else { eMap.put(field.getName(), field.get(e)); } } if (enumNameValue.startsWith(";")) { enumNameValue = enumNameValue.substring(1); } eMap.put(enumName, enumNameValue); resultList.add(eMap); } return resultList; } catch (RuntimeException | IllegalAccessException e) { } return null; } }
以上就是全部實現的代碼了。我們來寫一個測試類測試下效果
public class test { @Test public void tests(){ InterprectChineseUtils <ServiceOrgAreasExamine> interprectChineseUtils = new InterprectChineseUtils(); ServiceOrgAreasExamine serviceOrgAreasExamine = new ServiceOrgAreasExamine(); serviceOrgAreasExamine.setExamineStatus("1"); serviceOrgAreasExamine.setOrganId(1); interprectChineseUtils.reflexEnum(serviceOrgAreasExamine); System.out.println(serviceOrgAreasExamine.toString()); } }
運行后內容如下
至此大功告成。再也不用寫一堆麻煩的判斷進行翻譯說明了,用起來就很方便了。前端直接就能拿到想要顯示的內容了~
小小功能完成了,如果轉載請標明出處。