mybatis的繼承extend和導入import

本文做廢做廢。
緣由:跨xml引用: use in another mapper, you just need to specify the fully-qualified id.
本文的惟一一點好處能夠省去寫namespace的麻煩。node

1. 問題

在工做中和同事共同開發一個模塊,底層的數據模型用到的是同一個表。平常開發常規地都會動到這個數據模型實體的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

2. mybatis改動的地方

2.1 mybatis-3-mapper.dtd

須要改動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
>

2.2 XMLMapperBuilder.configurationElement

須要改動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"));
  }

3. 使用

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>
相關文章
相關標籤/搜索