关于POI的使用与小结
一切的开始
由于自己底子差,先前没有使用过也没有了解过poi,关于一个新技术的了解与使用,是建立在要用它实现什么需求,以及同样可以实现相同需求的其他技术的优缺点对比,关于我工作上要用到poi,先从需求说起。
需求:根据一个已有的Excel表格,将数据插入到数据库中,然后再将数据库中的数据生成excel表格,生成的格式差不多与已有的表格一样,尽可能的美观,然后实现在线下载。
需求说完,看一下表格是个什么格式
其实在使用poi之前,实现这个需求的是使用easyexcel实现的,不得不说,easyexcel的上手与使用要比poi快的多得多,但是在springboot中easyexcel没有创建表头以及插入图片的功能,所以使用了poi。
思路:从上到下,先将excel的表头以及logo生成出来,封装成一个方法,然后在实现数据插入,这样就可以实现表头与数据分离,更好的提高代码的复用性。
基本的表格格式就是这样,然后就是努力实现需求的过程,用了很长时间,故写此博客小结一下,方便忘记温习。
一、导入依赖
<!--poi-->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.17</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.17</version>
</dependency>
有一点要注意,两个的版本要一致,关于为什么选择3.17,是因为在网上搜寻资料时说这个版本稳定。
二、插入logo的实现
一开始实现logo导入的是在本地读取logo图片,然后再写到excel里,但是后来考虑到logo是不经常变得,而且换了环境之后,图片也要随着导入新环境下,及其不方便,所以使用base64编码,将图片编码,存储为一个字符串,在使用的时候再使用base64解码,实现即使环境不同,也不会导致logo图片丢失的问题。
下面是实现代码:
//创建XSSFWorkbook对象
XSSFWorkbook workbook = new XSSFWorkbook();
//使用XSSFWorkbook对象创建一个sheet
XSSFSheet sheet = workbook.createSheet(sheetName);
//获取画图的顶级管理器
XSSFDrawing patriarch = sheet.createDrawingPatriarch();
//图片Base64编码
String imgStr = "图片的base64编码字符串“;
BASE64Decoder base64Decoder = new BASE64Decoder();
byte[] imgBytes = new byte[0];
try {
//解码为图片
imgBytes = base64Decoder.decodeBuffer(imgStr);
for (int i = 0; i < imgBytes.length; ++i) {
if (imgBytes[i] < 0) {// 调整异常数据
imgBytes[i] += 256;
}
}
} catch (IOException e) {
e.printStackTrace();
}
//设置图片属性,里面的参数为决定图片插入的位置
XSSFClientAnchor xssfClientAnchor = new XSSFClientAnchor(0, 0, 0, 0, 0, 0, 2, 2);
xssfClientAnchor.setAnchorType(ClientAnchor.AnchorType.MOVE_AND_RESIZE);
// 插入图片内容
patriarch.createPicture(xssfClientAnchor, workbook.addPicture(imgBytes, XSSFWorkbook.PICTURE_TYPE_JPEG));
三、表头的实现
关于表头的实现,要考虑合并单元格,以及调整字体的大小、样式以及加粗。
实现代码如下:
//创建表头格式
XSSFCellStyle headStyle = workbook.createCellStyle();
XSSFFont headFont = workbook.createFont();
//设置字体
headFont.setFontName("宋体");
//设置字体大小
headFont.setFontHeightInPoints((short) 18);
//粗体显示
headFont.setBold(true);
//设置水平居中
headStyle.setAlignment(HorizontalAlignment.CENTER);
//设置垂直居中
headStyle.setVerticalAlignment(VerticalAlignment.CENTER);
headStyle.setFont(headFont);
//设置合并单元格参数 下标从0开始
//参数1:起始行 参数2:终止行 参数3:起始列 参数4:终止列
CellRangeAddress cellRangeAddress = new CellRangeAddress(2, 2, 0, 14);
sheet.addMergedRegion(cellRangeAddress);
//最后将格式对象setCellValue进列中即可
四、列标题的实现
在图片以及表头标题实现之后,最重要的是列标题实现,也是需求中最难实现的,因为列标题操作单元格的操作非常多,要更改字体大小、样式以及加粗,还要设置单元格上下左右边框的粗细以及颜色,还要更改单元格的背景颜色,以及设置单元格内字体的对齐方式,下面是实现功能的关键代码:
/*
关于列标题我选择的是数组遍历,将所有列标题定义一个数组,即使在列标题更改的情况下,也可以实现更改少量代码实现功能
*/
String[] list = {"测试方法", "测试案例编号", "测试需求编号", "MQC路径",
"案例名称", "案例描述", "前置条件", "步骤", "步骤描述", "输入要素名称",
"输入要素值", "预期结果属性", "预计执行时间", "案例性质", "失败是否终止",
"优先级", "设计人"};
/*
为了提高代码复用性,我将设置字体、单元格样式的代码封装成了一个函数,函数代码最后。
*/
XSSFCellStyle titleStyle = style(workbook,12,true,false);
//设置背景颜色
titleStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
titleStyle.setFillForegroundColor(IndexedColors.LIGHT_TURQUOISE.getIndex());// 设置背景色
//设置水平居中
titleStyle.setAlignment(HorizontalAlignment.CENTER);
for (int i = 0; i <= 4; i++) {
//创建行
XSSFRow forrow = sheet.createRow(i);
for (int j = 0; j < list.length; j++) {
//创建列
XSSFCell forcell = forrow.createCell(j);
if (i == 2 && j == 0) {
//设置合并单元格参数 下标从0开始
//参数1:起始行 参数2:终止行 参数3:起始列 参数4:终止列
CellRangeAddress cellRangeAddress = new CellRangeAddress(2, 2, 0, 14);
sheet.addMergedRegion(cellRangeAddress);
forcell.setCellValue(headName);
}
forcell.setCellStyle(headStyle);
if (i == 4) {
forcell.setCellValue(list[j]);
forcell.setCellStyle(titleStyle);
}
//设置列自适应宽度
sheet.autoSizeColumn(j);
}
forrow.setRowStyle(headStyle);
}
五、数据的实现
思路:将整体代码封装成一个函数,传入参数为一个实体类的List集合,代码内部逻辑进行List集合遍历,再将遍历到的每个实体类对应的属性值插入到excel的各列中,最后将XSSFWorkbook对象返回,供后期保存使用即可,单元格中数据长度过长,导致字体重叠,使用自适应行高解决。
/*
关于数据的遍历,使用的依旧是for循环,只放一些设置格式的代码
*/
//创建行
XSSFRow forrow = sheet.createRow(i+5);
//设置行高
forrow.setHeightInPoints(35);
//设置自适应行高
CTRow ctRow = forrow.getCTRow();
ctRow.setCustomHeight(false);
六、生成excel
最后生成的excel图片如下:
关于自适应行高
七、总结
1、设置样式的代码函数封装
public XSSFCellStyle style(XSSFWorkbook workbook, int fontSize, boolean fontBold, boolean autoWrap){
XSSFFont font = workbook.createFont();
XSSFCellStyle style = workbook.createCellStyle();
//设置字体
font.setFontName("宋体");
//设置字体大小
font.setFontHeightInPoints((short) fontSize);
//粗体显示
font.setBold(fontBold);
//设置水平居中
//style.setAlignment(HorizontalAlignment.CENTER);
//设置垂直居中
style.setVerticalAlignment(VerticalAlignment.CENTER);
style.setFont(font);
//设置单元格自动换行
style.setWrapText(autoWrap);
//设置单元格边框颜色以及边框粗细
style.setBottomBorderColor(IndexedColors.BLACK.getIndex());
style.setTopBorderColor(IndexedColors.BLACK.getIndex());
style.setRightBorderColor(IndexedColors.BLACK.getIndex());
style.setLeftBorderColor(IndexedColors.BLACK.getIndex());
style.setBorderBottom(BorderStyle.THIN);
style.setBorderTop(BorderStyle.THIN);
style.setBorderRight(BorderStyle.THIN);
style.setBorderLeft(BorderStyle.THIN);
return style;
}
2、样式设置代码总结
XSSFCellStyle style = workbook.createCellStyle();
//设置字体
font.setFontName("宋体");
//设置字体大小
font.setFontHeightInPoints((short) fontSize);
//粗体显示
font.setBold(fontBold);
//设置水平居中
style.setAlignment(HorizontalAlignment.CENTER);
//设置垂直居中
style.setVerticalAlignment(VerticalAlignment.CENTER);
style.setFont(font);
//设置单元格自动换行
style.setWrapText(autoWrap);
//设置单元格边框颜色
style.setBottomBorderColor(IndexedColors.BLACK.getIndex());
style.setTopBorderColor(IndexedColors.BLACK.getIndex());
style.setRightBorderColor(IndexedColors.BLACK.getIndex());
style.setLeftBorderColor(IndexedColors.BLACK.getIndex());
style.setBorderBottom(BorderStyle.THIN);
style.setBorderTop(BorderStyle.THIN);
style.setBorderRight(BorderStyle.THIN);
style.setBorderLeft(BorderStyle.THIN);
//设置自适应行高
CTRow ctRow = forrow.getCTRow();
ctRow.setCustomHeight(false);
//设置行高
forrow.setHeightInPoints(35);
//设置列自适应宽度
sheet.autoSizeColumn(j);
//设置合并单元格参数 下标从0开始
//参数1:起始行 参数2:终止行 参数3:起始列 参数4:终止列
CellRangeAddress cellRangeAddress = new CellRangeAddress(2, 2, 0, 14);
sheet.addMergedRegion(cellRangeAddress);
//设置单元格背景颜色
titleStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
titleStyle.setFillForegroundColor(IndexedColors.LIGHT_TURQUOISE.getIndex());// 设置背景色
/*
插入图片
*/
//设置图片属性
//获取画图的顶级管理器
XSSFDrawing patriarch = sheet.createDrawingPatriarch();
XSSFClientAnchor xssfClientAnchor = new XSSFClientAnchor(0, 0, 0, 0, 0, 0, 2, 2);
xssfClientAnchor.setAnchorType(ClientAnchor.AnchorType.MOVE_AND_RESIZE);
// 插入图片内容
patriarch.createPicture(xssfClientAnchor, workbook.addPicture(imgBytes, XSSFWorkbook.PICTURE_TYPE_JPEG));
//隐藏边框,可以创建一个无边框的excel表格
sheet.setDisplayGridlines(false);
关于poi操作excel的就这些,这些方法只是我工作上需要单纯为了完成需求的,poi的功能很强大,往往不只这些,end…