mybatis-plus如何配置自定義數(shù)據(jù)類型TypeHandle
如何配置自定義數(shù)據(jù)類型TypeHandle
1.背景
mybatis-plus在mybatis的基礎(chǔ)的上,做了全面增強功能,極大的提高了我們的開發(fā)效率。有時候我們使用的實體字段類型,與數(shù)據(jù)庫創(chuàng)建的字段類型無法對應(yīng)上,這時候就需要配之自定義的類型處理類,來處理代碼和數(shù)據(jù)庫之間的數(shù)據(jù)流轉(zhuǎn)。
2.舉例
我們有個實體類TestEntity,使用注解@TableName表示對應(yīng)數(shù)據(jù)庫表名為test
@Data
@TableName(value = "test")
public class TestEntity{
? private static final long serialVersionUID = 8565214506859404278L;
? private String id;
? private String type;
? private Document content;
}DAO層對象
@Mapper
public interface TestDao extends BaseMapper<TestEntity> {
}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.aisino.dao.TestDao"> ? ? <resultMap type="com.aisino.entity.TestEntity" id="testMap"> ? ? ? ? <result property="id" column="id"/> ? ? ? ? <result property="type" column="name"/> ? ? ? ? <result property="content" column="content"/> ? ? </resultMap> </mapper>
其中Document使用的是org.w3c.dom.Document對象,數(shù)據(jù)庫存儲的字段類型為bytea,我這里使用的是postgresql,顯然數(shù)據(jù)類型無法匹配,這里需要編寫類型處理類進(jìn)行數(shù)據(jù)類型轉(zhuǎn)換。
3.TypeHandle配置
1.編寫TypeHandle,首先需要明確我們代碼中和數(shù)據(jù)庫中各自的數(shù)據(jù)類型,編寫處理類DocumentTypeHandler繼承BaseTypeHandler,并重寫4個方法:
(1)setNonNullParameter表示從代碼中的數(shù)據(jù)類型轉(zhuǎn)換成數(shù)據(jù)庫數(shù)據(jù)類型,即Document轉(zhuǎn)為BLOB類型。這里的基本思路就是將Document轉(zhuǎn)為String再轉(zhuǎn)為字節(jié)流,最后利用setBinaryStream方法轉(zhuǎn)為數(shù)據(jù)庫對象。
(2)getNullableResult,getNullableResult,getNullableResult表示從數(shù)據(jù)庫類型中獲取數(shù)據(jù)并轉(zhuǎn)換為代碼中的數(shù)據(jù)類型,即BLOB轉(zhuǎn)為Document類型。這里的基本思路就是上一步的逆過程。
@MappedTypes中填寫的是我們代碼中的數(shù)據(jù)類型@MappedJdbcTypes中填寫的是數(shù)據(jù)庫中的數(shù)據(jù)類型
@MappedTypes(Document.class)
@MappedJdbcTypes(JdbcType.BLOB)
public class DocumentTypeHandler extends BaseTypeHandler {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) throws SQLException {
String docStr = docToString((org.w3c.dom.Document) parameter);
InputStream in = new ByteArrayInputStream(docStr.getBytes());
ps.setBinaryStream(i, in);
}
@Override
public Object getNullableResult(ResultSet rs, String columnName) throws SQLException {
byte[] bytes = rs.getBytes(columnName);
return !rs.wasNull() && bytes != null ? stringToDoc(new String(bytes)) : null;
}
@Override
public Object getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
byte[] bytes = rs.getBytes(columnIndex);
return !rs.wasNull() && bytes != null ? stringToDoc(new String(bytes)) : null;
}
@Override
public Object getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
byte[] bytes = cs.getBytes(columnIndex);
return !cs.wasNull() && bytes != null ? stringToDoc(new String(bytes)) : null;
}
public static String docToString(Document doc) {
// XML轉(zhuǎn)字符串
String xmlStr = "";
try {
TransformerFactory tf = TransformerFactory.newInstance();
Transformer t = tf.newTransformer();
t.setOutputProperty("encoding", "UTF-8");
ByteArrayOutputStream bos = new ByteArrayOutputStream();
t.transform(new DOMSource(doc), new StreamResult(bos));
xmlStr = bos.toString();
} catch (TransformerConfigurationException e) {
// TODO
e.printStackTrace();
} catch (TransformerException e) {
// TODO
e.printStackTrace();
}
return xmlStr;
}
public static Document stringToDoc(String xmlStr) {
//字符串轉(zhuǎn)XML
Document doc = null;
try {
xmlStr = new String(xmlStr.getBytes(), "UTF-8");
StringReader sr = new StringReader(xmlStr);
InputSource is = new InputSource(sr);
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder;
builder = factory.newDocumentBuilder();
doc = builder.parse(is);
} catch (ParserConfigurationException e) {
// TODO
e.printStackTrace();
} catch (SAXException e) {
// TODO
e.printStackTrace();
} catch (IOException e) {
// TODO
e.printStackTrace();
}
return doc;
}
}
2.回到實體類配置,以下是修改后的實體類
(1)在注解@TableName中增加autoResultMap = true表示使用xml中的映射配置
(2)增加注解配置@TableField(typeHandler = DocumentTypeHandler.class)表示content字段使用數(shù)據(jù)類型處理類DocumentTypeHandler.class
@Data
@TableName(value = "test",autoResultMap = true)
public class TestEntity{
private static final long serialVersionUID = 8565214506859404278L;
private String id;
private String type;
@TableField(typeHandler = DocumentTypeHandler.class)
private Document content;
}
3.以下是修改后的xml配置
(1)content字段配置jdbcType=“OTHER”,配置數(shù)據(jù)處理類typeHandler=“com.aisino.jdbc.ibatis.DocumentTypeHandler”
<?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.aisino.dao.TestDao"> ? ? <resultMap type="com.aisino.entity.TestEntity" id="testMap"> ? ? ? ? <result property="id" column="id"/> ? ? ? ? <result property="type" column="name"/> ? ? ? ? <result property="content" column="content" jdbcType="OTHER" typeHandler="com.aisino.jdbc.ibatis.DocumentTypeHandler"/> ? ? </resultMap> </mapper>
4.注意事項
(1)編寫TypeHandle類時候,繼承BaseTypeHandler<Document>試過不行,原因暫未深究。
(2)實體類的注解@TableField(typeHandler = DocumentTypeHandler.class)與xml配置的處理類路徑typeHandler="com.aisino.jdbc.ibatis.DocumentTypeHandler"缺一不可,因為看過網(wǎng)上說只配置注解即可,我試了不行,原因暫未深究。
自定義TypeHandler的使用筆記
可通過自定義的TypeHandler實現(xiàn)某個屬性在插入數(shù)據(jù)庫以及查詢時的自動轉(zhuǎn)換,本例中是要將Map類型的屬性轉(zhuǎn)化成CLOB,然后存入數(shù)據(jù)庫。由于是復(fù)雜的Map,mp自帶的json轉(zhuǎn)換器會丟失部分信息。
類型轉(zhuǎn)換器還可以通過注解配置java類型和jdbc類型
@MappedTypes:注解配置 java 類型@MappedJdbcTypes:注解配置 jdbc 類型
定義:
@Slf4j
@MappedTypes({Object.class})
@MappedJdbcTypes(JdbcType.VARCHAR)
public class WeightListTypeHandler extends AbstractJsonTypeHandler<Object> {
private static Gson gson = new Gson();
private final Class<?> type;
public WeightListTypeHandler(Class<?> type) {
if (log.isTraceEnabled()) {
log.trace("WeightListTypeHandler(" + type + ")");
}
Assert.notNull(type, "Type argument cannot be null");
this.type = type;
}
@Override
protected Object parse(String json) {
Type type1 = new TypeToken<Map<String, List<WeightItem>>>(){}.getType();
return gson.fromJson(json, type1);
}
@Override
protected String toJson(Object obj) {
return gson.toJson(obj);
}
public static void setGson(Gson gson) {
Assert.notNull(gson, "Gson should not be null");
WeightListTypeHandler.gson = gson;
}
}
使用:
注意@TableName 注解 autoResultMap 屬性
@Data
@NoArgsConstructor
@TableName(value = "mix_target",autoResultMap = true)
public class MixTarget extends Model<MixTarget> {
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**
*指標(biāo)描述
*/
@TableField("description")
private String description;
/**
* 指標(biāo)名
*/
@TableField("name")
private String name;
/**
* 對應(yīng)屬性名
*/
@TableField("property_name")
private String propertyName;
/**
* 起始點類型
*/
@TableField("source_type")
private String sourceType;
/**
* 屬性對應(yīng)權(quán)值列表
* key 屬性名 value指定條件下的權(quán)值
*/
@TableField(value = "weight_list",typeHandler = WeightListTypeHandler.class,jdbcType = JdbcType.CLOB)
private Map<String, List<WeightItem>> weightList;
/**
* 運行狀態(tài)
* 0 新建未運行
* 1 運行中
* 2 已運行 成功
* 3 已運行 失敗
*/
@TableField("status")
private Integer status;
/**
* 是否可用
* 1 true
* 0 false
*/
@TableField("enable")
private Integer enable;
@TableField("create_time")
private LocalDateTime createTime;
}
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
HashMap原理及手寫實現(xiàn)部分區(qū)塊鏈特征
這篇文章主要為大家介紹了HashMap原理及手寫實現(xiàn)部分區(qū)塊鏈特征,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09
劍指Offer之Java算法習(xí)題精講鏈表專項訓(xùn)練
跟著思路走,之后從簡單題入手,反復(fù)去看,做過之后可能會忘記,之后再做一次,記不住就反復(fù)做,反復(fù)尋求思路和規(guī)律,慢慢積累就會發(fā)現(xiàn)質(zhì)的變化2022-03-03
Spring Security添加二次認(rèn)證的項目實踐
在用戶自動登錄后,可以通過對密碼進(jìn)行二次校驗進(jìn)而確保用戶的真實性,本文就來介紹一下Spring Security添加二次認(rèn)證的項目實踐,具有一定的參考價值,感興趣的可以了解一下2023-12-12
Mybatis實現(xiàn)動態(tài)SQL編寫詳細(xì)代碼示例
這篇文章主要為大家詳細(xì)介紹了Mybatis中動態(tài)SQL的編寫使用,動態(tài)SQL技術(shù)是一種根據(jù)特定條件動態(tài)拼裝SQL語句的功能,它存在的意義是為了解決拼接SQL語句字符串時的痛點問題,感興趣想要詳細(xì)了解可以參考下文2023-05-05
SpringMVC異步處理操作(Callable和DeferredResult)
這篇文章主要介紹了SpringMVC異步處理操作(Callable和DeferredResult),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-01-01
Java 策略模式與模板方法模式相關(guān)總結(jié)
這篇文章主要介紹了Java 策略模式與模板方法模式相關(guān)總結(jié),幫助大家更好的理解和使用Java,感興趣的朋友可以了解下2021-01-01
Spring Security實現(xiàn)驗證碼登錄功能
這篇文章主要介紹了Spring Security實現(xiàn)驗證碼登錄功能,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-01-01

