mybatis枚举自动转换实现

Posted Fighter168

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mybatis枚举自动转换实现相关的知识,希望对你有一定的参考价值。

前言

           在设计数据库的时候,我们有时候会把表里的某个字段的值设置为数字或者为英文来表示他的一些特殊含义。就拿设置成数字来说,假如1对应是学生,2对应是教师,在java里面定义成这样的枚举,但是一般使用mybatis查出来的话,我们想要让它自动装换成我们想要的枚举,不需要再手动根据数值去判断设置成我们想要的枚举。要是实现这样的效果,那么我们就要用到mybatis的BaseTypeHandler了。

           

BaseTypeHandler介绍

             让我们来看看要继承BaseTypeHandler这个抽象类,需要覆写哪些方法:

  public abstract void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;

  public abstract T getNullableResult(ResultSet rs, String columnName) throws SQLException;

  public abstract T getNullableResult(ResultSet rs, int columnIndex) throws SQLException;

  public abstract T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException;

实现了这些抽象类,当得到结果集的时候,程序就会回调这些方法,例如根据名称获取当前行的某一列的值,那么就会直接回调getNullableResult(ResultSet rs, String columnName)这个方法,根据名称得到当行的当前列的值,然后我们在这里去调用枚举,匹配枚举中的每一个值,相等的话直接返回该枚举,达到自动转换成我们想要的枚举的效果。其他的重载方法类似,只不过是有些根据列索引,有些根据列名称做枚举自动转换而已。

好了,介绍就到这里,让我们来看看具体实现。。



自动转换实现例子

创建数据库表



创建枚举

package net.itaem.less;

import java.util.HashMap;
import java.util.Map;

/**
 * @author: Fighter168
 */
public enum PersonType 
	STUDENT("1","学生"),
	TEACHER("2","教师");
	
	private String value;
	private String displayName;
	
	static Map<String,PersonType> enumMap=new HashMap<String, PersonType>();
	static
		for(PersonType type:PersonType.values())
			enumMap.put(type.getValue(), type);
		
	
	
	private PersonType(String value,String displayName) 
		 this.value=value;
		 this.displayName=displayName;
	
	
	public String getValue() 
		return value;
	
	public void setValue(String value) 
		this.value = value;
	
	public String getDisplayName() 
		return displayName;
	
	public void setDisplayName(String displayName) 
		this.displayName = displayName;
	
	
	public static PersonType getEnum(String value) 
		return enumMap.get(value);
	





创建Po实体类

/**
 * @author: Fighter168
 */
public class Person 
	private String id;
	private String name;
	//枚举
	private PersonType personType;
        //set get 方法。。


创建Dao接口

创建一个简单的测试dao,这里简单的提供一个测试的查询方法。

/**
 * @author: Fighter168
 */
public interface PersonDao 

	public List<Person> query();


创建枚举转换处理器

package net.itaem.handler;

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

import net.itaem.less.PersonType;

import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;

/**
 * @author: Fighter168
 */
public class PersonTypeHandler extends BaseTypeHandler<PersonType>

	private Class<PersonType> type;

    private  PersonType[] enums;
    
    /**
     * 设置配置文件设置的转换类以及枚举类内容,供其他方法更便捷高效的实现
     * @param type 配置文件中设置的转换类
     */
    public PersonTypeHandler(Class<PersonType> 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.");
    

    @Override
    public PersonType getNullableResult(ResultSet rs, String columnName) throws SQLException 
        // 根据数据库存储类型决定获取类型,本例子中数据库中存放String类型
        String i = rs.getString(columnName);
        if (rs.wasNull()) 
            return null;
         else 
            // 根据数据库中的value值,定位PersonType子类
            return PersonType.getEnum(i);
        
    

    @Override
    public PersonType getNullableResult(ResultSet rs, int columnIndex) throws SQLException 
        // 根据数据库存储类型决定获取类型,本例子中数据库中存放String类型
    	 String i = rs.getString(columnIndex);
        if (rs.wasNull()) 
            return null;
         else 
        	 // 根据数据库中的value值,定位PersonType子类
            return PersonType.getEnum(i);
        
    

    @Override
    public PersonType getNullableResult(CallableStatement cs, int columnIndex) throws SQLException 
    	 // 根据数据库存储类型决定获取类型,本例子中数据库中存放String类型
   	 String i = cs.getString(columnIndex);
       if (cs.wasNull()) 
           return null;
        else 
       	 // 根据数据库中的value值,定位PersonType子类
           return PersonType.getEnum(i);
       
    

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, PersonType parameter, JdbcType jdbcType)
            throws SQLException 
        // baseTypeHandler已经帮我们做了parameter的null判断
        ps.setString(i, parameter.getValue());

    
	




