mybatis-plus是如何只做增強不做改變之通用列舉篇

介紹
首先,讓我們來看張高清無碼圖,左邊兩個是mybatis原生的,右邊的兩個是mybatis-plus的.
- EnumTypeHandler( mybatis包 ) : VARCHAR -任何相容的字串型別,儲存列舉的名稱
- EnumOrdinalTypeHandler: 任何相容的 NUMERIC 或 DOUBLE 型別,儲存列舉的索引
- EnumAnnotationTypeHandler: 處理自定義列舉屬性轉換器( 註解方式 ) 列舉類需要標記@EnumValue註解
- EnumTypeHandler( mybatis-plus包 ): 自定義列舉屬性轉換器( 非註解方式 ) 列舉類需要實現IEnum介面.
如何配置
-
mybatis原生配置方式:
)
-
mybatis-plus配置方式: 參考下官方使用文件吧,比較簡單,劃個重點( typeEnumsPackage配置 ) 通用列舉使用
原始碼解讀
//MybatisSqlSessionFactoryBean#buildSqlSessionFactory //判斷是否配置了列舉包掃描 if (hasLength(this.typeEnumsPackage)) { Set<Class> classes; // 掃描包下的class,這裡可以看出支援多個包配置.用,或;進行分隔 if (typeEnumsPackage.contains(StringPool.STAR) && !typeEnumsPackage.contains(StringPool.COMMA) && !typeEnumsPackage.contains(StringPool.SEMICOLON)) { // 配置包含*且不包含,和; classes = PackageHelper.scanTypePackage(typeEnumsPackage); if (classes.isEmpty()) { LOGGER.warn(() -> "Can't find class in '[" + typeEnumsPackage + "]' package. Please check your configuration."); } } else { //按,;進行包配置切割 String[] typeEnumsPackageArray = tokenizeToStringArray(this.typeEnumsPackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS); Assert.notNull(typeEnumsPackageArray, "not find typeEnumsPackage:" + typeEnumsPackage); classes = new HashSet<>(); //迴圈處理包下的class掃描 for (String typePackage : typeEnumsPackageArray) { Set<Class> scanTypePackage = PackageHelper.scanTypePackage(typePackage); if (scanTypePackage.isEmpty()) { LOGGER.warn(() -> "Can't find class in '[" + typePackage + "]' package. Please check your configuration."); } else { classes.addAll(PackageHelper.scanTypePackage(typePackage)); } } } // 取得型別轉換註冊器 TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry(); classes.forEach(cls ->{ //判斷當前類是不是列舉類,因為在同個包下,有可能不是列舉,所以跳過非列舉類 if (cls.isEnum()) { //判斷當前列舉類是不是實現類IEnum介面 if (IEnum.class.isAssignableFrom(cls)) { // 註冊上當前類的列舉處理器為EnumTypeHandler typeHandlerRegistry.register(cls, EnumTypeHandler.class); } else { // 非IEnum實現類,反射欄位遍歷,獲取第一個@EnumValue欄位 Optional<Field> optional = dealEnumType(cls); if (optional.isPresent()) { Field field = optional.get(); field.setAccessible(true); //快取下當前類對應的欄位----再次劃個重點 EnumAnnotationTypeHandler.addEnumType(cls, field); //註冊上當前類的列舉處理器為EnumAnnotationTypeHandler typeHandlerRegistry.register(cls, EnumAnnotationTypeHandler.class); } //這裡找不到了的話就會使用預設的mybatis列舉處理器了(配置方式參考後面). } } }); } //尋找類第一個標記@EnumValue的欄位 protected Optional<Field> dealEnumType(Class<?> clazz) { return clazz.isEnum() ? Arrays.stream(clazz.getDeclaredFields()).filter(field -> field.isAnnotationPresent(EnumValue.class)).findFirst() : Optional.empty(); } 複製程式碼
總結
mybatis-plus通過 typeEnumsPackage
這屬性,來進行列舉類掃描並註冊上對應的列舉處理器,在未配置列舉包掃描時或列舉不符合mybaits-plus的註冊條件(實現 IEnum
介面或註解 @EnumValue
欄位),一律走原生mybatis列舉處理,這項配置可通過設定mybatis的 defaultEnumTypeHandler
來指定.
小提示
最好不要將預設列舉型別處理器指定為mybatis-plus的 EnumAnnotationTypeHandler
,因為這個類在掃描的時候進行了欄位的快取,如果直接將預設列舉處理器指定它,是無法使用的.
指定預設列舉處理器方式
//javaconfig MybatisConfiguration configuration = new MybatisConfiguration(); configuration.setDefaultEnumTypeHandler(EnumOrdinalTypeHandler.class); 複製程式碼
#yaml mybatis-plus: configuration: default-enum-type-handler: org.apache.ibatis.type.EnumOrdinalTypeHandler 複製程式碼
<!--xml--> <setting name="defaultEnumTypeHandler" value="org.apache.ibatis.type.EnumOrdinalTypeHandler"/> 複製程式碼