javaspringmvc⽤线程池⾼效导出百万级csv数据,前端展现进度条
领导说公司的报表导出太慢还没有进度条展⽰,以前⽤的poi操作excel导出xls,从数据库查询数据,写⼊本地⽂件,然后读取本地⽂件下载效率低下,特别是数据量⼤的时候。所以我对后台cms系统导出做了优化,采⽤导出csv格式,这种格式下速度⽐xls快很多。
**csv和xls的区别**
经常会⽤户报表导出格式为csv和xls格式。他们的性能相差很⼤,我认为csv是⾮常⾼效的格式,⽽xls性能虽⽐csv差很多,但xls可以把格式做得很完美。现在我将两种不同格式做⼀些整理,希望对你们有点⽤。
xls ⽂件就是Microsoft excel电⼦表格的⽂件格式。我想就不⽤多介绍了吧,学校⾥多少都学过的。
CSV是最通⽤的⼀种⽂件格式,它可以⾮常容易地被导⼊各种PC表格及数据库中。此⽂件,⼀⾏即为数据表的⼀⾏。⽣成数据表字段⽤半⾓逗号隔开。
CSV是⽂本⽂件,⽤记事本就能打开,XLS是⼆进制的⽂件只有⽤EXCEL才能打
CSV(以逗号分隔)
CSV (*.csv) ⽂件格式只能保存活动⼯作表中的单元格所显⽰的⽂本和数值。⼯作表中所有的数据⾏和字符都将保存。数据列以逗号分隔,每⼀⾏数据都以回车符结束。如果单元格中包含逗号,则该单元格中的内容以双引号引起。
如果单元格显⽰的是公式⽽不是数值,该公式将转换为⽂本⽅式。所有格式、图形、对象和⼯作表的其他内容将全部丢失。欧元符号将转换为问号。
//⼯具类
import .*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
urrent.ThreadFactoryBuilder;
import com.StringUtil;
import com.sf.tuxiaoer.service.SfSQLBaseService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
//csv导出⼯具类
/**
功能描述 CSV下载⼯具类 实现Callable接⼝call()⽅法
@author hjli
@date 2019/7/13
@param
@return
*/
public class CsvDownload implements Callable {
private static final Logger logger = Logger(XlsDownload.class); private int index;
private int defaultNums;
private String sql_select;
private String[] columns;
private SfSQLBaseService sfSQLBaseService;
private CountDownLatch latch;
private HttpServletRequest request;
}
public CsvDownload (){
}
/**
功能描述
@author hjli
@date 2019/7/13
@param index,//数据查询分页下标
defaultNums, //默认⼀页的数量
sql_select, //sql查询语句
columns, //列名
sfSQLBaseService, //jdbctemplate
latch, //CountDownLatch计时器
request //HttpServletRequest 请求
@return
*/
public CsvDownload(int index,int defaultNums,String sql_select,
String[] columns,SfSQLBaseService sfSQLBaseService,
CountDownLatch latch,HttpServletRequest request){
this.index = index;
this.defaultNums = defaultNums;
this.sql_select = sql_select;
this.sfSQLBaseService = sfSQLBaseService;
this.latch = latch;
}
//返回csv后缀
private String getFileName(int rowSize) {
String dateString = ServerTime(“yyyyMMddHHmmss”);
String fileName = dateString + “_” + rowSize + “.csv”;
return fileName;
}
/**
* 功能描述 CSV下载
* @author hjli
* @date 2019/7/13
* @param request,
* response, //响应
* sfSQLBaseService, //jdbctemplate
* title,//表头名
* column, //列名
* sql_select, //sql查询语句
* sql_count //查询总数
* @return void
*/
public void csvDownLoad(HttpServletRequest request,
HttpServletResponse response,
SfSQLBaseService sfSQLBaseService,
String title, String column, String sql_select, String sql_count) throws InterruptedException {
String start_date = "";
String end_date = "";
//记录开始时间
start_date = ServerTime();
//⽤于存储数据
StringBuffer stringBuffer = new StringBuffer(1000);
String[] titles = StringUtil.split(title,",");
String[] columns = StringUtil.split(column,",");
//告诉前端下载选择类型导出类别 1:多线程、 2单线程
//得到数据总量
int rowSize = getSize(sfSQLBaseService, sql_count);
//根据数据总量分配线程
int defaultNums = 0;
jdbctemplate查询一条数据if(rowSize <= 3000){
defaultNums = 3000;
}else if(rowSize > 3000 && rowSize <= 10000){
defaultNums = 5000;
}else if(rowSize > 10000 && rowSize <= 50000){
defaultNums = 10000;
}else if(rowSize > 50000 && rowSize <= 100000){
defaultNums = 50000;
}else{
defaultNums = 100000;
}
//插⼊表头内容
for(int x = 0; x< titles.length; x++){
stringBuffer.append(titles[x]);
if(x < titles.length - 1){
if(x < titles.length - 1){
stringBuffer.append(",");
}
}
//换⾏
stringBuffer.append("\r\n");
//分成⼏页
int sheetNums = (int) getSheetNums(rowSize, defaultNums);
//数据存储起来⽤于前端展⽰进度条
//数据总量
//数据包总量
/
/⼿动创建线程池根据页数动态创建线程池
ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("thread-call-runner-%d").build();
ExecutorService es = new ThreadPoolExecutor(sheetNums,sheetNums,0L,TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>(),namedTh readFactory);
//动态创建计数器
CountDownLatch latch = new CountDownLatch(sheetNums);
//存储Future数据
List<Future> resultList = new ArrayList<>();
try {
for(int i=0;i<sheetNums;i++) {
/
/先睡⼀哈,保证查询顺序执⾏
Thread.sleep(108);
//这⾥调⽤call()返回string
Future<String> future = es.submit
(new XlsDownload(i, defaultNums, sql_select, columns, sfSQLBaseService,latch,request));
resultList.add(future);
}
//阻塞主进程,等待Count()为0时放⾏
latch.await();
}catch (Exception e){
e.printStackTrace();
}finally {
es.shutdownNow();//关闭线程池
//释放session资源
for(int i=0;i<sheetNums;i++){
}
}
//读取stringBuffer内容追加到主stringBuffer
for(int x=0;x<resultList.size();x++){
Future future = (x);
try {
try {
stringBuffer.());
} catch (ExecutionException e) {
e.printStackTrace();
}
}
logger.info("数据绑定成功,开始下载");
logger.info("每页共有" + defaultNums);
logger.info("共有" + sheetNums + "页");
OutputStream out = null;
response.addHeader("Content-Disposition", "attachment;filename=" + getFileName(rowSize)); response.addHeader("Content-Type","application/octet-stream;charset=UTF-8");
logger.info("下载结束");
end_date = ServerTime();
logger.info("start:"+start_date+">>end:"+end_date);
try {
//页⾯响应
out = OutputStream();
out.String().getBytes("UTF-8"));
}catch (Exception e){
e.printStackTrace();
}finally {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public String call() throws Exception {
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论