欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

MyBatis 添加元數(shù)據(jù)自定義元素標(biāo)簽的實(shí)現(xiàn)代碼

 更新時(shí)間:2020年07月24日 11:07:02   作者:小王886  
這篇文章主要介紹了MyBatis 添加元數(shù)據(jù)自定義元素標(biāo)簽的實(shí)現(xiàn)代碼,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

開發(fā)背景

 現(xiàn)有系統(tǒng)中維護(hù)了一套業(yè)務(wù)表相關(guān)列、鍵的元數(shù)據(jù),希望通過讀取元數(shù)據(jù)實(shí)現(xiàn)自動(dòng)封裝 SQL 語句、自定義主鍵策略。實(shí)現(xiàn)方案為入侵式修改 MyBatis,增加元素標(biāo)簽meta,支持業(yè)務(wù)開發(fā)中可以在XML映射文件中使用。

meta元素設(shè)計(jì)如下:

<!-- meta標(biāo)簽 可根據(jù)參數(shù)獲取到對(duì)應(yīng)的表名 動(dòng)態(tài)生成語句 -->
<!ELEMENT meta EMPTY>
<!ATTLIST meta
test CDATA #IMPLIED
type (update|insert|select|columns|pk-col|load|load-columns) #IMPLIED
ignore CDATA #IMPLIED
table CDATA #IMPLIED
func CDATA #IMPLIED
alias CDATA #IMPLIED
>

期望示例如下:

<insert id="insertMap" useGeneratedKeys="true" generator="meta">
 <meta table="USER" type="insert"/>
</insert>

<update id="updateMap">
 <meta table="USER" type="update"/>
</update>

<select id="selectOneByPk" resultType="java.util.HashMap">
 select 
 <meta table="USER" type="columns"/> 
 from USER 
 where <meta table="USER" type="pk-col"/> = #{__PK_VALUE}
</select>

開發(fā)準(zhǔn)備

 新建項(xiàng)目并引入 mybatis 、 mybatis-spring 兩個(gè)核心依賴。

<!-- mybatis -->
<dependency>
 <groupId>org.mybatis</groupId>
 <artifactId>mybatis</artifactId>
</dependency>
<!-- mybatis-spring -->
<dependency>
 <groupId>org.mybatis</groupId>
 <artifactId>mybatis-spring</artifactId>
</dependency>

增加自定義元素

創(chuàng)建 MetaHandler 和 MetaSqlNode

public class MetaHandler implements NodeHandler {

 private final CustomConfiguration configuration;

 protected MetaHandler(CustomConfiguration configuration) {
 this.configuration = configuration;
 }

 @Override
 public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {
 final String test = nodeToHandle.getStringAttribute("test");
 final String type = nodeToHandle.getStringAttribute("type");
 final String ignore = nodeToHandle.getStringAttribute("ignore");
 final String table = nodeToHandle.getStringAttribute("table");
 final String func = nodeToHandle.getStringAttribute("func");
 String alias = nodeToHandle.getStringAttribute("alias");
 if (!StringUtils.isEmpty(alias)) {
  alias = alias.trim();
  //是否無效 防止注入
  boolean invalid = alias.contains(" ") || alias.contains(".");
  if (invalid) {
  throw new RuntimeException("alias is invalid : " + alias);
  }
 }
 MetaSqlNode metaSqlNode = new MetaSqlNode(configuration, test, type, ignore, table, func, alias);
 targetContents.add(metaSqlNode);
 }
}
public class MetaSqlNode implements SqlNode {

 /**
 * mybatis核心數(shù)據(jù)
 */
 private final CustomConfiguration configuration;
 /**
 * 判斷語句校驗(yàn)器
 */
 private final ExpressionEvaluator evaluator;
 /**
 * 判斷語句,同if標(biāo)簽
 */
 private final String test;
 /**
 * 生成語句類型 update|insert|select|columns|pk-col|load|load-columns
 */
 private final TypeEnum type;
 /**
 * 忽略的列
 */
 private final String ignore;
 /**
 * 表名,未指定則從調(diào)用參數(shù)中獲取
 */
 private final String table;
 /**
 * 功能,未指定則從調(diào)用參數(shù)中獲取
 */
 private final String func;
 /**
 * 動(dòng)態(tài)列別名
 */
 private final String alias;

