沈阳网站怎么推广,东莞大朗现在有多少例,wordpress 页面 首页,怎么把广告发到各大平台目录
一、背景
二、注意
三、代码
四、使用示例
五、其他参考博客 一、背景
开发一个报表功能#xff0c;好几百行sql#xff0c;每次修改完想自测下都要重启服务器#xff0c;启动一次服务器就要3分钟#xff0c;重启10次就要半小时#xff0c;耗不起时间呀。于是在…目录
一、背景
二、注意
三、代码
四、使用示例
五、其他参考博客 一、背景
开发一个报表功能好几百行sql每次修改完想自测下都要重启服务器启动一次服务器就要3分钟重启10次就要半小时耗不起时间呀。于是在网上找半天没发现能直接用的, 最后还是乖乖用了自己的业余时间参考了网上内容写了个合适自己的类。 二、注意
1.本类在mybatis-plus-boot-starter 3.4.0 mybatis3.5.5下有效其他版本没试过
2.部分idea版本修改了xml中的sql后并不会直接写入到硬盘中而是保留在内存中需要手动ctrls或者切换到其他窗口才能触发写入新内容到硬盘所以使用本类时要确认你修改的sql确实已经保存进硬盘里了
3.xml所在文件夹的绝对位置需要你修改下再使用本类 三、代码
用一个类就能实现开发阶段sql热更新
这个类可以配置启动一个线程每10秒重新加载最近有修改过的sql
也可以调用一下接口重新修改过的sql
代码如下
package com.gree;import com.baomidou.mybatisplus.core.MybatisMapperRegistry;
import org.apache.ibatis.builder.xml.XMLMapperBuilder;
import org.apache.ibatis.builder.xml.XMLMapperEntityResolver;
import org.apache.ibatis.executor.ErrorContext;
import org.apache.ibatis.executor.keygen.SelectKeyGenerator;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.logging.LogFactory;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.parsing.XNode;
import org.apache.ibatis.parsing.XPathParser;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.*;/*** 本类用于热部署mybatis xml中修改的sql* 注意* 1.本类在mybatis-plus-boot-starter 3.4.0 和 mybatis3.5.5 下有效其他版本没试过* 2.部分idea版本修改了xml中的sql后并不会直接写入到硬盘中而是保留在内存中需要手动ctrls或者切换到其他窗口才能触发写入新内容到硬盘所以使用本类时要确认你修改的sql确实已经保存进硬盘里了* 3.xml所在文件夹的绝对位置需要你修改下再使用本类*/
RestController
public class MybatisMapperRefresh {//xml所在文件夹的绝对位置(这里改成你的位置)private String mapperPath D:\\wjh\\Mome\\openGitCode\\mybatisRefreshDemo\\src\\main\\resources\\mapper;//是否需要启动一个线程每隔一段时间就刷新下private boolean needStartThread false;//刷新间隔时间(秒)private int sleepSeconds 10;//项目启动时间或加载本class的时间private long startTime new Date().getTime();//上次执行更新xml的时间private long lasteUpdateTime 0;private static final Log logger LogFactory.getLog(MybatisMapperRefresh.class);private SqlSessionFactory sqlSessionFactory;private Configuration configuration;/*** 构造函数由spring调用生成bean* param sqlSessionFactory*/public MybatisMapperRefresh(SqlSessionFactory sqlSessionFactory) {this.sqlSessionFactory sqlSessionFactory;this.configuration sqlSessionFactory.getConfiguration();if (needStartThread) {this.startThread();}}/*** 调用这个接口刷新你的sql,接口会返回刷新了哪些xml* return*/RequestMapping(/sql/refresh)public ListString refreshMapper() {ListString refreshedList new ArrayList();try {refreshedList refreshDir();} catch (Exception e) {e.printStackTrace();}return refreshedList;}/*** 启动一个线程每间隔一段时间就更新下xml中的sql*/public void startThread() {new Thread(new Runnable() {Overridepublic void run() {while (true) {logger.warn(线程循环中!);try {refreshDir();} catch (Exception e) {e.printStackTrace();}try {Thread.sleep(sleepSeconds * 1000);} catch (Exception e) {e.printStackTrace();}}}}, mybatis-plus MapperRefresh).start();}/*** 刷新指定目录下所有xml文件** throws Exception*/private ListString refreshDir() throws Exception {ListString refreshedList new ArrayList();try {//获取指定目录下修改时间大于上次刷新时间并且修改时间大于项目启动时间的xmlListFile fileList FileUtil.getAllFiles(mapperPath);ArrayListFile needUpdateFiles new ArrayList();for (File file : fileList) {long lastModified file.lastModified();if (file.isFile() startTime lastModified lasteUpdateTime lastModified) {needUpdateFiles.add(file);continue;}}//逐个xml刷新if (needUpdateFiles.size() ! 0) {lasteUpdateTime new Date().getTime();}for (File file : needUpdateFiles) {Resource refresh refresh(new FileSystemResource(file));if(refresh ! null){refreshedList.add(refresh.getFile().getAbsolutePath());}}} catch (Exception e) {e.printStackTrace();}//返回已刷新的文件return refreshedList;}/*** 刷新mapper*/private Resource refresh(Resource resource) throws Exception {//打印一下流,看看有没有获取到更新的内容/*InputStream inputStream resource.getInputStream();InputStreamReader inputStreamReader new InputStreamReader(inputStream);BufferedReader bufferedReader new BufferedReader(inputStreamReader);String line;while ((line bufferedReader.readLine()) ! null) {System.out.println(line);}bufferedReader.close();*/boolean isSupper configuration.getClass().getSuperclass() Configuration.class;try {//清理loadedResources//loadedResources用于注册所有 Mapper XML 配置文件路径Field loadedResourcesField isSupper? configuration.getClass().getSuperclass().getDeclaredField(loadedResources): configuration.getClass().getDeclaredField(loadedResources);loadedResourcesField.setAccessible(true);SetString loadedResourcesSet ((SetString) loadedResourcesField.get(configuration));loadedResourcesSet.remove(resource.toString());//分析需要刷新的xml文件XPathParser xPathParser new XPathParser(resource.getInputStream(), true, configuration.getVariables(),new XMLMapperEntityResolver());//得到xml中的mapper节点XNode xNode xPathParser.evalNode(/mapper);String xNodeNamespace xNode.getStringAttribute(namespace);//清理mapperRegistry中的knownMappers//mapperRegistry用于注册 Mapper 接口信息建立 Mapper 接口的 Class 对象和 MapperProxyFactory 对象之间的关系其中 MapperProxyFactory 对象用于创建 Mapper 动态代理对象Field knownMappersField MybatisMapperRegistry.class.getDeclaredField(knownMappers);knownMappersField.setAccessible(true);Map knownMappers (Map) knownMappersField.get(configuration.getMapperRegistry());knownMappers.remove(Resources.classForName(xNodeNamespace));//清理caches//caches用于注册 Mapper 中配置的所有缓存信息其中 Key 为 Cache 的 id也就是 Mapper 的命名空间Value 为 Cache 对象configuration.getCacheNames().remove(xNodeNamespace);//其他清理操作cleanParameterMap(xNode.evalNodes(/mapper/parameterMap), xNodeNamespace);cleanResultMap(xNode.evalNodes(/mapper/resultMap), xNodeNamespace);cleanKeyGenerators(xNode.evalNodes(insert|update|select|delete), xNodeNamespace);cleanMappedStatements(xNode.evalNodes(insert|update|select|delete), xNodeNamespace);cleanSqlElement(xNode.evalNodes(/mapper/sql), xNodeNamespace);//重新加载xml文件XMLMapperBuilder xmlMapperBuilder new XMLMapperBuilder(resource.getInputStream(),configuration, resource.toString(),configuration.getSqlFragments());xmlMapperBuilder.parse();logger.warn(重新加载成功: resource );return resource;} catch (IOException e) {logger.error(重新加载失败 : ,e);} finally {ErrorContext.instance().reset();}return null;}/*** 清理parameterMap* parameterMap用于注册 Mapper 中通过 标签注册的参数映射信息。Key 为 ParameterMap 的 id由 Mapper 命名空间和 标签的 id 属性构成Value 为解析 标签后得到的 ParameterMap 对象** param list* param namespace*/private void cleanParameterMap(ListXNode list, String namespace) {for (XNode parameterMapNode : list) {String id parameterMapNode.getStringAttribute(id);configuration.getParameterMaps().remove(namespace . id);}}/*** 清理resultMap* resultMap用于注册 Mapper 配置文件中通过 标签配置的 ResultMap 信息ResultMap 用于建立 Java 实体属性与数据库字段之间的映射关系其中 Key 为 ResultMap 的 id该 id 是由 Mapper 命名空间和 标签的 id 属性组成的Value 为解析 标签后得到的 ResultMap 对象** param list* param namespace*/private void cleanResultMap(ListXNode list, String namespace) {for (XNode resultMapNode : list) {String id resultMapNode.getStringAttribute(id, resultMapNode.getValueBasedIdentifier());configuration.getResultMapNames().remove(id);configuration.getResultMapNames().remove(namespace . id);clearResultMap(resultMapNode, namespace);}}/*** 清理ResultMap* ResultMap用于注册 Mapper 配置文件中通过 标签配置的 ResultMap 信息ResultMap 用于建立 Java 实体属性与数据库字段之间的映射关系其中 Key 为 ResultMap 的 id该 id 是由 Mapper 命名空间和 标签的 id 属性组成的Value 为解析 标签后得到的 ResultMap 对象*/private void clearResultMap(XNode xNode, String namespace) {for (XNode resultChild : xNode.getChildren()) {if (association.equals(resultChild.getName()) || collection.equals(resultChild.getName())|| case.equals(resultChild.getName())) {if (resultChild.getStringAttribute(select) null) {configuration.getResultMapNames().remove(resultChild.getStringAttribute(id, resultChild.getValueBasedIdentifier()));configuration.getResultMapNames().remove(namespace . resultChild.getStringAttribute(id, resultChild.getValueBasedIdentifier()));if (resultChild.getChildren() ! null !resultChild.getChildren().isEmpty()) {clearResultMap(resultChild, namespace);}}}}}/*** 清理keyGenerators* keyGenerators用于注册 KeyGeneratorKeyGenerator 是 MyBatis 的主键生成器MyBatis 提供了三种KeyGenerator即 Jdbc3KeyGenerator(数据库自增主键、NoKeyGenerator无自增主键)、SelectKeyGenerator通过 select 语句查询自增主键例如 oracle 的 sequence** param list* param namespace*/private void cleanKeyGenerators(ListXNode list, String namespace) {for (XNode xNode : list) {String id xNode.getStringAttribute(id);configuration.getKeyGeneratorNames().remove(id SelectKeyGenerator.SELECT_KEY_SUFFIX);configuration.getKeyGeneratorNames().remove(namespace . id SelectKeyGenerator.SELECT_KEY_SUFFIX);}}/*** 清理MappedStatements* MappedStatement 对象描述 insert|selectlupdateldelete 等标签或者通过 Select|Delete|Update|Insert 等注解配置的 SQL 信息。MyBatis 将所有的 MappedStatement 对象注册到该属性中其中 Key 为 Mapper 的 Id Value 为 MappedStatement 对象** param list* param namespace*/private void cleanMappedStatements(ListXNode list, String namespace) {CollectionMappedStatement mappedStatements configuration.getMappedStatements();ListMappedStatement objects new ArrayList();for (XNode xNode : list) {String id xNode.getStringAttribute(id);IteratorMappedStatement it mappedStatements.iterator();while (it.hasNext()) {Object object it.next();if (object instanceof org.apache.ibatis.mapping.MappedStatement) {MappedStatement mappedStatement (MappedStatement) object;if (mappedStatement.getId().equals(namespace . id)) {objects.add(mappedStatement);}}}}mappedStatements.removeAll(objects);}/*** 清理sql节点缓存* 用于注册 Mapper 中通过 标签配置的 SQL 片段Key 为 SQL 片段的 idValue 为 MyBatis 封装的表示 XML 节点的 XNode 对象** param list* param namespace*/private void cleanSqlElement(ListXNode list, String namespace) {for (XNode context : list) {String id context.getStringAttribute(id);configuration.getSqlFragments().remove(id);configuration.getSqlFragments().remove(namespace . id);}}public static class FileUtil {/*** 列出执行文件夹下的所有文件包含子目录文件*/public static ListFile getAllFiles(String folderPath) {ListFile fileList new ArrayList();File folder new File(folderPath);if (!folder.exists() || !folder.isDirectory()) {return fileList;}File[] files folder.listFiles();for (File file : files) {if (file.isFile()) {fileList.add(file);} else if (file.isDirectory()) {fileList.addAll(getAllFiles(file.getAbsolutePath()));}}return fileList;}}
} pom.xml文件也贴出来给大家参考
?xml version1.0 encodingUTF-8?
project xmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersiongroupIdcom.greetree/groupIdartifactIdmybatisRefreshDemo/artifactIdversion1.0-SNAPSHOT/versionparentgroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-parent/artifactIdversion2.4.0/versionrelativePath/ !-- lookup parent from repository --/parentpropertiesjava.version1.8/java.version/propertiesdependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependencydependencygroupIdcom.baomidou/groupIdartifactIdmybatis-plus-boot-starter/artifactIdversion3.4.0/version/dependencydependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactIdversion8.0.25/version/dependencydependencygroupIdcom.github.pagehelper/groupIdartifactIdpagehelper-spring-boot-starter/artifactIdversion1.3.0/version/dependency/dependencies/project 四、使用示例
1. 将类MybatisMapperRefresh粘贴到可以被spring扫描到的任意目录 2. 修改类中的mapperPath改成你的xml文件所在目录 3. 启动服务器 4. 修改你的xml文件里的sql 5.ctrls保存文件确保idea将修改内容写入到硬盘而不是在内存中 6.调用接口http://localhost:{你项目端口号}/sql/refresh 更新sql接口会返回刷新了哪些xml 7.验证你的sql是否热更新了 五、其他参考博客
IDEA的热部署【MyBatis XML热部署 】_怎么配热部署实现更新ibatis的xml文件-CSDN博客