一、導出示例java
二、須要導入的包 poi 座標web
<!--核心jar包--> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>3.17</version> </dependency> <!--支持xlsx讀取--> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>3.17</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml-schemas</artifactId> <version>3.17</version> </dependency>
三、代碼spring
package com.anso.dma.common.util; import org.apache.commons.fileupload.disk.DiskFileItem; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.poi.ss.usermodel.*; import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.ss.util.RegionUtil; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.commons.CommonsMultipartFile; import java.io.OutputStream; import java.util.HashMap; import java.util.List; import java.util.Map; /** * 複合表頭的Excel導出工具類 * * @author liukun * @version 1.0 * @date 2020/2/18 20:22 */
public class ComplexExcelUtils {
/** * 導出(目前僅支持兩行表頭的合併操做) * @param realName 導出文件名 * @param data 導出數據 * @param fields 導出字段,好比 date|時間,firstHeader|表頭1,secondHeader|表頭2,sub001|編號-0001|子標題1,sub002|編號-0001|子標題2,sub003|編號-0001|子標題3,sub004|編號-0001|子標題4,remark|備註
* tips: 上述中的 date,firstHeader, ... ,remark 對應的是 data 導出數據中,數據的 key * @return */ public Integer export(String realName, List<Map<String, Object>> data, String fields) { String fileName = realName + DateUtils.getUserDate(DateUtils.yyyyMMdd_HHmmss) + ".xlsx";
// 這裏只是將生成的文件上傳,根據本身的需求,也能夠直接將文件返回 BaseResult baseResult = CommonClient.uploadFile(this.construct(fields, data, fileName)); if (null != baseResult && 0 == baseResult.getCode() ) { return Integer.parseInt(String.valueOf(baseResult.getData())); } throw new ServiceException(baseResult.getCode(),baseResult.getMessage()); } /** * 建立生成 excel 文檔 * @param fields 導出字段 * @param data 導出數據 * @param fileName 導出文檔名稱 * @return 生成的 excel 文檔 */ public MultipartFile construct(String fields, List<Map<String, Object>> data, String fileName) { Workbook workbook = new XSSFWorkbook(); Sheet sheet = workbook.createSheet(); CellStyle cellStyle = createCellStyle(workbook); Map<String, Integer> fieldOrder = getFieldOrder(fields); initHeader(sheet, cellStyle, fields); fillData(sheet, cellStyle, data, fieldOrder); DiskFileItem fileItem = (DiskFileItem)(new DiskFileItemFactory()).createItem("file", "text/plain", true, fileName); try { OutputStream os = fileItem.getOutputStream(); Throwable var8 = null; try { workbook.write(os); } catch (Throwable var18) { var8 = var18; throw var18; } finally { if (os != null) { if (var8 != null) { try { os.close(); } catch (Throwable var17) { var8.addSuppressed(var17); } } else { os.close(); } } } } catch (Exception var20) { throw new IllegalArgumentException("Invalid file: " + var20, var20); } return new CommonsMultipartFile(fileItem); } /** * 初始化表頭 * @param sheet sheet頁 * @param cellStyle 單元格樣式 * @param fields 導出字段 */ private void initHeader(Sheet sheet, CellStyle cellStyle, String fields) { // 構造表頭 Row row1 = sheet.createRow(0); Row row2 = sheet.createRow(1); String[] field = fields.split(","); // 上一個合併的表頭名稱 String preMergeName = null; // 合併的起止索引 int startIdx = 0,endIdx = -1; for (int i = 0; i < field.length; i++) { String[] f = field[i].split("\\|"); Cell c1 = row1.createCell(i); c1.setCellStyle(cellStyle); c1.setCellValue(f[1]); if (f.length > 2) { Cell c2 = row2.createCell(i); c2.setCellStyle(cellStyle); c2.setCellValue(f[f.length - 1]); if (preMergeName == null) { preMergeName = f[1]; startIdx = i; endIdx = startIdx; } else if (preMergeName.equals(f[1])){ endIdx++; } else { mergeRegion(sheet, 0, 0, startIdx, endIdx); preMergeName = f[1]; startIdx = i; endIdx = startIdx; } } else { mergeRegion(sheet, 0, 1, i, i); if (preMergeName != null) { mergeRegion(sheet, 0, 0, startIdx, endIdx); preMergeName = null; } } // 處理最後一次循環 if (i == field.length -1) { if (preMergeName != null) { mergeRegion(sheet, 0, 0, startIdx, endIdx); } } } } /** * 填充數據 * @param sheet sheet頁 * @param cellStyle 單元格樣式 * @param data 待填充的數據 * @param fieldOrder 字段填充順序 */ private void fillData(Sheet sheet, CellStyle cellStyle, List<Map<String, Object>> data, Map<String, Integer> fieldOrder) { for (int i = 0; i < data.size(); i++) { Row row = sheet.createRow(2 + i); data.get(i).forEach((key, value) -> { // 爲了保證只導出 fields 中的字段,這裏必須加這個判斷 if (fieldOrder.get(key) != null) { Cell cell = row.createCell(fieldOrder.get(key)); cell.setCellStyle(cellStyle); cell.setCellValue(String.valueOf(value == null ? "" : value)); } }); } } /** * 獲得字段的行索引 * @param fields 字段 * @return 字段索引map */ private Map<String, Integer> getFieldOrder(String fields) { Map<String, Integer> fieldOrder = new HashMap<>(16); String[] field = fields.split(","); for (int i = 0; i < field.length; ++i) { String[] f = field[i].split("\\|"); fieldOrder.put(f[0], i); } return fieldOrder; } /** * 建立自定義單元格樣式 * @param workbook 工做簿 */ private CellStyle createCellStyle(Workbook workbook) { // 爲單元格設置邊框線 CellStyle cellStyle = workbook.createCellStyle(); cellStyle.setBorderTop(BorderStyle.THIN); cellStyle.setBorderBottom(BorderStyle.THIN); cellStyle.setBorderLeft(BorderStyle.THIN); cellStyle.setBorderRight(BorderStyle.THIN); // 居中顯示 cellStyle.setAlignment(HorizontalAlignment.CENTER); cellStyle.setVerticalAlignment(VerticalAlignment.CENTER); return cellStyle; } /** * 合併區域 * @param sheet sheet頁 * @param firstRow 起始行 * @param lastRow 結束行 * @param firstCol 起始列 * @param lastCol 結束列 */ private void mergeRegion(Sheet sheet,int firstRow, int lastRow, int firstCol, int lastCol) { CellRangeAddress cra = new CellRangeAddress(firstRow, lastRow, firstCol, lastCol); sheet.addMergedRegion(cra); // 爲合併後的單元格添加邊框線 RegionUtil.setBorderTop(BorderStyle.THIN, cra, sheet); RegionUtil.setBorderBottom(BorderStyle.THIN, cra, sheet); RegionUtil.setBorderLeft(BorderStyle.THIN, cra, sheet); RegionUtil.setBorderRight(BorderStyle.THIN, cra, sheet); } }