 public MetaSqlNode(CustomConfiguration configuration, String test, String type, String ignore, String table, String func, String alias) {
 this.evaluator = new ExpressionEvaluator();
 this.configuration = configuration;
 this.test = test;
 this.type = TypeEnum.parse(type);
 this.ignore = ignore;
 this.table = table;
 this.func = func;
 this.alias = alias;
 }

 @Override
 public boolean apply(DynamicContext context) {
 // TODO 解析type與table,向context中添加語句
 context.appendSql(" insert ······ ");
 }
}

創(chuàng)建 CustomXMLScriptBuilder

 內(nèi)容復(fù)制自org.apache.ibatis.scripting.xmltags.XMLScriptBuilder,在 initNodeHandlerMap 方法中添加 MetaHandler。

private void initNodeHandlerMap() {
 nodeHandlerMap.put("trim", new TrimHandler());
 nodeHandlerMap.put("where", new WhereHandler());
 nodeHandlerMap.put("set", new SetHandler());
 nodeHandlerMap.put("foreach", new ForEachHandler());
 nodeHandlerMap.put("if", new IfHandler());
 nodeHandlerMap.put("choose", new ChooseHandler());
 nodeHandlerMap.put("when", new IfHandler());
 nodeHandlerMap.put("otherwise", new OtherwiseHandler());
 nodeHandlerMap.put("bind", new BindHandler());
 //增加元數(shù)據(jù)標(biāo)簽解析器
 if (configuration instanceof CustomConfiguration) {
 nodeHandlerMap.put("meta", new MetaHandler((CustomConfiguration) configuration));
 }
}

創(chuàng)建 CustomXMLLanguageDriver

 內(nèi)容復(fù)制自org.apache.ibatis.scripting.xmltags.XMLLanguageDriver,在 createSqlSource 方法中使用 CustomXMLScriptBuilder 來解析Xml生成 SqlSource。

@Override
public SqlSource createSqlSource(Configuration configuration, XNode script, Class<?> parameterType) {
 CustomXMLScriptBuilder builder = new CustomXMLScriptBuilder(configuration, script, parameterType);
 return builder.parseScriptNode();
}

創(chuàng)建 CustomConfiguration

 繼承org.apache.ibatis.session.Configuration,內(nèi)容復(fù)制自 Configuration。將構(gòu)造方法中的 XMLLanguageDriver 修改為 CustomConfiguration。

public CustomConfiguration() {
 
 ······
 
 //默認(rèn)使用自定義 LanguageDriver
 typeAliasRegistry.registerAlias("XML", CustomXMLLanguageDriver.class);
 
 ······
 
 //默認(rèn)使用自定義 LanguageDriver
 languageRegistry.setDefaultDriverClass(CustomXMLLanguageDriver.class);
 
 ······
 
}

創(chuàng)建 CustomXMLConfigBuilder

 內(nèi)容復(fù)制自org.apache.ibatis.builder.xml.XMLConfigBuilder,支持通過 XML 配置來創(chuàng)建 CustomConfiguration。

public class CustomXMLConfigBuilder extends BaseBuilder {
 
 ······
 
 private CustomXMLConfigBuilder(XPathParser parser, String environment, Properties props) {
 // 使用 CustomConfiguration
 super(new CustomConfiguration());
 ErrorContext.instance().resource("SQL Mapper Configuration");
 this.configuration.setVariables(props);
 this.parsed = false;
 this.environment = environment;
 this.parser = parser;
 }
 
 ······
 
}

創(chuàng)建 SqlSessionFactory

 復(fù)制自org.mybatis.spring.SqlSessionFactoryBean,將 buildSqlSessionFactory 方法中的 Configuration 替換為 CustomConfiguration。

