栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

MyBatis/MyBatis-Plus 使用枚举参数异常, SpringBoot枚举参数异常

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

MyBatis/MyBatis-Plus 使用枚举参数异常, SpringBoot枚举参数异常

视频地址: https://www.bilibili.com/video/BV1kf4y1i761?p=15


在开发中,有很多字段使用枚举类型可以更好地表达我们想要的效果。但在实际使用过程中,却存在两个问题

    枚举参数映射到数据库的时候类型匹配不上接收枚举参数的时候也会存在结果不对的情况

一、前提
1.1、StatusEnum

比如我们有一个这样的枚举

import lombok.Getter;
import lombok.ToString;


@Getter
@ToString
public enum StatusEnum {

    ENABLE(1, "启用"),
    DISABLE(0,"禁用")
    ;

    private Integer code;
    private String name;
    
    StatusEnum(Integer code, String name) {
        this.code = code;
        this.name = name;
    }
}

1-2、实体

定义一个这样的实体

public class Menu {

    
    @TableId
    private Integer id;

    
    @NotBlank(message = "菜单名称不能为空")
    private String name;

    
    private StatusEnum status;
}

1-3、使用

其它的参数封装,mapper注入不重要

menuMapper.insert(menu);

1.4、异常

运行上面的代码会报错

### The error occurred while setting parameters
### SQL: INSERT INTO xdx_menu  ( name,   status, create_at, create_by )  VALUES  ( ?,   ?, ?, ? )
### Cause: java.sql.SQLException: #HY000
; uncategorized SQLException; SQL state [HY000]; error code [1366]; #HY000; nested exception is java.sql.SQLException: #HY000

二、解决 MyBatis/MyBatis-Plus 使用枚举参数异常

之所以会发生这样的问题,是因为在MyBatis参数拼接的时候,它不知道你这个枚举参数是要传递什么样的值,并且每个人定义枚举的样式可能都不一样。解决办法:

    写一个 IbaseEnum 接口让所有的枚举都去继承这个接口,这样所有的枚举都有共性了自定义一个枚举处理器,继承 baseTypeHandler 或 实现 TypeHandler 接口配置handler default-enum-type-handler

在 TypeHandler里面有一个方法 setParameter 在进行SQL拼接的时候会调用这个方法获取参数。

这里我的做法是继承 baseTypeHandler 类,它里面其实也是实现了 TypeHandler 接口,对里面一些方法进行了实现

而在 baseTypeHandler 方法里面重写了 setParameter 方法,里面去调用了一个抽象方法 setNonNullParameter ,我们的实现方法主要是去重写这个方法就好了。


2-1、IbaseEnum

它里面的内容很简单,我们就是要通过这个接口,知道:

枚举的key是什么类型枚举的value是什么类型以及枚举是什么

import com.fasterxml.jackson.annotation.JsonCreator;
import java.util.linkedHashMap;
import java.util.Map;

public interface IbaseEnum> {

    K getCode();

    V getMsg();
}

2-2、StatusEnum

StatusEnum改造,实现 通用接口

import lombok.Getter;
import lombok.ToString;


@Getter
@ToString
public enum StatusEnum implements IbaseEnum{

    ENABLE(1, "启用"),
    DISABLE(0,"禁用")
    ;

    private Integer code;
    private String name;


    StatusEnum(Integer code, String name) {
        this.code = code;
        this.name = name;
    }

    @Override
    public String getMsg() {
        return this.name;
    }

    @Override
    public Integer getCode() {
        return this.code;
    }
}

2-3、EnumTypeHandler

这里面还重写了其它的方法,大家只要看 setNonNullParameter方法即可,有兴趣的可以自行研究其它的

import com.xdx97.blog.common.enums.IbaseEnum;
import org.apache.ibatis.type.baseTypeHandler;
import org.apache.ibatis.type.JdbcType;

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

public class EnumTypeHandler & IbaseEnum> extends baseTypeHandler {
    private Class type;

    public EnumTypeHandler(Class type) {
        if(type == null) {
            throw new IllegalArgumentException("Type argument cannot be null");
        } else {
            this.type = type;
        }
    }


    public void setNonNullParameter(PreparedStatement ps, int i, IbaseEnum parameter, JdbcType jdbcType) throws SQLException {
        if(jdbcType == null) {
            ps.setString(i, parameter.getCode().toString());
        } else {
            ps.setObject(i, parameter.getMsg(), 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);
    }
}

2-4、application.yml
mybatis-plus:
  configuration:
    # 枚举处理器
    default-enum-type-handler: com.xdx97.blog.common.handler.EnumTypeHandler

三、 SpringBoot枚举参数异常

之所以在接受枚举参数的时候和我们预期的结果不一致是因为系列化和反序列化导致的,SpringBoot默认是使用 jackson 序列化的。我们只需要自定义序列化的过程即可。


3-1、IbaseEnum

在上述的IbaseEnum 中新增2个方法

import com.fasterxml.jackson.annotation.JsonCreator;
import java.util.linkedHashMap;
import java.util.Map;

public interface IbaseEnum> {
    Map, Map> map = new linkedHashMap();

    default void initMap(K code, T t) {
        if (map.containsKey(t.getClass())) {
            Map tmp = (Map)map.get(t.getClass());
            tmp.put(code, t);
            map.put(t.getClass(), tmp);
        } else {
            Map tmp = new linkedHashMap();
            tmp.put(code, t);
            map.put(t.getClass(), tmp);
        }

    }

    @JsonCreator
    static , K> T get(Class clazz, K code) {
        if (map.get(clazz) == null) {
            return null;
        } else {
            Object _code = code;
            if (code instanceof String) {
                _code = code.toString().trim();
            }
            return (T) map.get(clazz).get(_code);
        }
    }

    K getCode();

    V getMsg();
}

3-2、StatusEnum

在枚举初始化的时候注入到IbaseEnum里面去 initMap, 新增序列化方法

import com.fasterxml.jackson.annotation.JsonCreator;
import lombok.Getter;
import lombok.ToString;


@Getter
@ToString
public enum StatusEnum implements IbaseEnum{

    ENABLE(1, "启用"),
    DISABLE(0,"禁用")
    ;

    private Integer code;
    private String name;


    StatusEnum(Integer code, String name) {
        this.code = code;
        this.name = name;
        initMap(code, this);
    }

    @Override
    public String getMsg() {
        return this.name;
    }

    @Override
    public Integer getCode() {
        return this.code;
    }

    @JsonCreator
    public static StatusEnum forValue(Integer code) {
        return IbaseEnum.get(StatusEnum.class, code);
    }
}



关注微信公众号(小道仙97)回复:xdxframeSimple 获取源码。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/763575.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号