java处理excel表格常用的框架库有: jxl
,POI
, EasyExcel
,EasyPoi
, hutool
。
最主要还是POI, 后三个都依赖于它。由于工作中项目重点使用阿里的EasyExcel
,以下重点介绍EasyExcel
以一个进销存表格为例子,演示EasyExcel如何导入导出Excel。下面是Excel模板实体,需要先导入pom依赖
@Data
public class InventoryItem {
@ExcelIgnore
private Integer id;
@ExcelProperty(index = 0, value = {"序号", "序号"})
private String no;
@ExcelProperty(index = 1, value = { "商品名称","商品名称"})
private String productName;
@ExcelProperty(index = 2, value = {"规格", "规格"})
private String spec;
@ExcelProperty(index = 3, value = {"单位", "单位"})
private String unit;
@ExcelProperty(index = 4, value = {"上月结存","数量"})
private String lastMonthStoreNum;
@ExcelProperty(index = 5, value = {"上月结存","单价"})
private String lastMonthStoreUnitPrice;
@ExcelProperty(index = 6, value = {"上月结存","金额"})
private String lastMonthStoreMount;
@ExcelProperty(index = 7, value = {"本月购入","数量"})
private String thisMonthPurchaseNum;
@ExcelProperty(index = 8, value = {"本月购入","单价"})
private String thisMonthPurchaseUnitPrice;
@ExcelProperty(index = 9, value = {"本月购入","金额"})
private String thisMonthPurchaseMount;
@ExcelProperty(index = 10, value = {"本月发出","数量"})
private String thisMonthSendNum;
@ExcelProperty(index = 11, value = {"本月发出","单价"})
private String thisMonthSendUnitPrice;
@ExcelProperty(index = 12, value = {"本月发出","金额"})
private String thisMontSendhMount;
@ExcelProperty(index = 13, value = {"本月结存","数量"})
private String thisMonthStoreNum;
@ExcelProperty(index = 14, value = {"本月结存","单价"})
private String thisMonthStoreUnitPrice;
@ExcelProperty(index = 15, value = {"本月结存","金额"})
private String thisMonthStoreMount;
@ExcelProperty(index = 16, value = {"月末盘点数量", "月末盘点数量"})
private String endOfMonthCheckNum;
@ExcelProperty(index = 17, value = {"差额", "差额"})
private String diff;
}
<dependency>
<groupId>com.alibabagroupId>
<artifactId>easyexcelartifactId>
<version>2.2.3version>
dependency>
读取Excel需要设置监听器
public class InventoryItemAnalysis extends AnalysisEventListener<InventoryItem> {
List<InventoryItem> list = new ArrayList<>();
@Override
public void invoke(InventoryItem data, AnalysisContext context) {
list.add(data);
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
}
public List<InventoryItem> getList() {
return list;
}
public void setOtnList(List<InventoryItem> list) {
this.list = list;
}
}
本地环境可以根据文件路径读取
InventoryItemAnalysis analysis = new InventoryItemAnalysis();
EasyExcel.read("C:\\Users\\root\\Desktop\\进销存.xlsx", InventoryItem.class, analysis ).sheet().doRead();
System.out.println(analysis.getList());
在web环境下可以用流读取
@PostMapping("/upload")
@ResponseBody
public Object excelImport(@RequestParam("uploadFile") MultipartFile file
) throws Exception {
InventoryItemAnalysis analysis = new InventoryItemAnalysis();
EasyExcel.read(file.getInputStream(), InventoryItem.class, analysis).sheet().doRead();
return analysis.getList();
}
本地导出
EasyExcel.write("C:\\Users\\root\\Desktop\\进销存导出.xlsx", InventoryItem.class).sheet().doWrite(analysis.getList());
web导出
@GetMapping("/download")
public void download(HttpServletResponse response) {
String fileName = "进销存数据.xlsx";
List<InventoryItem> list = new ArrayList<>();
setResponseHeader(response, fileName);
try {
EasyExcel.write(response.getOutputStream(), InventoryItem.class)
.sheet("总表").doWrite(list);
} catch (IOException e) {
e.printStackTrace();
}
}
private void setResponseHeader(HttpServletResponse response, String fileName) {
try {
response.setContentType("application/octet-stream;charset=ISO8859-1");
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName,"UTF-8"));
response.addHeader("Pargam", "no-cache");
response.addHeader("Cache-Control", "no-cache");
} catch (Exception ex) {
ex.printStackTrace();
}
}
EasyExcel默认样式不美观,需要自定义样式。EasyExcel提供一个类HorizontalCellStyleStrategy
,可用来配置一些表头和内容样式。
public static WriteHandler headStyle() {
// 头部样式策略
WriteCellStyle headWriteCellStyle = new WriteCellStyle();
headWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE1.getIndex());
WriteFont headWriteFont = new WriteFont();
headWriteFont.setFontHeightInPoints((short) 12);
headWriteFont.setBold(false);
headWriteCellStyle.setWriteFont(headWriteFont);
// 内容样式策略
WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
contentWriteCellStyle.setWrapped(true);
contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
// 设置内容边框样式
contentWriteCellStyle.setBorderLeft(THIN);
contentWriteCellStyle.setBorderTop(THIN);
contentWriteCellStyle.setBorderRight(THIN);
contentWriteCellStyle.setBorderBottom(THIN);
HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(headWriteCellStyle,
contentWriteCellStyle);
return horizontalCellStyleStrategy;
}
更细粒度控制可以通过实现com.alibaba.excel.write.handler.WriteHandler
的四个子接口来自定义样式或者内容。注意:多个Handler如果作用在同一个单元格,后面会覆盖前面的样式。
com.alibaba.excel.write.handler.CellWriteHandler
单元格处理器
beforeCellCreate
afterCellCreate
afterCellDataConverted
一个单元格数据转换后afterCellDispose
一个单元格所有操作完成后调用这个方法com.alibaba.excel.write.handler.RowWriteHandler
行处理器
beforeRowCreate
afterRowCreate
afterRowDispose
一行所有操作完成后调用这个方法com.alibaba.excel.write.handler.SheetWriteHandler
Sheet处理器
beforeSheetCreateSheet
afterSheetCreateSheet
com.alibaba.excel.write.handler.WorkbookWriteHandler
工作簿处理器
beforeWorkbookCreate
afterWorkbookCreate
afterWorkbookDispose
工作簿所有操作完成后调用这个方法自定义案例
案例1:在表格表头前添加标题等信息
public class CustomWriteHandler implements SheetWriteHandler {
@Override
public void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
}
@Override
public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
Workbook workbook = writeWorkbookHolder.getWorkbook();
Sheet sheet = workbook.getSheetAt(0);
//设置标题
Row row1 = sheet.createRow(0);
row1.setHeight((short) 800);
Cell cell1 = row1.createCell(0);
cell1.setCellValue("某某公司进销存报表");
CellStyle cellStyle = workbook.createCellStyle();
cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
cellStyle.setAlignment(HorizontalAlignment.CENTER);
Font font = workbook.createFont();
font.setBold(true);
font.setFontHeight((short) 400);
cellStyle.setFont(font);
cell1.setCellStyle(cellStyle);
sheet.addMergedRegionUnsafe(new CellRangeAddress(0, 0, 0, 17));
//设置填表日期,填报人,联系方式
Row row2 = sheet.createRow(1);
row2.setHeight((short) 500);
row2.createCell(1).setCellValue("填表日期");
row2.createCell(11).setCellValue("填表人");
row2.createCell(15).setCellValue("联系方式");
}
}
EasyExcel.write(response.getOutputStream(), InventoryItem.class)
.sheet("总表").registerWriteHandler(headStyle())
.registerWriteHandler(new CustomWriteHandler())
.relativeHeadRowIndex(2).doWrite(list);
最终样式
案例二:报表标颜色
进销存中上月库存数量小于10字体变红,否则变绿
public class ColorWriteHandler implements CellWriteHandler {
@Override
public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer columnIndex, Integer relativeRowIndex, Boolean isHead) {
}
@Override
public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
}
@Override
public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, CellData cellData, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
}
@Override
public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<CellData> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
if (!isHead) {
if (cell.getColumnIndex() == 4) {
String val = cell.getStringCellValue();
int num = 0;
try {
num = Integer.parseInt(val);
} catch (NumberFormatException e) {
e.printStackTrace();
}
if (num > 10) {
setColor(cell, writeSheetHolder, IndexedColors.RED);
} else {
setColor(cell, writeSheetHolder, IndexedColors.GREEN);
}
}
}
}
private void setColor(Cell cell, WriteSheetHolder writeSheetHolder, IndexedColors color) {
Sheet sheet = writeSheetHolder.getSheet();
Workbook workbook = sheet.getWorkbook();
Font font = workbook.createFont();
font.setColor(color.getIndex());
CellStyle cellStyle = workbook.createCellStyle();
cellStyle.setFont(font);
cellStyle.setBorderTop(BorderStyle.THIN);
cellStyle.setBorderBottom(BorderStyle.THIN);
cellStyle.setBorderLeft(BorderStyle.THIN);
cellStyle.setBorderRight(BorderStyle.THIN);
cell.setCellStyle(cellStyle);
}
}
public static void main(String[] args) {
List<InventoryItem> list = data();
EasyExcel.write("C:\\Users\\supre\\Desktop\\进销存导出.xlsx", InventoryItem.class)
.registerWriteHandler(normalStyle())
.registerWriteHandler(new ColorWriteHandler())
.sheet().doWrite(list);
}
public static List<InventoryItem> data() {
List<InventoryItem> list = new ArrayList<>();
for (int i = 0; i < 50; i++) {
String s = Integer.valueOf(i).toString();
InventoryItem inventoryItem = new InventoryItem();
inventoryItem.setId(i);
inventoryItem.setNo(s);
inventoryItem.setLastMonthStoreNum(s);
inventoryItem.setProductName("上衣+" + i);
list.add(inventoryItem);
}
return list;
}
public static WriteHandler normalStyle() {
// 头部样式策略
WriteCellStyle headWriteCellStyle = new WriteCellStyle();
headWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE1.getIndex());
WriteFont headWriteFont = new WriteFont();
headWriteFont.setFontHeightInPoints((short) 12);
headWriteFont.setBold(false);
headWriteCellStyle.setWriteFont(headWriteFont);
// 内容样式策略
WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
contentWriteCellStyle.setWrapped(true);
contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
// 设置内容边框样式
contentWriteCellStyle.setBorderLeft(THIN);
contentWriteCellStyle.setBorderTop(THIN);
contentWriteCellStyle.setBorderRight(THIN);
contentWriteCellStyle.setBorderBottom(THIN);
HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(headWriteCellStyle,
contentWriteCellStyle);
return horizontalCellStyleStrategy;
}
EasyExcel自2.1.1后提供了更强大的表格填充功能,提供一个模板文件,写一些模板参数,就可以快速生成表格
模板
将Excel实体类的属性用{.属性名}填入模板文件,样式也会被复制。注意:填充List时需要带个点,如果单个就不需要。
填充
EasyExcel.write("C:\\Users\\root\\Desktop\\进销存.xlsx")
.withTemplate("C:\\Users\\root\\Desktop\\进销存模板.xlsx").sheet().doFill(analysis.getList());
更复杂的填充
EasyExcel不仅支持竖向填充,还支持横向填充,多列表填充,详细信息可以查看官方文档