MyBatis-Plus 使用枚舉自動關聯注入

什麼是枚舉自動注入?

官方文檔是這麼解釋的java

解決了繁瑣的配置,讓 mybatis 優雅的使用枚舉屬性!git

按個人理解是維護在內存中且不易修改的輕量級字典。目前以爲這個功能的使用場景相對有限,可是若是有用到的話開箱即用也是很棒的。廢話很少說,接下來讓咱們看一下它的實際效果吧。github

實際效果

一般狀況下,咱們會這樣聲明一個用戶實體spring

public class User {
    private String id;
    private String name;
    private Integer age;
    private String phone;
    //省略getter&setter&constructor
    ...
}

那麼最終獲取到的JSON數據應該相似於這樣數據庫

{
        id: "1",
        name: "張三",
        age: 18,
        phone: "10000"
}

如若使用MyBatis-Plus的枚舉自動關聯注入,能夠更優雅的實現以下效果json

{
        id: "1",
        name: "張三",
        age: "十八歲",
        phone: "中國電信"
}

實現步驟

實現過程僅有三步且很是簡單,代碼量也很是的少,下面介紹一下實現步驟。mybatis

    1.建立兩個枚舉對象,分別爲AgeEnum與PhoneEnum,這裏使用枚舉創建一個映射關係。app

public enum AgeEnum implements IEnum {
    ONE(1, "一歲"),
    TWO(2, "二歲");

    private int age;
    private String desc;

    AgeEnum(final int age, final String desc) {
        this.age = age;
        this.desc = desc;
    }

    @Override
    public Serializable getValue() {
        return this.age;
    }

    @JsonValue
    public String getDesc(){
        return this.desc;
    }
}
public enum PhoneEnum implements IEnum {
    CMCC("10086", "中國移動"),
    CUCC("10010", "中國聯通"),
    CT("10000", "中國電信");

    private String phone;
    private String desc;

    PhoneEnum(final String phone, final String desc) {
        this.phone = phone;
        this.desc = desc;
    }

    @Override
    public Serializable getValue() {
        return this.phone;
    }

    @JsonValue
    public String getDesc(){
        return this.desc;
    }
}

注意:dom

  • @JsonValue是使用JackSon解析時有效,若使用fastjson,請看官方文檔提供的解決方案
  • 不要把@JsonValue打成@JsonView了,不然自動關聯注入的是枚舉名(name屬性),以下所示
  • 別忘記實現IEnum接口,不然自動關聯注入的是枚舉名(name屬性),以下所示
{
        id: "1",
        name: "張三",
        age: "十八歲",
        phone: "CT"
}

    2.將User實體中的屬性替換爲枚舉,例如ide

public class User {
    private String id;
    private String name;
    private AgeEnum age;
    private PhoneEnum phone;
    //省略getter&setter&constructor
    ...
}

    3.配置掃描枚舉,添加以下配置

mybatis-plus.typeEnumsPackage=com.xxx.xxx.enums//枚舉所在路徑

至此,使用MyBatis-Plus的枚舉自動關聯注入就完成了。

踩坑

在使用枚舉自動關聯注入時,還踩了一個坑。在代碼正確的狀況下出現了以下問題。

{
        id: null,
        name: null,
        age: null,
        phone: null
}

查出的全部值都爲null,經過DEBUG跟蹤代碼發現問題。數據庫中將實體中的某個枚舉屬性設置爲了tinyint類型,在數據庫中存儲的值是1,枚舉中也是使用1來映射關係,然而MyBaits-Plus在獲取值是卻讀成了true,所以枚舉並無映射成功,返回null值。

當獲取IsEnableEnum的枚舉時,會執行這行代碼獲取枚舉中的關係映射

EnumUtils.valueOf(this.type, rs.getObject(columnName));

可是MyBatis讀取到的值變成了true

沒法正確匹配到映射的值,返回null值,IsEnableEnum中聲明的映射關係以下。

ENABLE(1, "可用"), LIMIT(-1, "禁用");

解決方法

    1.將表中IsEnableEnum枚舉對應的字段is_enable類型由tinyint改成int便可,這種解決方法的優勢就是不用修改代碼就解決問題。

    2.MySQL中tinyint(1)對應Java中的boolean類型,非0爲true,0爲false。所以修改IsEnableEnum中的映射關係,以下。

ENABLE(true, "可用"), LIMIT(false, "禁用");

參數解析

當使用枚舉注入的方式時,做爲參數解析若是不注意會出現解析異常的狀況。這裏以修改User的is_enable值(數據庫表中字段屬性設置爲int)爲例看下具體解析異常狀況的問題。例如,咱們須要經過下面這個接口接收JSON請求參數來修改用戶的信息。

@PostMapping
public User saveUser(@RequestBody User user) {
    return userService.insertOrUpdate(user) ? userService.selectById(user.getId()) : null;
}

使用Postman模擬請求,JSON參數

{
	"id":"922000984245391362",
	"isEnable":-1
}

響應結果

{
    "timestamp": "2018-05-12T04:20:15.920+0000",
    "status": 400,
    "error": "Bad Request",
    "exception": "org.springframework.http.converter.HttpMessageNotReadableException",
    "message": "JSON parse error: Can not deserialize value of type com.github.common.domain.enums.IsEnableEnum from number -1: index value outside legal index range [0..1]; nested exception is com.fasterxml.jackson.databind.exc.InvalidFormatException: Can not deserialize value of type com.github.common.domain.enums.IsEnableEnum from number -1: index value outside legal index range [0..1]\n at [Source: java.io.PushbackInputStream@25386a8e; line: 3, column: 13] (through reference chain: com.github.common.domain.User[\"isEnable\"])",
    "path": "/"
}

從錯誤信息咱們可知,沒法將-1映射成IsEnableEnum枚舉,可用範圍是0..1,那麼應該怎麼解決呢?

本身摸索出的解決方式有兩種,分別爲

  1. 使用value屬性映射,通過測試0對應的是ENABLE(1, "可用"),1對應的是LIMIT(-1, "禁用")。很奇葩吧,所以不推薦此方式。
  2. 使用desc屬性映射,將JSON請求參數改爲以下就能夠解析成功不報錯。
{
	"id":"922000984245391362",
	"isEnable":"禁用"
}

總結

MyBatis-Plus這個特性目前用的仍是很少,本質上其實仍是把映射關係寫死在代碼中且我的以爲設計有些許不合理的地方,並不能替代字典,所以仍是推薦使用字典方式,能夠動態的修改映射關係。當項目遇到但願使用比字典更輕更快更容易上手的場景時,能夠嘗試使用枚舉注入的方式。

針對於解決方法的選擇我的想法是,當存儲的值僅有兩個且關係相對時,可使用方法二,而在任何場景下方法一都適用,所以我的比較推薦方法一,由於能夠存儲更多的值和映射關係,例如上文的電話號碼枚舉。

最後,貼上MyBatis-Plus的官方文檔,強烈推薦小夥伴們去嘗試使用,很是棒的一個開源項目。

相關文章
相關標籤/搜索