protected SqlSessionFactory buildSqlSessionFactory() throws Exception {

 final Configuration targetConfiguration;

 CustomXMLConfigBuilder xmlConfigBuilder = null;
 if (this.configuration != null) {
 targetConfiguration = this.configuration;
 if (targetConfiguration.getVariables() == null) {
  targetConfiguration.setVariables(this.configurationProperties);
 } else if (this.configurationProperties != null) {
  targetConfiguration.getVariables().putAll(this.configurationProperties);
 }
 } else if (this.configLocation != null) {
 // 使用 CustomXMLConfigBuilder 創(chuàng)建 CustomConfiguration
 xmlConfigBuilder = new CustomXMLConfigBuilder(this.configLocation.getInputStream(), null, this.configurationProperties);
 targetConfiguration = xmlConfigBuilder.getConfiguration();
 } else {
 LOGGER.debug(
  () -> "Property 'configuration' or 'configLocation' not specified, using default MyBatis Configuration");
 // 使用 CustomConfiguration
 targetConfiguration = new CustomConfiguration();
 Optional.ofNullable(this.configurationProperties).ifPresent(targetConfiguration::setVariables);
 }
 
 ······
 
 return this.sqlSessionFactoryBuilder.build(targetConfiguration);
}

修改DTD約束

 MyBatis 的約束文件并不支持自定義的 meta 元素,需要使用 CDATA 來處理。示例如下:

