闲碎记事本 闲碎记事本
首页
  • JAVA
  • Cloudflare
  • 学完再改一遍UI
友链
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

YAN

我要偷偷记录...
首页
  • JAVA
  • Cloudflare
  • 学完再改一遍UI
友链
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • java

    • SpringBoot

    • SpringSecurity

    • MybatisPlus

    • Netty

    • sip

    • 其他

      • MDC 使用
      • 位运算
      • RedisMQ实现
      • 自定义枚举序列化
      • Mybatis使用自定义枚举
        • 背景
        • 实现
          • 1. 首先定义一个公共接口 BaseBizEnum
          • 2. 改造下之前的枚举类
          • 3.自定义枚举处理器基类
          • 4.指定枚举处理器
          • 5.加入配置
      • Jackson反序列化泛型注意点
      • 敏感词过滤算法
      • 线程
      • 并发学习
      • jni使用
      • 关于注释
      • 为什么一个Byte用两个16进制表示
      • JAVA获取系统信息
      • 对extends和super的理解
      • JAVA系统API
      • java探针初探
      • JAVA获取USB信息
      • HashMap初探
      • JAVA远程调试
      • 初探webflux
      • SSE示例
  • linux

  • docker

  • redis

  • nginx

  • mysql

  • 其他

  • 环境搭建

  • 知识库
  • java
  • 其他
Yan
2023-03-06
目录

Mybatis使用自定义枚举

# MyBatis使用自定义枚举

# 背景

通常我们会使用类似 1==男,2==女的数据类型在mysql中进行存储。 但是这种数据类型不不易于维护的,在类型过多的情况下经常会忘记int值的含义。所以大多情况下会使用枚举类,示例如下:


@AllArgsConstructor
@Getter
public enum SexType  {
    /***/
    BOY(1,"男"),
    GIRL(2,"女");

    private final Integer code;

    private final String val;

}

# 实现

mybatis 默认的类型转换类为 BaseTypeHandler

通过观察BaseTypeHandler 子类,我们发现了EnumTypeHandler 再观察实现,发现他使用的是 parameter.name() 和Enum.valueOf() 看这里到能清楚的知道默认使用的是Enum.name()值,对应我们的枚举SexType也就是BOY/GIRL,显然不符合我们需要存储Enum.code值的需求。 所有我们需要自定义一个枚举转换器

# 1. 首先定义一个公共接口 BaseBizEnum

public interface BaseBizEnum {

    /**
     * 得到枚举code,对应数据库int值
     * @return int
     */
    Integer getCode();
    /**
     * 得到枚举值 ,对应前端显示值
     * @return str
     */
    String getVal();

}

# 2. 改造下之前的枚举类

@AllArgsConstructor
@Getter
public enum SexType implements BaseBizEnum {
    /***/
    BOY(1,"男"),
    GIRL(2,"女");


    private final Integer code;


    private final String val;

}

# 3.自定义枚举处理器基类

@Slf4j
public class BizEnumTypeHandler<E extends BaseBizEnum>  extends BaseTypeHandler<BaseBizEnum> {

    private Class<E> type;

    //初始化时定义枚举和code的映射关系
    private final Map<Integer,E> enumsMap = new HashMap<>();

    public BizEnumTypeHandler() {

    }

    public BizEnumTypeHandler(Class<E> type) {
        if (type == null) {
            throw new IllegalArgumentException("Type argument cannot be null");
        }
        this.type = type;
        for (E enumConstant : type.getEnumConstants()) {
            enumsMap.put(enumConstant.getCode(),enumConstant);
        }
        if (this.enumsMap.size() == 0) {
            throw new IllegalArgumentException(type.getSimpleName() + " does not represent an enum type.");
        }
    }

    @Override
    public void setNonNullParameter(PreparedStatement preparedStatement, int i, BaseBizEnum baseBizEnum, JdbcType jdbcType) throws SQLException {
        preparedStatement.setInt(i,baseBizEnum.getCode());
    }

    @Override
    public BaseBizEnum getNullableResult(ResultSet resultSet, String columnName) throws SQLException {
        if (resultSet.wasNull()) {
            return null;
        }
        int code = resultSet.getInt(columnName);
        return getEnum(code);
    }

    @Override
    public BaseBizEnum getNullableResult(ResultSet resultSet, int columnIndex) throws SQLException {

        if (resultSet.wasNull()) {
            return null;
        }
        int code = resultSet.getInt(columnIndex);
        return getEnum(code);
    }

    @Override
    public BaseBizEnum getNullableResult(CallableStatement callableStatement, int columnIndex) throws SQLException {

        if (callableStatement.wasNull()) {
            return null;
        }
        int code = callableStatement.getInt(columnIndex);
        return getEnum(code);
    }


    private E getEnum(Integer code) {
        try {
            return getEnumByValue(code);
        } catch (Exception ex) {
            throw new IllegalArgumentException(
                    "Cannot convert " + code + " to " + type.getSimpleName() + " by ordinal value.", ex);
        }
    }

    protected E getEnumByValue(Integer code) {
        return enumsMap.get(code);
    }

}

到了这一步,相信懂行的同学都已经明白啥意思了。很简单就是在构造器里简历 code-enum 的对应关系,存储时直接存储枚举的code值,取出时通过code值得到枚举值。那么问题来了,构造器啥时候调用呢。继续往下看。。。

# 4.指定枚举处理器

@MappedTypes(value = {SexType.class})
@MappedJdbcTypes(value = {JdbcType.INTEGER,JdbcType.TINYINT,JdbcType.SMALLINT})
public class SexTypeEnumTypeHandler extends BizEnumTypeHandler<SexType> {

    /**
     * 实例化时使用父类构造器
     */
    public SexTypeEnumTypeHandler() {
        super(SexType.class);
    }

}

# 5.加入配置

mybatis:
  type-handlers-package: com.xxx

到这里一切就结束了。此时如果有对象属性SexType==SexType.BOY 数据库将会存储1,SexType.GIRL 同理存储2。 获取时1,2将自动转换为SexType.BOY,SexType.GIRL。下面附上测试类有兴趣的同学可自行测试

@RestController
@RequestMapping(value = "/sex")
public class SexController {
    @Resource
    private TestSexMapper testSexMapper;

    @GetMapping(value = "insertTest")
    public Object insertTest(String name, SexType sexType) {
        MdcUtil.put("开始");
        System.out.println("name="+name+",agreementType="+sexType.name());
        return testSexMapper.insert(name,sexType);
    }
    @GetMapping(value = "getTest")
    public Object getTest( ) {
        MdcUtil.put("开始");
        return testSexMapper.selectByName();
    }
}

public interface TestSexMapper {

    @Insert("insert into test_agreement_info(name,agreement_type) value(#{name},#{sexType})")
    boolean insert(@Param("name") String name, @Param("agreementType") SexType sexType);

    @Select("select  *  from test_agreement_info")
    List<TestSexModel> selectByName();

}

@Data
public class TestSexModel implements Serializable {

    private static final long serialVersionUID = 3285353798809906968L;

    private String name;

    private SexType sexType;

}

上次更新: 2025/05/22, 07:52:48
自定义枚举序列化
Jackson反序列化泛型注意点

← 自定义枚举序列化 Jackson反序列化泛型注意点→

最近更新
01
Caddy操作指南
04-25
02
虚拟机磁盘扩展
04-22
03
Swap空间
04-22
更多文章>
Theme by Vdoing | Copyright © 2022-2025 YAN | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式