將資料庫的資料轉換為excel檔案下載到本地的方法中遇到的困難及解決方案
以下是將資料庫的資料轉換為excel檔案下載到本地的方法
@Autowired
private BooksService booksService;
@RequestMapping("/downloadBooksExcel")
public void downstudents(HttpServletRequest request, HttpServletResponse response)throws IOException {
String[] headers = { "序號", "作者", "出版社", "時間","專案編號","標題"};//匯出的Excel頭部,這個要根據自己專案改一下 List<TBooks> dataset = booksService.findAll();//查詢出來的資料,根據自己專案改一下 for (TBooks books: dataset) { } //下面的完全不動就行了(Excel資料中不包含圖片) // 宣告一個工作薄 HSSFWorkbook workbook = new HSSFWorkbook(); // 生成一個表格 HSSFSheet sheet = workbook.createSheet(); // 設定表格預設列寬度為15個位元組 sheet.setColumnWidth(5,8000); HSSFRow row = sheet.createRow(0); for (int i = 0; i < headers.length; i++) { HSSFCell cell = row.createCell(i); HSSFRichTextString text = new HSSFRichTextString(headers[i]); cell.setCellValue(text); } //遍歷集合資料,產生資料行 Iterator it = dataset.iterator(); int index = 0; while (it.hasNext()) { index++; row = sheet.createRow(index); TBooks t = (TBooks) it.next(); //利用反射,根據javabean屬性的先後順序,動態呼叫getXxx()方法得到屬性值 Field[] fields = t.getClass().getDeclaredFields(); for (int i = 0; i < fields.length; i++) { Field field = fields[i]; String fieldName = field.getName(); String getMethodName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1); HSSFCell cell = row.createCell(i); try { Class tCls = t.getClass(); Method getMethod = tCls.getMethod(getMethodName, new Class[]{}); System.out.println(getMethodName); Object value = null; if (getMethodName.equals("getStatus")) { //sheet.removeMergedRegion(getMergedRegionIndex(sheet, 1, 1)); continue;//相當於清空了是資料 } if (getMethodName.equals("getResultId")) { continue;//相當於清空了是資料 } //row.removeCell(cell); value = getMethod.invoke(t, new Object[]{}); if (getMethodName.equals("getId")) { cell.setCellValue(i+1);//如果是id列的話,直接將序號設定進去 } System.out.println(value); String textValue = null; if (value instanceof Date) { Date date = (Date) value; SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); textValue = sdf.format(date); } else { //其它資料型別都當作字串簡單處理 textValue = value.toString(); } HSSFRichTextString richString = new HSSFRichTextString(textValue); HSSFFont font3 = workbook.createFont(); font3.setColor(HSSFColor.BLUE.index);//定義Excel資料顏色 richString.applyFont(font3); cell.setCellValue(richString); } catch (SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (NoSuchMethodException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } response.setContentType("application/octet-stream"); response.setHeader("Content-disposition", "attachment;filename=createList.xls");//預設Excel名稱 response.flushBuffer(); workbook.write(response.getOutputStream()); }
今天在生成excel檔案的時候遇到一個bug,那就是我們在查詢資料庫的時候得到一個集合,但是這個集合裡面有一些欄位不是我們需要的,比如id,status(狀態)等資訊,這些資訊我們不需要生成excel表格,然後讓客戶下載下來。那麼問題來了,我們就需要把把這些資料刪掉。
if (getMethodName.equals("getStatus")) { continue;//相當於清空了是資料 } if (getMethodName.equals("getResultId")) { continue;//相當於清空了是資料 }
然後我就把資料刪掉了,但是這樣的話還是會存在問題,因為資料雖然刪掉了,但是生成的列還存在
就如上圖一樣,我們的專案編號是空的,因為if (getMethodName.equals(“getResultId”)) {
continue;//相當於清空了是資料
}清空了資料但是,沒有刪除列
然後我嘗試了很多方法進行刪除列
比如:sheet.removeMergedRegion(getMergedRegionIndex(sheet, 1, 1));
但是這個方法getMergedRegionIndex缺少依賴,無法正常使用
又嘗試了另一種方法
//deleteColumn(sheet,0,1); private static void deleteColumn(HSSFSheet sheet, int columnStartIndex, int columnNum) { Util.shiftCellsLeft(sheet, 0, columnStartIndex + columnNum, sheet.getPhysicalNumberOfRows() - 1, sheet.getRow(0).getPhysicalNumberOfCells() - 1, columnNum, true); Util.shiftCellsLeft(sheet, 0, sheet.getRow(0).getPhysicalNumberOfCells(), sheet.getPhysicalNumberOfRows() - 1, sheet.getRow(0).getPhysicalNumberOfCells() + columnNum, columnNum, true); }
這種方法是可以刪除列的,但是本人比較笨,這個方法的原始碼有點不是很懂,原始碼如下:
public static void shiftCellsLeft(Sheet sheet, int startRow, int startCol, int endRow, int endCol, int shiftNumber, boolean removeSourceMergedRegion) {
Set mergedRegions = new HashSet();
for(int rowNum = startRow; rowNum <= endRow; ++rowNum) {
boolean doSetWidth = true;
Row row = sheet.getRow(rowNum);
if (row != null) {
for(int colNum = startCol; colNum <= endCol; ++colNum) {
Cell cell = row.getCell(colNum);
if (cell == null) {
cell = row.createCell(colNum);
doSetWidth = false;
}
int destColNum = colNum - shiftNumber;
Cell destCell = row.getCell(destColNum);
if (destCell == null) {
destCell = row.createCell(destColNum);
}
copyCell(cell, destCell, true);
updateMergedRegionInRow(sheet, mergedRegions, rowNum, colNum, destColNum, removeSourceMergedRegion);
if (doSetWidth) {
sheet.setColumnWidth(destCell.getColumnIndex(), getWidth(sheet, cell.getColumnIndex()));
}
}
}
}
}
最後資料是刪除了,但是刪除的結果不是我想要的,刪除結果如下圖
應該是引數的問題,或者是呼叫的方法放的位置不對
然後我想著既然我不能刪除列,那我在建立列的時候不建立對應的列不就行了嗎
HSSFCell cell = null;
if(!getMethodName.equals("getStatus")||!getMethodName.equals("getResultId"){
cell = row.createCell(i);
}
但是事與願違,它還是生成了對應的列,沒有辦法,我只能另尋出路了
最後我把實體類的順序更改了一下,就完成了這個功能
更改前的順序
更改後的順序,把resultId(get/set方法也放在後面)放到最後了,雖然還會生成空的resultId的列,但是這是在後面,對我們的結果沒有影響,這樣雖然沒有實現真正的刪除列,但是我們得到了資料又有什麼影響呢?
還有就是id那一列,通過一下方法,將資料存入進去就行了
value = getMethod.invoke(t, new Object[]{});
if (getMethodName.equals("getId")) {
cell.setCellValue(i+1);//如果是id列的話,直接將序號設定進去
}
最後,訪問網頁http://localhost:8081/file/downloadBooksExcel就可以了
下載的資料如下圖,大功告成