mybatis枚举自动转换实现

版权声明:本文为Fighter168原创文章,未经允许不得转载。 https://blog.csdn.net/fighterandknight/article/details/51520402

前言

           在设计数据库的时候,我们有时候会把表里的某个字段的值设置为数字或者为英文来表示他的一些特殊含义。就拿设置成数字来说,假如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枚举自动转换(通用转换处理器实现)



阅读更多
换一批

没有更多推荐了,返回首页