自定義mybatis的 typeHandler 以及應用

在Java項目中一般我們都需要處理數據庫表到Java的Bean對象的映射關係,常用的ORM框架有mybatis,在大多數據情況下,數據庫的數據類型到Java的數據類型滿足我們的需要,例如varchar到String,int到int等,但是有些時候項目需要完成數據庫數據類型到Java的某個數據類型的映射,mybatis現有的typeHandler不滿足要求,所以需要用戶自己開發用戶自定義的typeHandler類型,以滿足要求;

例如,數據庫需要保存用戶喜歡的產品,表字段以varchar類型保存,同時是一個符合JSON格式的列表,每個產品信息按 "產品名稱(產品代碼)",所以最終結果:["產品名稱1(產品代碼1)","產品名稱2(產品代碼2)"],即符合列表格式的JSON字符串其對應的Java的Bean變量爲一個字符型的List變量,即List<String>所以需要完成數據庫表字段的Varchar數據類型到Java的List<String>的映射處理關係,現有的typeHandler類型不足以滿足要求,所以我們需要開發一個用戶自定義的mybatis的typeHandler來處理這個問題,然後應用到mapper的XML文件中,大致框架代碼(具體自行豐富補充)和步驟如下:

1,引入相關依賴Jar包,版本看自行根據需要定義

<!-- mybatis依賴 -->
<dependency>  
    <groupId>org.mybatis.spring.boot</groupId>  
    <artifactId>mybatis-spring-boot-starter</artifactId>  
    <version>2.0.0</version>  
</dependency>

<!-- 數據庫連接池 -->
<dependency>  
    <groupId>com.alibaba</groupId>  
    <artifactId>druid</artifactId>  
    <version>1.1.10</version>  
</dependency>

<!-- mysql數據庫連接 -->
<dependency>  
    <groupId>mysql</groupId>  
    <artifactId>mysql-connector-java</artifactId>  
    <version>5.1.48</version>
	<!--此僅參考,版本根據需要而定-->
</dependency>

2,用戶相關的JavaBean對象

package com.xx.yy.zz.model; 

import java.util.List;

public class UserProduct {
	private String userName;
	private String userCode
	
	//DB字段以JSON格式保存:["產品名1(產品代碼1)","產品名2(產品代碼2)",...]
	private List<String> likeProducts = new ArraryList<String>();
	
	//...other... 
	//...setter/getter省略...
	
}

 

3,自定義DB表字段(內容爲符合JSON格式的字符串列表)的varchar數據類型到Java的List的映射處理關係的typeHandler開發

package com.xx.yy.zz.orm; 

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.List;

import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;

import com.alibaba.fastjson.JSONObject; //需要fastjson的jar包支持

@MappedTypes(List.class) //映射的Java數據類型
@MappedJdbcTypes(JdbcType.VARCHAR)  //映射的JDBC數據類型
public class MyListTypeHandler extends BaseTypeHandler<List<String>>{
	//List列表中如果爲其它對象xxJavaBean則把String換爲目標對象	
	
	//重寫mybatis設置參數的方法
	@Override
	public void setNonNullParameter(PreparedStatement ps,int i, List<String> param,
		JdbcType jdbcType) throws SQLException {
		ps.setString(i, JSONObject.toJSONString(param));
	}
	
	//重寫mybatis獲取字段字符串型內容到Bean類List變量的方法
	@Override
	public List<String> getNullableResult(ResultSet rs, String columnName)
		throws SQLException{
		String tempJson = rs.getString(columnName);
		if (null != tempJson && !tempJson.trim().isEmpty()){
			return JSONObject.parseArray(tempJson,String.class);
		}
		return null;
	}
	
	
	@Override
	public List<String> getNullableResult(ResultSet rs, int columnIndex)
		throws SQLException{
		String tempJson = rs.getString(columnIndex);
		if (null != tempJson && !tempJson.trim().isEmpty()){
			return JSONObject.parseArray(tempJson,String.class);
		}
		return null;
	}
	
	
	@Override
	public List<String> getNullableResult(CallableStatement cs, int columnIndex)
		throws SQLException{
		String tempJson = cs.getString(columnName);
		if (null != tempJson && !tempJson.trim().isEmpty()){
			return JSONObject.parseArray(tempJson,String.class);
		}
		return null;
	}
	
}

 

