一、問題描述
???
該問題出現是因為在導出文件之后
用戶下載的是
.csv
文件,如果用文本編輯器打開可以查看所有記錄,但是如果用
excel
打開就出現一個
sheet
最多
6
萬條的記錄。因此就不可以使用保存為
csv
文件來實現
excel
文件的下載,需要使用新的方式去實現。
???
如果使用
jxl
開發包在
web
后臺去創建
Excel
文件,如果數據量比較大,則用戶需要等待很長很長的時間才可以下載到,因為
jxl
的對于
excel
文件的操作都是對象級的
,
文件中每一個格子都是一個
cell
對象,需要后臺去
new
。所以還需要考慮別的方式。
???
二、實現靈感
??? Excel
文件打開之后選擇另存為可以保存為
XML
類型文件,因此就考慮構造符合
Excel
可以打開的
XML
類型文件,并且對該
XML
文件進行最簡單化處理,去除
Excel
文件中的每個
cell
的
style
定義、
XML
文件頭部的多余信息,最后整理出一個符合資訊平臺所下載的
Excel
文件的格式
,
請看下面:
<!—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
文件第一個
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
文件第二個
SHEET --//>
<Worksheet ss:Name="sheet1">
<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>
</Workbook>
<!-- XML
文件結束
--//>
|
注釋:
a
、
<Worksheet ss:Name="sheet0">?
引號內部的是該
sheet
的名稱。
b
、
<Data ss:Type="String">aa1</Data> ?ss:Type
的值是用來定義該
cell
格數據的類型,例如可以為
Number,
表是該
cell
格數據是數字。
三、實現方式
???
通過第一步的分析可以發現只要我們構建這樣格式的
XML
數據,就可以通過
Excel
打開,并且可以實現分
sheet
的樣式。但是數據下載到用戶本地是
XML
類型的話,那是沒什么意義的,就算打開方式選擇使用
Excel
可以打開,因此如何將用戶下載的文件類型改為
XLS
呢?這里就可以通過在下載的
servlet
中設置
response.setContentType("application/vnd.ms-excel")
來實現。
package com.hoten.util.xmlxls;
import java.util.ArrayList;
?private final static String XML_HEARDER = "<?xml version=\"1.0\"?>";
?
?private List sheetList = new ArrayList(); //存放每行多個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(); //存放每行多個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的數據對象
??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數據類型
?private String value = ""; //cell數據
?
?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";
測試的方法:
PrintWriter out = response.getWriter();
???????? // 設置響應頭和下載保存的文件名
???????? response.setContentType("application/vnd.ms-excel");
???????? response.setHeader("Content-Disposition","attachment; filename=\""+Chinese.toPage(fileNametemp)+"\"");
????????
???????? String rows_temp = request.getParameter("rows");//頁面傳過來的每個SHEET可以存放的條數
???if (rows_temp == null){
????rows_temp = "20000";
???}
???int count_rows = Integer.parseInt(rows_temp);//一個SHEET有多行
????????
???????? WorkBook book = new WorkBook();
???????? Vector v_Rs = RsToVector.ResultSetToVector(rs);// 把RS的值轉換成VECTOR,這個可以看我上一版本,上面有詳細的寫法
?????????
???????? if (v_Rs != null) {
????int a = v_Rs.size();????
????int sheet_count = a / count_rows;// 30000行一個sheet。
????
????if (sheet_count >0){//大于0,則需要多個SHEET
?????for (int i = 0;i<sheet_count;i++){
??????WorkSheet sheet = new WorkSheet();//創建一個新的SHEET
??????sheet.setName("sheet" + i);//設置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);???????
???????//取出一個對象,把對象的值放到EXCEL里
???????TableRow row = new TableRow();//設置行?
???????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);
?????}
?????//還有剩余的數據
?????if (sheet_count * count_rows < a){
??????WorkSheet sheet = new WorkSheet();//創建一個新的SHEET
??????sheet.setName("sheet" + sheet_count);//設置SHEET的名稱
???????
??????for (int c = sheet_count* count_rows ;c<a ;c++){???????
???????Vector temp_vv = new Vector();
???????temp_vv =(Vector) v_Rs.get(c);
???????//取出一個對象,把對象的值放到EXCEL里
???????TableRow row = new TableRow();//設置行
???????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();//創建一個新的SHEET
??????sheet.setName("sheet1");//設置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);???????
???????//取出一個對象,把對象的值放到EXCEL里
???????TableRow row = new TableRow();//設置行?
???????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的時候重復代碼比較多,可以寫一個公用的方法,,我為了把XML描述的詳細一點,把這些都封裝成了對象,但在拼字符串的時候,對象就會太多,以后如果改版的話,可以把它盡量封裝少一點對象,這樣速度可能會快一點,內存可能會少用一點.
?
轉 : http://www.aygfsteel.com/wujiaqian/archive/2006/12/11/86970.html