<insert id="insertMap" useGeneratedKeys="true" generator="meta">
 <![CDATA[[
 <meta table="USER" type="insert"/>
 ]]>
</insert>

 如果不想要 CDATA,則需要通過修改DTD約束來完成。

  • 在 classes 下指定位置添加DTD約束文件org/apache/ibatis/builder/xml/mybatis-3-config.dtd達(dá)到覆蓋 MyBatis DTD的效果。
  • 重寫代碼來使用指定 DTD 。

創(chuàng)建 CustomXMLMapperEntityResolver

 復(fù)制自org.apache.ibatis.builder.xml.XMLMapperEntityResolver,將MYBATIS_MAPPER_DTD修改為指向本地 mybatis-3-mapper.dtd 文件,并在DTD文件中添加 meta 元素的約束。

public class CustomXMLMapperEntityResolver implements EntityResolver {
 
 ······
 
 private static final String MYBATIS_MAPPER_DTD = "com/my/ibatis/builder/xml/mybatis-3-mapper.dtd";
 
 ······
 
}
<!-- meta標(biāo)簽 可根據(jù)參數(shù)獲取到對(duì)應(yīng)的表名 動(dòng)態(tài)生成語句 -->
<!ELEMENT meta EMPTY>
<!ATTLIST meta
test CDATA #IMPLIED
type (update|insert|select|columns|pk-col|load|load-columns) #IMPLIED
ignore CDATA #IMPLIED
table CDATA #IMPLIED
func CDATA #IMPLIED
alias CDATA #IMPLIED
>

CustomXMLLanguageDriver

  Mapper動(dòng)態(tài)語句注解處理使用 CustomXMLMapperEntityResolver。

/**
 * Mapper動(dòng)態(tài)語句注解調(diào)用
 * <p>
 * "<script>select * from user <if test=\"id !=null \">where id = #{id} </if></script>"
 *
 * @param configuration mybatis配置
 * @param script 動(dòng)態(tài)語句字符串
 * @param parameterType 參數(shù)類型
 * @return org.apache.ibatis.mapping.SqlSource
 */
@Override
public SqlSource createSqlSource(Configuration configuration, String script, Class<?> parameterType) {
 // issue #3
 if (script.startsWith("<script>")) {
 //將動(dòng)態(tài)語句字符串轉(zhuǎn)換為XNode對(duì)象
 XPathParser parser = new XPathParser(script, false, configuration.getVariables(), new CustomXMLMapperEntityResolver());
 return createSqlSource(configuration, parser.evalNode("/script"), parameterType);
 } else {
 // issue #127
 script = PropertyParser.parse(script, configuration.getVariables());
 TextSqlNode textSqlNode = new TextSqlNode(script);
 if (textSqlNode.isDynamic()) {
  return new CustomDynamicSqlSource(configuration, textSqlNode);
 } else {
  return new RawSqlSource(configuration, script, parameterType);
 }
 }
}

創(chuàng)建 CustomXMLMapperBuilder

  復(fù)制自org.apache.ibatis.builder.xml.XMLMapperBuilder,修改構(gòu)造函數(shù)使用 CustomXMLMapperEntityResolver 解析xml。

public CustomXMLMapperBuilder(InputStream inputStream, Configuration configuration, String resource, Map<String, XNode> sqlFragments) {
 this(new XPathParser(inputStream, true, configuration.getVariables(), new CustomXMLMapperEntityResolver()),
  configuration, resource, sqlFragments);
}

SqlSessionFactory

 修改 buildSqlSessionFactory 方法,使用 CustomXMLMapperBuilder 來解析xml。

protected SqlSessionFactory buildSqlSessionFactory() throws Exception {

 ······
 try {
  //使用自定義 XMLMapperBuilder
  CustomXMLMapperBuilder xmlMapperBuilder = new CustomXMLMapperBuilder(mapperLocation.getInputStream(),
   targetConfiguration, mapperLocation.toString(), targetConfiguration.getSqlFragments());
  xmlMapperBuilder.parse();
 } catch (Exception e) {
  throw new NestedIOException("Failed to parse mapping resource: '" + mapperLocation + "'", e);
 } finally {
  ErrorContext.instance().reset();
 }
 
 ······
 
}

創(chuàng)建 CustomMapperAnnotationBuilder

 復(fù)制自org.apache.ibatis.builder.annotation.MapperAnnotationBuilder,修改 loadXmlResource 方法使用 CustomXMLMapperBuilder。

private void loadXmlResource() {
 if (!configuration.isResourceLoaded("namespace:" + type.getName())) {
  
 ······
 
  if (inputStream != null) {
   //使用自定義解析器支持自定義標(biāo)簽
   CustomXMLMapperBuilder xmlParser = new CustomXMLMapperBuilder(inputStream, assistant.getConfiguration(), xmlResource, configuration.getSqlFragments(), type.getName());
   xmlParser.parse();
  }
 }
}

創(chuàng)建 CustomMapperRegistry

  復(fù)制自org.apache.ibatis.binding.MapperRegistry,修改 addMapper 方法使用 CustomMapperAnnotationBuilder。

@Override
public <T> void addMapper(Class<T> type) {
 if (type.isInterface()) {
  
 ······
 
  try {
   knownMappers.put(type, new MapperProxyFactory<>(type));
   // It's important that the type is added before the parser is run
   // otherwise the binding may automatically be attempted by the
   // mapper parser. If the type is already known, it won't try.
   CustomMapperAnnotationBuilder parser = new CustomMapperAnnotationBuilder(config, type);
   parser.parse();
   loadCompleted = true;
  } finally {
   if (!loadCompleted) {
    knownMappers.remove(type);
   }
  }
 }
}

CustomConfiguration

 修改 mapperRegistry 屬性使用 CustomMapperRegistry。

public class CustomConfiguration extends Configuration {
  
 ······

 protected final MapperRegistry mapperRegistry = new CustomMapperRegistry(this);
  
 ······
 
}

在Spring中使用

<!-- Mybatis SessionFactory-->
<bean id="sqlSessionFactory" class="com.my.ibatis.SqlSessionFactoryBean">
 <property name="dataSource" ref="dataSource" />
 <property name="configurationProperties" >
  <bean class="org.springframework.beans.factory.config.PropertiesFactoryBean">
   <property name="locations" value="classpath*:mybatis.properties"/>
  </bean>
 </property>
</bean>
@Configuration
public class MybatisConfig {
 @Bean
 public PropertiesFactoryBean createPropertiesFactoryBean() throws IOException {
  PropertiesFactoryBean bean = new PropertiesFactoryBean();
  bean.setLocation(new ClassPathResource("mybatis.properties"));
  return bean;
 }

 @Bean("sqlSessionFactory")
 public SqlSessionFactoryBean createSqlSessionFactory(DataSource dataSource, PropertiesFactoryBean bean) throws IOException {
  SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
  factoryBean.setDataSource(dataSource);
  factoryBean.setConfigurationProperties(bean.getObject());
  return factoryBean;
 }
}

到此這篇關(guān)于MyBatis 添加元數(shù)據(jù)自定義元素標(biāo)簽的實(shí)現(xiàn)代碼的文章就介紹到這了,更多相關(guān)MyBatis自定義元素標(biāo)簽內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java文件處理工具類詳解

    java文件處理工具類詳解

    這篇文章主要為大家詳細(xì)介紹了java文件處理工具類的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-04-04
  • 在RedisTemplate中使用scan代替keys指令操作

    在RedisTemplate中使用scan代替keys指令操作

    這篇文章主要介紹了在RedisTemplate中使用scan代替keys指令操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-11-11
  • C# log4net使用案例詳解

    C# log4net使用案例詳解

    這篇文章主要介紹了C# log4net使用案例詳解,本篇文章通過簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • Java畢業(yè)設(shè)計(jì)實(shí)戰(zhàn)之線上水果超市商城的實(shí)現(xiàn)

    Java畢業(yè)設(shè)計(jì)實(shí)戰(zhàn)之線上水果超市商城的實(shí)現(xiàn)

    這是一個(gè)使用了java+SSM+springboot+redis開發(fā)的網(wǎng)上水果超市商城,是一個(gè)畢業(yè)設(shè)計(jì)的實(shí)戰(zhàn)練習(xí),具有水果超市商城該有的所有功能,感興趣的朋友快來看看吧
    2022-01-01
  • 小伙熬夜用Java重現(xiàn)經(jīng)典超級(jí)馬里奧代碼實(shí)例

    小伙熬夜用Java重現(xiàn)經(jīng)典超級(jí)馬里奧代碼實(shí)例

    這篇文章主要介紹了Java重現(xiàn)經(jīng)典超級(jí)馬里奧,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • Java使用Tinify實(shí)現(xiàn)圖片無損壓縮(4M無損壓縮到1M)的方法

    Java使用Tinify實(shí)現(xiàn)圖片無損壓縮(4M無損壓縮到1M)的方法

    在當(dāng)今的數(shù)字化時(shí)代,圖片已成為網(wǎng)站、應(yīng)用和社交媒體中不可或缺的元素,然而,大尺寸的圖片不僅會(huì)增加頁面或者客戶端加載時(shí)間,還會(huì)占用大量的存儲(chǔ)空間,本文將詳細(xì)介紹如何利用Tinify壓縮圖片,并將其上傳至OSS,重點(diǎn)介紹圖片壓縮實(shí)現(xiàn)方式,需要的朋友可以參考下
    2024-08-08
  • Java使用強(qiáng)大的Elastisearch搜索引擎實(shí)例代碼

    Java使用強(qiáng)大的Elastisearch搜索引擎實(shí)例代碼

    本篇文章主要介紹了Java使用強(qiáng)大的Elastisearch搜索引擎實(shí)例代碼,具有一定的參考價(jià)值,有興趣的可以了解一下
    2017-05-05
  • XML解析四種方式代碼示例詳解

    XML解析四種方式代碼示例詳解

    這篇文章主要介紹了XML解析四種方式代碼示例詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-12-12
  • slf4j?jcl?jul?log4j1?log4j2?logback各組件系統(tǒng)日志切換

    slf4j?jcl?jul?log4j1?log4j2?logback各組件系統(tǒng)日志切換

    這篇文章主要介紹了slf4j、jcl、jul、log4j1、log4j2、logback的大總結(jié),各個(gè)組件的jar包以及目前系統(tǒng)日志需要切換實(shí)現(xiàn)方式的方法,有需要的朋友可以借鑒參考下
    2022-03-03
  • Springboot集成Elasticsearch的步驟與相關(guān)功能

    Springboot集成Elasticsearch的步驟與相關(guān)功能

    ElasticSearch是開源搜索平臺(tái)領(lǐng)域的一個(gè)新成員,?ElasticSearch是一個(gè)基于Lucene構(gòu)建的開源,分布式,RESTful搜索引擎,這篇文章主要給大家介紹了關(guān)于Springboot集成Elasticsearch的相關(guān)資料,需要的朋友可以參考下
    2021-12-12

最新評(píng)論