詳解如何繼承Mybatis中Mapper.xml文件
引言
最近在寫一個(gè) Mybatis 代碼自動(dòng)生成插件,用的是Mybatis來擴(kuò)展,其中有一個(gè)需求就是 生成javaMapper文件和 xmlMapper文件的時(shí)候 希望另外生成一個(gè)擴(kuò)展類和擴(kuò)展xml文件。原文件不修改,只存放一些基本的信息,開發(fā)過程中只修改擴(kuò)展的Ext文件 形式如下: SrcTestMapper.java
修改擴(kuò)展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" 這個(gè)Map并沒有再這個(gè)xml中定義,這樣能使用嗎?
上面是我生成的代碼;并且能夠正常使用;
那么SrcTestMapperExt.xml是如何繼承SrcTestMapper.xml中的定義的呢?
修改命名空間
使他們的命名空間相同,namespace="com.test.dao.mapper.srctest.SrcTestMapperExt"
光這樣還不夠,因?yàn)檫@個(gè)時(shí)候你去運(yùn)行的時(shí)候會(huì)報(bào)錯(cuò)
Caused by: org.apache.ibatis.builder.BuilderException: Wrong namespace. Expected 'com.test.dao.mapper.srctest.SrcTestMapper' but found 'com.test.dao.mapper.srctest.SrcTestMapperExt'.
因?yàn)镸ybatis中是必須要 xml的文件包名和文件名必須跟 Mapper.java對(duì)應(yīng)起來的 比如com.test.dao.mapper.srctest.SrcTestMapper.java這個(gè)相對(duì)應(yīng)的是 com.test.dao.mapper.srctest.SrcTestMapper.xml 必須是這樣子,沒有例外,否則就會(huì)報(bào)錯(cuò) 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; }
這個(gè)this.currentNamespace 和參數(shù)傳進(jìn)來的currentNamespace比較是否相等;
參數(shù)傳進(jìn)來的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() ;
這個(gè)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的時(shí)候會(huì)跟相應(yīng)的xml映射,并且會(huì)去檢驗(yàn)namespace是否跟mapperInterface相等!
那么既然命名空間不能修改,那第一條不白說了?還怎么實(shí)現(xiàn)Mapper.xml的繼承?。?別慌,既然是這樣子,那我們可以讓 MapperInterface 中的SrcTestMapper.java別被加載進(jìn)來就行了?。?! 只加載 MapperExt.java不就行了?
修改applicationContext.xml,讓Mapper.java不被掃描
Mapper.java接口掃描配置
<!-- Mapper接口所在包名,Spring會(huì)自動(dòng)查找其下的Mapper --> <bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.test.dao.mapper"/> <!-- 該屬性實(shí)際上就是起到一個(gè)過濾的作用,如果設(shè)置了該屬性,那么MyBatis的接口只有包含該注解,才會(huì)被掃描進(jìn)去。 --> <property name="annotationClass" value="javax.annotation.Resource"/> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/> </bean>
basePackage 把Mapper.java掃描進(jìn)去沒有關(guān)系,重點(diǎn)是 <property name="annotationClass" value="javax.annotation.Resource"/>
這樣 MapperScanner會(huì)把沒有配置注解的過濾掉; 回頭看我們的MapperExt.java配置文件是有加上注解的
/** * SrcTestMapperExt接口 * Created by shirenchuang on 2018/6/30. */ @Resource public interface SrcTestMapperExt extends SrcTestMapper { List<SrcTest> selectExtTest(@Param("age") int age); }
這樣子之后,基本上問題就解決了,還有一個(gè)地方特別要注意一下的是.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>
這樣配置沒有錯(cuò),但是我之前的配置寫成了 <property name="mapperLocations" value="classpath:com/test/dao/mapper/**/*Mapper.xml"/>
這樣子 MapperExt.xml 沒有被掃描進(jìn)去,在我執(zhí)行單元測(cè)試的時(shí)候
@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);不會(huì)出錯(cuò) 原因就是 insertSelective是在SrcTestMapper.xml中存在 ,已經(jīng)被注冊(cè)到 com.test.dao.mapper.srctest.SrcTestMapperExt```命名空間了,但是selectExtTest由于沒有被注冊(cè),所以報(bào)錯(cuò)了;
有興趣可以下載閱讀或者直接使用我整合的 自動(dòng)生成擴(kuò)展插件
以上就是詳解如何繼承Mybatis中Mapper.xml文件的詳細(xì)內(nèi)容,更多關(guān)于Mybatis Mapper.xml文件繼承的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
解決IDEA2021版compiler.automake.allow.when.app.running不存在的問題
很多文章介紹IntelliJ IDEA開啟熱部署功能都會(huì)寫到在IntelliJ IDEA中的注冊(cè)表中開啟compiler.automake.allow.when.app.running選項(xiàng),此選項(xiàng)在IntelliJ IDEA 2021.2之后的版本遷移到高級(jí)設(shè)置中,下面看下設(shè)置方法2021-09-09JAVA中 Spring定時(shí)器的兩種實(shí)現(xiàn)方式
本文向您介紹Spring定時(shí)器的兩種實(shí)現(xiàn)方式,包括Java Timer定時(shí)和Quartz定時(shí)器,兩種Spring定時(shí)器的實(shí)現(xiàn)方式各有優(yōu)點(diǎn),可結(jié)合具體項(xiàng)目考慮是否采用。2015-09-09SpringCloud?Feign使用ApacheHttpClient代替默認(rèn)client方式
這篇文章主要介紹了SpringCloud?Feign使用ApacheHttpClient代替默認(rèn)client方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03Java中Final關(guān)鍵字的使用技巧及其性能優(yōu)勢(shì)詳解
這篇文章主要介紹了Java中Final關(guān)鍵字的使用技巧及其性能優(yōu)勢(shì)詳解,Java中的final關(guān)鍵字用于修飾變量、方法和類,可以讓它們?cè)诙x后不可更改,從而提高程序的穩(wěn)定性和可靠性,此外,final關(guān)鍵字還有一些使用技巧和性能優(yōu)勢(shì),需要的朋友可以參考下2023-10-10Java基于Swing實(shí)現(xiàn)的打獵射擊游戲代碼
這篇文章主要介紹了Java基于Swing實(shí)現(xiàn)的打獵射擊游戲代碼,包含完整的游戲事件處理與邏輯流程控制,具有不錯(cuò)的參考借鑒價(jià)值,需要的朋友可以參考下2014-11-11詳解Spring Cloud Eureka多網(wǎng)卡配置總結(jié)
本篇文章主要介紹了詳解Spring Cloud Eureka多網(wǎng)卡配置總結(jié),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-04-04Spring boot如何通過@Scheduled實(shí)現(xiàn)定時(shí)任務(wù)及多線程配置
這篇文章主要介紹了Spring boot如何通過@Scheduled實(shí)現(xiàn)定時(shí)任務(wù)及多線程配置,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-12-12