1、新建maven项目,pom引入如下
org.springframework
spring-context-support
${spring.version}
org.springframework
spring-jdbc
${spring.version}
org.springframework
spring-test
${spring.version}
org.mybatis
mybatis
${mybatis.version}
org.mybatis
mybatis-spring
${mybatis-spring.version}
mysql
mysql-connector-java
5.1.34
runtime
com.alibaba
druid
1.0.14
com.google.guava
guava
15.0
junit
junit
4.12
test
com.alibaba
fastjson
1.2.28
org.aspectj
aspectjweaver
1.8.8
org.slf4j
slf4j-api
1.7.12
org.slf4j
slf4j-log4j12
1.7.12
com.alibaba
easyexcel
1.1.2-beta5
org.apache.ant
ant
1.10.12
2、新建applicationContext-jdbc.xml配置文件,自定义DynamicDataSource
DB_SET=new HashSet<>(); //其他库 public static Set LOG1_DB_SET=new HashSet<>(); //log1对应的库 public static Set LOG2_DB_SET=new HashSet<>(); //log2对应的库 private static final String URL_PRE="jdbc:mysql://"; private static final String URL_SUFF="?useUnicode=true&characterEncoding=utf-8&autoReconnect=true"; public static final String DB_PRE="dn"; public static final String LOG1_DB_PRE="log1dn"; public static final String LOG2_DB_PRE="log2dn"; @Override protected Object determineCurrentLookupKey() { String dataSource = getDataSource(); _log.debug("the current datasource is :{}", dataSource); return dataSource; } public static void setDataSource(String dataSource) { contextHolder.set(dataSource); } public static String getDataSource() { return contextHolder.get(); } public static void clearDataSource() { contextHolder.remove(); } public void init(){ _log.info(">> >> >>初始化所有数据源..."); List dataNodeList= SchemaLoaderUtil.getDataNodeList(); String path= DynamicDataSource.class.getClassLoader().getResource("jdbc.properties").getPath(); PropertiesFileUtil propertiesFileUtil= PropertiesFileUtil.getInstance(path); Map
解析配置文件的getDataNodeList方法代码如下:
public static List getDataNodeList() {
Map dataHostMap = new HashMap<>();
List dataNodeList = new ArrayList<>();
documentBuilderFactory documentBuilderFactory = documentBuilderFactory.newInstance();
InputStream in = null;
try {
documentBuilderFactory.setValidating(false);
documentBuilderFactory.setNamespaceAware(false);
documentBuilderFactory.setFeature("http://xml.org/sax/features/namespaces", false);
documentBuilderFactory.setFeature("http://xml.org/sax/features/validation", false);
documentBuilderFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false);
documentBuilderFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
documentBuilder documentBuilder = documentBuilderFactory.newdocumentBuilder();
in = SchemaLoaderUtil.class.getClassLoader().getResourceAsStream("schema.xml");
document document = documentBuilder.parse(in);
Element rootElement = document.getdocumentElement();
//获取dataHost
NodeList dataHostNList = rootElement.getElementsByTagName("dataHost");
for (int i = 0; i < dataHostNList.getLength(); i++) {
Element dataHostEl = (Element) dataHostNList.item(i);
DataHost dataHost = wrappDataHost(dataHostEl);
dataHostMap.put(dataHost.getName(), dataHost);
}
//获取dataNode
NodeList dataNodeNList = rootElement.getElementsByTagName("dataNode");
for (int i = 0; i < dataNodeNList.getLength(); i++) {
Element dataHostEl = (Element) dataNodeNList.item(i);
List dataNodeListItem = wrappDataNode(dataHostEl, dataHostMap);
dataNodeList.addAll(dataNodeListItem);
}
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} finally {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return dataNodeList;
}
public static DataHost wrappDataHost(Element dataHostEl) {
DataHost dataHost = new DataHost();
dataHost.setName(dataHostEl.getAttribute("name"));
NodeList writeHostNode = dataHostEl.getElementsByTagName("writeHost");
if (writeHostNode.getLength() > 0) {
Element writeHostEl = (Element) writeHostNode.item(0);
dataHost.setWriteHostUrl(writeHostEl.getAttribute("url"));
dataHost.setUserName(writeHostEl.getAttribute("user"));
dataHost.setPassword(writeHostEl.getAttribute("password"));
NodeList readNodeList = writeHostEl.getElementsByTagName("readHost");
if (readNodeList.getLength() > 0) {
Element readHostEl = (Element) readNodeList.item(0);
dataHost.setReadHostUrl(readHostEl.getAttribute("url"));
}
}
return dataHost;
}
public static List wrappDataNode(Element dataNodeEl, Map dataHostMap) {
List dataNodeList = new ArrayList<>();
String nameM = dataNodeEl.getAttribute("name");
String databaseNameM = dataNodeEl.getAttribute("database");
String dataHost = dataNodeEl.getAttribute("dataHost");
if (nameM.equals("dndb0")) {
DataNode dataNode = new DataNode();
dataNode.setName(nameM);
dataNode.setDbName(databaseNameM);
dataNode.setDataHost(dataHostMap.get(dataHost));
dataNodeList.add(dataNode);
return dataNodeList;
}
String namePre = nameM.split("\$")[0];
String databaseNameMPre = databaseNameM.split("\$")[0];
String numScope = nameM.substring(nameM.indexOf("$") + 1);
String[] dbBanners = numScope.split("-");
int startN = Integer.valueOf(dbBanners[0]);
int endN = Integer.valueOf(dbBanners[1]);
for (int i = startN; i <= endN; i++) {
DataNode dataNode = new DataNode();
dataNode.setName(namePre + i);
dataNode.setDbName(databaseNameMPre + i);
dataNode.setDataHost(dataHostMap.get(dataHost));
dataNodeList.add(dataNode);
}
return dataNodeList;
}
5、定义导出的模板,在模板中定义数据源选择的规则init()方法,定义数据导出的规则,代码如下
package com.ds.tools.cmd;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.metadata.Sheet;
import com.ds.tools.datasource.DynamicDataSource;
import com.ds.tools.model.DBoffset;
import com.ds.tools.util.DateUtil;
import com.ds.tools.util.FileUtil;
import com.ds.tools.util.ZipUtil;
public abstract class ExportTemplate{
private final static Logger _log = LoggerFactory.getLogger(ExportTemplate.class);
//校验参数
private final static int MAX_ROW = 1000000;
Stack stack;
int DBType; //0:公共库,1:log1库;2:log2库
String fileNamePre;
Class entityClass;
public void init() {
stack = new Stack<>();
if (DBType == 0) {
stack.push(new DBoffset(DynamicDataSource.STANDALONE_DB));
} else if (DBType == 1) {
for (String logDb : DynamicDataSource.LOG1_DB_SET) {
stack.push(new DBoffset(logDb));
}
} else if (DBType == 2) {
for (String logDb : DynamicDataSource.LOG2_DB_SET) {
stack.push(new DBoffset(logDb));
}
} else {
for (String otherDb : DynamicDataSource.DB_SET) {
stack.push(new DBoffset(otherDb));
}
}
}
public abstract void setDBType();
public abstract void setFileNamePre();
public abstract void setEntityClass();
public abstract void validateArgs(String[] args);
public abstract List queryList(String[] args,int startOffset);
public void exprot(String[] args) {
validateArgs(args);
long startTime=System.currentTimeMillis();
setDBType();
setFileNamePre();
setEntityClass();
init();
List fileList = new ArrayList<>();
int fileCount = 1;
long rowCount = 0;
boolean needCreatFileFlag = true;
String fileName = null;
OutputStream out = null;
ExcelWriter writer = null;
Sheet sheet1 = null;
String dataDir= FileUtil.getDataDir();
String fileTime = DateUtil.getTime();
try {
while (!stack.empty()) {
DBoffset dBoffset = stack.pop();
if (needCreatFileFlag) {
fileName = fileNamePre + fileTime + "_" + fileCount + ".xlsx";
String filePath=dataDir+File.separator+fileName;
fileList.add(new File(filePath));
out = new FileOutputStream(filePath);
writer = EasyExcelFactory.getWriter(out);
sheet1 = new Sheet(1, 0, entityClass, "sheet1", null);
sheet1.setAutoWidth(Boolean.TRUE);
}
DynamicDataSource.setDataSource(dBoffset.getDbName());//动态选择数据源
_log.debug("当前数据源:{}", dBoffset.getDbName());
int startOffset = 0;
while (true) {
//单个sheet最大写入100万
if (rowCount > MAX_ROW) {
//关闭当前文件,重新压栈
writer.finish();
out.close();
fileCount++;
rowCount = 0;
needCreatFileFlag = true;
dBoffset.setOffset(startOffset);
stack.push(dBoffset);
break;
}
//重新压栈的需要跳步走
needCreatFileFlag = false;
if (dBoffset.getOffset() > 0&&rowCount==0) {
startOffset = dBoffset.getOffset();
}
List logList =queryList(args,startOffset);
writer.write(logList, sheet1);
rowCount = rowCount + logList.size();
if (logList.size() < 1000) {
break;
}
startOffset = startOffset + 1000;
_log.info(fileName + "已写行数:{}", rowCount);
}
}
writer.finish();
out.close();
//压缩文件
File file = new File(dataDir+File.separator+fileNamePre + fileTime + ".zip");
ZipUtil.zipFiles(fileList, file);
//删除源文件
for (File fileItem : fileList) {
fileItem.delete();
}
_log.info("导出结束!耗时:"+(System.currentTimeMillis()-startTime)/1000/60+"分钟");
} catch (Exception e) {
e.printStackTrace();
}
}
}
6、定义各个导出数据的入口,继承导出模板设置数据源类型,到这里为止,所有数据源动态切换的功能全部完成;代码如下:
package com.ds.tools.cmd;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.ds.tools.model.Log1;
import com.ds.tools.service.Log1Service;
import com.ds.tools.util.SpringContextUtil;
public class LogExportorTest1 extends ExportTemplate {
private final static Logger _log = LoggerFactory.getLogger(LogExportorTest1.class);
private Log1Service log1Service;
@Override
public void setDBType() {
this.DBType = 1;//设置类型
}
@Override
public void setFileNamePre() {
this.fileNamePre = "Log1导出";
}
@Override
public void setEntityClass() {
this.entityClass = Log1.class;
}
@Override
public void validateArgs(String[] args) {
//init spring 容器
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
log1Service = SpringContextUtil.getBean(Log1Service.class);
}
@Override
public List queryList(String[] args,int startOffset) {
Integer days=args.length==2?Integer.valueOf(args[1]):0;
List logList = log1Service.getLog1ByOffset(startOffset, 1000);
return logList;
}
}
7、使用main方法直接调用导出数据的入口,则会开启导出;代码如下:
public static void main(String[] args) {
System.out.println("开始导出Log1...");
LogExportorTest1 log1Exportor = new LogExportorTest1();
log1Exportor.exprot(null);//调用ExportTemplate的exprot方法执行导出
}



