1. 程式人生 > >mybatis 列舉自動轉換

mybatis 列舉自動轉換

基於springboot 整合mybatis  tk.mybatis   修改配置沒有生效,只好重寫 EnumTypeHandler 類

springboot 中 mybatis configuration 配置失效問題:https://blog.csdn.net/Keith003/article/details/84289638

結構如下

1、建立 BaseEnums 列舉公用介面

import java.io.Serializable;


public interface BaseEnums<E extends Enum<?>,T> extends Serializable {
    public String getLabel();
    public T getValue();

}

2、重寫 EnumTypeHandler 類

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 BaseTypeHandler typeHandler = null;

    public EnumTypeHandler(Class<E> type) {
        if (type == null) {
            throw new IllegalArgumentException("Type argument cannot be null");
        }
        if(isInterface(type, "BaseEnums介面得全路徑")){
            // 如果實現了 BaseEnums 則使用我們自定義的轉換器
            typeHandler = new CurrencyEnumHandler(type);
        }else {
            // 預設轉換器 也可換成 EnumOrdinalTypeHandler
            typeHandler = new DefaultEnumTypeHandler<>(type);
        }
    }

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType) throws SQLException {
        typeHandler.setNonNullParameter(ps,i, parameter,jdbcType);
    }

    @Override
    public E getNullableResult(ResultSet rs, String columnName) throws SQLException {
        return (E) typeHandler.getNullableResult(rs,columnName);
    }

    @Override
    public E getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return (E) typeHandler.getNullableResult(rs,columnIndex);
    }

    @Override
    public E getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return (E) typeHandler.getNullableResult(cs,columnIndex);
    }

    /***************************************************************************
     * 判斷物件o實現的所有介面中是否有szInterface
     * 2008-08-07修正多繼承中判斷介面的功能,
     * 以及修正介面繼承後的判斷功能
     * package test;
     *
     * public interfaceITest extends Serializable
     * public classTest1 implements ITest
     * public classTest2 extends Test1
     * public classTest3 extends Test2
     *
     * isInterface(Test3.class,"java.io.Serializable")=true
     * isInterface(Test3.class,"test.ITest")=true
     * @paramc
     * @paramsz Interface
     * @return
     */
    public boolean isInterface(Class c, String szInterface) {
        Class[] face = c.getInterfaces();
        for(int i=0,j = face.length; i<j; i++)
        {
            if(face[i].getName().equals(szInterface)) {
                return true;
            }else {
                Class[]face1 = face[i].getInterfaces();
                for(int x=0; x < face1.length; x++)
                {
                    if(face1[x].getName().equals(szInterface)) {
                        return true;
                    } else if(isInterface(face1[x],szInterface)) {
                        return true;
                    }
                }
            }
        }
        if(null!=c.getSuperclass()) {
            return isInterface(c.getSuperclass(),szInterface);
        }
        return false;
    }
}

3、建立 DefaultEnumTypeHandler類 內容為mybatis 中 EnumTypeHandler 類內容  為了不影響除列舉外得轉換

package org.apache.ibatis.type;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class DefaultEnumTypeHandler<E extends Enum<E>> extends BaseTypeHandler<E>  {
    private final Class<E> type;

    public DefaultEnumTypeHandler(Class<E> type) {
        if (type == null) {
            throw new IllegalArgumentException("Type argument cannot be null");
        }
        this.type = type;
    }

    @Override
    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); // see r3589
        }
    }

    @Override
    public E getNullableResult(ResultSet rs, String columnName) throws SQLException {
        String s = rs.getString(columnName);
        return s == null ? null : Enum.valueOf(type, s);
    }

    @Override
    public E getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        String s = rs.getString(columnIndex);
        return s == null ? null : Enum.valueOf(type, s);
    }

    @Override
    public E getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        String s = cs.getString(columnIndex);
        return s == null ? null : Enum.valueOf(type, s);
    }
}

4、建立  CurrencyEnumHandler類  自定義列舉轉換類

package org.apache.ibatis.type;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * class_name: CurrencyEnumHandler
 * package: org.apache.ibatis.type
 * describe: 列舉轉換類
 * creat_date: 2018/11/19
 * creat_time: 10:43
 **/
public class CurrencyEnumHandler<E extends Enum<E> & BaseEnums> extends BaseTypeHandler<E>{

    private Class<E> type;