4, 操作數據庫的DAO層定義

package com.xx.yy.zz.dao;

import com.xx.yy.zz.model.UserProduct;

public interface UserProductDao {
	
	int insertRecord(UserProduct record);
	
	int updateRecord(UserProduct record);
	
	//...more code...
	
}

 

5,在springboot的配置yml文件中進行mybatis相關配置

#其它配置項省略
mybatis:
  mapper-locations: classpath:mapper/*Mapper.xml
  type-aliases-package: com.xx.yy.zz.model

 

6,在Mapper的XML文件中應用自定義的typeHandler類型,部分代碼如下

<mapper namespace="com.xx.yy.zz.dao.UserProductDao" >
	<resultMap id="resultMap" type="com.xx.yy.zz.model.Product">
		<id column="id" property="id" jdbcType="Decimal">
		<result column="likeProdcts" property="likeProdcts" jdbcType="varchar"
			typeHandler="com.xx.yy.zz.orm.MyListTypeHandler">
		
		<!-- ...other result... -->
		
	</resultMap>
</mapper>

<!-- 新增 -->
<insert id="insertRecord" parameterType="UserProduct">
	insert into xxTable
	<trim prefix="(" suffix=")" suffixOverride=",">
		<if test="userName != null">
		userName,
		</if>
		
		<!-- ...other... -->
		
		<if test="likeProdcts != null">
		likeProdcts,
		</if>		
	</trim>
	<trim prefix=" values (" suffix=")" suffixOverride=",">
		<if test="userName != null">
		#{userName,jdbcType=varchar},
		</if
		
		<!-- ...other... -->
		
		<if test="likeProdcts != null">
		#{likeProdcts,jdbcType=varchar,typeHandler=com.xx.yy.zz.orm.MyListTypeHandler},
		</if>
	</trim>

</insert>

<!-- 更新 -->
<update id="updateRecord" parameterType="UserProduct">
	update xxTable 
	<set>
	
		<if test="likeProdcts != null">
		#{likeProdcts,jdbcType=varchar,typeHandler=com.xx.yy.zz.orm.MyListTypeHandler},
		</if>
		
		<!-- ...other... -->
		
	</set>
	where id = #{id,jdbcType=decimal}
</update>

這樣處理之後即可滿足,數據庫表字段數據類型爲varchar類型,字段保存內容爲符合JSON格式的字符串,到JavaBean對象爲List<String>列表類型的映射和處理從Java持久化到表字段時自動轉化爲符合JSON格式的內容保存,另一方面,程序從DB表字段內容讀取到Java程序時內容自動轉化爲List<String>,非常方便,另外數組類型String[]也可以,但是Java對數組的增刪等操作,不如 List 方便,所以推薦使用 List 比較好,當然,本例List中列表的項爲String類型,那如果爲某個JavaBean對象呢?其實完全可以,方法類似的,這裏爲簡單舉例就用String,本身String也是一個對象;

除了我們自定義的 MyListTypeHandler 類型外,其mybatis本身內部已經含有很多的typeHandler類型,例如:BooleanTypeHandler,ByteTypeHandler,ShortTypeHandler,IntegerTypeHandler,LongTypeHandler,FloatTypeHandler,DoubleTypeHandler,StringTypeHandler,ClobTypeHandler,DateTypeHandler等等這些其實就是默認已經在爲我們處理完成映射關係了,只不過內部已經有,且直接內部自動完成映射,我們不需要顯示指定typeHandler而已,這就是mybatis框架的功能,已經幫我們完成了絕大部分功能,我們僅需處理一下特別的或特定需要即可;

 

歡迎拍磚討論...

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章