先分享幾個鏈接:(POI的中文API,別人總結的拿來用特別方便) http://blog.csdn.net/m0_37505412/article/details/71109503 https://www.cnblogs.com/fqfanqi/p/6172223.html 我在項目中做這個功能的時 ...
先分享幾個鏈接:(POI的中文API,別人總結的拿來用特別方便)
http://blog.csdn.net/m0_37505412/article/details/71109503
https://www.cnblogs.com/fqfanqi/p/6172223.html
我在項目中做這個功能的時候,其實項目中是有現成代碼的,本來我以為我只需要修改一下,後來看過代碼才發現和我要的不一樣,於是只能重寫一個。
導出功能:
1、在action層拿到要導出的數據 -- results
2、同樣在action層拿到要導出數據的欄位集,即列 -- exportFields
解釋一下,一般我們在獲取數據的時候,往往會把一些表中的冗餘欄位或者一些我不需要的欄位也獲取了,我們不可能也把它們導出來。其實這個欄位集,就是我們在Excel表中要顯示的列。在現成的功能中支持在頁面選擇要導出的欄位,而我的導出功能不支持選擇,導出的欄位是寫死的。
3、拿到導出時一張表中存多少條數據 -- rowNum
在現成的功能中還支持這個由用戶選,就是導出到一張表,要太多條數據,然後我們根據這個值去劃分數據,比如這個值是5000,然後我們就每5000條數據新建一個工作表,再繼續存放數據。我的功能……這個值同樣寫死的。
4、調用Service層方法,傳入上面的參數和HttpServletResponse 。傳哪些參數大家隨意,當然 results是肯定不能少的。
5、在Service層寫方法,接受剛纔的四個參數
1 @Override 2 public void createExcelWorkBookInfo(HttpServletResponse response, List<BaseAlumni> results, String exportFields, 3 Integer rowNum) { 4 String nowStr = new Date().getTime() + ""; 5 //這個out我還不太瞭解就不給你們說了,大致意思就是導出動作吧 6 OutputStream out = null; 7 try { 8 out = response.getOutputStream(); 9 response.reset(); 10 //設置表名 11 response.setHeader("content-disposition", 12 "attachment;filename=" + new String(("校友信息" + nowStr).getBytes("gb2312"), "ISO8859-1") + ".xls"); 13 response.setContentType("APPLICATION/msexcel"); 14 //創建Excel表 15 HSSFWorkbook workbook = new HSSFWorkbook(); 16 //調用導出方法 17 excelSrv.export(results, exportFields, workbook, rowNum); 18 workbook.write(out); 19 } catch (IOException e) { 20 e.printStackTrace(); 21 } finally { 22 try { 23 // 強行將響應緩存中的內容發送到目的地 24 response.flushBuffer(); 25 if (out != null) { 26 out.flush(); 27 out.close(); 28 } 29 } catch (IOException e) { 30 LOGGER.error(e); 31 } 32 } 33 }
5、寫export方法,在現成的方法中,封裝好了一個方法,行,列的生成都是通過foreach,很高大上。在這裡,我先附上我寫的,後面再附上現成的,給自己做一個對比。
1 @Override 2 public void alumniBranchExport(List<BaseAlumniBranch> results, Map<String, String> fildsMap, HSSFWorkbook wb) { 3 //因為之前沒有傳,所以在這寫死,這個功能大家不想要也是可以的 -- rowMaxNum = 10000 4 Integer rowNum = rowMaxNum; 5 for (int i = 0; i < results.size(); i += rowNum) { 6 List<BaseAlumniBranch> newlist = new ArrayList<>(); 7 if ((i + rowNum) < results.size()) { 8 //數據的截取 9 newlist = results.subList(i, i + rowNum); 10 } else { 11 newlist = results.subList(i, results.size()); 12 } 13 //創建工作表 14 HSSFSheet sheet = wb.createSheet(); 15 for (int j = 0; j < fildsMap.size(); j++) { 16 //設置列寬,第一個參數是列,第二個參數是寬值 17 sheet.setColumnWidth(i, 5000); 18 } 19 //填充表頭 20 this.fillClubExcelHeader(wb, sheet, fildsMap); 21 //填充內容 22 this.fillClubExcelBody(newlist, sheet, wb, fildsMap); 23 } 24 }
6、其實現成的代碼和我這個是差不多一樣的,不一樣的地方就是在填充的那兩個方法裡面
這是現成的header填充:
1 private void fillCommonHeader(HSSFWorkbook wb, HSSFSheet sheet, Map<String, String> fildsMap) { 2 //創建樣式 3 HSSFCellStyle style = wb.createCellStyle(); 4 style.setAlignment(HSSFCellStyle.ALIGN_CENTER); 5 //字體的顏色,大小 6 HSSFFont font = wb.createFont(); 7 font.setColor(HSSFColor.BLACK.index); 8 font.setFontHeightInPoints((short) 18); 9 style.setFont(font); 10 //創建第一行,從0開始,參數是第幾行的索引,第一行是0 11 HSSFRow row = sheet.createRow(0); 12 //在這裡說一下,foreach是拿不到index的,這裡在外面聲明一個i,在表示第幾列 13 int i = 0; 14 //迴圈傳過來的欄位集 15 for (String key : fildsMap.keySet()) { 16 //創建一個單元格,創建完後i自增1 17 HSSFCell cell = row.createCell(i++); 18 String value = fildsMap.get(key); 19 //給單元格賦值 20 cell.setCellValue(value); 21 //給單元格設置樣式 22 cell.setCellStyle(style); 23 } 24 //在這裡有一個順序的問題,我也是用傳參的方式,但是我的fildsMap的順序就是亂了,我又不會調,尷尬 25 }
這是我的header填充:
1 private void fillClubExcelHeader(HSSFWorkbook wb, HSSFSheet sheet, Map<String, String> fildsMap) { 2 HSSFCellStyle style = wb.createCellStyle(); 3 style.setAlignment(HSSFCellStyle.ALIGN_CENTER); 4 HSSFFont font = wb.createFont(); 5 font.setColor(HSSFColor.BLACK.index); 6 font.setFontHeightInPoints((short) 18); 7 style.setFont(font); 8 // 創建第一行 9 HSSFRow row = sheet.createRow(0); 10 // 創建第一列 11 HSSFCell cell = row.createCell(0); 12 // 賦值 13 cell.setCellValue(fildsMap.get("clubName")); 14 cell.setCellStyle(style); 15 // 創建第二列,在這裡不能再出現HSSFCell聲明,為什麼……我也是一知半解,就不說了 16 cell = row.createCell(1); 17 cell.setCellValue(fildsMap.get("clubWechatId")); 18 cell.setCellStyle(style); 19 // 創建第三列…… 20 cell = row.createCell(2); 21 cell.setCellValue(fildsMap.get("clubAddress")); 22 cell.setCellStyle(style); 23 cell = row.createCell(3); 24 cell.setCellValue(fildsMap.get("clubEmail")); 25 cell.setCellStyle(style); 26 cell = row.createCell(4); 27 cell.setCellValue(fildsMap.get("clubEstablishedTime")); 28 cell.setCellStyle(style); 29 cell = row.createCell(5); 30 cell.setCellValue(fildsMap.get("name")); 31 cell.setCellStyle(style); 32 cell = row.createCell(6); 33 cell.setCellValue(fildsMap.get("staff")); 34 cell.setCellStyle(style); 35 cell = row.createCell(7); 36 cell.setCellValue(fildsMap.get("phone")); 37 cell.setCellStyle(style); 38 cell = row.createCell(8); 39 cell.setCellValue(fildsMap.get("email")); 40 cell.setCellStyle(style); 41 }
這是現成的body填充:
1 private <T> void fillCommonBody(List<T> results, HSSFSheet sheet, HSSFWorkbook wb, Map<String, String> fildsMap) { 2 HSSFCellStyle style = wb.createCellStyle(); 3 style.setAlignment(HSSFCellStyle.ALIGN_CENTER); 4 HSSFFont font = wb.createFont(); 5 font.setColor(HSSFColor.BLACK.index); 6 font.setFontHeightInPoints((short) 16); 7 style.setFont(font); 8 int i = 1; 9 for (T inst : results) { 10 HSSFRow row = sheet.createRow(i++); 11 row.setRowStyle(style); 12 int j = 0; 13 for (String key : fildsMap.keySet()) { 14 HSSFCell cell = row.createCell(j++); 15 String val = setCell(key, inst); //在里我這差點被騙了,也不知道是誰命名的,還以為單元格帶有的get,set方法 16 cell.setCellValue(val); 17 } 18 } 19 }
這個方法主要是寫如何從results中拿值的,我看了半天沒看懂
1 @SuppressWarnings("rawtypes") 2 private <T> String setCell(String field, T data) { 3 String val = ""; 4 5 Class clazz = data.getClass(); 6 Field[] fields = ArrayUtils.addAll(clazz.getDeclaredFields(), clazz.getSuperclass().getDeclaredFields()); 7 for (int i = 0; i < fields.length; i++) { 8 if (fields[i].getName().equals(field)) { 9 try { 10 Object resultObject = invokeMethod(data, fields[i].getName(), null); 11 if (resultObject == null) { 12 resultObject = ""; 13 } 14 val = resultObject.toString(); 15 break; 16 } catch (SecurityException | NoSuchMethodException | IllegalArgumentException | IllegalAccessException 17 | InvocationTargetException e) { 18 e.printStackTrace(); 19 } 20 } 21 } 22 23 return val; 24 }
我的body方法:
1 private <T> void fillClubExcelBody(List<BaseAlumniBranch> results, HSSFSheet sheet, HSSFWorkbook wb, 2 Map<String, String> fildsMap) { 3 HSSFCellStyle style = wb.createCellStyle(); 4 style.setAlignment(HSSFCellStyle.ALIGN_CENTER); 5 HSSFFont font = wb.createFont(); 6 font.setColor(HSSFColor.BLACK.index); 7 font.setFontHeightInPoints((short) 16); 8 style.setFont(font); 9 int k = 1; 10 if (results.size() < 2 || "null".equals(results.size())) { 11 LOGGER.error("alumniBranchExport but results is empty !"); 12 return; 13 } 14 for (int i = 0; i < results.size(); i++) { 15 BaseAlumniBranch inst = results.get(i); 16 if (inst.getStaffList().size() < 1 || "null".equals(inst.getStaffList().size())) { 17 HSSFRow row = sheet.createRow(k++); 18 row.setRowStyle(style); 19 HSSFCell cell = row.createCell(0); 20 cell.setCellValue(inst.getName()); 21 cell.setCellStyle(style); 22 cell = row.createCell(1); 23 cell.setCellValue(inst.getWechatId()); 24 cell.setCellStyle(style); 25 cell = row.createCell(2); 26 cell.setCellValue(inst.getAddress()); 27 cell.setCellStyle(style); 28 cell = row.createCell(3); 29 cell.setCellValue(inst.getEmail()); 30 cell.setCellStyle(style); 31 cell = row.createCell(4); 32 cell.setCellValue(inst.getEstablishedTime()); 33 cell.setCellStyle(style); 34 cell = row.createCell(5); 35 cell.setCellValue(""); 36 cell.setCellStyle(style); 37 cell = row.createCell(6); 38 cell.setCellValue(""); 39 cell.setCellStyle(style); 40 cell = row.createCell(7); 41 cell.setCellValue(""); 42 cell.setCellStyle(style); 43 cell = row.createCell(8); 44 cell.setCellValue(""); 45 cell.setCellStyle(style); 46 } else { 47 for (int j = 0; j < inst.getStaffList().size(); j++) { 48 HSSFRow row = sheet.createRow(k++); 49 row.setRowStyle(style); 50 HSSFCell cell = row.createCell(0); 51 cell.setCellValue(inst.getName()); 52 cell.setCellStyle(style); 53 cell = row.createCell(1); 54 cell.setCellValue(inst.getWechatId()); 55 cell.setCellStyle(style); 56 cell = row.createCell(2); 57 cell.setCellValue(inst.getAddress()); 58 cell.setCellStyle(style); 59 cell = row.createCell(3); 60 cell.setCellValue(inst.getEmail()); 61 cell.setCellStyle(style); 62 cell = row.createCell(4); 63 cell.setCellValue(inst.getEstablishedTime()); 64 cell.setCellStyle(style); 65 cell = row.createCell(5); 66 cell.setCellValue(inst.getStaffList().get(j).getName()); 67 cell.setCellStyle(style); 68 cell = row.createCell(6); 69 cell.setCellValue(inst.getStaffList().get(j).getStaff()); 70 cell.setCellStyle(style); 71 cell = row.createCell(7); 72 cell.setCellValue(inst.getStaffList().get(j).getPhone()); 73 cell.setCellStyle(style); 74 cell = row.createCell(8); 75 cell.setCellValue(inst.getStaffList().get(j).getEmail()); 76 cell.setCellStyle(style); 77 } 78 for (int column = 0; column < 5; column++) { 79 mergeCell(sheet, k - inst.getStaffList().size(), k - 1, column, column); 80 } 81 82 } 83 } 84 }
7、我在方法的最後做了合併單元格,這是在原方法上改不動的,所以我必須再寫一個方法。
傳的參數中,從左到右:工作表名,起始行,結束行,起始列,結束行
就是要合併單元格,合併從哪行開始到哪行,從哪列開始到哪列
1 public void mergeCell(HSSFSheet sheet, int rolStart, int rolEnd, int cowStart, int cowEnd) { 2 CellRangeAddress region = new CellRangeAddress(rolStart, rolEnd, cowStart, cowEnd); 3 sheet.addMergedRegion(region); 4 }
8、到此,導出結束。
9、過程中碰到的坎坷:
Excel表我聲明瞭兩次,導致到後來導出的內容是沒有行的,如圖:(要註意,不止是表,行,列也不能重覆,否則就會出錯)
10、最後的成功: