一、介绍
什么是POI?
Apache POI是基于Office Open XML标准(OOXML)和Microsoft的OLE 2复合文档格式(OLE2)处理各种文件格式的开源项目。 简而言之,您可以使用Java读写MS Excel文件,可以使用Java读写MS Word和MS PowerPoint文件。
二、Maven依赖
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
三、简单场景案例
场景:目前有一张对班级统计表报如下(班级口号这个字段不需要填写内容)
班级编号 | 班主任 | 班级口号 | 班级男生人数 | 班级女生人数 |
---|---|---|---|---|
思路:根据注解扫描实现
定义注解IgnoreExportField, 标注在导出字段上,表示该字段不参与导出
import java.lang.annotation.*;
/**
* @description 标注在导出字段上,表示该字段不参与导出
*/
@Documented
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface IgnoreExportField {
}
定义班级DTO:在不想导出的属性上加上注解
import lombok.Data;
@Data
public class ClassDTO {
private String classNo; //班级编号
private String classTeacher; //班主任
@IgnoreExportField
private String classSlogan; //班级口号
private int boyNum; //男孩人数
private int girlNum; //女孩人数
}
这时候我们模拟从前端传入一串Json数据:
//模拟前端传入的报表数据内容
public List<ClassDTO> loadData() {
List<ClassDTO> list = new ArrayList();
for (int i = 0; i < 10; i++) {
ClassDTO class1 = new ClassDTO();
class1.setClassNo("20200" + i);
class1.setClassTeacher("老师" + i);
class1.setClassSlogan("班级口号" + i);
class1.setBoyNum(30 + i % 3);
class1.setGirlNum(20 + i % 2);
list.add(class1);
}
return list;
}
//模拟前端传入的表格头
private List<String> constructColumnTitles() {
//这个可以根据前端报表行选择列头传入
List<String> list = new ArrayList<>();
list.add("班级编号");
list.add("班主任");
list.add("班级口号");
list.add("男生人数");
list.add("女生人数");
return list;
}
定义需要导出报表的路径:
public String getOutPath() {
//设置导出路径
StringBuilder sb = new StringBuilder(System.getProperty("user.dir") + "/src/main/resources/inexport/");
sb.append(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
sb.append("/");
return sb.toString();
}
进行报表导出:
/**
* 导出报表
* @param outputPath 导出路径
* @param listDTO 传入的数据
* @param title 报表标题
* @param tableHead 表头
* @param <T>
* @throws IOException
*/
public <T> void createExcel(String outputPath, List<T> listDTO, String title, List<String> tableHead) throws IOException {
//验证数据....
//创建工作簿
XSSFWorkbook workBook = new XSSFWorkbook();
//定义行
int currentRowIndex = 0;
//创建一个单元格 当做标题
XSSFSheet sheet = workBook.createSheet();
//设置标题和标题格式
if (StringUtils.isNotBlank(title)) {
//合并单元格
sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, tableHead.size() - 1));
// 创建表格行,设置总标题
XSSFRow totalTitleRow = sheet.createRow(currentRowIndex);
totalTitleRow.createCell(currentRowIndex).setCellValue(title);
XSSFCellStyle cellStyle = totalTitleRow.getCell(0).getCellStyle();
//总标题列内容居中
cellStyle.setAlignment(HorizontalAlignment.CENTER);
//总标题行样式
XSSFCellStyle style = workBook.createCellStyle();
//垂直居中
style.setVerticalAlignment(VerticalAlignment.CENTER);
//右对齐
style.setAlignment(HorizontalAlignment.RIGHT);
totalTitleRow.setRowStyle(style);
//填充完了行数记得+1
currentRowIndex++;
}
//创建表格【列标题】行
XSSFRow titleRow = sheet.createRow(currentRowIndex);
for (int j = 0; j < tableHead.size(); j++) {
titleRow.createCell(j).setCellValue(tableHead.get(j));
}
currentRowIndex++;
if (CollectionUtils.isNotEmpty(listDTO)) {
//创建数据行
int cellIndex;
for (T t : listDTO) {
cellIndex = 0;
XSSFRow row = sheet.createRow(currentRowIndex++);
//通过获取类中的字段(包括父类)
Field[] fieldList = getFieldsFromClass(null, t.getClass());
if (ArrayUtils.isEmpty(fieldList))
return;
//循环出所有导出列
for (int j = 0; j < fieldList.length; j++) {
Field field = fieldList[j];
if (field.isSynthetic())
continue;
//扫描注解 如果有这个注解的话 单元格+1
IgnoreExportField annotation = field.getAnnotation(IgnoreExportField.class);
if (annotation != null) {
cellIndex++;
continue;
}
//填充数据
try {
field.setAccessible(true);
Object o = field.get(t);
XSSFCell cell = row.createCell(cellIndex++);
if (o != null) {
if (o instanceof Long) {
cell.setCellValue((long) o);
} else if (o instanceof Integer) {
cell.setCellValue((int) o);
} else if (o instanceof Double)
cell.setCellValue((double) o);
else if (o instanceof BigDecimal)
cell.setCellValue(((BigDecimal) o).doubleValue());
else
cell.setCellValue(String.valueOf(o));
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
FileOutputStream outStream = null;
try {
//判断输出的文件夹是否存在,不存在,则创建
File file = new File(outputPath);
if (!file.exists())
file.mkdirs();
//创建导出文件
file = File.createTempFile("报表名..."+LocalDateTime.now().format(DateTimeFormatter.ofPattern("HH-mm-ss")), ".xlsx", file);
outStream = new FileOutputStream(file);
workBook.write(outStream);
outStream.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (outStream != null) {
outStream.close();
}
}
}
}
/**
* 获取类中的所有字段(包括父类)
* @param fieldList
* @param clazz
* @return
*/
private static Field[] getFieldsFromClass(Field[] fieldList, Class<?> clazz) {
if (clazz == null) {
return fieldList;
}
Field[] fieldArray = clazz.getDeclaredFields();
if (fieldList != null) {
fieldArray = ArrayUtils.addAll(fieldList, fieldArray);
}
fieldArray = getFieldsFromClass(fieldArray, clazz.getSuperclass());
return fieldArray;
}
导出结果: