在使用kendoui的Grid導(dǎo)出Excel報(bào)表的過(guò)程中出現(xiàn)的幾個(gè)問(wèn)題:
1芹壕、在打開(kāi)下載好的文檔時(shí)會(huì)出現(xiàn)警告
2淆两、打開(kāi)Excel時(shí)师崎,發(fā)現(xiàn)Excel的列是緊湊的铺敌,不能保證正常的表格的寬度
目前上述問(wèn)題汇歹,我還沒(méi)找到問(wèn)題是如何發(fā)生的,且沒(méi)有合適的解決辦法(猜測(cè)是由于JsZip庫(kù)導(dǎo)致的該類型問(wèn)題)
因此偿凭,我希望能將Excel報(bào)表的導(dǎo)出放到服務(wù)器上去完成秤朗!
POI:Apache旗下的一個(gè)開(kāi)源函式庫(kù),提供了 API 給 Java 對(duì) Microsoft Office 格式檔案讀和寫(xiě)的功能笔喉;
結(jié)構(gòu):
對(duì)應(yīng)POI文檔:http://tool.oschina.net/apidocs/apidoc?api=apache-POI (咳咳取视。我這里不知道為什么官網(wǎng)進(jìn)不去!所以只提供鏡像鏈接常挚!官網(wǎng)傳送門(mén))
接下來(lái)以xlsx文件為例展示來(lái)做一個(gè)輸出的流程作谭;
因?yàn)橐谕ㄟ^(guò)瀏覽器端和服務(wù)端交互做導(dǎo)出表格的工作,那么就應(yīng)該是在瀏覽器端發(fā)送請(qǐng)求后奄毡,服務(wù)器做出響應(yīng)折欠,在響應(yīng)中增加要導(dǎo)出報(bào)表的相關(guān)信息;
因?yàn)檫€有其他需求可能會(huì)用到這些部分吼过,我將創(chuàng)建導(dǎo)出xlsx文件的操作包裝成了一個(gè)根據(jù)類锐秦,具體請(qǐng)參照代碼;
其中要特別注意火狐瀏覽器盗忱,火狐瀏覽器的編碼規(guī)則不同與其他瀏覽器的編解碼規(guī)則酱床,火狐要求必須使用iso-8859-1進(jìn)行傳輸信息,直接使用utf8會(huì)出現(xiàn)亂碼問(wèn)題趟佃。
import org.apache.poi.openxml4j.exceptions.OpenXML4JRuntimeException;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
public class ReportUtil {
/**
* 根據(jù)傳入的請(qǐng)求和文件名扇谣,創(chuàng)建一個(gè)輸出流
* @param request 瀏覽器請(qǐng)求昧捷,如果請(qǐng)求來(lái)判斷當(dāng)前瀏覽器類型,進(jìn)行轉(zhuǎn)碼工作
* @param httpServletResponse 服務(wù)端響應(yīng)罐寨,通過(guò)響應(yīng)中的輸出流導(dǎo)出文件
* @param fileName 文件名
* @return 一個(gè)響應(yīng)輸出流
* @throws IOException 在編碼過(guò)程中會(huì)出現(xiàn)IO異常
*/
public static ServletOutputStream createOutputStream(HttpServletRequest request,HttpServletResponse httpServletResponse, String fileName) throws IOException {
// 通常解決漢字亂碼方法用URLEncoder.encode(...)
String fileNameDisplay = URLEncoder.encode(fileName, "UTF-8") + ".xlsx";
if ("FF".equals(getBrowser(request))) {
// 針對(duì)火狐瀏覽器處理方式不一樣了
fileNameDisplay = new String(fileName.getBytes("UTF-8"),
"iso-8859-1") + ".xlsx";
}
httpServletResponse.addHeader("Content-Disposition", "attachment;filename=" + fileNameDisplay);
// httpServletResponse.addHeader("Content-Disposition", "attachment;filename=\"" + URLEncoder.encode(fileName + ".xlsx", "UTF-8") + "\"");
httpServletResponse.setContentType("application/vnd.ms-excel;charset=UTF-8");
httpServletResponse.setHeader("Accept-Ranges", "bytes");
ServletOutputStream outputStream = httpServletResponse.getOutputStream();
return outputStream;
}
/**
* 工作流寫(xiě)入workbook并關(guān)閉當(dāng)前管控的對(duì)應(yīng)的workbook和輸出流
* @param wb 當(dāng)前服務(wù)器管控的workbook對(duì)象靡挥,用于輸出的excel
* @param outputStream 需要寫(xiě)入對(duì)應(yīng)的workbook中的輸出流
* @throws IOException 在寫(xiě)入workbook時(shí)可能會(huì)拋出的異常,此異常提交到上一層解決
*/
public static void streamWriteAndClose(XSSFWorkbook wb,ServletOutputStream outputStream) throws IOException{
try{
wb.write(outputStream);
}catch (OpenXML4JRuntimeException e){
System.err.println(e.getMessage());
}
finally {//包裝到finally中保證關(guān)閉操作必執(zhí)行
//關(guān)閉流
try{
outputStream.close();
}catch (Exception ose){
System.err.println(ose.getMessage());
}
try{
wb.close();
}
catch (Exception wbe){
System.err.println(wbe.getMessage());
}
}
}
// 以下為服務(wù)器端判斷客戶端瀏覽器類型的方法
private static String getBrowser(HttpServletRequest request) {
String UserAgent = request.getHeader("USER-AGENT").toLowerCase();
if (UserAgent != null) {
if (UserAgent.indexOf("msie") >= 0)
return "IE";
if (UserAgent.indexOf("firefox") >= 0)
return "FF";
if (UserAgent.indexOf("safari") >= 0)
return "SF";
}
return null;
}