MyBatis实现自定义TypeHandler进行数据转换

场景

在 Java 实体类中,定义时间的属性一般是Date 类型,但数据库中却是字符串类型,每次查询、新增等操作都要做类型转换,但如果使用 Mybatis 提供的自定义 TypeHandler 的功能就能完美的解决这个问题。
实体类User.java

package com.lks.domain;

import java.io.Serializable;
import java.util.Date;

/**
 * Created by likaisong on 2019/2/24.
 */
public class User implements Serializable {
    private int id;
    private String name;
    private int age;
    private String county;
    private Date date;

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public String getCounty() {
        return county;
    }

    public void setId(int id) {
        this.id = id;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void setCounty(String county) {
        this.county = county;
    }

    public Date getDate() {
        return date;
    }
    public void setDate(Date date) {
        this.date= date;
    }

    @Override
    public String toString() {
        return "User [id=" + id + ", name=" + name + ", age=" + age + ", county=" + county + ", date=" + date + "]";
    }
}

自定义TypeHandle,有两种实现方式:直接实现 TypeHandler 也可以继承 BaseTypeHandler,这里我选择直接实现 TypeHandler :
DateToStringTypeHandler.java

package com.lks.handler;

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

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * Created by likaisong on 2019/2/25.
 */
public class DateToStringTypeHandler implements TypeHandler{
    /**
     * 将时间戳传入数据库
     * @param preparedStatement
     * @param i
     * @param o
     * @param jdbcType
     * @throws java.sql.SQLException
     */
    @Override
    public void setParameter(PreparedStatement preparedStatement, int i, Object o, JdbcType jdbcType) throws SQLException {
        Date date = (Date) o;
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dateString = formatter.format(date);
        preparedStatement.setString(i, dateString);
    }

    /**
     * 将字符串类型的时间戳转换为Date
     * @param resultSet
     * @param s
     * @return
     * @throws SQLException
     */
    @Override
    public Object getResult(ResultSet resultSet, String s) throws SQLException {
        String timeStr = resultSet.getString(s);
        if (timeStr != null || "".equals(timeStr)){
            return stringToDate(timeStr);
        }
        return null;
    }

    @Override
    public Object getResult(ResultSet resultSet, int i) throws SQLException {
        String timeStr = resultSet.getString(i);
        if (timeStr != null || "".equals(timeStr)){
            return stringToDate(timeStr);
        }
        return null;
    }

    @Override
    public Object getResult(CallableStatement callableStatement, int i) throws SQLException {
        String timeStr = callableStatement.getString(i);
        if (timeStr != null || "".equals(timeStr)){
            return stringToDate(timeStr);
        }
        return null;
    }

    private Date stringToDate(String timeStr) {
        if (timeStr != null || "".equals(timeStr)) {
            SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            ParsePosition pos = new ParsePosition(0);
            Date date = formatter.parse(timeStr, pos);
            return date;
        }
        return null;
    }
}

mybatis配置文件中配置自定义typeHandler,主要看typeHandler标签:
mybatis-config:

<?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="com.lks.handler.DateToStringTypeHandler" javaType="java.util.Date" jdbcType = "VARCHAR"/>
    </typeHandlers>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis_demo"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="userMapper.xml"/>
    </mappers>
</configuration>

mapper文件中新增或查询操作:

<?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,namespace的值习惯上设置成包名+sql映射文件名,这样就能够保证namespace的值是唯一的-->
<mapper namespace="userMapper">
    <!--类型转换-->
    <insert id="dateToString" parameterType="com.lks.domain.User" useGeneratedKeys="true" keyProperty="id">
        insert into users (id, name, age, county, date)
        values (#{id},#{name},#{age},#{county},#{date, typeHandler=com.lks.handler.DateToStringTypeHandler})
    </insert>
    <resultMap id="userResultMap" type="com.lks.domain.User">
        <result property="date" column="date" typeHandler="com.lks.handler.DateToStringTypeHandler"/>
    </resultMap>
    <select id="stringToDate" parameterType="int"
            resultType="com.lks.domain.User" resultMap="userResultMap">
        select * from users where id=#{id}
    </select>
</mapper>

新增数据的操作只要对需要进行类型转换的字段添加相关配置即可,但查询操作需要借助resultMap来实现转换。
对操作执行测试方法:
TestMain.java

package com.lks.test;

import com.lks.domain.User;
import com.lks.mapper.UserMapper;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.testng.annotations.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.Date;

/**
 * Created by likaisong on 2019/2/24.
 */
public class TestMain {
    private static SqlSession getSqlSession(String resource){
        if (resource == null || "".equals(resource)){
            return null;
        }
        InputStream inputStream = null;
        try {
            inputStream = Resources.getResourceAsStream(resource);
        } catch (IOException e) {
            e.printStackTrace();
        }
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession session = sqlSessionFactory.openSession();
        return session;
    }
    @Test
    public static void testDateToString(){
        String resource = "mybatis-config.xml";
        SqlSession session = getSqlSession(resource);
        try {
            String statement = "userMapper.dateToString";
            User user = new User();
            user.setName("阿飞");
            user.setAge(20);
            user.setCounty("中国");
            user.setDate(new Date());
            session.insert(statement, user);
            session.commit();
            System.out.println("插入数据后返回的自增ID:" + user.getId());
        } finally {
            session.close();
        }
    }

    @Test
    public static void testStringToDate(){
        String resource = "mybatis-config.xml";
        SqlSession session = getSqlSession(resource);
        try {
            //先插入一条数据
            String insertStatement = "userMapper.dateToString";
            User user = new User();
            user.setName("阿飞");
            user.setAge(20);
            user.setCounty("中国");
            user.setDate(new Date());
            session.insert(insertStatement, user);
            session.commit();
            System.out.println("插入数据后返回的自增ID:" + user.getId());
            //查询刚插入的数据
            String selectStatement = "userMapper.stringToDate";
            User resUser = session.selectOne(selectStatement, user.getId());
            System.out.println(resUser);
        } finally {
            session.close();
        }
    }
}

通过查表或由直接打印出来对内容可以看到时间字段可以在Date和String中实现灵活准换,自定义的 TypeHandler 也经常用来解决项目中的枚举类型,也是比较方便的。

猜你喜欢

转载自blog.csdn.net/lks1139230294/article/details/87923363