一、問題描述
???
該問題出現(xiàn)是因?yàn)樵趯?dǎo)出文件之后
用戶下載的是
.csv
文件,如果用文本編輯器打開可以查看所有記錄,但是如果用
excel
打開就出現(xiàn)一個(gè)
sheet
最多
6
萬條的記錄。因此就不可以使用保存為
csv
文件來實(shí)現(xiàn)
excel
文件的下載,需要使用新的方式去實(shí)現(xiàn)。
???
如果使用
jxl
開發(fā)包在
web
后臺(tái)去創(chuàng)建
Excel
文件,如果數(shù)據(jù)量比較大,則用戶需要等待很長(zhǎng)很長(zhǎng)的時(shí)間才可以下載到,因?yàn)?/span>
jxl
的對(duì)于
excel
文件的操作都是對(duì)象級(jí)的
,
文件中每一個(gè)格子都是一個(gè)
cell
對(duì)象,需要后臺(tái)去
new
。所以還需要考慮別的方式。
???
二、實(shí)現(xiàn)靈感
??? Excel
文件打開之后選擇另存為可以保存為
XML
類型文件,因此就考慮構(gòu)造符合
Excel
可以打開的
XML
類型文件,并且對(duì)該
XML
文件進(jìn)行最簡(jiǎn)單化處理,去除
Excel
文件中的每個(gè)
cell
的
style
定義、
XML
文件頭部的多余信息,最后整理出一個(gè)符合資訊平臺(tái)所下載的
Excel
文件的格式
,
請(qǐng)看下面:
<!—XML
文件頭部
--//>
<?xml version="1.0"?>
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
?xmlns:o="urn:schemas-microsoft-com:office:office"
?xmlns:x="urn:schemas-microsoft-com:office:excel"
?xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
?xmlns:html="http://www.w3.org/TR/REC-html40">
<!—Excel
文件第一個(gè)
SHEET --//>
<Worksheet ss:Name="sheet0">
<Table>
<Row>
<Cell><Data ss:Type="String">aa0</Data></Cell>
<Cell><Data ss:Type="String">aa1</Data></Cell>
<Cell><Data ss:Type="String">aa2</Data></Cell>
</Row>
<Row>
<Cell><Data ss:Type="String">aa0</Data></Cell>
<Cell><Data ss:Type="String">aa1</Data></Cell>
<Cell><Data ss:Type="String">aa2</Data></Cell>
</Row>
</Table>
</Worksheet>
<!—Excel
文件第二個(gè)
SHEET --//>
<Worksheet ss:Name="sheet1">
<Table>
??? <!—
一行數(shù)據(jù)
--//>
<Row>
<Cell><Data ss:Type="String">aa0</Data></Cell>
<Cell><Data ss:Type="String">aa1</Data></Cell>
<Cell><Data ss:Type="String">aa2</Data></Cell>
</Row>
<Row>
<Cell><Data ss:Type="String">aa0</Data></Cell>
<Cell><Data ss:Type="String">aa1</Data></Cell>
<Cell><Data ss:Type="String">aa2</Data></Cell>
</Row>
</Table>
</Worksheet>
</Workbook>
<!-- XML
文件結(jié)束
--//>
|
注釋:
a
、
<Worksheet ss:Name="sheet0">?
引號(hào)內(nèi)部的是該
sheet
的名稱。
b
、
<Data ss:Type="String">aa1</Data> ?ss:Type
的值是用來定義該
cell
格數(shù)據(jù)的類型,例如可以為
Number,
表是該
cell
格數(shù)據(jù)是數(shù)字。
三、實(shí)現(xiàn)方式
???
通過第一步的分析可以發(fā)現(xiàn)只要我們構(gòu)建這樣格式的
XML
數(shù)據(jù),就可以通過
Excel
打開,并且可以實(shí)現(xiàn)分
sheet
的樣式。但是數(shù)據(jù)下載到用戶本地是
XML
類型的話,那是沒什么意義的,就算打開方式選擇使用
Excel
可以打開,因此如何將用戶下載的文件類型改為
XLS
呢?這里就可以通過在下載的
servlet
中設(shè)置
response.setContentType("application/vnd.ms-excel")
來實(shí)現(xiàn)。
package com.hoten.util.xmlxls;
import java.util.ArrayList;
?private final static String XML_HEARDER = "<?xml version=\"1.0\"?>";
?
?private List sheetList = new ArrayList(); //存放每行多個(gè)sheet的list
?
?/**
? * 取得workbook的xml文件的頭部字符串
? * @return
? */
?private String getHeader(){??
??return XML_HEARDER +
??? "<Workbook xmlns=\"urn:schemas-microsoft-com:office:spreadsheet\"" + Contants.SEP_N +
??? " xmlns:o=\"urn:schemas-microsoft-com:office:office\"" + Contants.SEP_N +
??? " xmlns:x=\"urn:schemas-microsoft-com:office:excel\"" +? Contants.SEP_N +
??? " xmlns:ss=\"urn:schemas-microsoft-com:office:spreadsheet\"" + Contants.SEP_N +
??? " xmlns:html=\"http://www.w3.org/TR/REC-html40\">" + Contants.SEP_N ;
?}?
?
?private String getFoot(){
??return "</Workbook>";
?}
?
?public String toString(){
??StringBuffer strBuff = new StringBuffer();
??
??strBuff.append(getHeader());
??
??int len = sheetList.size();
??for(int i=0;i<len;i++){
???WorkSheet sheet = (WorkSheet)sheetList.remove(0);
???strBuff.append(sheet.toString());
???sheet = null;
??}??
??sheetList.clear();
??
??strBuff.append(getFoot());
??
??return strBuff.toString();
?}
?
?public void addSheet(WorkSheet sheet){
??sheetList.add(sheet);
?}
?
?public void removeSheet(int i){
??sheetList.remove(i);
?}??
}
package com.hoten.util.xmlxls;
import java.util.ArrayList;
?
?private String name = ""; //該sheet的name
?
?private List rowList = new ArrayList(); //存放每行多個(gè)row的list
?
?public String toString(){
??StringBuffer strBuff = new StringBuffer();
??
??strBuff.append("<Worksheet ss:Name=\"" + name + "\">").append(Contants.SEP_N);
??strBuff.append("<Table>").append(Contants.SEP_N);
??
??int len = rowList.size();
??for(int i=0;i<len;i++){
???TableRow row = (TableRow)rowList.remove(0);
???strBuff.append(row.toString());
???row = null;
??}??
??rowList.clear();
??
??strBuff.append("</Table>").append(Contants.SEP_N);
??strBuff.append("</Worksheet>").append(Contants.SEP_N);
??
??return strBuff.toString();
?}
?
?public void addRow(TableRow row){
??rowList.add(row);
?}
?
?public void removeRow(int i){
??rowList.remove(i);
?}
??return name;
?}
??this.name = name;
?}?
}
package com.hoten.util.xmlxls;
import java.util.ArrayList;
?
?
?public String toString(){
??StringBuffer strBuff = new StringBuffer();
??
??strBuff.append("<Row>").append(Contants.SEP_N);
??int len = cellList.size();
??for(int i=0;i<len;i++){
???TableCell cell = (TableCell)cellList.remove(0);
???strBuff.append(cell.toString()).append(Contants.SEP_N);
???cell = null;???
??}
??cellList.clear();
??
??strBuff.append("</Row>").append(Contants.SEP_N);
??
??return strBuff.toString();
?}?
?
?public void addCell(TableCell cell){
??cellList.add(cell);
?}
?
?public void removeCell(int i){
??cellList.remove(i);
?}
?
}
package com.hoten.util.xmlxls;
?private String index = ""; //cell在每行顯示的索引位置,可以不填
?
?private CellData data = new CellData(); //cell的數(shù)據(jù)對(duì)象
??return data;
?}
??this.data = data;
?}
??return index;
?}
??this.index = index;
?}
?
?
?public String toString(){
??return "<Cell>" + data.toString() + "</Cell>";
?}
?
}
package com.hoten.util.xmlxls;
?private String type = "String"; //cell數(shù)據(jù)類型
?private String value = ""; //cell數(shù)據(jù)
?
?public String getType() {
??return type;
?}
?public void setType(String type) {
??this.type = type;
?}
?public String getValue() {
??return value;
?}
?public void setValue(String value) {
??this.value = value;
?}
?
?
?public String toString(){
??return "<Data ss:Type=\"" + type + "\">" + value + "</Data>";
?}
}
package com.hoten.util.xmlxls;
?public final static String SEP_N = "\n";
?/**
? * XML中常量定義
? */
?public final static String SS_NAME = "ss:Name";
?public final static String SS_INDEX = "ss:Index";
?public final static String SS_TYPE = "ss:Type";
測(cè)試的方法:
PrintWriter out = response.getWriter();
???????? // 設(shè)置響應(yīng)頭和下載保存的文件名
???????? response.setContentType("application/vnd.ms-excel");
???????? response.setHeader("Content-Disposition","attachment; filename=\""+Chinese.toPage(fileNametemp)+"\"");
????????
???????? String rows_temp = request.getParameter("rows");//頁(yè)面?zhèn)鬟^來的每個(gè)SHEET可以存放的條數(shù)
???if (rows_temp == null){
????rows_temp = "20000";
???}
???int count_rows = Integer.parseInt(rows_temp);//一個(gè)SHEET有多行
????????
???????? WorkBook book = new WorkBook();
???????? Vector v_Rs = RsToVector.ResultSetToVector(rs);// 把RS的值轉(zhuǎn)換成VECTOR,這個(gè)可以看我上一版本,上面有詳細(xì)的寫法
?????????
???????? if (v_Rs != null) {
????int a = v_Rs.size();????
????int sheet_count = a / count_rows;// 30000行一個(gè)sheet。
????
????if (sheet_count >0){//大于0,則需要多個(gè)SHEET
?????for (int i = 0;i<sheet_count;i++){
??????WorkSheet sheet = new WorkSheet();//創(chuàng)建一個(gè)新的SHEET
??????sheet.setName("sheet" + i);//設(shè)置SHEET的名稱
???????????
??????for (int b = i* count_rows ;b<(i+1) * count_rows ;b++){???????
???????//temp_v.add(v_Rs.get(b));
???????Vector temp_v = new Vector();
???????temp_v =(Vector) v_Rs.get(b);???????
???????//取出一個(gè)對(duì)象,把對(duì)象的值放到EXCEL里
???????TableRow row = new TableRow();//設(shè)置行?
???????for(int m=0;m<numColumns;m++){
?????????? ???TableCell cell = new TableCell();
?????????? ???CellData data = new CellData();
?????????? ???data.setValue((String)temp_v.get(m));
?????????? ???cell.setData(data);?????????? ???
?????????? ???row.addCell(cell);
?????????? ??}?????????? ??
?????????? ??sheet.addRow(row);
??????}?
??????book.addSheet(sheet);
?????}
?????//還有剩余的數(shù)據(jù)
?????if (sheet_count * count_rows < a){
??????WorkSheet sheet = new WorkSheet();//創(chuàng)建一個(gè)新的SHEET
??????sheet.setName("sheet" + sheet_count);//設(shè)置SHEET的名稱
???????
??????for (int c = sheet_count* count_rows ;c<a ;c++){???????
???????Vector temp_vv = new Vector();
???????temp_vv =(Vector) v_Rs.get(c);
???????//取出一個(gè)對(duì)象,把對(duì)象的值放到EXCEL里
???????TableRow row = new TableRow();//設(shè)置行
???????for(int m=0;m<numColumns;m++){
?????????? ???TableCell cell = new TableCell();
?????????? ???CellData data = new CellData();
?????????? ???data.setValue((String)temp_vv.get(m));
?????????? ???cell.setData(data);?????????? ???
?????????? ???row.addCell(cell);
?????????? ??}?????????? ??
?????????? ??sheet.addRow(row);???????
??????}
??????book.addSheet(sheet);???????
?????}
????}else{
?????
?????
??????WorkSheet sheet = new WorkSheet();//創(chuàng)建一個(gè)新的SHEET
??????sheet.setName("sheet1");//設(shè)置SHEET的名稱
???????????
??????for (int bb=0? ;bb<a ;bb++){???????
???????//temp_v.add(v_Rs.get(b));
???????Vector temp_v = new Vector();
???????temp_v =(Vector) v_Rs.get(bb);???????
???????//取出一個(gè)對(duì)象,把對(duì)象的值放到EXCEL里
???????TableRow row = new TableRow();//設(shè)置行?
???????for(int m=0;m<numColumns;m++){
?????????? ???TableCell cell = new TableCell();
?????????? ???CellData data = new CellData();
?????????? ???data.setValue((String)temp_v.get(m));
?????????? ???cell.setData(data);?????????? ???
?????????? ???row.addCell(cell);
?????????? ??}?????????? ??
?????????? ??sheet.addRow(row);
??????}?
??????book.addSheet(sheet);
????}
????????
????out.print(book.toString());
???}
??? 以上拼XML的時(shí)候重復(fù)代碼比較多,可以寫一個(gè)公用的方法,,我為了把XML描述的詳細(xì)一點(diǎn),把這些都封裝成了對(duì)象,但在拼字符串的時(shí)候,對(duì)象就會(huì)太多,以后如果改版的話,可以把它盡量封裝少一點(diǎn)對(duì)象,這樣速度可能會(huì)快一點(diǎn),內(nèi)存可能會(huì)少用一點(diǎn).
?
轉(zhuǎn) : http://www.aygfsteel.com/wujiaqian/archive/2006/12/11/86970.html