項目中使用POI生成excle報表
maven:
<groupId>org.apache.poi ? <artifactId>poi? <version>4.0.1</dependency>?
POI中概念:
HSSFWorkbook : 相當于一個excel文件
HSSFSheet:一張excel表妨蛹,excel左下角的sheet0,sheet1..
HSSFRow:一張表格中的某一行
HSSFCell:一張表格中的一個單元格
1.創(chuàng)建一個workBook.
HSSFWorkbook wb = new HSSFWorkbook();
2.創(chuàng)建一張sheet
HSSFSheet sheet = wb.createSheet("sheet0");
3.創(chuàng)建第一行
HSSFRow row = sheet.createRow(0);
構造方法中的數(shù)值表示創(chuàng)建第幾行砾嫉,索引從0開始
4.創(chuàng)建一個單元格
HSSFCell cell = row.createCell(0);
構造方法中的數(shù)值表示創(chuàng)建第幾列簇爆,索引從0開始
5.向表格中添加數(shù)據(jù)
cell.setCellValue().
此時谷市,一個excel的雛形已經(jīng)創(chuàng)建好了砂缩,但是胁出,怎么導出并下載呢沟启?
需要用到HttpServletResponse忆家。
1.設置響應類型,告知類型為excel文件
response.setContentType("application/vnd.ms-excel");
2.設置字符編碼
response.setCharacterEncoding("utf-8");
3.根據(jù)瀏覽器進行轉(zhuǎn)碼德迹,使其支持中文文件名
String browse = Excelutil.checkBrowse(request);String fileName ="新建表格";try {if ("MSIE".equalsIgnoreCase(browse.substring(0, 4))) {response.setHeader("content-disposition", "attachment;filename=" + java.net.URLEncoder.encode(fileName, "UTF-8") +".xls");? ? }else {String newtitle =new String(fileName.getBytes("UTF-8"), "ISO8859-1");? ? ? ? response.setHeader("content-disposition", "attachment;filename=" + newtitle +".xls");? ? }}catch (Exception e) {e.printStackTrace();}?
4.導出
OutputStream out =null;try {out = response.getOutputStream();? ? wb.write(out);}catch (Exception e) {e.printStackTrace();}finally {if (null != out) {try {out.close();? ? ? ? }catch (IOException e) {e.printStackTrace();? ? ? ? }}}
到此為止可以導出一個excel表格了芽卿。
還沒完,實際生產(chǎn)過程中需要用到的報表格式要復雜得多
1.首先胳搞,設置各個單元格的格式卸例,比如大小称杨,居中什么的(新版本的API可能不一樣,具體可以看看官方API)
設置格式需要用到HSSFCellStyle筷转。由HSSFWorkbook 生成姑原,在方法定義中明確表示一個workbook
最多只能有4000個HSSFCellStyle
HSSFCellStyle cs = wb.createCellStyle();cs.setAlignment(HSSFCellStyle.ALIGN_CENTER);水平居中cs.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);垂直居中cs.setWrapText(true);字體是否加粗,默認為falsecs.setBorderBottom(BorderStyle.DOTTED);設置下邊框樣式旦装,BorderStyle是一個枚舉页衙,有很多類型,具體可以看官方文檔阴绢。cs.setBorderTop(BorderStyle.DOTTED)cs.setBorderLeft(BorderStyle.DOTTED)cs.setBorderRight(BorderStyle.DOTTED)cs.setBottomBorderColor(short color)設置邊框顏色店乐,有對應的上下左右方法cs.setFillBackgroundColor(short color)設置背景顏色cs.setFilllBackgroundColor(short color)設置前景顏色cs.setFont(HSSFFont font)設置字體HSSFFont font = wb.createFont();font.setFontName("黑體“)font.setFontHeightInPoints((short)12)設置字體
讓格式生效
cell.setCellStyle(cs)
也可以使用
sheet.setColumnWidth(int columnIndex,int width);
設置某一列的寬度
2.合并單元格
sheet.addMergedRegion(new CellRangeAddress(int firstRow,int lastRow,int firstCol, int lastCol));
將多個單元格合成一個單元格,參數(shù)依次為起始行呻袭,結束行眨八,起始列,結束列左电。
使用時先生成一個單元格廉侧,比如我要合并第一行的第一個和第二個單元格
1.先生成第一個單元格
HSSFCell cell = row.createCell(0);
2.合并
sheet.addMergedRegion(new CellRangeAddress(0,0,0, 1));
3.如果要生成下一個單元格,記得單元格的下標應該為2而不是1篓足,因為你已經(jīng)合并了一個單元
格段誊,原則:生成新的單元格的時候要判斷前面是否有合并的單元格,如果有栈拖,需要將合并的單元格也算進去连舍。
4.poi也可以通過讀取excel模板來生成新的excel報表
首先,需要將excel模板文件放入項目資源文件夾中涩哟,然后獲取該模板文件的路徑
String path = AbroadCountUtils.class.getClassLoader().getResource("abroad.xls").getPath();
File file =newFile(path);
生成HSSFWorkbook
HSSFWorkbook wb =newHSSFWorkbook();
生成HSSFSheet
HSSFSheet sheet = wb.createSheet("sheet0");
后面的步驟就是一樣的了索赏,通過導入模板可以簡化生成復雜表頭的步驟,避免出錯贴彼。
5.checkbrowser方法
private final staticStringIE11="rv:11.0";
private final staticStringIE10="MSIE 10.0";
private final staticStringIE9="MSIE 9.0";
private final staticStringIE8="MSIE 8.0";
private final staticStringIE7="MSIE 7.0";
private final staticStringIE6="MSIE 6.0";
private final staticStringMAXTHON="Maxthon";
private final staticStringQQ="QQBrowser";
private final staticStringGREEN="GreenBrowser";
private final staticStringSE360="360SE";
private final staticStringFIREFOX="Firefox";
private final staticStringOPERA="Opera";
private final staticStringCHROME="Chrome";
private final staticStringSAFARI="Safari";
private final staticStringOTHER="其它";
public staticStringcheckBrowse(HttpServletRequest request) {
String userAgent = request.getHeader("USER-AGENT");
if(regex(OPERA,userAgent))
returnOPERA;
if(regex(CHROME,userAgent))
returnCHROME;
if(regex(FIREFOX,userAgent))
returnFIREFOX;
if(regex(SAFARI,userAgent))
returnSAFARI;
if(regex(SE360,userAgent))
returnSE360;
if(regex(GREEN,userAgent))
returnGREEN;
if(regex(QQ,userAgent))
returnQQ;
if(regex(MAXTHON,userAgent))
returnMAXTHON;
if(regex(IE11,userAgent))
returnIE11;
if(regex(IE10,userAgent))
returnIE10;
if(regex(IE9,userAgent))
returnIE9;
if(regex(IE8,userAgent))
returnIE8;
if(regex(IE7,userAgent))
returnIE7;
if(regex(IE6,userAgent))
returnIE6;
returnOTHER;
}
public static booleanregex(String regex,String str) {
Pattern p = Pattern.compile(regex,Pattern.MULTILINE);
Matcher m = p.matcher(str);
returnm.find();}
貼上從前端請求到后端處理的整個代碼潜腻。
1.前端js方法,該方法為按鈕的點擊事件綁定的方法器仗,點擊后通過將參數(shù)拼接到url的方式進行傳參融涣。(有點丑,有更好的可以推薦G嘧啤)
?function exportExcel() { var startDate = $('#startTime').val(); var endDate = $('#endTime').val(); var condition = $('#condition').val(); var url = 'exportExcel.do'; url = url + '?start=' + startDate + '&end=' + endDate + '&condition=' + condition; location.href = url;}
2.controller中的方法
?@RequestMapping("exportExcel.do")
public void exportExcel(HttpServletRequest request, HttpServletResponse response) {
String start = request.getParameter("start");
String end = request.getParameter("end");
String condition = request.getParameter("condition");
List titleList = new ArrayList<>();
titleList.add("ID");
titleList.add("name");
titleList.add("age");
List<List<String>> content = new ArrayList();
HSSFWorkbook wb = GenerateExcelUtil.generateExcel(titleList, content);
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
String browse = GenerateExcelUtil.checkBrowse(request);
String fileName = "newExcel";
try { if ("MSIE".equalsIgnoreCase(browse.substring(0, 4))) {
response.setHeader("content-disposition", "attachment;filename=" + java.net.URLEncoder.encode(fileName, "UTF-8") + ".xls"); }
else { String newtitle = new String(fileName.getBytes("UTF-8"), "ISO8859-1"); response.setHeader("content-disposition", "attachment;filename=" + newtitle + ".xls"); }
} catch (Exception e) { e.printStackTrace(); } OutputStream out = null; try { out = response.getOutputStream(); wb.write(out); } catch (Exception e) { e.printStackTrace(); }finally { if (null != out) { try { out.close(); } catch (IOException e) { e.printStackTrace(); } } }}
3.生成excel工具類
public class GenerateExcelUtil {
private final static String IE11="rv:11.0";
private final static String IE10="MSIE 10.0";
private final static String IE9="MSIE 9.0";
private final static String IE8="MSIE 8.0";
private final static String IE7="MSIE 7.0";
private final static String IE6="MSIE 6.0";
private final static String MAXTHON="Maxthon";
private final static String QQ="QQBrowser";
private final static String GREEN="GreenBrowser";
private final static String SE360="360SE";
private final static String FIREFOX="Firefox";
private final static String OPERA="Opera";
private final static String CHROME="Chrome";
private final static String SAFARI="Safari";
private final static String OTHER="其它";
public static HSSFWorkbook generateExcel(List<String> titles, List<List<String>> contents){
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet sheet = wb.createSheet();
sheet.setColumnWidth(1,256*32); sheet.setColumnWidth(4,256*20);
sheet.setColumnWidth(5,256*50); sheet.setColumnWidth(6,256*20);
sheet.setColumnWidth(8,256*20);
sheet.setDefaultRowHeight((short)(20*20));
HSSFRow row = sheet.createRow(0);
for (int i = 0 ;i< titles.size();i++) {
HSSFCell cell = row.createCell(i);
cell.setCellValue(titles.get(i));
HSSFCellStyle cs = wb.createCellStyle();
cs.setAlignment(HSSFCellStyle.ALIGN_CENTER);
cs.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
cs.setWrapText(true); cell.setCellStyle(cs); }
for (int i = 1;i<=contents.size();i++) {
HSSFRow row1 = sheet.createRow(i);
List list = contents.get(i - 1);
for(int j= 0;j<list.size();j++){
? ? HSSCell cell = row1.createCell(j);
?? cell.setCellValue(list.get(j))
}
public static String checkBrowse(HttpServletRequest request) {
String userAgent = request.getHeader("USER-AGENT");
if(regex(OPERA,userAgent)){ return OPERA; }
if(regex(CHROME,userAgent)){ return CHROME;}
if(regex(FIREFOX,userAgent)){ return FIREFOX;}
if(regex(SAFARI,userAgent)){ return SAFARI;}
if(regex(SE360,userAgent)){ return SE360;}
if(regex(GREEN,userAgent)){ return GREEN;}
if(regex(QQ,userAgent)){ return QQ;}
if(regex(MAXTHON,userAgent)){ return MAXTHON;}
if(regex(IE11,userAgent)){ return IE11;}
if(regex(IE10,userAgent)){ return IE10;}
if(regex(IE9,userAgent)){ return IE9;}
if(regex(IE8,userAgent)){ return IE8;}
if(regex(IE7,userAgent)){ return IE7;}
if(regex(IE6,userAgent)){ return IE6;}
return OTHER;}
private static boolean regex(String regex, String str) {
Pattern p = Pattern.compile(regex, Pattern.MULTILINE);
Matcher m = p.matcher(str);
return m.find();}
出現(xiàn)的問題:導出按鈕在一個iframe中暴心,使用ajax請求,服務器文件生成成功了杂拨,但是瀏覽器卻沒出現(xiàn)下載的文件专普。
解決方式:借助FileSaver插件https://github.com/eligrey/FileSaver.js
function exportExcel() {
var url ='/export';
? ? var xhr =new XMLHttpRequest();
? ? xhr.open('POST', url, true);? ? // 也可以使用POST方式,根據(jù)接口
? ? xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
? ? xhr.responseType ="blob";? // 返回類型blob
? ? // 定義請求完成的處理函數(shù)弹沽,請求前也可以增加加載框/禁用下載按鈕邏輯
? ? xhr.onload =function () {
var data =this.response;
? ? ? ? // 請求完成
? ? ? ? if (this.status ===200) {
var blob =new Blob([data], {type:"application/vnd.ms-excel"});
? ? ? ? ? ? saveAs(blob, "demo.xls");
? ? ? ? }else {
alert("導出失敗!")
}
};
? ? // 發(fā)送ajax請求
?? xhr.send($("#form").serialize())}
ps:如果導出的excel數(shù)據(jù)量特別大檀夹,XSSFWorkbook 了解下筋粗。