詳解如何繼承Mybatis中Mapper.xml文件
引言
最近在寫一個 Mybatis 代碼自動生成插件,用的是Mybatis來擴展,其中有一個需求就是 生成javaMapper文件和 xmlMapper文件的時候 希望另外生成一個擴展類和擴展xml文件。原文件不修改,只存放一些基本的信息,開發(fā)過程中只修改擴展的Ext文件 形式如下: SrcTestMapper.java
修改擴展Ext文件
package com.test.dao.mapper.srctest;
import com.test.dao.model.srctest.SrcTest;
import com.test.dao.model.srctest.SrcTestExample;
import java.util.List;
import org.apache.ibatis.annotations.Param;
public interface SrcTestMapper {
long countByExample(SrcTestExample example);
int deleteByExample(SrcTestExample example);
int deleteByPrimaryKey(Integer id);
int insert(SrcTest record);
int insertSelective(SrcTest record);
List<SrcTest> selectByExample(SrcTestExample example);
SrcTest selectByPrimaryKey(Integer id);
int updateByExampleSelective(@Param("record") SrcTest record, @Param("example") SrcTestExample example);
int updateByExample(@Param("record") SrcTest record, @Param("example") SrcTestExample example);
int updateByPrimaryKeySelective(SrcTest record);
int updateByPrimaryKey(SrcTest record);
}
SrcTestMapperExt.java
package com.test.dao.mapper.srctest;
import com.test.dao.model.srctest.SrcTest;
import org.apache.ibatis.annotations.Param;
import javax.annotation.Resource;
import java.util.List;
/**
* SrcTestMapperExt接口
* Created by shirenchuang on 2018/6/30.
*/
@Resource
public interface SrcTestMapperExt extends SrcTestMapper {
List<SrcTest> selectExtTest(@Param("age") int age);
}
SrcTestMapper.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.test.dao.mapper.srctest.SrcTestMapperExt">
<resultMap id="BaseResultMap" type="com.test.dao.model.srctest.SrcTest">
<id column="id" jdbcType="INTEGER" property="id" />
<result column="name" jdbcType="VARCHAR" property="name" />
<result column="age" jdbcType="INTEGER" property="age" />
<result column="ctime" jdbcType="BIGINT" property="ctime" />
</resultMap>
<!-- 省略....-->
</mapper>
SrcTestMapperExt.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.test.dao.mapper.srctest.SrcTestMapperExt">
<select id="selectExtTest" resultMap="BaseResultMap">
select * from src_test where age>#{age}
</select>
</mapper>
注意:這里返回的resultMap="BaseResultMap" 這個Map并沒有再這個xml中定義,這樣能使用嗎?
上面是我生成的代碼;并且能夠正常使用;
那么SrcTestMapperExt.xml是如何繼承SrcTestMapper.xml中的定義的呢?
修改命名空間
使他們的命名空間相同,namespace="com.test.dao.mapper.srctest.SrcTestMapperExt"
光這樣還不夠,因為這個時候你去運行的時候會報錯
Caused by: org.apache.ibatis.builder.BuilderException: Wrong namespace. Expected 'com.test.dao.mapper.srctest.SrcTestMapper' but found 'com.test.dao.mapper.srctest.SrcTestMapperExt'.
因為Mybatis中是必須要 xml的文件包名和文件名必須跟 Mapper.java對應(yīng)起來的 比如com.test.dao.mapper.srctest.SrcTestMapper.java這個相對應(yīng)的是 com.test.dao.mapper.srctest.SrcTestMapper.xml 必須是這樣子,沒有例外,否則就會報錯 show the code MapperBuilderAssistant
public void setCurrentNamespace(String currentNamespace) {
if (currentNamespace == null) {
throw new BuilderException("The mapper element requires a namespace attribute to be specified.");
}
if (this.currentNamespace != null && !this.currentNamespace.equals(currentNamespace)) {
throw new BuilderException("Wrong namespace. Expected '"
+ this.currentNamespace + "' but found '" + currentNamespace + "'.");
}
this.currentNamespace = currentNamespace;
}
這個this.currentNamespace 和參數(shù)傳進來的currentNamespace比較是否相等;
參數(shù)傳進來的currentNamespace就是我們xml中的 <mapper namespace="com.test.dao.mapper.srctest.SrcTestMapperExt">值;
this.currentNamespace 設(shè)置
然后this.currentNamespace是從哪里設(shè)置的呢?this.currentNamespace = currentNamespace;
跟下代碼:MapperAnnotationBuilder
public void parse() {
String resource = type.toString();
if (!configuration.isResourceLoaded(resource)) {
loadXmlResource();
configuration.addLoadedResource(resource);
assistant.setCurrentNamespace(type.getName());
parseCache();
parseCacheRef();
Method[] methods = type.getMethods();
for (Method method : methods) {
try {
// issue #237
if (!method.isBridge()) {
parseStatement(method);
}
} catch (IncompleteElementException e) {
configuration.addIncompleteMethod(new MethodResolver(this, method));
}
}
}
parsePendingMethods();
}
看到 assistant.setCurrentNamespace(type.getName()); 它獲取的是 type.getName() ;
這個type的最終來源是 MapperFactoryBean
@Override
protected void checkDaoConfig() {
super.checkDaoConfig();
notNull(this.mapperInterface, "Property 'mapperInterface' is required");
Configuration configuration = getSqlSession().getConfiguration();
if (this.addToConfig && !configuration.hasMapper(this.mapperInterface)) {
try {
configuration.addMapper(this.mapperInterface);
} catch (Exception e) {
logger.error("Error while adding the mapper '" + this.mapperInterface + "' to configuration.", e);
throw new IllegalArgumentException(e);
} finally {
ErrorContext.instance().reset();
}
}
}
看configuration.addMapper(this.mapperInterface);這行應(yīng)該就明白了 加載mapperInterface的時候會跟相應(yīng)的xml映射,并且會去檢驗namespace是否跟mapperInterface相等!
那么既然命名空間不能修改,那第一條不白說了?還怎么實現(xiàn)Mapper.xml的繼承?。?別慌,既然是這樣子,那我們可以讓 MapperInterface 中的SrcTestMapper.java別被加載進來就行了啊??! 只加載 MapperExt.java不就行了?
修改applicationContext.xml,讓Mapper.java不被掃描
Mapper.java接口掃描配置
<!-- Mapper接口所在包名,Spring會自動查找其下的Mapper -->
<bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.test.dao.mapper"/>
<!--
該屬性實際上就是起到一個過濾的作用,如果設(shè)置了該屬性,那么MyBatis的接口只有包含該注解,才會被掃描進去。
-->
<property name="annotationClass" value="javax.annotation.Resource"/>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>
basePackage 把Mapper.java掃描進去沒有關(guān)系,重點是 <property name="annotationClass" value="javax.annotation.Resource"/> 這樣 MapperScanner會把沒有配置注解的過濾掉; 回頭看我們的MapperExt.java配置文件是有加上注解的
/**
* SrcTestMapperExt接口
* Created by shirenchuang on 2018/6/30.
*/
@Resource
public interface SrcTestMapperExt extends SrcTestMapper {
List<SrcTest> selectExtTest(@Param("age") int age);
}
這樣子之后,基本上問題就解決了,還有一個地方特別要注意一下的是.xml文件的配置
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<!-- 必須將mapper,和mapperExt也一起掃描-->
<property name="mapperLocations" value="classpath:com/test/dao/mapper/**/*.xml"/>
</bean>
這樣配置沒有錯,但是我之前的配置寫成了 <property name="mapperLocations" value="classpath:com/test/dao/mapper/**/*Mapper.xml"/>
這樣子 MapperExt.xml 沒有被掃描進去,在我執(zhí)行單元測試的時候
@Test
public void selectExt(){
List<SrcTest> tests = srcTestService.selectExtTest(9);
System.out.println(tests.toString());
}
err_console
org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.test.dao.mapper.srctest.SrcTestMapperExt.selectExtTest
但是執(zhí)行 ````srcTestService.insertSelective(srcTest);不會出錯 原因就是 insertSelective是在SrcTestMapper.xml中存在 ,已經(jīng)被注冊到 com.test.dao.mapper.srctest.SrcTestMapperExt```命名空間了,但是selectExtTest由于沒有被注冊,所以報錯了;
有興趣可以下載閱讀或者直接使用我整合的 自動生成擴展插件
以上就是詳解如何繼承Mybatis中Mapper.xml文件的詳細內(nèi)容,更多關(guān)于Mybatis Mapper.xml文件繼承的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
springboot項目配置logback日志系統(tǒng)的實現(xiàn)
這篇文章主要介紹了springboot項目配置logback日志系統(tǒng)的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2021-04-04
教你用java實現(xiàn)學生成績管理系統(tǒng)(附詳細代碼)
教學管理系統(tǒng)很適合初學者對于所學語言的練習,下面這篇文章主要給大家介紹了關(guān)于如何用java實現(xiàn)學生成績管理系統(tǒng)的相關(guān)資料,文中給出了詳細的實例代碼,需要的朋友可以參考下2023-06-06
利用Jackson實現(xiàn)數(shù)據(jù)脫敏的示例詳解
在我們的企業(yè)項目中,為了保護用戶隱私,數(shù)據(jù)脫敏成了必不可少的操作,那么我們怎么優(yōu)雅的利用Jackson實現(xiàn)數(shù)據(jù)脫敏呢,本文就來和大家詳細聊聊,希望對大家有所幫助2023-05-05

