例如:
准备insert的实体类:
insert到mySql之后:
select返回的实体类:
Mybatis可以做到枚举类型的自动转换,但是结果不是我们想要的,比如:
STUDENT("01","学生"),
CIVIL_SERVANT("02","公务员"),
FARMER("03","农民"),
PROGRAMMER("04","程序员")
如果插入时在代码里不做任何转换,插入之后,user_type=这4个类型之一(STUDENT、CIVIL_SERVANT.......),查询时会可以自动转换成枚举类型。如何实现上面的效果
引入依赖
org.mybatis.spring.boot
mybatis-spring-boot-starter
1.3.1
org.projectlombok
lombok
mysql
mysql-connector-java
5.1.46
com.alibaba
druid
1.1.9
1、user_info
CREATE TABLE user_info (
user_id bigint(20) NOT NULL COMMENT '用户id',
name varchar(32) NOT NULL COMMENT '用户姓名',
age int(2) NOT NULL COMMENT '用户年龄',
gender varchar(2) NOT NULL COMMENT '性别 01:男,02女',
user_type varchar(2) NOT NULL COMMENT '用户类型 01:学生,02:公务员,03:伟大的农民,04:程序员',
address varchar(64) DEFAULT NULL,
create_time datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
update_time datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
PRIMARY KEY (user_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT '用户表'
2、UserInfo
package com.cn.dl.bean;
import com.cn.dl.enums.GenderEnum;
import com.cn.dl.enums.UserTypeEnum;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 用户信息
* Created by yanshao on 2019/3/24.
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class UserInfo {
private long userId;
private String name;
private int age;
private GenderEnum gender;
private UserTypeEnum userType;
private String address;
}
3、定义自动转换枚举的工具类:UniversalEnumHandler,参考这篇博客
package com.cn.dl.handler;
import com.cn.dl.enums.BaseEnum;
import com.cn.dl.enums.GenderEnum;
import com.cn.dl.enums.UserTypeEnum;
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;
/**
* 枚举转换
* Created by yanshao on 2019/3/21.
*/
@MappedTypes({GenderEnum.class, UserTypeEnum.class})
public class UniversalEnumHandler extends BaseTypeHandler {
private Class type;
private E [] enums;
/**
* 设置配置文件设置的转换类以及枚举类内容,供其他方法更便捷高效的实现
* @param type 配置文件中设置的转换类
*/
public UniversalEnumHandler(Class 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 void setNonNullParameter(PreparedStatement ps, int i, E parameter,
JdbcType jdbcType) throws SQLException {
//BaseTypeHandler已经帮我们做了parameter的null判断
ps.setObject(i,parameter.getValue(), jdbcType.TYPE_CODE);
}
@Override
public E getNullableResult(ResultSet rs, String columnName)
throws SQLException {
// 根据数据库存储类型决定获取类型,本例子中数据库中存放String类型
String i = rs.getString(columnName);
if (rs.wasNull()) {
return null;
} else {
// 根据数据库中的value值,定位PersonType子类
return locateEnumStatus(i);
}
}
@Override
public E getNullableResult(ResultSet rs, int columnIndex)
throws SQLException {
// 根据数据库存储类型决定获取类型,本例子中数据库中存放String类型
String i = rs.getString(columnIndex);
if (rs.wasNull()) {
return null;
} else {
// 根据数据库中的value值
return locateEnumStatus(i);
}
}
@Override
public E getNullableResult(CallableStatement cs, int columnIndex)
throws SQLException {
// 根据数据库存储类型决定获取类型,本例子中数据库中存放String类型
String i = cs.getString(columnIndex);
if (cs.wasNull()) {
return null;
} else {
// 根据数据库中的value值
return locateEnumStatus(i);
}
}
/**
* 枚举类型转换,由于构造函数获取了枚举的子类enums,让遍历更加高效快捷
* @param value 数据库中存储的自定义value属性
* @return value对应的枚举类
*/
private E locateEnumStatus(String value) {
for(E e : enums) {
if(String.valueOf(e.getValue()).equals(value)) {
return e;
}
}
return null;
}
}
其中@MappedTypes,指定了需要转换那些枚举
4、GenderEnum
package com.cn.dl.enums;
import lombok.Getter;
/**
* 性别类型
* Created by yanshao on 2019/3/24.
*/
public enum GenderEnum implements BaseEnum{
MALE("01","男性"),
FEMALE("02","女性"),
;
@Getter
private String value;
@Getter
private String desc;
GenderEnum(String value, String desc) {
this.value = value;
this.desc = desc;
}
public static GenderEnum getByValue(String value){
GenderEnum genderEnums[] = GenderEnum.values();
for(GenderEnum genderEnum : genderEnums){
if(genderEnum.getValue().equals(value)){
return genderEnum;
}
}
return null;
}
}
5、UserTypeEnum
package com.cn.dl.enums;
import lombok.Getter;
/**
* 用户类型
* Created by yanshao on 2019/3/24.
*/
public enum UserTypeEnum implements BaseEnum{
STUDENT("01","学生"),
CIVIL_SERVANT("02","公务员"),
FARMER("03","伟大的农民"),
PROGRAMMER("04","程序员")
;
@Getter
private String value;
@Getter
private String desc;
UserTypeEnum(String value, String desc) {
this.value = value;
this.desc = desc;
}
public static UserTypeEnum getByValue(String value){
UserTypeEnum userTypeEnums[] = UserTypeEnum.values();
for(UserTypeEnum userTypeEnum : userTypeEnums){
if(userTypeEnum.getValue().equals(value)){
return userTypeEnum;
}
}
return null;
}
}
6、UserInfoMapper
package com.cn.dl.dao;
import com.cn.dl.bean.UserInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
/**
* Created by yanshao on 2019/3/24.
*/
@Mapper
public interface UserInfoMapper {
int insert(UserInfo userInfo);
UserInfo getByUserId(@Param("userId") long userId);
}
7、UserInfoMapper.xml
user_id,name,age,gender,user_type,address,create_time,update_time
insert into user_info (user_id,age,name,gender,user_type,address)
values (
#{userId,jdbcType=BIGINT},
#{age,jdbcType=INTEGER},
#{name,jdbcType=VARCHAR},
#{gender,jdbcType=VARCHAR},
#{userType,jdbcType=VARCHAR},
#{address,jdbcType=VARCHAR}
)
8、application.properties配置
#mybatis
#开启mybatis驼峰命名,这样可以将mysql中带有下划线的映射成驼峰命名的字段
mybatis.configuration.map-underscore-to-camel-case=true
mybatis.mapper-locations=classpath*:mapper/*.xml
mybatis.type-aliases-package=com.cn.dl
mybatis.type-handlers-package=com.cn.dl.handler
datasource
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/tiger_base?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&autoReconnect=true&generateSimpleParameterMetadata=true
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.max-idle=10
spring.datasource.max-wait=60000
spring.datasource.min-idle=5
spring.datasource.initial-size=5
spring.datasource.validationQuery=select 'x'
如果没有在application.properties中申明(mybatis.mapper-locations=mapper的路径),默认和XXXMapper.class的路径是一致的
9、UserInfoMapperTest
package com.cn.dl.dao;
import com.cn.dl.bean.UserInfo;
import com.cn.dl.enums.GenderEnum;
import com.cn.dl.enums.UserTypeEnum;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.Optional;
/**
* Test
* Created by yanshao on 2019/3/24.
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserInfoMapperTest {
@Autowired
private UserInfoMapper userInfoDao;
@Test
public void insert() throws Exception {
UserInfo userInfo = UserInfo.builder()
.userId(13240116)
.name("zhoudl")
.age(23)
.gender(GenderEnum.MALE)
.userType(UserTypeEnum.PROGRAMMER)
.address("上海")
.build();
int num = userInfoDao.insert(userInfo);
Assert.assertEquals("insert 失败",num,1);
}
@Test
public void getByUserId() throws Exception {
long userId = 13240117;
UserInfo userInfo = userInfoDao.getByUserId(userId);
Optional.ofNullable(userInfo).
ifPresent(userInfo1 -> System.out.println("userInfo >>> " + userInfo1.toString()))
;
}
}
如果没有在UniversalEnumHandler类上使用注解@MappedTypes指定那些需要转换的枚举,需要在XXXXMapper.xml中指定
例如:
注意:如果在代码里配置了sqlSessionFactory,需要做一下配置,否则在application.properties中配置是不生效的,比如枚举类型转换失败、 Invalid bound statement (not found)
org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.cn.dl.dao.UserInfoMapper.insert
at org.apache.ibatis.binding.MapperMethod$SqlCommand.(MapperMethod.java:225)
at org.apache.ibatis.binding.MapperMethod.(MapperMethod.java:48)
at org.apache.ibatis.binding.MapperProxy.cachedMapperMethod(MapperProxy.java:65)
每天进步一点点!!!