JAva springmvcスレッドプールで百万級csvデータを効率的にエクスポートし、フロントエンドに進捗バーを表示
13997 ワード
リーダーは、会社のレポートのエクスポートが遅すぎてまだ進捗バーが表示されていないと言っています.以前使っていたpoi操作excelでxlsをエクスポートし、データベースからデータを照会し、ローカルファイルに書き込み、ローカルファイルのダウンロード効率が低下し、特にデータ量が大きい場合です.だから私はバックグラウンドcmsシステムのエクスポートを最適化して、csvフォーマットをエクスポートして、このフォーマットの下で速度はxlsよりずっと速いです.
//ツールクラスimport java.io.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.google.common.util.concurrent.ThreadFactoryBuilder; import com.sf.utils.core.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 = LoggerFactory.getLogger(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//HttpServeretRequestリクエスト @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.columns = columns; this.sfSQLBaseService = sfSQLBaseService; this.latch = latch; this.request = request; }
//csv接尾辞private String getFileName(int rowSize){String dateString=DateTimeUtils.getServer Time("yyyyyyMMddHHmmss");String file Name=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(HttpServertRequest request,HttpServertResponse response,SfSQLbaseServicesfSQLbaseServices,String title,String column,String sql_select,String sql_count)throws InterruptedException{
@Override public String call() throws Exception {
前にセッションで多くのデータが格納されています.主にフロントエンドページの進捗バーの表示に使用されます.ここでは進捗バーのリスニングのcontrollerを作成する必要があります.
//controller import com.sf.tuxiaoer.web.BaseController; import net.sf.json.JSONArray; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import javax.servlet.http.HttpServletResponse; import java.io.PrintWriter; import java.text.DecimalFormat; import java.util.HashMap; import java.util.Map;
//フロントエンドjsページ展示、パブリックjspページに書くことで、すべてのページで進捗バー//CSSを呼び出すことができます
**csv xls **
csv xls 。 , csv , xls csv , xls 。 , 。
xls Microsoft excel 。 , 。
CSV , PC 。 , 。 。
CSV , ,XLS EXCEL
CSV( )
CSV (*.csv) 。 。 , 。 , 。
, 。 、 、 。 。
//ツールクラスimport java.io.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.google.common.util.concurrent.ThreadFactoryBuilder; import com.sf.utils.core.StringUtil; import com.sf.tuxiaoer.service.SfSQLBaseService; import org.slf4j.Logger; import org.slf4j.LoggerFactory;//csvエクスポートツールクラス/**
//csv接尾辞private String getFileName(int rowSize){String dateString=DateTimeUtils.getServer Time("yyyyyyMMddHHmmss");String file Name=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(HttpServertRequest request,HttpServertResponse response,SfSQLbaseServicesfSQLbaseServices,String title,String column,String sql_select,String sql_count)throws InterruptedException{
String start_date = "";
String end_date = "";
//
start_date = DateTimeUtils.getServerTime();
//
StringBuffer stringBuffer = new StringBuffer(1000);
String[] titles = StringUtil.split(title,",");
String[] columns = StringUtil.split(column,",");
// 1: 、 2
request.getSession().setAttribute("downloadType", 1);
//
int rowSize = getSize(sfSQLBaseService, sql_count);
//
int defaultNums = 0;
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){
stringBuffer.append(",");
}
}
//
stringBuffer.append("\r
");
//
int sheetNums = (int) getSheetNums(rowSize, defaultNums);
//
//
request.getSession().setAttribute("total_data",rowSize);
//
request.getSession().setAttribute("total_packet",sheetNums);
//
ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("thread-call-runner-%d").build();
ExecutorService es = new ThreadPoolExecutor(sheetNums,sheetNums,0L,TimeUnit.MILLISECONDS,new LinkedBlockingQueue(),namedThreadFactory);
//
CountDownLatch latch = new CountDownLatch(sheetNums);
// Future
List resultList = new ArrayList<>();
try {
for(int i=0;i future = es.submit
(new XlsDownload(i, defaultNums, sql_select, columns, sfSQLBaseService,latch,request));
resultList.add(future);
}
// , latch.getCount() 0
latch.await();
}catch (Exception e){
e.printStackTrace();
}finally {
es.shutdownNow();//
// session
request.getSession().setAttribute("progress_flag",false);
request.getSession().removeAttribute("total_data");
request.getSession().removeAttribute("total_packet");
for(int i=0;i>end:"+end_date);
try {
//
out = response.getOutputStream();
out.write(stringBuffer.toString().getBytes("UTF-8"));
}catch (Exception e){
e.printStackTrace();
}finally {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override public String call() throws Exception {
String tmpSelect = sql_select + " LIMIT " + index * defaultNums + ", " + defaultNums;
List dataList = sfSQLBaseService.queryForList(tmpSelect);
String _status = "";
StringBuffer sb = new StringBuffer();
for(int i=0;i
";
request.getSession().setAttribute("thread_"+index,_status);
}
sb.append("\r
");
request.getSession().setAttribute("size_"+index,(i+1));
request.getSession().setAttribute("count_"+index,index);
request.getSession().setAttribute("packet_"+index,index);
}
logger.info(" :{} , ID:{}",index,Thread.currentThread().getName());
latch.countDown();// countDown
return sb.toString();
}
前にセッションで多くのデータが格納されています.主にフロントエンドページの進捗バーの表示に使用されます.ここでは進捗バーのリスニングのcontrollerを作成する必要があります.
//controller import com.sf.tuxiaoer.web.BaseController; import net.sf.json.JSONArray; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import javax.servlet.http.HttpServletResponse; import java.io.PrintWriter; import java.text.DecimalFormat; import java.util.HashMap; import java.util.Map;
/**
*
* @author hjli
* @date 2019/7/13
* @param
* @return
*/
@Controller
public class ProgressBar extends BaseController {
private DecimalFormat df = new DecimalFormat("0.00");
/**
*
* @author hjli
* @date 2019/7/13
* @param response
* @return void
*/
@RequestMapping("/wash/progress/progressBarStatu")
public void progressBarStatu(HttpServletResponse response){
Map dataMap = new HashMap();
try {
boolean progress_flag = (boolean)request.getSession().getAttribute("progress_flag");
//
boolean showFlag = false;
//
if(progress_flag == true){
// 1: 、 2
int downloadType = request.getSession().getAttribute("downloadType") != null ? (int)request.getSession().getAttribute("downloadType") : 9;
//
if(downloadType == 1){
int total_data =request.getSession().getAttribute("total_data") != null ? (int)request.getSession().getAttribute("total_data") : 0;
int total_packet = request.getSession().getAttribute("total_packet") != null ? (int)request.getSession().getAttribute("total_packet") : 0;
//
dataMap.put("total_packet",total_packet);
//
dataMap.put("total_data",total_data);
//
if(total_packet > 0){
int _count = 0;
int _size = 0;
StringBuffer stringBuffer = new StringBuffer();
for(int i=0;i 0){
//
showFlag = true;
//
String status = (String)request.getSession().getAttribute("status");
dataMap.put("status",status);
dataMap.put("total_size",total_size);
//
float progress = (float)size * 100 / total_size;
dataMap.put("progress",df.format(progress)+"%");
}
}
// 1: 、 2
dataMap.put("downloadType",downloadType);
}
// true false
dataMap.put("showFlag",showFlag);
// true false
dataMap.put("progress_flag",progress_flag);
PrintWriter out = response.getWriter();
out.print(JSONArray.fromObject(dataMap).toString());
out.close();
}catch (Exception e){e.printStackTrace();}
}
//フロントエンドjsページ展示、パブリックjspページに書くことで、すべてのページで進捗バー//CSSを呼び出すことができます
.mydiv {
-moz-border-radius: 16px;
-webkit-border-radius: 16px;
border-radius: 16px;
background-color:lavender;
text-align: center;
z-index:99;
width:38%;
height: auto;
left:38%;/*FF IE7*/
top: 8%;/*FF IE7*/
margin-left:-130px!important;/*FF IE7 */
margin-top:-20px!important;/*FF IE7 */
margin-top:0px;
position:fixed!important;/*FF IE7*/
position:absolute;/*IE6*/
}
.bbg {
background-color: #878b80;
width: 100%;
height: 100%;
left:0;
top:0;/*FF IE7*/
filter:alpha(opacity=50);/*IE*/
opacity:0.5;/*FF*/
z-index:1;
position:fixed!important;/*FF IE7*/
position:absolute;/*IE6*/
}
//html
" +
" :"+time+"s
" ;
if(objs[0].showFlag == true){
// 1: 、 2
if(objs[0].downloadType == 1){
msg += " :"+objs[0].total_data+"
" +
" :"+objs[0]._count+" / "+objs[0].total_packet+"
" ;
msg += ""+objs[0].stringBuffer+"
" +
" :"+objs[0].progress+"";
}else if(objs[0].downloadType == 2){
msg += ""+objs[0].status+"
" +
" :"+objs[0].progress+"" ;
}
$("#progress_bar").html(msg);
}
}else{
time = 0;
//window.clearInterval(task);
$("#progress_bar").html(" , ...");
$("#bbg").css({display:'none'});
$("#bpopDiv").css({display:'none'});
}
}
});
},interval_time);
//js
var interval_time = 1000;
var time = 0;
//
var task = window.setInterval(function(){
time++;
$.ajax({
url:'wash/progress/progressBarStatu',
type:'post',
success:function(data){
var objs = jQuery.parseJSON(data);
if(objs[0].progress_flag == true){
$("#bbg").css({display:'block'});
$("#bpopDiv").css({display:'block'});
var msg = " , ......