mybatis中實(shí)現(xiàn)枚舉自動(dòng)轉(zhuǎn)換方法詳解
前言
最近在工作中遇到一個(gè)問(wèn)題,在設(shè)計(jì)數(shù)據(jù)庫(kù)的時(shí)候,我們有時(shí)候會(huì)把表里的某個(gè)字段的值設(shè)置為數(shù)字或者為英文來(lái)表示他的一些特殊含義。就拿設(shè)置成數(shù)字來(lái)說(shuō),假如1對(duì)應(yīng)是學(xué)生,2對(duì)應(yīng)是教師,在Java里面定義成這樣的枚舉,但是一般使用mybatis查出來(lái)的話(huà),我們想要讓它自動(dòng)裝換成我們想要的枚舉,不需要再手動(dòng)根據(jù)數(shù)值去判斷設(shè)置成我們想要的枚舉。要是實(shí)現(xiàn)這樣的效果,那么我們就要用到mybatis的BaseTypeHandler了。
BaseTypeHandler介紹
讓我們來(lái)看看要繼承BaseTypeHandler這個(gè)抽象類(lèi),需要覆寫(xiě)哪些方法:
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;
實(shí)現(xiàn)了這些抽象類(lèi),當(dāng)?shù)玫浇Y(jié)果集的時(shí)候,程序就會(huì)回調(diào)這些方法,例如根據(jù)名稱(chēng)獲取當(dāng)前行的某一列的值,那么就會(huì)直接回調(diào)getNullableResult(ResultSet rs, String columnName)這個(gè)方法,根據(jù)名稱(chēng)得到當(dāng)行的當(dāng)前列的值,然后我們?cè)谶@里去調(diào)用枚舉,匹配枚舉中的每一個(gè)值,相等的話(huà)直接返回該枚舉,達(dá)到自動(dòng)轉(zhuǎn)換成我們想要的枚舉的效果。其他的重載方法類(lèi)似,只不過(guò)是有些根據(jù)列索引,有些根據(jù)列名稱(chēng)做枚舉自動(dòng)轉(zhuǎn)換而已。
好了,介紹就到這里,讓我們來(lái)看看具體實(shí)現(xiàn)。。
自動(dòng)轉(zhuǎn)換實(shí)現(xiàn)例子
創(chuàng)建數(shù)據(jù)庫(kù)表

