mybatis 中使用枚举

    xiaoxiao2023-10-28  149

    文章目录

    mybatis 中使用枚举1. 内置枚举转换器1.1 内置枚举转换器介绍1.1.1 EnumTypeHandler1.1.2 EnumOrdinalTypeHandler 1.2 内置枚举转换器使用 2. 自定义类型转换器2.1 BaseTypeHandler 抽象类2.2 自定义枚举转换器实现2.2.1 枚举接口2.2.2 自定义类型转换器 2.3 自定义枚举转换器测试2.3.1 用户实体对象2.3.2 控制层2.3.3 接口层2.3.4 接口实现层2.3.5 持久层2.3.6 mybatis 配置文件2.3.7 mybatis 映射文件 2.4 数据库脚本2.5 接口测试2.6 Reference  

    mybatis 中使用枚举

    1. 内置枚举转换器

    1.1 内置枚举转换器介绍

    1.1.1 EnumTypeHandler

    默认的枚举转换器,该转换器将枚举实例转换为实例名称的字符串,即将 SexEnum.MAN 转换 MAN

    1.1.2 EnumOrdinalTypeHandler

    将枚举实例的 ordinal 属性作为取值,即 SexEnum.MAN 转换为 0, SexEnum.WOMAN转换为 1

    MyBatis内置枚举转换器

    org.apache.ibatis.type.EnumTypeHandlerorg.apache.ibatis.type.EnumOrdinalTypeHandler

     

    1.2 内置枚举转换器使用

    mybatis-config.xml

    <typeHandlers> <typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler" javaType="com.answer.aal.entity.StatusEnum" /> <typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler" javaType="com.answer.aal.entity.SexEnum" /> </typeHandlers>

     


    2. 自定义类型转换器

    2.1 BaseTypeHandler 抽象类

    public abstract class BaseTypeHandler<T> extends TypeReference<T> implements TypeHandler<T> { // ... /** * 用于定义设置参数时,该如何把Java类型的参数转换为对应的数据库类型 * */ public abstract void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException; /** * 用于定义通过字段名称获取字段数据时,如何把数据库类型转换为对应的Java类型 * */ public abstract T getNullableResult(ResultSet rs, String columnName) throws SQLException; /** * 用于定义通过字段索引获取字段数据时,如何把数据库类型转换为对应的Java类型 * */ public abstract T getNullableResult(ResultSet rs, int columnIndex) throws SQLException; /** * 用定义调用存储过程后,如何把数据库类型转换为对应的Java类型 * */ public abstract T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException; }

     

    2.2 自定义枚举转换器实现

    2.2.1 枚举接口

    枚举通用行为接口: IEnum

    public interface IEnum<E extends Enum<?>, T> { T getValue(); }

      性别枚举: SexEnum

    public enum SexEnum implements IEnum<EducationEnum, Integer> { /** 男 */ MAN(0), /** 女 */ WOMAN(1); private int value; SexEnum(int value) { this.value = value; } @Override public Integer getValue() { return value; } }

      学历枚举: EducationEnum

    public enum EducationEnum implements IEnum<EducationEnum, String> { /** 小学 */ PRIMARY_SCHOOL("PRIMARY"), /** * 初中 * */ JUNIOR_SCHOOL("JUNIOR"), /** * 高中 * */ HIGH_SCHOOL("HIGH"), /** * 大学 * */ UNIVERSITY_SCHOOL("UNIVERSITY") ; private String value; EducationEnum(String value) { this.value = value; } @Override public String getValue() { return value; } }

     

    2.2.2 自定义类型转换器

    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; import java.util.Objects; @MappedTypes(value = {SexEnum.class, EducationEnum.class}) public class BaseEnumTypeHandler<E extends Enum<E> & IEnum> extends BaseTypeHandler<E> { /** * 枚举的class */ private Class<E> type; /** * 枚举的每个子类枚 */ private E[] enums; /** * 一定要有默认的构造函数, 不然抛出 not found method 异常 */ public BaseEnumTypeHandler() { } /** * 设置配置文件设置的转换类以及枚举类内容, 供其他方法更便捷高效的实现 * * @param type 配置文件中设置的转换类 */ public BaseEnumTypeHandler(Class<E> type) { if (type == null) { throw new IllegalArgumentException("Type argument cannot be null"); } this.type = type; this.enums = type.getEnumConstants(); if (this.enums == null) { throw new IllegalArgumentException(type.getSimpleName() + " does not represent an enum type."); } } /** * 用于定义设置参数时,该如何把Java类型的参数转换为对应的数据库类型 * */ @Override public void setNonNullParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType) throws SQLException { /* * BaseTypeHandler已经帮我们做了parameter的null判断 * 数据库存储的是枚举的值, 所以我们这里使用 value , 如果需要存储 name, 可以自定义修改 */ if (jdbcType == null) { ps.setString(i, Objects.toString(parameter.getValue())); } else { ps.setObject(i, parameter.getValue(), jdbcType.TYPE_CODE); } } /** * 用于定义通过字段名称获取字段数据时,如何把数据库类型转换为对应的Java类型 * */ @Override public E getNullableResult(ResultSet rs, String columnName) throws SQLException { String i = rs.getString(columnName); if (rs.wasNull()) { return null; } else { return locateEnumStatus(i); } } /** * 用于定义通过字段索引获取字段数据时,如何把数据库类型转换为对应的Java类型 * */ @Override public E getNullableResult(ResultSet rs, int columnIndex) throws SQLException { String i = rs.getString(columnIndex); if (rs.wasNull()) { return null; } else { return locateEnumStatus(i); } } /** * 用定义调用存储过程后,如何把数据库类型转换为对应的Java类型 * */ @Override public E getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { String i = cs.getString(columnIndex); if (cs.wasNull()) { return null; } else { return locateEnumStatus(i); } } /** * 枚举类型转换 * * @param value 数据库中存储的自定义value属性 * @return value 对应的枚举类 */ private E locateEnumStatus(String value) { for (E e : enums) { if (Objects.toString(e.getValue()).equals(value)) { return e; } } throw new IllegalArgumentException("未知的枚举类型:" + value + ",请核对" + type.getSimpleName()); } }

    注意: 如果使用了 @MappedTypes 注解, 需要在 application.properties 中添加如下配置

    # 类型处理器类所在的包路径. eg: BaseEnumTypeHandler mybatis.type-handlers-package=com.answer.aal.entity

    否则, 直接在 mybatis 配置文件 mybatis-config.xml 添加如下配置

    <typeHandlers> <typeHandler handler="com.answer.aal.entity.BaseEnumTypeHandler" javaType="com.answer.aal.entity.EducationEnum" /> <typeHandler handler="com.answer.aal.entity.BaseEnumTypeHandler" javaType="com.answer.aal.entity.SexEnum" /> </typeHandlers>

     

    2.3 自定义枚举转换器测试

    2.3.1 用户实体对象

    import com.fasterxml.jackson.annotation.JsonFormat; import lombok.Data; import lombok.NoArgsConstructor; import java.util.Date; @Data /** * MyBatis 映射的实体对象必须提供一个无参构造方法 * */ @NoArgsConstructor public class User { /** * 主键ID * */ private Long id; private String userName; private SexEnum sex; @JsonFormat(pattern = "yyyy-MM-dd") private Date birthDay; private EducationEnum education; @JsonFormat(pattern = "yyyy-MM-dd HH-mm-ss") private Date createTime; @JsonFormat(pattern = "yyyy-MM-dd HH-mm-ss") private Date updateTime; public User(String userName, SexEnum sex, Date birthDay, EducationEnum education, Date createTime, Date updateTime) { this.userName = userName; this.sex = sex; this.birthDay = birthDay; this.education = education; this.createTime = createTime; this.updateTime = updateTime; } }

     

    2.3.2 控制层

    import com.answer.aal.entity.SexEnum; import com.answer.aal.entity.EducationEnum; import com.answer.aal.entity.User; import com.answer.aal.service.IUserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.Date; import java.util.List; @RestController @RequestMapping(value = "/user") public class UserController { @Autowired private IUserService userService; @RequestMapping("findUsers") public List<User> findUsers() { return userService.findUsers(); } @RequestMapping("finUserById/{id}") public User finUserById(@PathVariable("id") Long id) { return userService.findUserById(id); } @RequestMapping("insert") public Long insert(){ User user = new User("AnsweAIL", SexEnum.MAN, new Date(), EducationEnum.HIGH_SCHOOL, new Date(), new Date()); return userService.insertUer(user); } }

     

    2.3.3 接口层

    import com.answer.aal.entity.User; import java.util.List; public interface IUserService { List<User> findUsers(); User findUserById(Long id); Long insertUer(User user); }

     

    2.3.4 接口实现层

    import com.answer.aal.dao.UserDao; import com.answer.aal.entity.User; import com.answer.aal.service.IUserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; @Service public class UserServiceImpl implements IUserService { @Autowired private UserDao userDao; @Override public List<User> findUsers() { return userDao.findUsers(); } @Override public User findUserById(Long id) { return userDao.findUserById(id); } @Override public Long insertUer(User user) { return userDao.insertUer(user); } }

     

    2.3.5 持久层

    import com.answer.aal.entity.User; import java.util.List; public interface UserDao { List<User> findUsers(); User findUserById(Long id); Long insertUer(User user); }

     

    2.3.6 mybatis 配置文件

    <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <settings> <setting name="mapUnderscoreToCamelCase" value="true"/> </settings> <typeAliases> <typeAlias alias="User" type="com.answer.aal.entity.User"/> </typeAliases> <typeHandlers> <!-- 如果此处配置了映射, 则 BaseEnumTypeHandler 中就不需要 @MappedTypes 注解和 application.xml 中不需要设置属性 mybatis.type-handlers-package--> <typeHandler handler="com.answer.aal.entity.BaseEnumTypeHandler" javaType="com.answer.xsf.entity.EducationEnum" /> <typeHandler handler="com.answer.xsf.entity.BaseEnumTypeHandler" javaType="com.answer.aal.entity.SexEnum" /> </typeHandlers> </configuration>

    注意: 如果 BaseEnumTypeHandler 中设置了 @MappedTypes 注解, 此步骤 mybatis 配置文件 可省去  

    2.3.7 mybatis 映射文件

    <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace="com.answer.aal.dao.UserDao" > <resultMap id="user_mapper" type="User"> <id column="id" property="id" jdbcType="BIGINT" /> <result column="user_name" property="userName" jdbcType="VARCHAR" /> <result column="sex" property="sex" /> <result column="birth_day" property="birthDay" jdbcType="DATE" /> <result column="education" property="education" /> <result column="create_time" property="createTime" jdbcType="TIMESTAMP" /> <result column="update_time" property="updateTime" jdbcType="TIMESTAMP" /> </resultMap> <sql id="user_columns"> id, user_name, sex, birth_day, education, create_time, update_time </sql> <select id="findUsers" resultMap="user_mapper"> select <include refid="user_columns" /> from sf_user </select> <select id="findUserById" resultMap="user_mapper"> select <include refid="user_columns" /> from sf_user where id = #{id} </select> <insert id="insertUer" useGeneratedKeys="true" keyProperty="id"> insert into sf_user <trim prefix="(" suffix=")" suffixOverrides="," > <if test="userName != null" >user_name,</if> <if test="sex != null" >sex,</if> <if test="birthDay != null" >birth_day,</if> <if test="education != null" >education,</if> <if test="createTime != null" >create_time,</if> <if test="updateTime != null" >update_time,</if> </trim> <trim prefix="values (" suffix=")" suffixOverrides="," > <if test="userName != null" >#{userName},</if> <if test="sex != null" >#{sex},</if> <if test="birthDay != null" >#{birthDay},</if> <if test="education != null" >#{education},</if> <if test="createTime != null" >#{createTime},</if> <if test="updateTime != null" >#{updateTime},</if> </trim> </insert> </mapper>

     

    2.4 数据库脚本

    CREATE TABLE `sf_user` ( `id` bigint(18) NOT NULL AUTO_INCREMENT, `user_name` varchar(20) DEFAULT NULL, `sex` enum('1','0') DEFAULT '0', `birth_day` date DEFAULT NULL, `education` enum('UNIVERSITY','HIGH','JUNIOR','PRIMARY') DEFAULT 'PRIMARY', `create_time` datetime DEFAULT NULL, `update_time` datetime DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

     

    2.5 接口测试

     

    2.6 Reference

    github 源码地址 如何在MyBatis中优雅的使用枚举 学习Spring Boot:(十二)Mybatis 中自定义枚举转换器
    最新回复(0)