    /**
     * 設定配置檔案設定的轉換類以及列舉類內容,供其他方法更便捷高效的實現
     * @param type 配置檔案中設定的轉換類
     */
    public CurrencyEnumHandler(Class<E> type) {
        if (type == null)
            throw new IllegalArgumentException("Type argument cannot be null");
        this.type = type;
    }
    /**
     * class_name:
     * param: 
     * describe: 用於定義設定引數時,該如何把 Java 型別的引數轉換為對應的資料庫型別
     * creat_date: 2018/11/19
     * creat_time: 11:34
     **/
    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, E parameter,
                                    JdbcType jdbcType) throws SQLException {
        //BaseTypeHandler已經幫我們做了parameter的null判斷
        if (jdbcType == null) {
            ps.setObject(i, getFieldValueByFieldName("value",parameter));
        } else {
            ps.setObject(i, getFieldValueByFieldName("value",parameter), jdbcType.TYPE_CODE);
        }
    }
    /**
     * class_name:
     * param: 
     * describe: 用於定義通過欄位名稱獲取欄位資料時,如何把資料庫型別轉換為對應的 Java 型別
     * creat_date: 2018/11/19
     * creat_time: 11:39
     **/
    @Override
    public E getNullableResult(ResultSet rs, String columnName)
            throws SQLException {
        // 根據資料庫儲存型別決定獲取型別
        Object code = rs.getObject(columnName);
        return rs.wasNull() ? null :  codeOf(code);
    }
    /**
     * class_name:
     * param: 
     * describe: 用於定義通過欄位索引獲取欄位資料時,如何把資料庫型別轉換為對應的 Java 型別
     * creat_date: 2018/11/19
     * creat_time: 11:41
     **/
    @Override
    public E getNullableResult(ResultSet rs, int columnIndex)
            throws SQLException {
        Object code = rs.getObject(columnIndex);
        return rs.wasNull() ? null :  codeOf(code);
    }
    /**
     * class_name: 
     * param: 
     * describe: 用定義呼叫儲存過程後,如何把資料庫型別轉換為對應的 Java 型別
     * creat_date: 2018/11/19
     * creat_time: 11:42
     **/
    @Override
    public E getNullableResult(CallableStatement cs, int columnIndex)
            throws SQLException {
        Object code = cs.getObject(columnIndex);
        return cs.wasNull() ? null : codeOf(code);
    }
    /**
     * class_name: 
     * param:
     * describe: 獲取列舉
     * creat_date: 2018/11/19
     * creat_time: 19:54
     **/
    private E codeOf(Object code){
        try {
            Method codeOf = type.getMethod("codeOf", Object.class);
            Object invoke = codeOf.invoke(codeOf, code);
            return (E)invoke;
        } catch (Exception ex) {
            throw new IllegalArgumentException("Cannot convert " + code + " to " + type.getSimpleName() + " by code value.", ex);
        }
    }

    /**
     * 根據屬性名獲取屬性值
     *
     * @param fieldName
     * @param object
     * @return
     */
    private Object getFieldValueByFieldName(String fieldName, Object object) {
        try {
            Field field = object.getClass().getDeclaredField(fieldName);
            //設定物件的訪問許可權,保證對private的屬性的訪問
            field.setAccessible(true);
            return  field.get(object);
        } catch (Exception e) {
            return null;
        }
    }


}

5、建立自己得列舉 實現BaseEnums 介面

package mmall.enums;

import com.fasterxml.jackson.annotation.JsonValue;

/**
 * class_name: UpperLowerShelfStateEnum
 * package: mmall.enums
 * describe: 活動上下架列舉狀態
 *              0:待上架   1:上架    2:下架
 * creat_date: 2018/11/19
 * creat_time: 10:38
 **/
public enum UpperLowerShelfStateEnum implements BaseEnums<UpperLowerShelfStateEnum, String> {

    To_be_on_the_shelfteacher("待上架","0"),
    On_the_shelf("上架","1"),
    Lower_frame("下架","2");

    private String value;
    private String lable;

    private UpperLowerShelfStateEnum(String lable, String value) {
        this.value = value;
        this.lable = lable;
    }
    @JsonValue
    public String getValue() {
        return value;
    }
    public void setValue(String value) {
        this.value = value;
    }

    public String getLabel() {
        return lable;
    }
    public void getLabel(String lable) {
        this.lable = lable;
    }
    /**
    * 通過value 值進行查詢對應列舉
    */
    public static UpperLowerShelfStateEnum codeOf(Object code){
        UpperLowerShelfStateEnum[] values = UpperLowerShelfStateEnum.values();
        for (UpperLowerShelfStateEnum e : values) {
            if (e.getValue().equals(code)) {
                return e;
            }
        }
        return null;
    }
}

注:本文中向資料庫中儲存得是列舉中value 值 如果需要 可自行修改