創(chuàng)建枚舉
package net.itaem.less;
import java.util.HashMap;
import java.util.Map;
/**
* @author: Fighter168
*/
public enum PersonType{
STUDENT("1","學(xué)生"),
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);
}
}
創(chuàng)建Po實(shí)體類(lèi)
/**
* @author: Fighter168
*/
public class Person {
private String id;
private String name;
//枚舉
private PersonType personType;
//set get 方法。。
}
創(chuàng)建Dao接口
創(chuàng)建一個(gè)簡(jiǎn)單的測(cè)試dao,這里簡(jiǎn)單的提供一個(gè)測(cè)試的查詢(xún)方法。
/**
* @author: Fighter168
*/
public interface PersonDao {
public List<Person> query();
}
創(chuàng)建枚舉轉(zhuǎn)換處理器
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;
/**
* 設(shè)置配置文件設(shè)置的轉(zhuǎn)換類(lèi)以及枚舉類(lèi)內(nèi)容,供其他方法更便捷高效的實(shí)現(xiàn)
* @param type 配置文件中設(shè)置的轉(zhuǎn)換類(lèi)
*/
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 {
// 根據(jù)數(shù)據(jù)庫(kù)存儲(chǔ)類(lèi)型決定獲取類(lèi)型,本例子中數(shù)據(jù)庫(kù)中存放String類(lèi)型
String i = rs.getString(columnName);
if (rs.wasNull()) {
return null;
} else {
// 根據(jù)數(shù)據(jù)庫(kù)中的value值,定位PersonType子類(lèi)
return PersonType.getEnum(i);
}
}
@Override
public PersonType getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
// 根據(jù)數(shù)據(jù)庫(kù)存儲(chǔ)類(lèi)型決定獲取類(lèi)型,本例子中數(shù)據(jù)庫(kù)中存放String類(lèi)型
String i = rs.getString(columnIndex);
if (rs.wasNull()) {
return null;
} else {
// 根據(jù)數(shù)據(jù)庫(kù)中的value值,定位PersonType子類(lèi)
return PersonType.getEnum(i);
}
}
@Override
public PersonType getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
// 根據(jù)數(shù)據(jù)庫(kù)存儲(chǔ)類(lèi)型決定獲取類(lèi)型,本例子中數(shù)據(jù)庫(kù)中存放String類(lèi)型
String i = cs.getString(columnIndex);
if (cs.wasNull()) {
return null;
} else {
// 根據(jù)數(shù)據(jù)庫(kù)中的value值,定位PersonType子類(lèi)
return PersonType.getEnum(i);
}
}
@Override
public void setNonNullParameter(PreparedStatement ps, int i, PersonType parameter, JdbcType jdbcType)
throws SQLException {
// baseTypeHandler已經(jīng)幫我們做了parameter的null判斷
ps.setString(i, parameter.getValue());
}
}
創(chuàng)建Mapper映射文件
PersonDao對(duì)應(yīng)的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>
其實(shí)handler還可以寫(xiě)在PersonMapper.xml這里,寫(xiě)成下面這樣:
<result column="type" property="personType" typeHandler="net.itaem.handler.PersonTypeHandler"/>
創(chuàng)建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"/> <!-- 連接池啟動(dòng)時(shí)候的初始連接數(shù) --> <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>
創(chuàng)建mybatis的配置文件
下面是為mybatis創(chuàng)建配置文件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>
創(chuàng)建測(cè)試用例
/**
* @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());
}
}
}
測(cè)試結(jié)果展示
結(jié)果是成功自動(dòng)轉(zhuǎn)換成了我們想要的枚舉

總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來(lái)一定的幫助,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
spring?boot項(xiàng)目實(shí)戰(zhàn)之實(shí)現(xiàn)與數(shù)據(jù)庫(kù)的連接
在我們?nèi)粘5拈_(kāi)發(fā)過(guò)程中,肯定不可避免的會(huì)使用到數(shù)據(jù)庫(kù)以及SQL?語(yǔ)句,下面這篇文章主要給大家介紹了關(guān)于spring?boot項(xiàng)目實(shí)戰(zhàn)之實(shí)現(xiàn)與數(shù)據(jù)庫(kù)連接的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-05-05
java數(shù)據(jù)結(jié)構(gòu)基礎(chǔ):順序隊(duì)列和循環(huán)隊(duì)列
下面小編就為大家分享一篇java隊(duì)列實(shí)現(xiàn)方法(順序隊(duì)列,循環(huán)隊(duì)列),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-08-08
SpringBoot+Redis實(shí)現(xiàn)消息的發(fā)布與訂閱的示例代碼
本文主要介紹了SpringBoot+Redis實(shí)現(xiàn)消息的發(fā)布與訂閱,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-04-04
java必學(xué)必會(huì)之網(wǎng)絡(luò)編程
java必學(xué)必會(huì)之網(wǎng)絡(luò)編程,學(xué)習(xí)了解java網(wǎng)絡(luò)編程、網(wǎng)絡(luò)通信協(xié)議、TCP協(xié)議和UDP協(xié)議,對(duì)各個(gè)協(xié)議進(jìn)行深入學(xué)習(xí),做到必學(xué)必會(huì)2015-12-12
Spring?Aop+Redis實(shí)現(xiàn)優(yōu)雅記錄接口調(diào)用情況
通常情況下,開(kāi)發(fā)完一個(gè)接口,無(wú)論是在測(cè)試階段還是生產(chǎn)上線(xiàn),我們都需要對(duì)接口的執(zhí)行情況做一個(gè)監(jiān)控,所以本文為大家整理了Spring統(tǒng)計(jì)接口調(diào)用的多種方法,希望對(duì)大家有所幫助2023-06-06
Java并發(fā)編程示例(四):可控的線(xiàn)程中斷
這篇文章主要介紹了Java并發(fā)編程示例(四):可控的線(xiàn)程中斷,在本節(jié),我們將使用一個(gè)線(xiàn)程查找指定目錄及其子目錄下文件來(lái)演示通過(guò)使用InterruptedException異??刂凭€(xiàn)程中斷,需要的朋友可以參考下2014-12-12

