本文做廢做廢。
緣由:跨xml引用: use in another mapper, you just need to specify the fully-qualified id.
本文的惟一一點好處能夠省去寫namespace的麻煩。node
在工做中和同事共同開發一個模塊,底層的數據模型用到的是同一個表。平常開發常規地都會動到這個數據模型實體的mapper。合併代碼的時候確定會有衝突相互覆蓋。後來想各自寫mapper.xml處理相關的邏輯,可是這樣resultMap就會有多份。需求常常變,到時候多份resultMap維護起來也麻煩。sql
因此想到能夠擴展一下mybatis支持xml繼承。後來查找了一下發現mybatis的resultMap支持繼承,利用extends屬性擴展原有的定義。最後決定在也在mapper元素上增長extends屬性保存要繼承的mapper.xml文件。能夠把公共的配置提取出來,把複雜的業務邏輯sql和基礎的curd sql寫在不一樣的文件裏。apache
後來有另外加入import功能,<import src="xx.xx.xx">
導入其餘文件的配置,原理也和extends差很少。類比 類的繼承和組合。mybatis
須要改動org.apache.ibatis.builder.xml包下的mybatis-3-mapper.dtd,給mapper增長extends屬性app
<!ELEMENT mapper (cache-ref | cache | import* | resultMap* | parameterMap* | sql* | insert* | update* | delete* | select* )+> <!ATTLIST mapper xmlns:fo CDATA #IMPLIED namespace CDATA #IMPLIED extends CDATA #IMPLIED > <!ELEMENT import EMPTY> <!ATTLIST import src CDATA #REQUIRED >
須要改動XMLMapperBuilder.configurationElement解析映射xml的處理過程:增長extends屬性的處理,具體代碼。沒有作循環依賴處理:ui
private void configurationElement(XNode context) { try { //1.配置namespace String namespace = context.getStringAttribute("namespace"); if (namespace.equals("")) { throw new BuilderException("Mapper's namespace cannot be empty"); } builderAssistant.setCurrentNamespace(namespace); extendsElement(context); mapperChildElement(context); } catch (Exception e) { throw new BuilderException("Error parsing Mapper XML. Cause: " + e, e); } } /**根據mapper上的extends所指向的xml文件,加載xml的配置 * 增長父extends,繼承xml裏mapper下的全部元素*/ private void extendsElement(XNode context) throws Exception { String extend = context.getStringAttribute("extends"); if(extend==null) return; String[] xmlResources=extend.replace('.', '/').split(","); for(String xmlResource:xmlResources){ fileElements(xmlResource); } } private void importElement(List<XNode> list) throws Exception { for(XNode node:list) { String src = node.getStringAttribute("src"); if(src==null) return; String[] xmlResources=src.replace('.', '/').split(","); for(String xmlResource:xmlResources) fileElements(xmlResource); } } private void fileElements(String xmlResource) throws Exception { xmlResource = xmlResource+ ".xml"; InputStream inputStream = Resources.getResourceAsStream(Thread.currentThread().getContextClassLoader(),xmlResource); XPathParser xpathParser=new XPathParser(inputStream, true, configuration.getVariables(), new XMLMapperEntityResolver()); XNode extendsContext=xpathParser.evalNode("/mapper"); extendsElement(extendsContext); mapperChildElement(extendsContext); } private void mapperChildElement(XNode context) throws Exception { //1.import importElement(context.evalNodes("/mapper/import")); //2.配置cache-ref cacheRefElement(context.evalNode("cache-ref")); //3.配置cache cacheElement(context.evalNode("cache")); //4.配置parameterMap(已經廢棄,老式風格的參數映射) parameterMapElement(context.evalNodes("/mapper/parameterMap")); //5.配置resultMap(高級功能) resultMapElements(context.evalNodes("/mapper/resultMap")); //6.配置sql(定義可重用的 SQL 代碼段) sqlElement(context.evalNodes("/mapper/sql")); //7.配置select|insert|update|delete TODO buildStatementFromContext(context.evalNodes("select|insert|update|delete")); }
1)普通的HelloWordMapper.xml映射文件,在mapper元素上加extends繼承cn.alpha.demo.BaseMapperspa
<mapper namespace="cn.alpha.demo.persistence.HelloWorldMapper" extends="cn.alpha.demo.BaseMapper"> <select id="getData" resultMap="ActivRePropMap" flushCache="false"> select NAME_,VALUE_,REV_ from act_ge_property </select> </mapper>
2)BaseMapper.xml父映射文件, 在mapper元素上加extends繼承cn.alpha.demo.BaseMapper2code
<mapper namespace="cn.alpha.BaseMapper" extends="cn.alpha.demo.BaseMapper2"> <resultMap id="ActivRePropMap" type="cn.alpha.demo.bo.ActivReProp" extends="ActivRePropMap-base"> <result property="rev" column="REV_"/> </resultMap> </mapper>
3)BaseMapper2.xml祖先映射文件xml
<mapper namespace="cn.alpha.BaseMapper2" > <resultMap id="ActivRePropMap-base" type="cn.alpha.demo.bo.ActivReProp"> <id property="name" column="NAME_" /> <result property="value" column="VALUE_"/> </resultMap> </mapper>