产品提的需求,将数据添加到excel中,其中有些图片,需要添加到excel中,这块两种方案,一是将图片直接写入excel中,二是图片和excel放在同一个目录,excel中使用超链接,点击超链接,打开对应的图片。
最后使用方案二,方案一poi也可以实现,文中我也会把实现方式写出来,但是方案一中由于图片全写到excel中,导致excel会很大,查看excel和操作不是很灵活,相比来看方案二就比较灵活,excel只存数据,图片单独存,操作起来很方便,excel看着也很整洁。
上述方案二,需要将excel和图片放在同一个目录下,使用相对路径,这样在拷贝操作之后,保证excel中的超链接还可以正常点击,打开超链接的图片。
具体文件目录结构:
–整体文件夹:
----excel文件
----图片文件夹:
----------图片1
----------图片2
拷贝的时候,直接拷贝整体文件夹,即可实现在哪都能正常打开超链接的功能。
还有个地方需要注意:超链接的文字需要修改下字体颜色和样式,设置成蓝色,加下划线。要不看不出来哪个文字有超链接,哪个没有。
poi功能还是很强大的,基本能想到的功能都能通过poi实现。
org.apache.poi
poi
3.17
org.apache.poi
poi-ooxml
3.17
org.apache.poi
ooxml-schemas
1.1
单元格配置类用于设置每个单元格的字体颜色,是否有超链接等。具体看代码和注释吧。
package com.psim.project.patrol.domain;
import lombok.Data;
/**
* 用于向对应的单元格设置对应的内容
*
* @author thcb
*/
@Data
public class ExcelVo {
/**
* Excel表的行,Excel中的第一行为此处的第0行
*/
public int row;
/**
* Excel表的列,Excel中的第一列为此处的第0列
*/
public int column;
/**
* 单元格内容
*/
public String content;
/**
* 单元格批注
*/
public String comment;
/**
* 合并单元格参数,起始行
*/
public int firstRow;
/**
* 合并单元格参数,结束行
*/
public int lastRow;
/**
* 合并单元格参数,起始列
*/
public int firstCol;
/**
* 合并单元格参数,结束列
*/
public int lastCol;
/**
* 字体颜色
*/
public short frontColor;
/**
* 超连接
*/
public String hyperLink = "";
public ExcelVo(int row, int column, String content) {
this.row = row;
this.column = column;
this.content = content;
this.comment = "";
this.firstRow = 0;
this.lastRow = 0;
this.firstCol = 0;
this.lastCol = 0;
this.frontColor = 0;
this.hyperLink = "";
}
public ExcelVo(int row, int column, String content, short frontColor) {
this.row = row;
this.column = column;
this.content = content;
this.firstRow = 0;
this.lastRow = 0;
this.firstCol = 0;
this.lastCol = 0;
this.frontColor = frontColor;
this.hyperLink = "";
}
public ExcelVo(int row, int column, String content, int firstRow, int lastRow, int firstCol, int lastCol) {
this.row = row;
this.column = column;
this.content = content;
this.firstRow = firstRow;
this.lastRow = lastRow;
this.firstCol = firstCol;
this.lastCol = lastCol;
this.frontColor = 0;
this.hyperLink = "";
}
public ExcelVo(int row, int column, String content, int firstRow, int lastRow, int firstCol, int lastCol, String hyperLink) {
this.row = row;
this.column = column;
this.content = content;
this.firstRow = firstRow;
this.lastRow = lastRow;
this.firstCol = firstCol;
this.lastCol = lastCol;
this.frontColor = 0;
this.hyperLink = hyperLink;
}
public ExcelVo(int row, int column, String content, int firstRow, int lastRow, int firstCol, int lastCol, short frontColor) {
this.row = row;
this.column = column;
this.content = content;
this.firstRow = firstRow;
this.lastRow = lastRow;
this.firstCol = firstCol;
this.lastCol = lastCol;
this.frontColor = frontColor;
this.hyperLink = "";
}
}
其中字体颜色(frontColor)参数的取值如下,我没找到具体的api描述,各个值代表什么颜色,这个是我自己试出来的,后面应该还有其他颜色,我没往下试…
/**
* Excel字体颜色
*/
interface ExcelColor {
/**
* Excel字体颜色:黑色
*/
short BLACK = 0;
/**
* Excel字体颜色:红色
*/
short RED = 10;
/**
* Excel字体颜色:绿色
*/
short GREEN = 11;
/**
* Excel字体颜色:蓝色
*/
short BLUE = 12;
/**
* Excel字体颜色:黄色
*/
short YELLOW = 13;
/**
* Excel字体颜色:紫色
*/
short PURPLE = 14;
/**
* Excel字体颜色:青色
*/
short CYAN = 15;
/**
* Excel字体颜色:棕色
*/
short BROWN = 16;
/**
* Excel字体颜色:深绿
*/
short DARK_GREEN = 17;
/**
* Excel字体颜色:深蓝
*/
short DARK_BLUE = 18;
/**
* Excel字体颜色:深黄
*/
short DARK_YELLOW = 19;
}
首先创建ExcelVo对象,/test/test1.jpg为超链接的文件路径
excelVo = new ExcelVo(4, 2, "这是超链接", 4, 6, 2, 2, "/test/test1.jpg");
File file = new File(filePath);
Workbook workbook = getReportTemplate(file.getAbsolutePath());
setCell(workbook, excelVo);
workbook.write(new FileOutputStream(file));
根据xls和xlsx区分打开的文件,两个格式的创建方式有所区别
/**
* 获得巡检报表
*
* @param filePath 报表文件路径
*/
public Workbook getReportTemplate(String filePath) {
Workbook workbook;
FileInputStream fileInputStream;
FileOutputStream out = null;
try {
fileInputStream = new FileInputStream(filePath);
if (filePath.endsWith(".xlsx")) {
FileInputStream fileSystem = new FileInputStream(filePath);
workbook = new XSSFWorkbook(fileSystem);
fileSystem.close();
return workbook;
}
if (filePath.endsWith(".xls")) {
POIFSFileSystem fileSystem = new POIFSFileSystem(fileInputStream);
workbook = new HSSFWorkbook(fileSystem);
return workbook;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
中间创建excel的步骤略过了,直接调用此方法设置单元格具体样式即可。其中workbook就是生成的excel
/**
* 根据ExcelVo修改Excel中的指定单元格的值
*
* @param ExcelVo Excel单元格
*/
public void setCell(Workbook workbook, ExcelVo excelVo) {
Cell cell = createCell(workbook, polRecordTemplateVo);
if (cell != null) {
// 单元格样式
CellStyle cellStyle = workbook.createCellStyle();
//不直接使用getCellStyle(),用cloneStyleFrom就能实现保持原有样式
cellStyle.cloneStyleFrom(cell.getCellStyle());
// 设置单元格字体颜色
if (excelVo.frontColor != 0) {
Font font = workbook.createFont();
font.setColor(excelVo.frontColor);
cellStyle.setFont(font);
}
if (StringUtils.isNotEmpty(excelVo.hyperLink)) {
// 设置超链接
CreationHelper createHelper = workbook.getCreationHelper();
Hyperlink link = createHelper.createHyperlink(HyperlinkType.FILE);
link.setAddress(excelVo.hyperLink);
cell.setHyperlink(link);
// 设置字体
Font font = workbook.createFont();
font.setColor(ExcelColor.BLUE);
font.setUnderline((byte) 1);
cellStyle.setFont(font);
}
// 设置单元格显示内容
cell.setCellValue(excelVo.content);
// 设置单元格样式
cell.setCellStyle(cellStyle);
}
}
创建单元格的方法
/**
* 创建单元格excelVo
*/
public Cell createCell(Workbook workbook, ExcelVo excelVo) {
if (workbook != null) {
Sheet sheet = workbook.getSheetAt(0);
if (sheet != null && excelVo != null) {
Cell cell = null;
if (excelVo.getFirstCol() == 0
&& excelVo.getLastCol() == 0
&& excelVo.getFirstRow() == 0
&& excelVo.getLastRow() == 0) {
// 合并参数都为0,正常创建和对单元格赋值
if (sheet.getRow(excelVo.row) != null) {
Row row = sheet.getRow(excelVo.row);
row.setHeightInPoints(PolPatrolConstants.ROW_HEIGHT);
if (row.getCell(excelVo.column) != null) {
cell = row.getCell(excelVo.column);
} else {
cell = row.createCell(excelVo.column);
}
} else {
Row row = sheet.createRow(excelVo.row);
row.setHeightInPoints(PolPatrolConstants.ROW_HEIGHT);
if (row.getCell(excelVo.column) != null) {
cell = row.getCell(excelVo.column);
} else {
cell = row.createCell(excelVo.column);
}
}
} else {
// 有不为0的合并参数,需要创建合并单元格
CellRangeAddress cellRangeAddress = new CellRangeAddress(
excelVo.firstRow,
excelVo.lastRow,
excelVo.firstCol,
excelVo.lastCol);
sheet.addMergedRegion(cellRangeAddress);
if (sheet.getRow(excelVo.row) != null) {
Row row = sheet.getRow(excelVo.row);
row.setHeightInPoints(PolPatrolConstants.ROW_HEIGHT);
if (row.getCell(excelVo.column) != null) {
cell = row.getCell(excelVo.column);
} else {
cell = row.createCell(excelVo.column);
}
} else {
Row row = sheet.createRow(excelVo.row);
row.setHeightInPoints(PolPatrolConstants.ROW_HEIGHT);
if (row.getCell(excelVo.column) != null) {
cell = row.getCell(excelVo.column);
} else {
cell = row.createCell(excelVo.column);
}
}
}
return cell;
} else {
log.error("setCell:shell is null");
}
} else {
log.error("workbook:workbook is null");
}
return null;
}
仅写出了关键性的代码,需要注意的是合并的时候,一个单元格只能有一个合并的操作,如果合并一个已经合并过的单元格,程序会报错。