Time out問題可以和提供接口方商討,按照分頁的方式即可解決。
我們重點(diǎn)關(guān)注一下OM的問題吧。這里有幾種解決方案:
1.用POI或JXL
POI是apache公司的一個子項(xiàng)目,主要提供一組windows文檔的Java API;
JXL是Java Excel的簡稱,一個開放源碼的項(xiàng)目,通過它Java開發(fā)人員可以操作Excel 文件的內(nèi)容,可能它更專注些,比如名字就叫做java(不包含其他編程語言)的excel(不處理windows的其他文件),所以大數(shù)據(jù)量稍大時(shí)效率以及在消耗內(nèi)存方面,略勝前者一籌,這里我就不再贅述兩者之間的差別了,在網(wǎng)絡(luò)上大家可以搜索到一大籮筐關(guān)于此信息。
大數(shù)據(jù)應(yīng)用量
POI/JXL
加載時(shí)間(ms)
總耗時(shí)(ms)
1千條:746K
POI
499
515
JXL
203
359
1萬條:7.3M
POI
1716
1731
JXL
390
1108
5萬條:36.8M
POI
7878
7925
JXL
2309
5711
我們來說說稍微好些的插件JXL的處理方式,JXL是將每個單元格生成一個Cell對象,每一個對象都要消耗一定的內(nèi)存空間,每個對象的大小不同,也會影響內(nèi)存的使用,所以很容易導(dǎo)致內(nèi)存溢出。
2.用數(shù)據(jù)流的方法
從消耗內(nèi)存的原因出發(fā),既然上述表現(xiàn)較好的JXL由于生成大量的對象導(dǎo)致,我們就采用避免java創(chuàng)建太多的對象,就不用jxl了。用數(shù)據(jù)流的方法解決。
可以直接寫txt文本文件,可以用”/t”來分割內(nèi)容的話,用戶就可以直接把txt生成的內(nèi) 容直接復(fù)制到excel中去。
也可以用流的方式寫成.csv格式,寫入方式和寫txt文件類似,可以用流的方式追加,只要在每列之間以固定標(biāo)示符進(jìn)行間隔,不存在內(nèi)存和格式問題。這種格式可以讓用戶直接以exl方式打開,而不用復(fù)制進(jìn)去了。
3.HTML方式
其實(shí)我們就是用頁面元素的屬性設(shè)置,來達(dá)到和xls相互轉(zhuǎn)換,所以可以先寫HTML,這樣內(nèi)存不會溢出,寫好后,用xls方式打開即可。
不妨你可以試一試,打開一個xls,選擇另存為網(wǎng)頁,可以查看下這個經(jīng)過轉(zhuǎn)換后的html的源碼,直接把這個HTML文件后綴改為xls,打開后效果和剛剛的那個xls一樣。
這種方式正是我們現(xiàn)在項(xiàng)目所采用的方式,但我們采用的是jsp默認(rèn)的輸出數(shù)據(jù)到頁面,并沒有通過java的io程序來實(shí)時(shí)控制,當(dāng)數(shù)據(jù)量比較大的時(shí)候,進(jìn)行適當(dāng)?shù)膄lush。所以目前的項(xiàng)目中這種方式,也存在著潛在的OM的可能。
實(shí)踐驗(yàn)證:
數(shù)據(jù)流方式csv生成:
public class CSVUtils {
/**
* 導(dǎo)出為CVS文件
* @param exportData
*/
public static File createCSVFile(List exportData, LinkedHashMap rowMapper, String outPutPath) {
File csvFile = null;
BufferedWriter csvFileOutputStream = null;
try {
csvFile = File.createTempFile("temp", ".csv", new File(outPutPath));
// GB2312使正確讀取分隔符","
csvFileOutputStream = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(csvFile), "GB2312"),
1024);
// 寫入文件頭部
for (Iterator propertyIterator = rowMapper.entrySet().iterator(); propertyIterator.hasNext();) {
java.util.Map.Entry propertyEntry = (java.util.Map.Entry) propertyIterator.next();
csvFileOutputStream.write("/"" + propertyEntry.getValue().toString() + "/"");
if (propertyIterator.hasNext()) {
csvFileOutputStream.write(",");
}
}
csvFileOutputStream.newLine();
// 寫入文件內(nèi)容
for (Iterator iterator = exportData.iterator(); iterator.hasNext();) {
Object row = (Object) iterator.next();
for (Iterator propertyIterator = rowMapper.entrySet().iterator(); propertyIterator.hasNext();) {
java.util.Map.Entry propertyEntry = (java.util.Map.Entry) propertyIterator.next();
csvFileOutputStream.write("/""
+ BeanUtils.getProperty(row, propertyEntry.getKey().toString()).toString() + "/"");
if (propertyIterator.hasNext()) {
csvFileOutputStream.write(",");
}
}
if (iterator.hasNext()) {
csvFileOutputStream.newLine();
}
}
csvFileOutputStream.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
csvFileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return csvFile;
}
}
用html方式:
/**
*html方式導(dǎo)出數(shù)據(jù)
*
*這個格式怎樣得到呢?方法是這樣:
*你先建一個excel文件,如a.xls。填上兩條偽數(shù)據(jù)。然后另存為網(wǎng)頁,即htm格式,如a.htm。
*然后,用記事本打開htm格式的a.htm,這樣excel文件格式代碼就暴露在你面前。
*剩下的事,就是把a(bǔ).htm源代碼的偽數(shù)據(jù)部分,替成數(shù)據(jù)庫里的數(shù)據(jù),然后把替換后的整個a.htm源代碼,用java的io寫成一個后綴為xls的文件。就打完收工了。
*
*注意:
*為了不給內(nèi)存增加壓力,要把a(bǔ).htm源代碼分成三部分:頭(偽數(shù)據(jù)部分 前的代碼) + 偽數(shù)據(jù)部分 + 尾(偽數(shù)據(jù)部分 后的代碼)。
*先把 頭 寫到文件,并flush。
*然后是 偽數(shù)據(jù)部分 ,替一條數(shù)據(jù)庫里的記錄就寫到文件里,并flush。
*最后把 尾 寫到文件,并flush。
*/
public class htmlAndExcel {
public static void exportToExcel(OutputStream out) throws Exception{
String str = "<html xmlns:o='urn:schemas-microsoft-com:office:office'"+
"xmlns:x='urn:schemas-microsoft-com:office:excel'"+
"xmlns='http://www.w3.org/TR/REC-html40'>"+
"<head>"+
"<meta http-equiv=Content-Type content='text/html; charset=gb2312'>"+
"<meta name=ProgId content=Excel.Sheet>"+
"<meta name=Generator content='Microsoft Excel 11'>"+
"<link rel=File-List href='1111.files/filelist.xml'>"+
"<link rel=Edit-Time-Data href='1111.files/editdata.mso'>"+
"<link rel=OLE-Object-Data href='1111.files/oledata.mso'>"+
"<!--[if gte mso 9]><xml>"+
"<o:DocumentProperties>"+
"<o:Created>1996-12-17T01:32:42Z</o:Created>"+
"<o:LastSaved>2010-03-17T06:50:36Z</o:LastSaved>"+
"<o:Version>11.5606</o:Version>"+
"</o:DocumentProperties>"+
"<o:OfficeDocumentSettings>"+
"<o:RemovePersonalInformation/>"+
"</o:OfficeDocumentSettings>"+
"</xml><![endif]-->"+
"<style>"+
"<!--table"+
"{mso-displayed-decimal-separator:'//.';"+
"so-displayed-thousand-separator:'//,';}"+
"@page"+
"{margin:1.0in .75in 1.0in .75in;"+
"mso-header-margin:.5in;"+
"mso-footer-margin:.5in;}"+
"tr"+
"{mso-height-source:auto;"+
"mso-ruby-visibility:none;}"+
"col"+
"{mso-width-source:auto;"+
"mso-ruby-visibility:none;}"+
"br"+
"{mso-data-placement:same-cell;}"+
".style0"+
"{mso-number-format:General;"+
"text-align:general;"+
"vertical-align:bottom;"+
";"+
"mso-rotate:0;"+
"mso-background-source:auto;"+
"mso-pattern:auto;"+
"color:windowtext;"+
"font-size:12.0pt;"+
"font-weight:400;"+
"font-style:normal;"+
"text-decoration:none;"+
"font-family:宋體;"+
"mso-generic-font-family:auto;"+
"mso-font-charset:134;"+
"border:none;"+
"mso-protection:locked visible;"+
"mso-style-name:常規(guī);"+
"mso-style-id:0;}"+
"td"+
"{mso-style-parent:style0;"+
"padding-top:1px;"+
"padding-right:1px;"+
"padding-left:1px;"+
"mso-ignore:padding;"+
"color:windowtext;"+
"font-size:12.0pt;"+
"font-weight:400;"+
"font-style:normal;"+
"text-decoration:none;"+
"font-family:宋體;"+
"mso-generic-font-family:auto;"+
"mso-font-charset:134;"+
"mso-number-format:General;"+
"text-align:general;"+
"vertical-align:bottom;"+
"border:none;"+
"mso-background-source:auto;"+
"mso-pattern:auto;"+
"mso-protection:locked visible;"+
";"+
"mso-rotate:0;}"+
"ruby"+
"{ruby-align:left;}"+
"rt"+
"{color:windowtext;"+
"font-size:9.0pt;"+
"font-weight:400;"+
"font-style:normal;"+
"text-decoration:none;"+
"font-family:宋體;"+
"mso-generic-font-family:auto;"+
"mso-font-charset:134;"+
"mso-char-type:none;"+
"display:none;}"+
"-->"+
"</style>"+
"<!--[if gte mso 9]><xml>"+
"<x:ExcelWorkbook>"+
"<x:ExcelWorksheets>"+
"<x:ExcelWorksheet>"+
"<x:Name>Sheet1</x:Name>"+
"<x:WorksheetOptions>"+
"<x:DefaultRowHeight>285</x:DefaultRowHeight>"+
"<x:CodeName>Sheet1</x:CodeName>"+
"<x:Selected/>"+
"<x:Panes>"+
"<x:Pane>"+
"<x:Number>3</x:Number>"+
"<x:ActiveRow>4</x:ActiveRow>"+
"<x:ActiveCol>4</x:ActiveCol>"+
"</x:Pane>"+
"</x:Panes>"+
"<x:ProtectContents>False</x:ProtectContents>"+
"<x:ProtectObjects>False</x:ProtectObjects>"+
"<x:ProtectScenarios>False</x:ProtectScenarios>"+
"</x:WorksheetOptions>"+
"</x:ExcelWorksheet>"+
"<x:ExcelWorksheet>"+
"<x:Name>Sheet2</x:Name>"+
"<x:WorksheetOptions>"+
"<x:DefaultRowHeight>285</x:DefaultRowHeight>"+
"<x:CodeName>Sheet2</x:CodeName>"+
"<x:ProtectContents>False</x:ProtectContents>"+
"<x:ProtectObjects>False</x:ProtectObjects>"+
"<x:ProtectScenarios>False</x:ProtectScenarios>"+
"</x:WorksheetOptions>"+
"</x:ExcelWorksheet>"+
"<x:ExcelWorksheet>"+
"<x:Name>Sheet3</x:Name>"+
"<x:WorksheetOptions>"+
"<x:DefaultRowHeight>285</x:DefaultRowHeight>"+
"<x:CodeName>Sheet3</x:CodeName>"+
"<x:ProtectContents>False</x:ProtectContents>"+
"<x:ProtectObjects>False</x:ProtectObjects>"+
"<x:ProtectScenarios>False</x:ProtectScenarios>"+
"</x:WorksheetOptions>"+
"</x:ExcelWorksheet>"+
"</x:ExcelWorksheets>"+
"<x:WindowHeight>4530</x:WindowHeight>"+
"<x:WindowWidth>8505</x:WindowWidth>"+
"<x:WindowTopX>480</x:WindowTopX>"+
"<x:WindowTopY>120</x:WindowTopY>"+
"<x:AcceptLabelsInFormulas/>"+
"<x:ProtectStructure>False</x:ProtectStructure>"+
"<x:ProtectWindows>False</x:ProtectWindows>"+
"</x:ExcelWorkbook>"+
"</xml><![endif]-->"+
"</head>"+
"<body link=blue vlink=purple>";
str += "<table x:str border=0 cellpadding=0 cellspacing=0 width=144 style='border-collapse:collapse;table-layout:fixed;width:108pt'>"+
"<col width=72 span=2 style='width:54pt'>";
int count = 1000;
while (count>0) {
str += "<tr height=19 style='height:14.25pt'>"+
"<td height=19 align=right width=72 style='height:14.25pt;width:54pt' x:num>"+count+"</td>"+
"<td width=72 style='width:54pt'>"+"僅僅為了測試,^_^"+"</td>"+
"</tr>";
count--;
}
str += "<![endif]>"+
"</table>"+
"</body>"+
"</html";
System.out.println(str);
out.write(str.getBytes());
out.close();
}
}
結(jié)論:
綜合上述幾種分析,由于項(xiàng)目的特點(diǎn),暫時(shí)采用讀取內(nèi)容到csv文件中,用戶可以用xls方式打開。2003版本的excel單sheet是只能65535行,
我們在程序中判斷,當(dāng)達(dá)到10000條數(shù)據(jù)時(shí),就要new sheet