关于Mybatis中使用自定义类型通过 自定义TypeHandler类型处理器进行类型转换的两种配置方案-枚举类型示例
- 环境介绍
- 情景与实现目标
- 配置前的准备工作
- 整体项目组织结构(较乱勿喷,有些额外文件)
- 1. Java程序的目标POJO类-User (User.java)
- 2 POJO类User中使用的枚举类型SexEnum (SexEnum.java)
- 3 User类对应的数据库中的表(user)
- 4.1 针对POJO类User的映射接口 (UserMapper.java)
- 4.2 针对POJO类User的映射配置文件 (初始未配置版本,必然转换自定义类型失败) (UserMapper.xml)
- 5 整个Maven项目的Mybatis配置文件(mybatis-config.xml,初始未配置版本,必然转换自定义类型失败)
- 5.1 关于Maven项目如何查找静态资源 xml文件 的注意事项
- 6 自定义类型转换器(SexHandler.java)
- 解决方案1: 通过整个Mybatis项目配置声明处理自定义类型时使用自定义Handler转换器
- 解决方案2: 通过具体的Mapper映射xml配置文件中,直接显式指定数据库字段对应的java属性所需要使用的自定义转换器。
参考书籍:Java EE互联网轻量级框架整合开发 杨开振 周吉文等著 (书中描述相对混杂)
环境介绍
IDEA-2018 Maven项目
数据库: Mysql
情景与实现目标
针对向Java程序向Mysql数据库中
插入 自定义Enum枚举类型 ,
采用 自定义的类型转换器 进行处理。(示例为SexEnum类型转为Integer类型)
从而使自定义类型(枚举类型示例)能使用自定义的转换器安全的向数据库中
实现数据记录的传递。
配置前的准备工作
整体项目组织结构(较乱勿喷,有些额外文件)
1. Java程序的目标POJO类-User (User.java)
public class User {
private Long id;
private String userName;
private SexEnum sex;
private String mess;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public SexEnum getSex() {
return sex;
}
public void setSex(SexEnum sex) {
this.sex = sex;
}
public String getMess() {
return mess;
}
public void setMess(String mess) {
this.mess = mess;
}
public String toString(){
return userName +"[" + sex +"]: " + mess;
}
}
2 POJO类User中使用的枚举类型SexEnum (SexEnum.java)
public enum SexEnum {
MALE(0, "男"),
FEMALE(1, "女");
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getname() {
return name;
}
public void setname(String name) {
this.name = name;
}
SexEnum(int id, String name){
this.id = id;
this.name = name;
}
/**
* 为方便自定义类型处理器转换所使用的辅助静态方法
* @param id
* @return
*/
public static SexEnum getSexByID(int id){
for(SexEnum sex: SexEnum.values()){
if(sex.getId() == id){
return sex;
}
}
return null;
}
}
3 User类对应的数据库中的表(user)
4.1 针对POJO类User的映射接口 (UserMapper.java)
public interface UserMapper {
User getUser(Long id);
int insertUser(User user);
int deleteUser(Long id);
}
4.2 针对POJO类User的映射配置文件 (初始未配置版本,必然转换自定义类型失败) (UserMapper.xml)
<?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.castle.mapper.UserMapper">
<!--在编写SQL语句时,数据库字段必须对应好POJO类的相应属性,若不一致使用AS指定-->
<select id="getUser" parameterType="long" resultType="com.castle.POJO.User" >
SELECT id, user_name AS userName, sex, mess FROM `user` WHERE id = #{id}
</select>
<insert id="insertUser" parameterType="com.castle.POJO.User">
INSERT `user`(id, user_name, sex, mess) VALUES (#{id}, #{userName}, #{sex}, #{mess})
</insert>
</mapper>
5 整个Maven项目的Mybatis配置文件(mybatis-config.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>
<!--引入外部properties文件以获取外部属性引用-->
<properties resource="jdbc.properties"/>
<!--数据库环境-->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${database.driver}"/>
<property name="url" value="${database.url}"/>
<property name="username" value="${database.username}"/>
<property name="password" value="${database.password}"/>
</dataSource>
</environment>
</environments>
<!--映射文件-->
<mappers>
<!--注册先前编写的UserMapper.xml文件-->
<mapper resource="UserMapper.xml"/>
</mappers>
</configuration>
5.1 关于Maven项目如何查找静态资源 xml文件 的注意事项
由于IDEA默认忽略自定义xml配置文件(如UserMapper.xml),会导致即使路径正确也无法找到相应的xml文件。
解决办法:在整个Maven项目的pom.xml配置文件中进行注册。需要使用指定配置文件时(如UserMapper.xml),可以直接使用文件名,不必在乎路径。
具体修改pom.xml文件(在< build >标签下 将指定目录的任意.xml文件添加为项目资源):
6 自定义类型转换器(SexHandler.java)
public class SexHandler implements TypeHandler<SexEnum> {
Logger logger = Logger.getLogger(SexHandler.class);
/**
* 将SexEnum的id写入数据库做数据库数据
* @param preparedStatement
* @param i
* @param sexEnum
* @param jdbcType
* @throws SQLException
*/
@Override
public void setParameter(PreparedStatement preparedStatement, int i, SexEnum sexEnum, JdbcType jdbcType) throws SQLException {
preparedStatement.setInt(i, sexEnum.getId());
logger.info("输入完数据库sex参数:" + sexEnum);
}
/**
* 根据数据库的整形数据,再借助SexEnum的类方法,返回相应的SexEnum类型
* @param resultSet
* @param s
* @return
* @throws SQLException
*/
@Override
public SexEnum getResult(ResultSet resultSet, String s) throws SQLException {
int id = resultSet.getInt(s);
SexEnum result = SexEnum.getSexByID(id);
logger.info("输出数据库sex参数:" + result);
return result;
}
@Override
public SexEnum getResult(ResultSet resultSet, int i) throws SQLException {
int id = resultSet.getInt(i);
SexEnum result = SexEnum.getSexByID(id);
logger.info("输出数据库sex参数:" + result);
return result;
}
@Override
public SexEnum getResult(CallableStatement callableStatement, int i) throws SQLException {
int id = callableStatement.getInt(i);
SexEnum result = SexEnum.getSexByID(id);
logger.info("输出数据库sex参数:" + result);
return result;
}
}
解决方案1: 通过整个Mybatis项目配置声明处理自定义类型时使用自定义Handler转换器
具体做法:修改mybatis-config.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>
<!--引入外部properties文件以获取外部属性引用-->
<properties resource="jdbc.properties"/>
<!--自定义类型处理器-->
<typeHandlers>
<!--采用全局声明的方式对SexEnum类型使用自定义处理器-->
<typeHandler handler="com.castle.handlers.SexHandler" javaType="com.castle.tools.SexEnum" jdbcType="INTEGER"/>
</typeHandlers>
<!--数据库环境-->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${database.driver}"/>
<property name="url" value="${database.url}"/>
<property name="username" value="${database.username}"/>
<property name="password" value="${database.password}"/>
</dataSource>
</environment>
</environments>
<!--映射文件-->
<mappers>
<!--注册先前编写的UserMapper.xml文件-->
<mapper resource="UserMapper.xml"/>
</mappers>
</configuration>
解决方案2: 通过具体的Mapper映射xml配置文件中,直接显式指定数据库字段对应的java属性所需要使用的自定义转换器。
具体做法:修改UserMapper.xml文件
① 针对Select的SQL语句,可以使用resultMap属性来指定本xml文件中声明好的变量,如此处使用map1
② 针对Insert的SQL语句,由于没有resultMap属性,可以在插入的语句中,具体为VALUES()语句中对指定的Java的User类相应属性,使用typeHandler进行指定。如:#{sex, typeHandler=com.castle.handlers.SexHandler}
<?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.castle.mapper.UserMapper">
<!--采用显示声明的方式为指定字段sex设置自定义处理器-->
<resultMap id="map1" type="com.castle.POJO.User">
<result property="id" column="id"/>
<!--当使用user_name带下划线的名称时,会导致变量读取为null,解决办法为删去下划线即可-->
<result property="userName" column="username"/>
<result property="sex" column="sex" typeHandler="com.castle.handlers.SexHandler"/>
<result property="mess" column="mess"/>
</resultMap>
<!--在编写SQL语句时,数据库字段必须对应好POJO类的相应属性,若不一致使用AS指定-->
<select id="getUser" parameterType="long" resultType="com.castle.POJO.User" resultMap="map1">
SELECT id, user_name AS userName, sex, mess FROM `user` WHERE id = #{id}
</select>
<insert id="insertUser" parameterType="com.castle.POJO.User">
INSERT `user`(id, user_name, sex, mess) VALUES (#{id}, #{userName}, #{sex, typeHandler=com.castle.handlers.SexHandler}, #{mess})
</insert>
</mapper>