easyexcel 学习

it2024-06-28  45

EasyExcel

EasyExcel是一个基于Java的简单、省内存的读写Excel的开源项目。在尽可能节约内存的情况下支持读写百M的Excel。语雀.写excel

引言

首先简单讲解一下EasyExcel的写语法,方便理解后续的代码。

最简单的写

// 写法1 EasyExcel.write(fileName, DemoData.class).sheet("模板").doWrite(data());

写法1通过建造者模式将写easyexcel的代码浓缩成一段简单的代码,省略了中间的一些中介类。核心建造者类为ExcelWriterSheetBuilder。

// 写法2 fileName = TestFileUtil.getPath() + "simpleWrite" + System.currentTimeMillis() + ".xlsx"; // 这里 需要指定写用哪个class去写 ExcelWriter excelWriter = null; try { excelWriter = EasyExcel.write(fileName, DemoData.class).build(); WriteSheet writeSheet = EasyExcel.writerSheet("模板").build(); excelWriter.write(data(), writeSheet); } finally { // 千万别忘记finish 会帮忙关闭流 if (excelWriter != null) { excelWriter.finish(); } }

写法2的话就需要创建ExcelWriter与WriteSheet,但是写法2可以反复调用 excelWriter.write()。

不创建对象的写

/** * 不创建对象的写 */ @Test public void noModelWrite() { // 写法1 String fileName = TestFileUtil.getPath() + "noModelWrite" + System.currentTimeMillis() + ".xlsx"; // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 EasyExcel.write(fileName).head(head()).sheet("模板").doWrite(dataList()); } private List<List<String>> head() { List<List<String>> list = new ArrayList<List<String>>(); List<String> head0 = new ArrayList<String>(); head0.add("字符串" + System.currentTimeMillis()); List<String> head1 = new ArrayList<String>(); head1.add("数字" + System.currentTimeMillis()); List<String> head2 = new ArrayList<String>(); head2.add("日期" + System.currentTimeMillis()); list.add(head0); list.add(head1); list.add(head2); return list; } private List<List<Object>> dataList() { List<List<Object>> list = new ArrayList<List<Object>>(); for (int i = 0; i < 10; i++) { List<Object> data = new ArrayList<Object>(); data.add("字符串" + i); data.add(new Date()); data.add(0.56); list.add(data); } return list; }

不创建对象的写,与创建对象的写的区别就是没有传入Class,其次就是传入了head。

两者区别

根据源码,我们可以看出传入Class的写有执行 excelWriterBuilder.head(head)的一步,我们可以姑且认为就是从Class文件中读取到了head,通过反射。

public static ExcelWriterBuilder write(String pathName, Class head) { ExcelWriterBuilder excelWriterBuilder = new ExcelWriterBuilder(); excelWriterBuilder.file(pathName); if (head != null) { excelWriterBuilder.head(head); } return excelWriterBuilder; }

注解形式自定义样式

/** * 样式的数据类 * * @author Jiaju Zhuang **/ @Data // 头背景设置成红色 IndexedColors.RED.getIndex() @HeadStyle(fillPatternType = FillPatternType.SOLID_FOREGROUND, fillForegroundColor = 10) // 头字体设置成20 @HeadFontStyle(fontHeightInPoints = 20) // 内容的背景设置成绿色 IndexedColors.GREEN.getIndex() @ContentStyle(fillPatternType = FillPatternType.SOLID_FOREGROUND, fillForegroundColor = 17) // 内容字体设置成20 @ContentFontStyle(fontHeightInPoints = 20) public class DemoStyleData { // 字符串的头背景设置成粉红 IndexedColors.PINK.getIndex() @HeadStyle(fillPatternType = FillPatternType.SOLID_FOREGROUND, fillForegroundColor = 14) // 字符串的头字体设置成20 @HeadFontStyle(fontHeightInPoints = 30) // 字符串的内容的背景设置成天蓝 IndexedColors.SKY_BLUE.getIndex() @ContentStyle(fillPatternType = FillPatternType.SOLID_FOREGROUND, fillForegroundColor = 40) // 字符串的内容字体设置成20 @ContentFontStyle(fontHeightInPoints = 30) @ExcelProperty("字符串标题") private String string; @ExcelProperty("日期标题") private Date date; @ExcelProperty("数字标题") private Double doubleData; }

自定义样式

/** * 自定义样式 * <p>1. 创建excel对应的实体对象 参照{@link DemoData} * <p>2. 创建一个style策略 并注册 * <p>3. 直接写即可 */ @Test public void styleWrite() { String fileName = TestFileUtil.getPath() + "styleWrite" + System.currentTimeMillis() + ".xlsx"; // 头的策略 WriteCellStyle headWriteCellStyle = new WriteCellStyle(); // 背景设置为红色 headWriteCellStyle.setFillForegroundColor(IndexedColors.RED.getIndex()); WriteFont headWriteFont = new WriteFont(); headWriteFont.setFontHeightInPoints((short)20); headWriteCellStyle.setWriteFont(headWriteFont); // 内容的策略 WriteCellStyle contentWriteCellStyle = new WriteCellStyle(); // 这里需要指定 FillPatternType 为FillPatternType.SOLID_FOREGROUND 不然无法显示背景颜色.头默认了 FillPatternType所以可以不指定 contentWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND); // 背景绿色 contentWriteCellStyle.setFillForegroundColor(IndexedColors.GREEN.getIndex()); WriteFont contentWriteFont = new WriteFont(); // 字体大小 contentWriteFont.setFontHeightInPoints((short)20); contentWriteCellStyle.setWriteFont(contentWriteFont); // 这个策略是 头是头的样式 内容是内容的样式 其他的策略可以自己实现 HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle); // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 EasyExcel.write(fileName, DemoData.class).registerWriteHandler(horizontalCellStyleStrategy).sheet("模板") .doWrite(data()); }

WriteCellStyle 类的源码如下,就是一堆样式设置

public class WriteCellStyle { private Short dataFormat; private WriteFont writeFont; private Boolean hidden; private Boolean locked; private Boolean quotePrefix; private HorizontalAlignment horizontalAlignment; private Boolean wrapped; private VerticalAlignment verticalAlignment; private Short rotation; private Short indent; private BorderStyle borderLeft; private BorderStyle borderRight; private BorderStyle borderTop; private BorderStyle borderBottom; private Short leftBorderColor; private Short rightBorderColor; private Short topBorderColor; private Short bottomBorderColor; private FillPatternType fillPatternType; private Short fillBackgroundColor; private Short fillForegroundColor; private Boolean shrinkToFit; ... }

HorizontalCellStyleStrategy 类的源码如下,继承了AbstractCellStyleStrategy类。我们能看到有使用cell.setCellStyle(headCellStyle)去设置单元格的样式。easyexcel也是包装了poi的代码。

/** * * Use the same style for the row * * @author Jiaju Zhuang */ public class HorizontalCellStyleStrategy extends AbstractCellStyleStrategy { private WriteCellStyle headWriteCellStyle; private List<WriteCellStyle> contentWriteCellStyleList; private CellStyle headCellStyle; private List<CellStyle> contentCellStyleList; ... @Override protected void initCellStyle(Workbook workbook) { if (headWriteCellStyle != null) { headCellStyle = StyleUtil.buildHeadCellStyle(workbook, headWriteCellStyle); } if (contentWriteCellStyleList != null && !contentWriteCellStyleList.isEmpty()) { contentCellStyleList = new ArrayList<CellStyle>(); for (WriteCellStyle writeCellStyle : contentWriteCellStyleList) { contentCellStyleList.add(StyleUtil.buildContentCellStyle(workbook, writeCellStyle)); } } } @Override protected void setHeadCellStyle(Cell cell, Head head, Integer relativeRowIndex) { if (headCellStyle == null) { return; } cell.setCellStyle(headCellStyle); } @Override protected void setContentCellStyle(Cell cell, Head head, Integer relativeRowIndex) { if (contentCellStyleList == null || contentCellStyleList.isEmpty()) { return; } cell.setCellStyle(contentCellStyleList.get(relativeRowIndex % contentCellStyleList.size())); } }

自定义拦截器

/** * 自定义拦截器。对第一行第一列的头超链接到:https://github.com/alibaba/easyexcel * * @author Jiaju Zhuang */ public class CustomCellWriteHandler implements CellWriteHandler { private static final Logger LOGGER = LoggerFactory.getLogger(CustomCellWriteHandler.class); @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 afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<CellData> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { // 这里可以对cell进行任何操作 LOGGER.info("第{}行,第{}列写入完成。", cell.getRowIndex(), cell.getColumnIndex()); if (isHead && cell.getColumnIndex() == 0) { CreationHelper createHelper = writeSheetHolder.getSheet().getWorkbook().getCreationHelper(); Hyperlink hyperlink = createHelper.createHyperlink(HyperlinkType.URL); hyperlink.setAddress("https://github.com/alibaba/easyexcel"); cell.setHyperlink(hyperlink); } } } /** * 自定义拦截器.对第一列第一行和第二行的数据新增下拉框,显示 测试1 测试2 * * @author Jiaju Zhuang */ public class CustomSheetWriteHandler implements SheetWriteHandler { private static final Logger LOGGER = LoggerFactory.getLogger(CustomSheetWriteHandler.class); @Override public void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) { } @Override public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) { LOGGER.info("第{}个Sheet写入成功。", writeSheetHolder.getSheetNo()); // 区间设置 第一列第一行和第二行的数据。由于第一行是头,所以第一、二行的数据实际上是第二三行 CellRangeAddressList cellRangeAddressList = new CellRangeAddressList(1, 2, 0, 0); DataValidationHelper helper = writeSheetHolder.getSheet().getDataValidationHelper(); DataValidationConstraint constraint = helper.createExplicitListConstraint(new String[] {"测试1", "测试2"}); DataValidation dataValidation = helper.createValidation(constraint, cellRangeAddressList); writeSheetHolder.getSheet().addValidationData(dataValidation); } } /** * 下拉,超链接等自定义拦截器(上面几点都不符合但是要对单元格进行操作的参照这个) * <p> * demo这里实现2点。1. 对第一行第一列的头超链接到:https://github.com/alibaba/easyexcel 2. 对第一列第一行和第二行的数据新增下拉框,显示 测试1 测试2 * <p> * 1. 创建excel对应的实体对象 参照{@link DemoData} * <p> * 2. 注册拦截器 {@link CustomCellWriteHandler} {@link CustomSheetWriteHandler} * <p> * 2. 直接写即可 */ @Test public void customHandlerWrite() { String fileName = TestFileUtil.getPath() + "customHandlerWrite" + System.currentTimeMillis() + ".xlsx"; // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 EasyExcel.write(fileName, DemoData.class).registerWriteHandler(new CustomSheetWriteHandler()) .registerWriteHandler(new CustomCellWriteHandler()).sheet("模板").doWrite(data()); }

我们可以注册自定义的拦截器,easyexcel在执行时会调用这个拦截器来实现我们的一些特殊需求。CustomCellWriteHandler会拦截每个cell的写入,CustomSheetWriteHandler会在sheet创建成功后执行操作。

HorizontalCellStyleStrategy 分析

如上图所示,刚刚的HorizontalCellStyleStrategy 类也是继承自CellWriteHandler,也就是每次cell都会执行一步操作。 如上图所示,我们能看到有调用setHeadCellStyle、 setContentCellStyle。 如上图所示setHeadCellStyle、 setContentCellStyle两个方法有调用cell.setCellStyle方法来设置样式。通过这几步的分析,我们也能自定义一个拦截器类来实现我们对每个单元格的自定义样式。

自定义样式以及单元格合并

1.首先定义三个类,这个三个类是来指定一个点或者一个矩形区域。 point

@Data public abstract class Point{ public abstract boolean contain(int x,int y); }

ExcelPoint

@Data @NoArgsConstructor @AllArgsConstructor public class ExcelPoint extends Point { private int x; //row private int y; //col @Override public boolean contain(int x, int y) { if(this.x==x&&this.y==y){ return true; } return false; } }

ExcelRect

@Data @AllArgsConstructor public class ExcelRect extends Point { private int x;//row1 private int y;//row2 private int z;//col1 private int w;//col2 @Override public boolean contain(int x, int y) {//row,col if(this.x<=x&&this.y>=x && this.z<=y&&this.w>=y){ return true; } return false; } }

2.定义一个样式封装类,包含样式以及坐标,WriteCellStyle是easyexcel自带的样式类,其中已经包含了边框样式。

@Data public class ExcelStyle{ private Point point; private WriteCellStyle style; public boolean contain(int x,int y){ return point.contain(x,y); } public ExcelStyle(WriteCellStyle style) { this.style = style; } public ExcelStyle(int x, int y,int z,int w, WriteCellStyle style) { this.point = new ExcelRect(x, y, z, w); this.style = style; } public ExcelStyle(int x, int y, WriteCellStyle style) { this.point = new ExcelPoint(x, y); this.style = style; } public ExcelStyle(Point point, WriteCellStyle style) { this.point = point; this.style = style; } }

3.ExcelStyleUtil,封装一些常用的样式。比如左边框,右边框,上边框等待,可以将所有样式都添加到这里,免得导出代码里面样式代码太多,扰乱代码。

public class ExcelStyleUtil { private ExcelStyleUtil() {} /** * @param workbook * @return */ public static CellStyle buildDefaultCellStyle(Workbook workbook) { CellStyle newCellStyle = workbook.createCellStyle(); newCellStyle.setWrapText(true); newCellStyle.setVerticalAlignment(VerticalAlignment.CENTER); newCellStyle.setAlignment(HorizontalAlignment.CENTER); newCellStyle.setLocked(true); newCellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); newCellStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex()); newCellStyle.setBorderTop(BorderStyle.THIN); newCellStyle.setBorderBottom(BorderStyle.THIN); newCellStyle.setBorderLeft(BorderStyle.THIN); newCellStyle.setBorderRight(BorderStyle.THIN); return newCellStyle; } /** * Build head cell style * * @param workbook * @param writeCellStyle * @return */ public static CellStyle buildHeadCellStyle(Workbook workbook, WriteCellStyle writeCellStyle) { CellStyle cellStyle = buildDefaultCellStyle(workbook); if (writeCellStyle == null) { return cellStyle; } buildCellStyle(workbook, cellStyle, writeCellStyle, true); return cellStyle; } /** * Build content cell style * * @param workbook * @param writeCellStyle * @return */ public static CellStyle buildContentCellStyle(Workbook workbook, WriteCellStyle writeCellStyle) { CellStyle cellStyle = workbook.createCellStyle(); if (writeCellStyle == null) { return cellStyle; } buildCellStyle(workbook, cellStyle, writeCellStyle, false); return cellStyle; } public static void buildCellStyle(Workbook workbook,Cell cell,CellStyle cellStyle, ExcelStyle excelStyle) { buildCellStyle(workbook, cellStyle, excelStyle.getStyle(), false); } public static void buildCellStyle(Workbook workbook, CellStyle cellStyle, WriteCellStyle writeCellStyle, boolean isHead) { buildFont(workbook, cellStyle, writeCellStyle.getWriteFont(), isHead); if (writeCellStyle.getDataFormat() != null) { cellStyle.setDataFormat(writeCellStyle.getDataFormat()); } if (writeCellStyle.getHidden() != null) { cellStyle.setHidden(writeCellStyle.getHidden()); } if (writeCellStyle.getLocked() != null) { cellStyle.setLocked(writeCellStyle.getLocked()); } if (writeCellStyle.getQuotePrefix() != null) { cellStyle.setQuotePrefixed(writeCellStyle.getQuotePrefix()); } if (writeCellStyle.getHorizontalAlignment() != null) { cellStyle.setAlignment(writeCellStyle.getHorizontalAlignment()); } if (writeCellStyle.getWrapped() != null) { cellStyle.setWrapText(writeCellStyle.getWrapped()); } if (writeCellStyle.getVerticalAlignment() != null) { cellStyle.setVerticalAlignment(writeCellStyle.getVerticalAlignment()); } if (writeCellStyle.getRotation() != null) { cellStyle.setRotation(writeCellStyle.getRotation()); } if (writeCellStyle.getIndent() != null) { cellStyle.setIndention(writeCellStyle.getIndent()); } if (writeCellStyle.getBorderLeft() != null) { cellStyle.setBorderLeft(writeCellStyle.getBorderLeft()); } if (writeCellStyle.getBorderRight() != null) { cellStyle.setBorderRight(writeCellStyle.getBorderRight()); } if (writeCellStyle.getBorderTop() != null) { cellStyle.setBorderTop(writeCellStyle.getBorderTop()); } if (writeCellStyle.getBorderBottom() != null) { cellStyle.setBorderBottom(writeCellStyle.getBorderBottom()); } if (writeCellStyle.getLeftBorderColor() != null) { cellStyle.setLeftBorderColor(writeCellStyle.getLeftBorderColor()); } if (writeCellStyle.getRightBorderColor() != null) { cellStyle.setRightBorderColor(writeCellStyle.getRightBorderColor()); } if (writeCellStyle.getTopBorderColor() != null) { cellStyle.setTopBorderColor(writeCellStyle.getTopBorderColor()); } if (writeCellStyle.getBottomBorderColor() != null) { cellStyle.setBottomBorderColor(writeCellStyle.getBottomBorderColor()); } if (writeCellStyle.getFillPatternType() != null) { cellStyle.setFillPattern(writeCellStyle.getFillPatternType()); } if (writeCellStyle.getFillBackgroundColor() != null) { cellStyle.setFillBackgroundColor(writeCellStyle.getFillBackgroundColor()); } if (writeCellStyle.getFillForegroundColor() != null) { cellStyle.setFillForegroundColor(writeCellStyle.getFillForegroundColor()); } if (writeCellStyle.getShrinkToFit() != null) { cellStyle.setShrinkToFit(writeCellStyle.getShrinkToFit()); } } private static void buildFont(Workbook workbook, CellStyle cellStyle, WriteFont writeFont, boolean isHead) { Font font = null; if (isHead) { font = workbook.createFont(); font.setFontName("宋体"); font.setFontHeightInPoints((short)14); font.setBold(true); cellStyle.setFont(font); } if (writeFont == null) { return; } if (!isHead) { font = workbook.createFont(); cellStyle.setFont(font); } if (writeFont.getFontName() != null) { font.setFontName(writeFont.getFontName()); } if (writeFont.getFontHeightInPoints() != null) { font.setFontHeightInPoints(writeFont.getFontHeightInPoints()); } if (writeFont.getItalic() != null) { font.setItalic(writeFont.getItalic()); } if (writeFont.getStrikeout() != null) { font.setStrikeout(writeFont.getStrikeout()); } if (writeFont.getColor() != null) { font.setColor(writeFont.getColor()); } if (writeFont.getTypeOffset() != null) { font.setTypeOffset(writeFont.getTypeOffset()); } if (writeFont.getUnderline() != null) { font.setUnderline(writeFont.getUnderline()); } if (writeFont.getCharset() != null) { font.setCharSet(writeFont.getCharset()); } if (writeFont.getBold() != null) { font.setBold(writeFont.getBold()); } } public static void buildBorderStyle(Sheet sheet, CellRangeAddress address, ExcelBorderStyle style) { if ( style.getBorderBottom() != null) { RegionUtil.setBorderBottom(style.getBorderBottom(),address, sheet); } if ( style.getBorderLeft() != null) { RegionUtil.setBorderLeft(style.getBorderLeft(),address, sheet); } if ( style.getBorderRight() != null) { RegionUtil.setBorderRight(style.getBorderRight(),address, sheet); } if ( style.getBorderTop() != null) { RegionUtil.setBorderTop(style.getBorderTop(),address, sheet); } if(style.getColorBottom()!= null){ RegionUtil.setBottomBorderColor(style.getColorBottom(),address, sheet); } if(style.getColorLeft()!= null){ RegionUtil.setLeftBorderColor(style.getColorLeft(),address, sheet); } if(style.getColorRight()!= null){ RegionUtil.setRightBorderColor(style.getColorRight(),address, sheet); } if(style.getColorTop()!= null){ RegionUtil.setTopBorderColor(style.getColorTop(),address, sheet); } } public static WriteCellStyle GenericStyle(){ WriteCellStyle style= new WriteCellStyle(); style.setHorizontalAlignment(HorizontalAlignment.CENTER); style.setVerticalAlignment(VerticalAlignment.TOP); style.setWrapped(true); WriteFont font = new WriteFont(); font.setFontName("宋体"); font.setFontHeightInPoints((short) 11); style.setWriteFont(font); return style; } public static WriteCellStyle GenericBorderStyle(){ WriteCellStyle style= new WriteCellStyle(); style.setBorderTop(BorderStyle.THIN); style.setBorderBottom(BorderStyle.THIN); style.setBorderLeft(BorderStyle.THIN); style.setBorderRight(BorderStyle.THIN); return style; } public static WriteCellStyle RightMediumBorderStyle(){ WriteCellStyle style= new WriteCellStyle(); style.setBorderTop(BorderStyle.THIN); style.setBorderBottom(BorderStyle.THIN); style.setBorderLeft(BorderStyle.THIN); style.setBorderRight(BorderStyle.MEDIUM); return style; } public static WriteCellStyle LeftMediumBorderStyle(){ WriteCellStyle style= new WriteCellStyle(); style.setBorderTop(BorderStyle.THIN); style.setBorderBottom(BorderStyle.THIN); style.setBorderLeft(BorderStyle.MEDIUM); style.setBorderRight(BorderStyle.THIN); return style; } public static WriteCellStyle BottomMediumBorderStyle(){ WriteCellStyle style= new WriteCellStyle(); style.setBorderTop(BorderStyle.THIN); style.setBorderBottom(BorderStyle.MEDIUM); style.setBorderLeft(BorderStyle.THIN); style.setBorderRight(BorderStyle.THIN); return style; } public static WriteCellStyle LeftBottomMediumBorderStyle(){ WriteCellStyle style= new WriteCellStyle(); style.setBorderTop(BorderStyle.THIN); style.setBorderBottom(BorderStyle.MEDIUM); style.setBorderLeft(BorderStyle.MEDIUM); style.setBorderRight(BorderStyle.THIN); return style; } public static WriteCellStyle RightBottomMediumBorderStyle(){ WriteCellStyle style= new WriteCellStyle(); style.setBorderTop(BorderStyle.THIN); style.setBorderBottom(BorderStyle.MEDIUM); style.setBorderLeft(BorderStyle.THIN); style.setBorderRight(BorderStyle.MEDIUM); return style; } public static WriteCellStyle TitleStyle(){ WriteCellStyle style= new WriteCellStyle(); WriteFont font = new WriteFont(); font.setFontName("宋体"); font.setFontHeightInPoints((short) 18); style.setWriteFont(font); return style; }

4.MergeRect、ExcelBorderStyle 类,合并单元格的坐标以及边框样式,为什么需要边框样式,因为合并单元格的边框样式不会自动合并(大概就是必须重新设置一下)。ExcelBorderStyle 可以想办法跟WriteCellStyle合并一下,毕竟也是从WriteCellStyle中提取出来的。

@Data @AllArgsConstructor public class MergeRect{ private ExcelRect address; private ExcelBorderStyle style; private int eachRow ; private int eachCol ; public MergeRect(ExcelRect address) { this.address = address; } public MergeRect(ExcelRect address, ExcelBorderStyle style) { this.address = address; this.style = style; } public MergeRect(ExcelRect address, int eachRow, int eachCol) { this.address = address; this.eachRow = eachRow; this.eachCol = eachCol; } public boolean contain(int x, int y) { if(address.getX()<=x&&address.getY()>=x && address.getZ()<=y&&address.getW()>=y){ return true; } return false; } } @Data @NoArgsConstructor @AllArgsConstructor public class ExcelBorderStyle { BorderStyle BorderRight; BorderStyle BorderBottom; BorderStyle BorderLeft; BorderStyle BorderTop; Integer ColorRight; Integer ColorBottom; Integer ColorLeft; Integer ColorTop; public static ExcelBorderStyle LeftRightMediumBorder(){ ExcelBorderStyle style= new ExcelBorderStyle(); style.setBorderRight(BorderStyle.MEDIUM); style.setBorderLeft(BorderStyle.MEDIUM); style.setBorderBottom(BorderStyle.THIN); style.setBorderTop(BorderStyle.THIN); return style; } public static ExcelBorderStyle RightMediumBorder(){ ExcelBorderStyle style= new ExcelBorderStyle(); style.setBorderRight(BorderStyle.MEDIUM); style.setBorderLeft(BorderStyle.THIN); style.setBorderBottom(BorderStyle.THIN); style.setBorderTop(BorderStyle.THIN); return style; } public static ExcelBorderStyle TopRightLeftMediumBorder(){ ExcelBorderStyle style= new ExcelBorderStyle(); style.setBorderRight(BorderStyle.MEDIUM); style.setBorderTop(BorderStyle.MEDIUM); style.setBorderLeft(BorderStyle.MEDIUM); style.setBorderBottom(BorderStyle.THIN); return style; } public static ExcelBorderStyle TopRightMediumBorder(){ ExcelBorderStyle style= new ExcelBorderStyle(); style.setBorderRight(BorderStyle.MEDIUM); style.setBorderTop(BorderStyle.MEDIUM); style.setBorderLeft(BorderStyle.THIN); style.setBorderBottom(BorderStyle.THIN); return style; } public static ExcelBorderStyle BottomRightMediumBorder(){ ExcelBorderStyle style= new ExcelBorderStyle(); style.setBorderRight(BorderStyle.MEDIUM); style.setBorderTop(BorderStyle.THIN); style.setBorderLeft(BorderStyle.THIN); style.setBorderBottom(BorderStyle.MEDIUM); return style; } public static ExcelBorderStyle BottomMediumBorder(){ ExcelBorderStyle style= new ExcelBorderStyle(); style.setBorderRight(BorderStyle.THIN); style.setBorderTop(BorderStyle.THIN); style.setBorderLeft(BorderStyle.THIN); style.setBorderBottom(BorderStyle.MEDIUM); return style; } public static ExcelBorderStyle LeftMediumBorder(){ ExcelBorderStyle style= new ExcelBorderStyle(); style.setBorderRight(BorderStyle.THIN); style.setBorderLeft(BorderStyle.MEDIUM); style.setBorderBottom(BorderStyle.THIN); style.setBorderTop(BorderStyle.THIN); return style; } public static ExcelBorderStyle NormalBorder(){ ExcelBorderStyle style= new ExcelBorderStyle(); style.setBorderRight(BorderStyle.THIN); style.setBorderLeft(BorderStyle.THIN); style.setBorderBottom(BorderStyle.THIN); style.setBorderTop(BorderStyle.THIN); return style; } }

5.样式拦截器

public class ExcelCellStrategy implements CellWriteHandler { private List<ExcelStyle> rangeList=new ArrayList<>(); private Map<Point,ExcelStyle> pointList=new HashMap<>(); public void appendCellStyle(ExcelStyle style){ Point point=style.getPoint(); if(point instanceof ExcelPoint){ pointList.put(point,style); }else{ rangeList.add(style); } } @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) { // 这里可以对cell进行任何操作 Workbook workbook = writeSheetHolder.getSheet().getWorkbook(); //创建cellStyle CellStyle cellStyle = workbook.createCellStyle(); //循环rangeList检查 int x=cell.getRowIndex(); int y=cell.getColumnIndex(); for(ExcelStyle i:rangeList){ //全局样式 if(i.getPoint()==null){ ExcelStyleUtil.buildCellStyle(workbook,cell ,cellStyle, i); } else if(i.contain(x,y)){ ExcelStyleUtil.buildCellStyle(workbook,cell ,cellStyle, i); }; } //判断pointList里面是否存在 ExcelPoint point= new ExcelPoint(x,y); if(pointList.containsKey(point)){ //取出样式 ExcelStyle excelStyle= pointList.get(point); ExcelStyleUtil.buildCellStyle(workbook,cell ,cellStyle, excelStyle); } //执行样式设置 cell.setCellStyle(cellStyle); } }

6.单元格合并拦截器

public class ExcelMergeStrategy extends AbstractMergeStrategy { //合并坐标集合 private Map<ExcelPoint, MergeRect> addresses = new HashMap<>(); private List<MergeRect> eachMerges=new ArrayList<>(); /** * 创建左下角坐标点,在左下角执行合并时所有单元格都已创建完毕,否则样式不会生效 * @param firstRow * @param lastRow * @param firstCol * @param lastCol * @param style */ public void add(int firstRow, int lastRow, int firstCol, int lastCol, ExcelBorderStyle style) { ExcelRect address= new ExcelRect(firstRow,lastRow,firstCol,lastCol); addresses.put(new ExcelPoint(lastRow,firstCol),new MergeRect(address,style)); } public void add(int firstRow, int lastRow, int firstCol, int lastCol) { ExcelRect address= new ExcelRect(firstRow,lastRow,firstCol,lastCol); addresses.put(new ExcelPoint(lastRow,firstCol),new MergeRect(address)); } public void addEachMerge(int firstRow, int lastRow, int firstCol, int lastCol,int eachRow,int eachCol) { ExcelRect address= new ExcelRect(firstRow,lastRow,firstCol,lastCol); eachMerges.add(new MergeRect(address,eachRow,eachCol)); } public void addEachMerge(int firstRow, int lastRow, int firstCol, int lastCol,int eachRow,int eachCol,ExcelBorderStyle style) { ExcelRect address= new ExcelRect(firstRow,lastRow,firstCol,lastCol); eachMerges.add(new MergeRect(address,style,eachRow,eachCol)); } public boolean contain(ExcelPoint point){ if(addresses.containsKey(point)){ return true; } else{ return false; } } public MergeRect get(ExcelPoint point){ return addresses.get(point); } @Override protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) { //合并单元格 int x=cell.getRowIndex(); int y=cell.getColumnIndex(); ExcelPoint point=new ExcelPoint(x,y); if (contain(point)) { MergeRect mergeRect= get(point); ExcelRect address=mergeRect.getAddress(); CellRangeAddress cellRangeAddress =new CellRangeAddress(address.getX(),address.getY(),address.getZ(),address.getW()); //检查一下,如何格子大小为1,就不需要合并了,免得报错了,在外面控制也麻烦 if(!(address.getX()==address.getY()&&address.getZ()==address.getW())){ //执行合并 sheet.addMergedRegion(cellRangeAddress); //执行style ExcelBorderStyle style= mergeRect.getStyle(); if(style!=null) ExcelStyleUtil.buildBorderStyle(sheet,cellRangeAddress,style); } }else{ //遍历 for(MergeRect mRect:eachMerges){ //判断该单元格是否处于本合并规则区域 if(mRect.contain(cell.getRowIndex(),cell.getColumnIndex())){ //取出规则参数 int eachRow=mRect.getEachRow();//隔几行合并 int eachCol=mRect.getEachCol();//隔几列合并 ExcelRect address=mRect.getAddress(); //计算出该点是否在合并的点中 if((x-address.getX())%eachRow==0&&(y-address.getZ())%eachCol==0){ //创建合并单元,执行合并 CellRangeAddress cellRangeAddress= new CellRangeAddress(x,x+eachRow-1,y,y+eachCol-1); if(!(x==x+eachRow-1&&y==y+eachCol-1)){ sheet.addMergedRegion(cellRangeAddress); ExcelBorderStyle style= mRect.getStyle(); if(style!=null) ExcelStyleUtil.buildBorderStyle(sheet,cellRangeAddress,style); } } } } } } }

7.行拦截器,目前主要作行高设置

public class ExcelRowStrategy extends AbstractRowWriteHandler { //行高 HashMap<Integer,Float> rowHeight=new HashMap<>(); public void appendRowHeight(String key,Float value) { //转换一下 if(key.contains("-")){ String[] columns=key.split("-"); int min=Integer.valueOf(columns[0]); int max=Integer.valueOf(columns[1]); for(int i=min;i<max;i++){ rowHeight.put(i,value); } }else{ int c= Integer.valueOf(key); rowHeight.put(c,value); } } @Override public void afterRowDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Integer relativeRowIndex, Boolean isHead) { int rownum=row.getRowNum(); //设置行高 if(rowHeight.containsKey(rownum)){ row.setHeightInPoints(rowHeight.get(rownum)); } } }

8.sheet拦截器,主要设置页面页脚,列宽。

public class ExcelSheetStrategy extends AbstractSheetWriteHandler { //页脚信息 private HashMap<String,String> footInfo =new HashMap<>(); //列宽 HashMap<Integer,Integer> columnWidth=new HashMap<>(); public void appendFootInfo(String key,String info){ footInfo.put(key,info); } public void appendColumnWidth(String key,Integer value) { //转换一下 if(key.contains("-")){ String[] columns=key.split("-"); int min=Integer.valueOf(columns[0])-1; int max=Integer.valueOf(columns[1]); for(int i=min;i<max;i++){ columnWidth.put(i,value); } }else{ int c= Integer.valueOf(key)-1; columnWidth.put(c,value); } } @Override public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) { Sheet sheet= writeSheetHolder.getSheet(); //设置列宽 for (Map.Entry<Integer, Integer> entry : columnWidth.entrySet()) { sheet.setColumnWidth(entry.getKey(),entry.getValue()); } PrintSetup printSetup = sheet.getPrintSetup(); //设置打印方向是否为横向 printSetup.setLandscape(false); // 打印方向,true:横向,false:纵向 //设置打印纸张大小 printSetup.setPaperSize(HSSFPrintSetup.A4_PAPERSIZE); //设置页眉页脚的边距 printSetup.setHeaderMargin(0.196f);//英寸<->0.5厘米 printSetup.setFooterMargin(0.196f);//英寸<->0.5厘米 //设置打印缩放为100% printSetup.setScale((short) 100); //设置页边距 sheet.setMargin(SXSSFSheet.TopMargin,0.3543f);//英寸<->0.9厘米 sheet.setMargin(SXSSFSheet.BottomMargin,0.3543f);//英寸<->0.9厘米 sheet.setMargin(SXSSFSheet.RightMargin,0.3149f);//英寸<->0.8厘米 sheet.setMargin(SXSSFSheet.LeftMargin,0.3149f);//英寸<->0.8厘米 //设置整体水平居中 sheet.setHorizontallyCenter(true); //设置页眉 /* Header header = sheet.getHeader(); //给页眉赋值及设置字体样式 header.setCenter(HSSFHeader.font("宋体","")+HSSFHeader.fontSize((short) 18)+"这是页眉");*/ //设置页脚 Footer footer = sheet.getFooter(); String footerInfo="第"+ HSSFFooter.page()+"页,共"+HSSFFooter.numPages()+"页"; if(footInfo.size()>=1){ for (Map.Entry<String, String> entry : footInfo.entrySet()) { footerInfo+=" "+entry.getKey()+":"+entry.getValue(); } } footer.setCenter(footerInfo); } }

Demo

public static void test(){ //首先创建四个拦截器 ExcelSheetStrategy sheetStyle=new ExcelSheetStrategy(); //定义sheet样式拦截器,页面打印设置,页眉页脚,页边距 ExcelRowStrategy rowStyle=new ExcelRowStrategy();//定义row样式拦截器,设置行高 ExcelMergeStrategy mergeStrategy= new ExcelMergeStrategy(); //定义cell合并拦截器 ExcelCellStrategy cellStyle= new ExcelCellStrategy(); //定义cell样式拦截器类 //设置全局样式 // 列宽,列宽的值有一个计算函数,设置的好像是像素点 sheetStyle.appendColumnWidth("1", (int) (256*10.5+160));//10.5字符 sheetStyle.appendColumnWidth("29", (int) (256*9.5+160));//9.5字符 //样式:水平方向居中,垂直方向顶部居中,默认宋体11号字体,设置自动换行 cellStyle.appendCellStyle(new ExcelStyle(ExcelStyleUtil.GenericStyle())); //边框:单元格的样式,以及最左边框加粗,通常来说点样式会覆盖区域样式的相同样式,也就是点样式比区域样式迟执行。随便设置一下 final int lastRow=10; final int lastCol=10; cellStyle.appendCellStyle(new ExcelStyle(new ExcelRect(0,lastRow,0,lastCol),ExcelStyleUtil.GenericBorderStyle())); //设置通用内部边框 cellStyle.appendCellStyle(new ExcelStyle(new ExcelRect(0,lastRow,0,0),ExcelStyleUtil.LeftMediumBorderStyle())); //设置最左边边框加粗 cellStyle.appendCellStyle(new ExcelStyle(new ExcelRect(0,lastRow,lastCol,lastCol),ExcelStyleUtil.RightMediumBorderStyle()));//设置最右边框加粗 cellStyle.appendCellStyle(new ExcelStyle(new ExcelRect(lastRow,lastRow,0,lastCol),ExcelStyleUtil.BottomMediumBorderStyle())); //设置最底部边框加粗 //左右下角的那个点的位置的样式 cellStyle.appendCellStyle(new ExcelStyle(new ExcelPoint(lastRow,lastCol),ExcelStyleUtil.RightBottomMediumBorderStyle()));//设置最右下角那个点右下边框加粗 cellStyle.appendCellStyle(new ExcelStyle(new ExcelPoint(lastRow,0),ExcelStyleUtil.LeftBottomMediumBorderStyle()));//设置最左下角那个点右下边框加粗 //创建 ExcelWriter ExcelWriter excelWriter = null; try { excelWriter = EasyExcel.write("d:\\test.xlsx") .registerWriteHandler(cellStyle) .registerWriteHandler(mergeStrategy) .registerWriteHandler(sheetStyle) .registerWriteHandler(rowStyle) .build(); WriteSheet writeSheet = EasyExcel.writerSheet("sheet1").build(); //定义内容 List<List<Object>> list = new ArrayList<List<Object>>(); list.add(Lists.newArrayList("工资单") ); list.add(Lists.newArrayList("原谅我太水了") ); list.add( Lists.newArrayList("啊", "王敏","","","") ); list.add( Lists.newArrayList("", "","","","") ); list.add( Lists.newArrayList("喜欢的不得了") ); //样式 cellStyle.appendCellStyle(new ExcelStyle(new ExcelPoint(0,0),ExcelStyleUtil.TitleStyle())); //合并单元格 mergeStrategy.add(0,0,0,lastCol); mergeStrategy.add(1,1,7,lastCol); mergeStrategy.add(2,2,0,lastCol, ExcelBorderStyle.TopRightLeftMediumBorder()); mergeStrategy.add(3,8,4,lastCol, ExcelBorderStyle.RightMediumBorder()); mergeStrategy.add(9,9,0,lastCol, ExcelBorderStyle.LeftRightMediumBorder()); mergeStrategy.add(16,16,0,lastCol,ExcelBorderStyle.LeftRightMediumBorder()); mergeStrategy.add(17,17,2,lastCol-1,ExcelBorderStyle.NormalBorder()); mergeStrategy.add(17,18,0,0,ExcelBorderStyle.LeftMediumBorder()); mergeStrategy.add(17,18,1,1,ExcelBorderStyle.NormalBorder()); mergeStrategy.add(17,18,lastCol,lastCol,ExcelBorderStyle.RightMediumBorder()); mergeStrategy.add(19,20,0,0,ExcelBorderStyle.LeftMediumBorder()); mergeStrategy.add(19,20,1,1,ExcelBorderStyle.NormalBorder()); mergeStrategy.add(19,20,lastCol,lastCol,ExcelBorderStyle.RightMediumBorder()); mergeStrategy.add(lastRow,lastRow,6,7, ExcelBorderStyle.BottomMediumBorder()); mergeStrategy.add(lastRow,lastRow,8,lastCol,ExcelBorderStyle.BottomRightMediumBorder()); //行高 rowStyle.appendRowHeight("0",35.1f); rowStyle.appendRowHeight("1",17.25f); rowStyle.appendRowHeight("2-8",16.5f); rowStyle.appendRowHeight("9",19.5f); rowStyle.appendRowHeight("10-15",16.5f); rowStyle.appendRowHeight("16",19.5f); rowStyle.appendRowHeight("17-20",16.5f); excelWriter.write(list, writeSheet); } finally { // 千万别忘记finish 会帮忙关闭流 if (excelWriter != null) { excelWriter.finish(); } } }

大致就这样使用就行了,基本就是先设置全局样式,边框呀,行高,列宽。其次就是单元格合并的一些东西了。这样下来其实要设置的地方还是很多,还是很复杂,但是稍微明了一些,熟悉那几个类之后就知道怎么写了。

这个demo就这样了,实在是不知道做个什么样的表格出来,没有实际需求,还真不知道做成什么样合适。反正大致知道怎么用就行了。

最新回复(0)