這里使用的是 springboot 項目
導入 easypoi 的 starter
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-spring-boot-starter</artifactId>
<version>4.0.0</version>
</dependency>
// 用於校驗 excel 字段
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
ExcelPoiUtil 工具類
/**
* @author sunhw
* @date 2021/5/29
*/
@Slf4j
public class EasyPoiUtil {
/**
* 構建 sheet
*
* @param sheetName sheet 名字
* @param clazz clazz
* @param list 列表
* @return {@link Map<String, Object>}
*/
public static Map<String, Object> buildSheet(String sheetName, Class<?> clazz, List<?> list) {
ExportParams exportParams = new ExportParams();
exportParams.setType(ExcelType.XSSF);
exportParams.setSheetName(sheetName);
// 導出樣式
exportParams.setStyle(EasyPoiExcelStyleUtil.class);
Map<String, Object> map = new HashMap<>(4);
// title的參數為ExportParams類型
map.put("title", exportParams);
// 模版導出對應得實體類型
map.put("entity", clazz);
// sheet中要填充得數據
map.put("data", list);
return map;
}
/**
* 下載 excel
*
* 前端如果用xlsx格式接收表格 后台用XSSFWorkbook workbook = new XSSFWorkbook();創建工作薄
* response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
* response.addHeader("Content-Disposition", "attachment;filename=fileName" + ".xlsx");
*
* 前端如果用用xls格式接收表格 后台 用HSSFWorkbook workbook = new HSSFWorkbook();創建工作薄
* response.setContentType("application/vnd.ms-excel");
* response.addHeader("Content-Disposition", "attachment;filename=fileName"+".xls");
*
* @param fileName 文件名稱
* @param response 響應
* @param workbook 工作簿
*/
public static void downLoadExcel(String fileName, HttpServletResponse response, Workbook workbook) {
try {
response.setCharacterEncoding("UTF-8");
response.setHeader("Access-Control-Expose-Headers",
"Content-Disposition");
response.setHeader("content-Type", "application/vnd.ms-excel");
response.setHeader("Content-Disposition", "attachment;filename="
+ URLEncoder.encode(fileName + ".xlsx", "UTF-8"));
workbook.write(response.getOutputStream());
} catch (IOException e) {
log.info("文件下載失敗", e);
throw new RuntimeException(e);
}
}
/**
* 功能描述:根據接收的Excel文件來導入Excel,並封裝成實體類
*
* @param file 文件
* @param sheetNum 第幾個 sheet
* @param titleRows title 行數
* @param headerRows 標題 行數
* @param pojoClass pojo類
* @return {@link List<T>}
*/
public static <T> List<T> importExcel(MultipartFile file, Integer sheetNum, Integer titleRows, Integer headerRows, Class<T> pojoClass) {
if (Objects.isNull(file)) {
return Collections.emptyList();
}
ImportParams params = new ImportParams();
params.setStartSheetIndex(sheetNum);
params.setTitleRows(titleRows);
params.setHeadRows(headerRows);
List<T> list = null;
try {
list = ExcelImportUtil.importExcel(file.getInputStream(), pojoClass,
params);
} catch (NoSuchElementException e) {
throw new RuntimeException("excel文件不能為空");
} catch (Exception e) {
throw new RuntimeException(e.getMessage());
}
return list;
}
/**
* 功能描述:根據接收的 Excel 文件來導入 Excel,並封裝成 Map
*
* @param file 文件
* @param sheetNum 第幾個 sheet
* @param titleRows title 行數
* @param headerRows 標題 行數
* @return {@link List<T>}
*/
public static <T> List<T> parseExcelMap(MultipartFile file, Integer sheetNum, Integer titleRows, Integer headerRows) {
if (Objects.isNull(file)) {
return Collections.emptyList();
}
ImportParams params = new ImportParams();
params.setStartSheetIndex(sheetNum);
params.setTitleRows(titleRows);
params.setHeadRows(headerRows);
params.setNeedCheckOrder(true);
List<T> list = null;
try {
list = ExcelImportUtil.importExcel(file.getInputStream(), Map.class,
params);
} catch (NoSuchElementException e) {
throw new RuntimeException("excel文件不能為空");
} catch (Exception e) {
log.info("excel 文件讀取失敗", e);
throw new RuntimeException("文件讀取失敗");
}
return list;
}
/**
* 得到 Workbook 對象
*
* @param file
* @return
* @throws IOException
*/
public static Workbook getWorkBook(MultipartFile file) throws IOException {
//這樣寫 excel 能兼容03和07
InputStream is = file.getInputStream();
Workbook hssfWorkbook = null;
try {
hssfWorkbook = new HSSFWorkbook(is);
} catch (Exception ex) {
is = file.getInputStream();
hssfWorkbook = new XSSFWorkbook(is);
}
return hssfWorkbook;
}
/**
* 檢查excel
*
* @param file 文件
* @param sheetNum 第幾個 sheet
* @param titleRows title 所占行數
* @param headerRows head 所占行數
* @param clazz clazz
* @return {@link ExcelImportResult<T>}
*/
public static <T> ExcelImportResult<T> checkExcel(MultipartFile file, Integer sheetNum, Integer titleRows, Integer headerRows, Class<T> clazz) {
if (Objects.isNull(file)) {
return new ExcelImportResult<>();
}
ImportParams params = new ImportParams();
params.setStartSheetIndex(sheetNum);
params.setTitleRows(titleRows);
params.setHeadRows(headerRows);
// 開啟校驗
params.setNeedVerify(true);
ExcelImportResult<T> result = null;
try {
result = ExcelImportUtil.importExcelMore(
file.getInputStream(), clazz, params);
} catch (NoSuchElementException e) {
throw new RuntimeException("excel文件不能為空");
} catch (Exception e) {
log.info("excel 文件讀取失敗", e);
throw new RuntimeException("文件讀取失敗");
}
return result;
}
}
測試 VO 實體類
@Data
public class CreditDebt implements Serializable, IExcelDataModel, IExcelModel {
private static final long serialVersionUID = 1L;
@Excel(name = "債券代碼")
@NotBlank(message = "債券代碼不可為空")
private String bondCode;
/**
* 行號
*/
private int rowNum;
/**
* 錯誤消息
*/
private String errorMsg;
}
@Data
public class IndustryInfo implements Serializable, IExcelDataModel, IExcelModel {
private static final long serialVersionUID = 1L;
@Excel(name = "行業")
@NotBlank(message = "行業名稱不可為空")
private String industry;
@Excel(name = "行業整體評級")
@NotBlank(message = "行業整體評級不可為空")
@Pattern(regexp = "^優秀|良好$")
private String industryGood;
/**
* 行號
*/
private int rowNum;
/**
* 錯誤消息
*/
private String errorMsg;
}
ExcelController Demo
/**
* @author sunhw
* @date 2021/5/28 使用 ExcelPoi 進行 Excel 的導出
*/
@RestController
@RequestMapping("/excel")
public class ExcelController {
/**
* 多 sheet 導出
*/
@GetMapping("/download")
public void download(HttpServletResponse response) {
Map<String, Object> creditSheet = EasyPoiUtil.buildSheet("信用債",
CreditDebt.class, Collections.EMPTY_LIST);
Map<String, Object> industrySheet = EasyPoiUtil.buildSheet("行業",
IndustryInfo.class, Collections.EMPTY_LIST);
List<Map<String, Object>> sheetsList = new ArrayList<>();
sheetsList.add(creditSheet);
sheetsList.add(industrySheet);
Workbook workBook = ExcelExportUtil.exportExcel(sheetsList, ExcelType.XSSF);
EasyPoiUtil.downLoadExcel("資產類型", response, workBook);
}
/**
* 解析 excel 實體類
*
* @param file 文件
*/
@GetMapping("/parse")
public String parse(@RequestParam("file") MultipartFile file) throws IOException {
String fileType = FileTypeUtil.getFileType(file);
if (!FileTypeUtil.isAllowedTypes(fileType)) {
return "文件格式不支持";
}
List<CreditDebt> creditDebtList = EasyPoiUtil.importExcel(file,
0, 0, 1, CreditDebt.class);
List<IndustryInfo> industryInfoList = EasyPoiUtil.importExcel(file,
1, 0, 1, IndustryInfo.class);
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.writeValueAsString(creditDebtList);
}
/**
* 解析 excel Map結構
*
* @param file 文件
*/
@GetMapping("/parseMap")
public String parseMap(@RequestParam("file") MultipartFile file) throws IOException {
String fileType = FileTypeUtil.getFileType(file);
if (!FileTypeUtil.isAllowedTypes(fileType)) {
return "文件格式不支持";
}
List<List<Object>> excelInfoList = new ArrayList<>();
Workbook workbook = EasyPoiUtil.getWorkBook(file);
int sheetNum = workbook.getNumberOfSheets();
for (int i = 0; i < sheetNum; i++) {
excelInfoList.add(EasyPoiUtil.parseExcelMap(file, i, 0, 1));
}
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.writeValueAsString(excelInfoList);
}
/**
* 校驗 excel
*
* @param file 文件
* @return {@link String}
*/
@GetMapping("/check")
public String check(@RequestParam("file") MultipartFile file) throws Exception {
String fileType = FileTypeUtil.getFileType(file);
if (!FileTypeUtil.isAllowedTypes(fileType)) {
return "文件格式不支持";
}
ExcelImportResult<CreditDebt> result = EasyPoiUtil.checkExcel(file, 0, 0, 1, CreditDebt.class);
ExcelImportResult<IndustryInfo> result2= EasyPoiUtil.checkExcel(file, 1, 0, 1, IndustryInfo.class);
ObjectMapper objectMapper = new ObjectMapper();
System.out.println("是否校驗失敗: " + result.isVerfiyFail());
System.out.println("校驗失敗的集合:" + objectMapper.writeValueAsString(result.getFailList()));
System.out.println("校驗通過的集合:" + objectMapper.writeValueAsString(result.getList()));
System.out.println("是否校驗失敗: " + result2.isVerfiyFail());
System.out.println("校驗失敗的集合:" + objectMapper.writeValueAsString(result2.getFailList()));
System.out.println("校驗通過的集合:" + objectMapper.writeValueAsString(result2.getList()));
for (CreditDebt entity : result.getFailList()) {
String msg = "第" + entity.getRowNum() + "行的錯誤是:" + entity.getErrorMsg();
System.out.println(msg);
}
for (IndustryInfo entity : result2.getFailList()) {
String msg = "第" + entity.getRowNum() + "行的錯誤是:" + entity.getErrorMsg();
System.out.println(msg);
}
return "false";
}
}
調整 Excel 樣式的工具類
/**
* excel風格
*
* @author sunhw
* @date 2021/05/29
*/
public class EasyPoiExcelStyleUtil implements IExcelExportStyler {
private static final short STRING_FORMAT = (short) BuiltinFormats.getBuiltinFormat("TEXT");
private static final short FONT_SIZE_TEN = 9;
private static final short FONT_SIZE_ELEVEN = 10;
private static final short FONT_SIZE_TWELVE = 11;
/**
* 大標題樣式
*/
private CellStyle headerStyle;
/**
* 每列標題樣式
*/
private CellStyle titleStyle;
/**
* 數據行樣式
*/
private CellStyle styles;
public EasyPoiExcelStyleUtil(Workbook workbook) {
this.init(workbook);
}
/**
* 初始化樣式
*
* @param workbook
*/
private void init(Workbook workbook) {
this.headerStyle = initHeaderStyle(workbook);
this.titleStyle = initTitleStyle(workbook);
this.styles = initStyles(workbook);
}
/**
* 大標題樣式
*
* @param color
* @return
*/
@Override
public CellStyle getHeaderStyle(short color) {
return headerStyle;
}
/**
* 每列標題樣式
*
* @param color
* @return
*/
@Override
public CellStyle getTitleStyle(short color) {
return titleStyle;
}
/**
* 數據行樣式
*
* @param parity 可以用來表示奇偶行
* @param entity 數據內容
* @return 樣式
*/
@Override
public CellStyle getStyles(boolean parity, ExcelExportEntity entity) {
return styles;
}
/**
* 獲取樣式方法
*
* @param dataRow 數據行
* @param obj 對象
* @param data 數據
*/
@Override
public CellStyle getStyles(Cell cell, int dataRow, ExcelExportEntity entity, Object obj, Object data) {
return getStyles(true, entity);
}
/**
* 模板使用的樣式設置
*/
@Override
public CellStyle getTemplateStyles(boolean isSingle, ExcelForEachParams excelForEachParams) {
return null;
}
/**
* 初始化--大標題樣式
*
* @param workbook
* @return
*/
private CellStyle initHeaderStyle(Workbook workbook) {
CellStyle style = getBaseCellStyle(workbook);
style.setFont(getFont(workbook, FONT_SIZE_TWELVE, true));
return style;
}
/**
* 初始化--每列標題樣式
*
* @param workbook
* @return
*/
private CellStyle initTitleStyle(Workbook workbook) {
CellStyle style = getBaseCellStyle(workbook);
style.setFont(getFont(workbook, FONT_SIZE_ELEVEN, false));
//背景色
style.setFillForegroundColor(IndexedColors.WHITE1.getIndex());
style.setFillPattern(FillPatternType.NO_FILL);
return style;
}
/**
* 初始化--數據行樣式
*
* @param workbook
* @return
*/
private CellStyle initStyles(Workbook workbook) {
CellStyle style = getBaseCellStyle(workbook);
style.setFont(getFont(workbook, FONT_SIZE_TEN, false));
style.setDataFormat(STRING_FORMAT);
return style;
}
/**
* 基礎樣式
*
* @return
*/
private CellStyle getBaseCellStyle(Workbook workbook) {
CellStyle style = workbook.createCellStyle();
//下邊框
style.setBorderBottom(BorderStyle.THIN);
//左邊框
style.setBorderLeft(BorderStyle.THIN);
//上邊框
style.setBorderTop(BorderStyle.THIN);
//右邊框
style.setBorderRight(BorderStyle.THIN);
//水平居中
style.setAlignment(HorizontalAlignment.CENTER);
//上下居中
style.setVerticalAlignment(VerticalAlignment.CENTER);
//設置自動換行
style.setWrapText(false);
return style;
}
/**
* 字體樣式
*
* @param size 字體大小
* @param isBold 是否加粗
* @return
*/
private Font getFont(Workbook workbook, short size, boolean isBold) {
Font font = workbook.createFont();
//字體樣式
font.setFontName("宋體");
//是否加粗
font.setBold(isBold);
//字體大小
font.setFontHeightInPoints(size);
return font;
}
}
參考鏈接: