Hutool excel導出


easyExcel 文檔不是很友好,所以轉用hutool 工具導出excel,百度到的很多都沒多少營養,略作總結,望君不吝賜教。
該篇博客可以讓你畫出不是太復雜的excel 如:


 
image.png

ps: 該篇文章為代碼畫excel,不介紹模板填充方式,因為模板填充較為簡單。

excel導出Hutool官方教程
excel導出Hutool api 地址
https://apidoc.gitee.com/loolly/hutool/cn/hutool/poi/excel/package-frame.html

版本依賴,項目中直接引入了hutool-all依賴包,其中包括了導出excel所需的所有依賴包

<dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.5.0</version> </dependency> 

api 中已經詳細寫了方法的說明,再此不多加闡述

1.字體樣式常用方法

    /** * 方法描述: 設置基礎字體樣式字體 這里保留最基礎的樣式使用 * * @param workbook 工作簿 * @param bold 是否粗體 * @param fontName 字體名稱 * @param fontSize 字體大小 * @return org.apache.poi.ss.usermodel.Font * @author wqf * @date 2021/5/19 15:58 */ public static Font setBaseFont(Workbook workbook, boolean bold, boolean italic, String fontName, int fontSize) { Font font = workbook.createFont(); //設置字體名稱 宋體 / 微軟雅黑 /等 font.setFontName(fontName); //設置是否斜體 font.setItalic(italic); //設置字體高度 //font.setFontHeight((short) fontHeight); //設置字體大小 以磅為單位 font.setFontHeightInPoints((short) fontSize); //設置是否加粗 font.setBold(bold); //默認字體顏色 // font.setColor(Font.COLOR_NORMAL); //紅色 //font.setColor(Font.COLOR_RED); //設置下划線樣式 //font.setUnderline(Font.ANSI_CHARSET); //設定文字刪除線 //font.setStrikeout(true); return font; } 
  1. 全局樣式設置
 private static StyleSet GlobalStyleSet(ExcelWriter writer, Workbook workbook,Font font) { //全局樣式設置 StyleSet styleSet = writer.getStyleSet(); CellStyle cellStyle = styleSet.getCellStyle(); //設置全局文本居中 styleSet.setAlign(HorizontalAlignment.CENTER, VerticalAlignment.CENTER); //設置全局字體樣式 styleSet.setFont(font); //設置背景顏色 第二個參數表示是否將樣式應用到頭部 styleSet.setBackgroundColor(IndexedColors.WHITE, true); //設置自動換行 當文本長於單元格寬度是否換行 styleSet.setWrapText(); // 設置全局邊框樣式 styleSet.setBorder(BorderStyle.THIN, IndexedColors.BLACK); return styleSet; } 
  1. 頭部標題樣式
//設置全局樣式 StyleSet styleSet = GlobalStyleSet(writer, workbook); //設置頭部標題樣式 CellStyle headCellStyle = styleSet.getHeadCellStyle(); //水平居中 headCellStyle.setAlignment(HorizontalAlignment.CENTER); //垂直居中 headCellStyle.setVerticalAlignment(VerticalAlignment.CENTER); //設置字體樣式 headCellStyle.setFont(setBaseFont(workbook, true, false, "宋體", 12)); writer.setStyleSet(styleSet); 
  1. 數字保留小數
    例:保留兩位小數
CellStyle cellStyleForNumber = styleSet.getCellStyleForNumber(); cellStyleForNumber.setDataFormat((short)2); 

5.時間格式化
例如格式為:YYYY/MM/dd 格式

CellStyle cellStyleForDate = styleSet.getCellStyleForDate(); //14 代表的時間格式是 yyyy/MM/dd cellStyleForDate.setDataFormat((short)14); 

時間格式占時只看到這一種格式常見些,像yyyy-MM-dd 格式都沒找到,就只有在寫入數據寫先處理下時間格式了。

  1. 行(Row)樣式
//獲取輸出構造器 設置工作簿名稱 ExcelWriter writer = ExcelUtil.getWriterWithSheet(sheetName); Workbook workbook = writer.getWorkbook(); Sheet sheet = writer.getSheet(); Row row = sheet.getRow(rowIndex); if(sheet.getRow(rowIndex )==null){ //rowIndex 表示的是第幾行,例:創建第二行,rowIndex=1 sheet.createRow(rowIndex ); } //創建樣式 CellStyle cellStyle = workbook.createCellStyle(); cellStyle .setVerticalAlignment(VerticalAlignment.CENTER); cellStyle .setAlignment(HorizontalAlignment.LEFT); cellStyle .setFont(setBaseFont(workbook, true, false, "宋體", 12)); cellStyle .setBorderBottom(BorderStyle.THIN); cellStyle .setBorderLeft(BorderStyle.THIN); cellStyle .setBorderRight(BorderStyle.THIN); cellStyle .setBorderTop(BorderStyle.THIN); //應用樣式到某一行( row .setRowStyle(cellStyle ); //應用樣式到某一行 (或者這樣寫) rowIndex 表示的是第幾行 //writer.setRowStyle(rowIndex ,cellStyle ); 
  1. 單元格(Cell)樣式
Row row = sheet.getRow(rowIndex); if(sheet.getRow(rowIndex )==null){ //rowIndex 表示的是第幾行,例:創建第二行,rowIndex=1 sheet.createRow(rowIndex ); } //創建本行的第幾個單元格 cellIndex=0 表示第一個 if(row.get(cellIndex)==null){ row .createCell(cellIndex); } //創建樣式 CellStyle cellStyle = workbook.createCellStyle(); cellStyle .setVerticalAlignment(VerticalAlignment.CENTER); cellStyle .setAlignment(HorizontalAlignment.LEFT); cellStyle .setFont(setBaseFont(workbook, true, false, "宋體", 12)); cellStyle .setBorderBottom(BorderStyle.THIN); cellStyle .setBorderLeft(BorderStyle.THIN); cellStyle .setBorderRight(BorderStyle.THIN); cellStyle .setBorderTop(BorderStyle.THIN); //應用樣式到某一行( row .setRowStyle(cellStyle ); //應用樣式到某一行 (或者這樣寫) rowIndex 表示的是第幾行 //writer.setRowStyle(rowIndex ,cellStyle ); 
  1. 合並單元格
    //處理標題行 合並某行的單元格,並寫入對象到單元格,如果寫到單元格中的內容非null,行號自動+1,否則當前行號不變
//主要有兩種方式 1. writer.merge(cellIndex, content, true); 表示當前行 合並從第一個單元到cellIndex+1個單元,並填充內容content,第三個參數表示是否將頭部標題樣式應用到這里。 或者 2.writer.merge(startRowIndex,endRowIndex, startCellIndex, endCellIndex, content, false); 表示和並第startRowIndex+1行到endRowIndex+1行 ,並合並從第endCellIndex+1個單元到endCellIndex+1個單元格,並填充content內容,最后一個字段表示是否將頭部標題樣式應用到這里。 
  1. 列表別名
//LinkedHashMap 中的數據是根據put先后順序來的,HashMap數據時無序的。 //使用方法 writer.setHeaderAlias(headerAlias); 時如果使用HashMap 可能展示的數 //據順序會錯亂 Map<String, String> headerAlias = new LinkedHashMap<>(); headerAlias.put(字段名1, 列名1); headerAlias.put(字段名2, 列名2); headerAlias.put(字段名3, 列名3); headerAlias.put(字段名4, 列名4); headerAlias.put(字段名5, 列名5); writer.setHeaderAlias(headerAlias); //或者一項一項設置列的別名 列別名順序會跟代碼中addHeaderAlias順序一致 writer.addHeaderAlias(字段名1,列名1); writer.addHeaderAlias(字段名2,列名2); 
  1. 列寬問題
    8.1 自動列寬 百度查到一個方法有用 ,但實際好像還是會有點問題,大家可以先試試
    博客鏈接 :https://blog.csdn.net/kongbai953/article/details/110382544
/** * 自適應寬度(中文支持) * @param sheet * @param size 因為for循環從0開始,size值為 列數-1 */ public static void setSizeColumn(Sheet sheet, int size) { for (int columnNum = 0; columnNum <= size; columnNum++) { int columnWidth = sheet.getColumnWidth(columnNum) / 256; for (int rowNum = 0; rowNum <= sheet.getLastRowNum(); rowNum++) { Row currentRow; //當前行未被使用過 if (sheet.getRow(rowNum) == null) { currentRow = sheet.createRow(rowNum); } else { currentRow = sheet.getRow(rowNum); } if (currentRow.getCell(columnNum) != null) { Cell currentCell = currentRow.getCell(columnNum); if (currentCell.getCellType() == XSSFCell.CELL_TYPE_STRING) { int length = currentCell.getStringCellValue().getBytes().length; if (columnWidth < length) { columnWidth = length; } } } } sheet.setColumnWidth(columnNum, columnWidth * 256); } } 

8.2 手動列寬設置

//表示 第一列的列寬是15 writer.setColumnWidth(0, 15); 
  1. 另外常用方法

//跳過當前行 即當前行不寫內容

writer.passCurrentRow(); 

//定位到最后一行,常用於在末尾追加數據

writer.setCurrentRowToEnd(); 

10 . 下載excel代碼 在數據都填充完成后,調用該方法即可

 /** * 方法描述: 下載excel文件 * * @param response 響應 * @param fileName 文件名稱 * @param writer writer * @return void * @author wqf * @date 2021/5/24 16:20 */ private static void downloadExcel(HttpServletResponse response, String fileName, ExcelWriter writer) { response.setContentType("application/vnd.ms-excel;charset=utf-8"); // test.xls是彈出下載對話框的文件名,不能為中文,中文請自行編碼 ServletOutputStream out = null; try { // 設置請求頭屬性 response.setHeader("Content-Disposition", "attachment;filename=" + new String((fileName + ".xlsx").getBytes(), StandardCharsets.ISO_8859_1)); out = response.getOutputStream(); // 寫出到文件 writer.flush(out, true); // 關閉writer,釋放內存 writer.close(); // 此處記得關閉輸出Servlet流 IoUtil.close(out); } catch (IOException e) { log.error(e.getMessage()); e.printStackTrace(); } } 
  1. excel 添加下拉框
CellRangeAddressList addressList = new CellRangeAddressList(2, 2, 5, 5); DataValidationHelper helper = sheet.getDataValidationHelper(); // 設置下拉框數據 String[] str = new String[]{"男", "女","陰陽人"}; DataValidationConstraint constraint = helper.createExplicitListConstraint(str); DataValidation dataValidation = helper.createValidation(constraint, addressList); writer.addValidationData(dataValidation); 

12.背景色填充

//示例:將單元格背景填充為黃色 short index = IndexedColors.YELLOW.index; cellStyle.setFillForegroundColor(index); cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); 

總結 : 整合了一個工具類,僅作參考

/** * @Author: wqf * @Date: 2021/05/28 * @Description: hutool 工具導出excel(非填充模板,手工畫) */ @Slf4j public class HutoolExcelUtil { /** * YYYY/MM/dd 時間格式 */ private static final short LOCAL_DATE_FORMAT_SLASH = 14; /** * 方法描述: 創建excel * * @param isXlsx excel文件類型 true-xlsx/false-xls * @return cn.hutool.poi.excel.ExcelWriter * @author wqf * @date 2021/6/1 9:47 */ public static ExcelWriter createExcel(boolean isXlsx) { return ExcelUtil.getWriter(isXlsx); } /** * 方法描述: 全局基礎樣式設置 * 默認 全局水平居中+垂直居中 * 默認 自動換行 * 默認單元格邊框顏色為黑色,細線條 * 默認背景顏色為白色 * * @param writer writer * @param font 字體樣式 * @return cn.hutool.poi.excel.StyleSet * @author wqf * @date 2021/5/28 10:43 */ public static StyleSet setBaseGlobalStyle(ExcelWriter writer, Font font) { //全局樣式設置 StyleSet styleSet = writer.getStyleSet(); //設置全局文本居中 styleSet.setAlign(HorizontalAlignment.CENTER, VerticalAlignment.CENTER); //設置全局字體樣式 styleSet.setFont(font, true); //設置背景顏色 第二個參數表示是否將樣式應用到頭部 styleSet.setBackgroundColor(IndexedColors.WHITE, true); //設置自動換行 當文本長於單元格寬度是否換行 //styleSet.setWrapText(); // 設置全局邊框樣式 styleSet.setBorder(BorderStyle.THIN, IndexedColors.BLACK); return styleSet; } /** * 方法描述: 設置標題的基礎樣式 * * @param styleSet StyleSet * @param font 字體樣式 * @param horizontalAlignment 水平排列方式 * @param verticalAlignment 垂直排列方式 * @return org.apache.poi.ss.usermodel.CellStyle * @author wqf * @date 2021/5/28 10:16 */ public static CellStyle createHeadCellStyle(StyleSet styleSet, Font font, HorizontalAlignment horizontalAlignment, VerticalAlignment verticalAlignment) { CellStyle headCellStyle = styleSet.getHeadCellStyle(); headCellStyle.setAlignment(horizontalAlignment); headCellStyle.setVerticalAlignment(verticalAlignment); headCellStyle.setFont(font); return headCellStyle; } /** * 方法描述: 設置基礎字體樣式字體 這里保留最基礎的樣式使用 * * @param bold 是否粗體 * @param fontName 字體名稱 * @param fontSize 字體大小 * @return org.apache.poi.ss.usermodel.Font * @author wqf * @date 2021/5/19 15:58 */ public static Font createFont(ExcelWriter writer, boolean bold, boolean italic, String fontName, int fontSize) { Font font = writer.getWorkbook().createFont(); //設置字體名稱 宋體 / 微軟雅黑 /等 font.setFontName(fontName); //設置是否斜體 font.setItalic(italic); //設置字體大小 以磅為單位 font.setFontHeightInPoints((short) fontSize); //設置是否加粗 font.setBold(bold); return font; } /** * 方法描述: 設置行或單元格基本樣式 * * @param writer writer * @param font 字體樣式 * @param verticalAlignment 垂直居中 * @param horizontalAlignment 水平居中 * @return void * @author wqf * @date 2021/5/28 10:28 */ public static CellStyle createCellStyle(ExcelWriter writer, Font font, boolean wrapText, VerticalAlignment verticalAlignment, HorizontalAlignment horizontalAlignment) { CellStyle cellStyle = writer.getWorkbook().createCellStyle(); cellStyle.setVerticalAlignment(verticalAlignment); cellStyle.setAlignment(horizontalAlignment); cellStyle.setWrapText(wrapText); cellStyle.setFont(font); return cellStyle; } /** * 方法描述: 設置邊框樣式 * * @param cellStyle 樣式對象 * @param bottom 下邊框 * @param left 左邊框 * @param right 右邊框 * @param top 上邊框 * @return void * @author wqf * @date 2021/5/28 10:23 */ public static void setBorderStyle(CellStyle cellStyle, BorderStyle bottom, BorderStyle left, BorderStyle right, BorderStyle top) { cellStyle.setBorderBottom(bottom); cellStyle.setBorderLeft(left); cellStyle.setBorderRight(right); cellStyle.setBorderTop(top); } /** * 方法描述: 獲取對象需要導出的列和別名 這里按字段順序來(可以在自定義注解上添加屬性標識字段順序,重寫方法) * 在需要導出的字段上貼上注解 這里是@ExcelProperty,也可以用自定義注解 * 注解需要有value 標識別名 order 標識字段順序 * * @param clazz 對象類型 * @return int 導出的字段個數 * @author wqf * @date 2021/4/29 16:56 */ public static int setHeaderAlias(ExcelWriter writer, Class<?> clazz) { //需要導出的字段數 Field[] fields = clazz.getDeclaredFields(); TreeMap<Integer, Map<String, String>> headerAliasMap = new TreeMap<>(); Arrays.stream(fields).forEach(f -> { if (f.isAnnotationPresent(ExcelProperty.class)) { ExcelProperty annotation = f.getAnnotation(ExcelProperty.class); //別名 String[] value = annotation.value(); int order = annotation.order(); Map<String, String> alisMap = new HashMap<>(); String fieldName = f.getName(); //字段名 String headerAlias = value[0]; alisMap.put(fieldName, headerAlias); headerAliasMap.put(order, alisMap); } }); LinkedHashMap<String, String> linkedMap = new LinkedHashMap<>(); for (Map.Entry<Integer, Map<String, String>> entry : headerAliasMap.entrySet()) { linkedMap.putAll(entry.getValue()); } writer.setHeaderAlias(linkedMap); return linkedMap.size(); } /** * 方法描述: 自適應寬度(中文支持) * * @param sheet 頁 * @param size 因為for循環從0開始,size值為 列數-1 * @return void * @author wqf * @date 2021/5/28 14:06 */ public static void setSizeColumn(Sheet sheet, int size) { for (int columnNum = 0; columnNum <= size; columnNum++) { int columnWidth = sheet.getColumnWidth(columnNum) / 256; for (int rowNum = 0; rowNum <= sheet.getLastRowNum(); rowNum++) { Row currentRow; //當前行未被使用過 if (sheet.getRow(rowNum) == null) { currentRow = sheet.createRow(rowNum); } else { currentRow = sheet.getRow(rowNum); } if (currentRow.getCell(columnNum) != null) { Cell currentCell = currentRow.getCell(columnNum); if (currentCell.getCellType() == CellType.STRING) { int length = currentCell.getStringCellValue().getBytes().length; if (columnWidth < length) { columnWidth = length; } } } } sheet.setColumnWidth(columnNum, columnWidth * 256); } } /** * 方法描述: excel 導出下載 * * @param response 響應 * @param fileName 文件名 * @param writer writer * @return void * @author wqf * @date 2021/6/1 11:11 */ public static void downloadExcel(HttpServletResponse response, String fileName, ExcelWriter writer) { response.setContentType("application/vnd.ms-excel;charset=utf-8"); // test.xls是彈出下載對話框的文件名,不能為中文,中文請自行編碼 ServletOutputStream out = null; try { // 設置請求頭屬性 response.setHeader("Content-Disposition", "attachment;filename=" + new String((fileName + ".xlsx").getBytes(), StandardCharsets.ISO_8859_1)); out = response.getOutputStream(); // 寫出到文件 writer.flush(out, true); // 關閉writer,釋放內存 writer.close(); // 此處記得關閉輸出Servlet流 IoUtil.close(out); } catch (IOException e) { log.info("文件下載失敗==" + e); } } /** * 方法描述: 最簡單的導出,直接將數據放到excel * 導入的數據最好是List<map>格式數據,主要原因是List<Object> , * 對象有字段是LocalDate或者是LocalDateTime類型的數據, * 時間格式化可能達不到想要的效果 * * @param data 對象集合 兩種 * @param globalFont 全局字體樣式 * @param clazz 導出的對應class類型 * @return void * @author wqf * @date 2021/5/28 11:22 */ public static ExcelWriter exportBaseExcel(ExcelWriter writer, List<?> data, Font globalFont, Class clazz) { Sheet sheet = writer.getSheet(); writer.setStyleSet(setBaseGlobalStyle(writer, globalFont)); int columnSize = setHeaderAlias(writer, clazz); writer.setOnlyAlias(true); writer.write(data); setSizeColumn(sheet, columnSize); return writer; } } 
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM