日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

SpringBoot Mybatis EnumTypeHandler自定义统一处理器

發布時間:2024/9/30 javascript 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 SpringBoot Mybatis EnumTypeHandler自定义统一处理器 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
  • 需求
    mybatis目前已經內嵌入了springboot中了,這說明其目前在數據訪問層的絕對優勢。而我們在開發的過程中,往往會在程序中使用枚舉(enum) 來表示一些狀態或選項,而在數據庫中使用數字來存儲。這樣做的好處是在程序中使用enum更直觀的可以知道每個值代表的狀態及含義,還可以做國際化的功能。那么這樣會帶來一個問題那就是:程序中的枚舉?與?數據庫中的數字?轉換問題。

  • 介紹
    抱歉,最近因為實在太忙,所以寫一半就停了。等有空繼續。不將就哈。停了大概一周的時間,在周一的早上繼續來完成這篇文章。

    無論是 MyBatis 在預處理語句(PreparedStatement)中設置一個參數時,還是從結果集中取出一個值時,都會用類型處理器將獲取的值以合適的方式轉換成 Java 類型。Mybatis默認為我們實現了許多TypeHandler, 當我們沒有配置指定TypeHandler時,Mybatis會根據參數或者返回結果的不同,默認為我們選擇合適的TypeHandler處理。

    對于enum而言,在mybatis中已經存在了EnumTypeHandler和EnumOrdinalTypeHandler兩大處理器,他們都是繼承自BaseTypeHandler處理器,那為何不能使用mybatis自定義的enum處理器而是要自己再定義枚舉處理器呢?下面為您一步一步剖析。

  • 分析
    首先說說EnumTypeHandler與EnumOrdinalTypeHandler兩者之間的區別吧:
    EnumTypeHandler存入數據庫的是枚舉的name,EnumOrdinalTypeHandler存入數據庫的是枚舉的位置。例如下方的枚舉,當我們有一個枚舉值是EStatus.init時,這時我們使用mybatis?EnumTypeHandler存入數據庫的是"init"字符串;而EnumOrdinalTypeHandler存入的是3,因為init是第四個值,第一個值disable的index是0。public enum EStatus {disable("0"), enable("1"), deleted("2"),init("10"), start("11"), wait("12"), end("13");}上面是一個簡單的枚舉。它包含了7個狀態值,當我們沒有設置枚舉處理器時,mybatis默認使用EnumTypeHandler作為缺省處理器,當需要將枚舉存入數據庫時它調用的是枚舉的name()方法從而獲取的是像:disable,enable這樣的值存入了數據庫,并不是我們想要的(value)value存入數據庫,可以看看源碼:
    // // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) //package org.apache.ibatis.type;import java.sql.CallableStatement; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException;public class EnumTypeHandler<E extends Enum<E>> extends BaseTypeHandler<E> {private Class<E> type;public EnumTypeHandler(Class<E> type) {if(type == null) {throw new IllegalArgumentException("Type argument cannot be null");} else {this.type = type;}}public void setNonNullParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType) throws SQLException {if(jdbcType == null) {ps.setString(i, parameter.name());} else {ps.setObject(i, parameter.name(), jdbcType.TYPE_CODE);}}public E getNullableResult(ResultSet rs, String columnName) throws SQLException {String s = rs.getString(columnName);return s == null?null:Enum.valueOf(this.type, s);}public E getNullableResult(ResultSet rs, int columnIndex) throws SQLException {String s = rs.getString(columnIndex);return s == null?null:Enum.valueOf(this.type, s);}public E getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {String s = cs.getString(columnIndex);return s == null?null:Enum.valueOf(this.type, s);} }大家可以看到setNonNullParameter方法中ps.setString(i, parameter.name());調用的確實是name()方法。
    而在將數據庫字段轉java Bean字段的時候使用的方法getNullableResult中都是調用Enum.valueOf(this.type, s),而這個方法底層調用的是get(name)方法。
    所以EnumTypeHandler對我們來說并不適用,因為它在java Bean轉數據庫數據時獲取的是枚舉的name而不是value。
    而EnumOrdinalTypeHandler存入數據庫的是參數的位置,所以這兩個處理器都不是我們想要的。但是我們可以根據EnumTypeHandler的設計思想轉變一下,變成符合我們想要的統一處理器。

  • 教程
    首先我們定義一個BaseEnumTypeHandler繼承BaseTypeHandler,并實現抽象方法。
    package com.cmc.base.handler;import com.cmc.base.enums.EStatus; import com.cmc.base.utils.EnumUtil; import org.apache.ibatis.type.BaseTypeHandler; import org.apache.ibatis.type.JdbcType; import org.apache.ibatis.type.MappedTypes;import java.sql.CallableStatement; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException;public class BaseEnumTypeHandler<E extends Enum<E>> extends BaseTypeHandler<E> {private Class<E> type;public BaseEnumTypeHandler() {}public BaseEnumTypeHandler(Class<E> type) {this.type = type;}@Overridepublic void setNonNullParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType) throws SQLException {if (jdbcType == null) {ps.setString(i, parameter.toString());} else {ps.setObject(i, parameter.name(), jdbcType.TYPE_CODE);}}@Overridepublic E getNullableResult(ResultSet rs, String columnName) throws SQLException {return get(rs.getString(columnName));}@Overridepublic E getNullableResult(ResultSet rs, int columnIndex) throws SQLException {return get(rs.getString(columnIndex));}@Overridepublic E getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {return get(cs.getString(columnIndex));}private <E extends Enum<E>> E get(String v) {if (v == null) return null;if (StringUtils.isNumeric(v)) {return get(type, Integer.parseInt(v));} else {return Enum.valueOf(type, v);}}private <E extends Enum<E>> E get(Class<E> type, int v) {Method method = null;E result = null;try {method = type.getMethod("get", int.class);result = (E)method.invoke(type, v);} catch (NoSuchMethodException e) {result = Enum.valueOf(type, String.valueOf(v));e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}return result;} }在上面的方法setNonNullParameter中大家可以看到我使用parameter.toString()替換了原來的parameter.name()方法,其實做到能統一處理枚舉的關鍵就是這里,因為toString方法是Object的方法,所以不管傳入的類型是什么都適用。而從數據庫中取出的數據轉Bean我使用的是和默認的處理器一致的方法get()。

    所以我們需要在枚舉中定義toString和get方法
    package com.cmc.base.enums;/*** 狀態枚舉* @author chenmc**/ public enum EStatus {disable("0"), enable("1"), deleted("2"),init("10"), start("11"), wait("12"), end("13");private final String value;private EStatus(String v) {this.value = v;}public String toString() {return this.value;}public static EStatus get(int v) {String str = String.valueOf(v);return get(str);}public static EStatus get(String str) {for (EStatus e : values()) {if(e.toString().equals(str)) {return e;}}return null;}/*public static String getName(EStatus e, Locale locale) {return I18N.getEnumName(e, locale);}*/ }大家可看到toString方法返回的是當前對象的value值,這樣就是我們想要的了。
    既然方法都寫好了,那下面給大家講講如何在springboot中使用。
    1.在application.properties或者application.yml中添加
    mybatis:mapperLocations: classpath:mapper/*.xmltypeAliasesPackage: com.cmc.schedule.model.entitytypeHandlersPackage: com.cmc.schedule.model.handlertypeHandlersPackage就是你自定義handler的包名,上面我們定義了一個BaseEnumTypeHandler,往往我們不太會在基類中修改或添加,因為基類可能是多個模塊公用的,這時在我們的項目中定義一個EnumTypeHandler去繼承我們的BaseEnumTypeHandler。
    package com.cmc.schedule.model.handler;import com.cmc.base.enums.EStatus; import com.cmc.base.handler.BaseEnumTypeHandler; import com.cmc.schedule.model.enums.EFeedback; import org.apache.ibatis.type.MappedTypes;/*** @author chenmc*/@MappedTypes(value = { EFeedback.class, EStatus.class}) public class EnumTypeHandler<E extends Enum<E>> extends BaseEnumTypeHandler<E> {public EnumTypeHandler(Class<E> type) {super(type);} }這樣有多少個enum需要轉換就可以在@MappedTypes注解中添加。是不是很方便了。

  • 結語
    希望可以幫助到大家,如果你有任何疑問都可以在下面留言,我會每天回復你。






總結

以上是生活随笔為你收集整理的SpringBoot Mybatis EnumTypeHandler自定义统一处理器的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。