创建Mapper映射文件

PersonDao对应的PersonMapper映射文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://www.mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="net.itaem.dao.PersonDao" >
  
  <resultMap id="resultMap" type="net.itaem.po.Person" >
	    <result column="id" property="id" jdbcType="CHAR" />
	    <result column="name" property="name" jdbcType="CHAR" />
	    <result column="type" property="personType" jdbcType="CHAR" />
  </resultMap>
 
 <select id="query"  resultMap="resultMap">
 	select * from person
 </select>
  
</mapper>
其实handler还可以写在PersonMapper.xml这里,写成下面这样:

	    <result column="type" property="personType"  typeHandler="net.itaem.handler.PersonTypeHandler"/>





创建Spring的配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
	 <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> 
	     <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
	     <property name="url" value="jdbc:mysql://localhost:3306/test"/>
	     <property name="username" value="root"/>
	     <property name="password" value="123abc"/>
	     <!-- 连接池启动时候的初始连接数 -->
	     <property name="initialSize" value="10"/>
	     <!-- 最小空闲值 -->
	     <property name="minIdle" value="5"/>
	     <!-- 最大空闲值 -->
	     <property name="maxIdle" value="20"/>
	     <property name="maxWait" value="2000"/>
	     <!-- 连接池最大值 -->
	     <property name="maxActive" value="50"/>
	     <property name="logAbandoned" value="true"/>
	     <property name="removeAbandoned" value="true"/>
	     <property name="removeAbandonedTimeout" value="180"/>
	</bean>
	
	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="configLocation" value="classpath:/resource/cfg.xml"/>
		<property name="dataSource" ref="dataSource"/>
	</bean>
 
	 <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		 <property name="basePackage" value="net.itaem.dao"/> 
	 </bean>
</beans>

创建mybatis的配置文件

下面是为mybatis创建配置文件cfg.xml

<?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>  
    <typeHandlers>
   	 <typeHandler handler="net.itaem.handler.PersonTypeHandler"
   		 javaType="net.itaem.less.PersonType" jdbcType="CHAR"/>
    </typeHandlers>
    <!-- mapping 文件路径配置 -->  
    <mappers>  
        <mapper resource="resource/PersonMapper.xml" />  
    </mappers>  
</configuration>

创建测试用例

/**
 * @author: Fighter168
 */
public class SpringTest 

	public static void main(String[] args) 
		ApplicationContext context=new ClassPathXmlApplicationContext("resource/ApplicationContext.xml");
		PersonDao personDao=(PersonDao) context.getBean("personDao");
		List<Person> list=personDao.query();
		for(Person p:list)
			System.out.println(p.toString());
		
	

测试结果展示

结果是成功自动转换成了我们想要的枚举




万能枚举转换处理器?

             也许我们还在想,如果我们有几十个枚举,这样转换的话,那我们岂不是要分别为每一个枚举定义一个Handler,然后为每一个Handler注册。其实不必这样,我们可以定义成一个通用的枚举转换处理器,具体怎么实现呢,下一篇博客我会告诉大家   mybatis枚举自动转换(通用转换处理器实现)



以上是关于mybatis枚举自动转换实现的主要内容,如果未能解决你的问题,请参考以下文章

mybatis 自动生成插件整合lombok,同时自动生成中文注释

MyBatis对于Java对象里的枚举类型处理

关于Mybatis中使用自定义类型通过 自定义TypeHandler类型处理器进行类型转换的两种配置方案-枚举类型示例

mybatis-plus设置了自动生成uuid,因为业务需求,怎么样才可以直接设置id不要他的生成然后添加到表里呢?

springboot mybatis自定义枚举enum转换

自定义枚举 --- MyBatis字段映射