springboot整合EasyExcel
easyexcel是阿里开源的解析excel的工具,可以把它看作对poi的优化版。
Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有一些缺陷,比如07版Excel解压缩以及解压后存储都是在内存中完成的,内存消耗依然很大。easyexcel重写了poi对07版Excel的解析,能够原本一个3M的excel用POI sax依然需要100M左右内存降低到KB级别,并且再大的excel不会出现内存溢出,03版依赖POI的sax模式。在上层做了模型转换的封装,让使用者更加简单方便。
easyexcel核心功能
功能描述参考:Java解析excel工具easyexcel 助你快速简单避免OOM_成长中的巨人-CSDN博客_excel解析
- 读任意大小的03、07版Excel不会OOM
- 读Excel自动通过注解,把结果映射为java模型
- 读Excel支持多sheet
- 读Excel时候是否对Excel内容做trim()增加容错
- 写小量数据的03版Excel(不要超过2000行)
- 写任意大07版Excel不会OOM
- 写Excel通过注解将表头自动写入Excel
- 写Excel可以自定义Excel样式 如:字体,加粗,表头颜色,数据内容颜色
- 写Excel到多个不同sheet
- 写Excel时一个sheet可以写多个Table
- 写Excel时候自定义是否需要写表头
1、引入依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>1.1.2-beta5</version>
</dependency>
依赖包是目前最新的版本
2、实体类
package com.xxx.xxxutils.utils;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.metadata.BaseRowModel;
import lombok.*;
@EqualsAndHashCode(callSuper = true)
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class TableHeaderExcelProperty extends BaseRowModel{
/**
* value: 表头名称
* index: 列的号, 0表示第一列
*/
@ExcelProperty(value = "姓名", index = 0)
private String name;
@ExcelProperty(value = "年龄",index = 1)
private int age;
@ExcelProperty(value = "学校",index = 2)
private String school;
}
3、excel工具方法
package com.xxx.xxxutils.utils;
import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.metadata.BaseRowModel;
import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.util.CollectionUtils;
import com.alibaba.excel.util.StringUtils;
import com.xxx.xxxutils.listener.ExcelListener;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.poifs.filesystem.FileMagic;
import java.io.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@Slf4j
public class ExcelUtil{
/**
* 从Excel中读取文件,读取的文件是一个DTO类,该类必须继承BaseRowModel
* 导入方法 第一个参数文件输入流,第二个参数实体类,必须继承自BaseRowModel
* 参考:https://github.com/alibaba/easyexcel
* 字符流必须支持标记,FileInputStream 不支持标记,可以使用BufferedInputStream 代替
* BufferedInputStream bis = new BufferedInputStream(new FileInputStream(...));
*/
public static <T extends BaseRowModel> List<T> readExcel(final InputStream inputStream, final Class<? extends BaseRowModel> clazz) {
if (null == inputStream) {
throw new NullPointerException("the inputStream is null!");
}
ExcelListener<T> listener = new ExcelListener<>();
// ExcelListener,读取大于1000行的数据才需要传入此参数
ExcelReader reader = new ExcelReader(inputStream, valueOf(inputStream), null, listener);
reader.read(new Sheet(1, 1, clazz));
return listener.getRows();
}
/**
* 从Excel中读取文件,读取的文件是一个DTO类,该类必须继承BaseRowModel
* 导出方法 第一个参数文件,第二个参数实体类集合,必须继承自BaseRowModel
*/
public static void writeExcel(final File file, List<? extends BaseRowModel> list) {
try (OutputStream out = new FileOutputStream(file)) {
ExcelWriter writer = new ExcelWriter(out, ExcelTypeEnum.XLSX);
//写第一个sheet, 有模型映射关系
Class<? extends BaseRowModel> t = list.get(0).getClass();
Sheet sheet = new Sheet(1, 0, t);
writer.write(list, sheet);
writer.finish();
} catch (IOException e) {
log.warn("fail to write to excel file: file[{}]", file.getName(), e);
}
}
/**
* 根据输入流,判断为xls还是xlsx,该方法原本存在于easyexcel 1.1.0 的ExcelTypeEnum中。
*/
public static ExcelTypeEnum valueOf(InputStream inputStream) {
try {
FileMagic fileMagic = FileMagic.valueOf(inputStream);
if (FileMagic.OLE2.equals(fileMagic)) {
return ExcelTypeEnum.XLS;
}
if (FileMagic.OOXML.equals(fileMagic)) {
return ExcelTypeEnum.XLSX;
}
throw new IllegalArgumentException("excelTypeEnum can not null");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/****************************************************************************/
private static Sheet initSheet;
static {
initSheet = new Sheet(1, 0);
initSheet.setSheetName("sheet");
//设置自适应宽度
initSheet.setAutoWidth(Boolean.TRUE);
}
/**
* 导入方法,读取少于1000行数据
* @param filePath 文件绝对路径
* @return
*/
public static List<Object> readLessThan1000Row(String filePath){
return readLessThan1000RowBySheet(filePath,null);
}
/**
* 导入方法,读小于1000行数据, 带样式
* filePath 文件绝对路径
* initSheet :
* sheetNo: sheet页码,默认为1
* headLineMun: 从第几行开始读取数据,默认为0, 表示从第一行开始读取
* clazz: 返回数据List<Object> 中Object的类名
*/
public static List<Object> readLessThan1000RowBySheet(String filePath, Sheet sheet){
if(!StringUtils.hasText(filePath)){
return null;
}
sheet = sheet != null ? sheet : initSheet;
InputStream fileStream = null;
try {
fileStream = new FileInputStream(filePath);
return EasyExcelFactory.read(fileStream, sheet);
} catch (FileNotFoundException e) {
log.info("找不到文件或文件路径错误, 文件:{}", filePath);
}finally {
try {
if(fileStream != null){
fileStream.close();
}
} catch (IOException e) {
log.info("excel文件读取失败, 失败原因:{}", e);
}
}
return null;
}
/**
* 导入方法,读大于1000行数据
* @param filePath 文件觉得路径
* @return
*/
public static List<Object> readMoreThan1000Row(String filePath){
return readMoreThan1000RowBySheet(filePath,null);
}
/**
* 导入方法,读大于1000行数据, 带样式
* @param filePath 文件觉得路径
* @return
*/
public static List<Object> readMoreThan1000RowBySheet(String filePath, Sheet sheet){
if(!StringUtils.hasText(filePath)){
return null;
}
sheet = sheet != null ? sheet : initSheet;
InputStream fileStream = null;
try {
fileStream = new FileInputStream(filePath);
ExcelListenerPlus excelListener = new ExcelListenerPlus();
EasyExcelFactory.readBySax(fileStream, sheet, excelListener);
return excelListener.getDatas();
} catch (FileNotFoundException e) {
log.error("找不到文件或文件路径错误, 文件:{}", filePath);
}finally {
try {
if(fileStream != null){
fileStream.close();
}
} catch (IOException e) {
log.error("excel文件读取失败, 失败原因:{}", e);
}
}
return null;
}
/**
* 导出方法,生成excle
* @param filePath 绝对路径, 如:/home/chenmingjian/Downloads/aaa.xlsx
* @param data 数据源
* @param head 表头
*/
public static void writeBySimple(String filePath, List<List<Object>> data, List<String> head){
writeSimpleBySheet(filePath,data,head,null);
}
/**
* 导出方法,生成excle
* @param filePath 绝对路径, 如:/home/chenmingjian/Downloads/aaa.xlsx
* @param data 数据源
* @param sheet excle页面样式
* @param head 表头
*/
public static void writeSimpleBySheet(String filePath, List<List<Object>> data, List<String> head, Sheet sheet){
sheet = (sheet != null) ? sheet : initSheet;
if(head != null){
List<List<String>> list = new ArrayList<>();
head.forEach(h -> list.add(Collections.singletonList(h)));
sheet.setHead(list);
}
OutputStream outputStream = null;
ExcelWriter writer = null;
try {
outputStream = new FileOutputStream(filePath);
writer = EasyExcelFactory.getWriter(outputStream);
writer.write1(data,sheet);
} catch (FileNotFoundException e) {
log.error("找不到文件或文件路径错误, 文件:{}", filePath);
}finally {
try {
if(writer != null){
writer.finish();
}
if(outputStream != null){
outputStream.close();
}
} catch (IOException e) {
log.error("excel文件导出失败, 失败原因:{}", e);
}
}
}
/**
* 导出方法,生成excle
* @param filePath 绝对路径, 如:/home/chenmingjian/Downloads/aaa.xlsx
* @param data 数据源
*/
public static void writeWithTemplate(String filePath, List<? extends BaseRowModel> data){
writeWithTemplateAndSheet(filePath,data,null);
}
/**
* 导出方法,生成excle
* @param filePath 绝对路径, 如:/home/chenmingjian/Downloads/aaa.xlsx
* @param data 数据源
* @param sheet excle页面样式
*/
public static void writeWithTemplateAndSheet(String filePath, List<? extends BaseRowModel> data, Sheet sheet){
if(CollectionUtils.isEmpty(data)){
return;
}
sheet = (sheet != null) ? sheet : initSheet;
sheet.setClazz(data.get(0).getClass());
OutputStream outputStream = null;
ExcelWriter writer = null;
try {
outputStream = new FileOutputStream(filePath);
writer = EasyExcelFactory.getWriter(outputStream);
writer.write(data,sheet);
} catch (FileNotFoundException e) {
log.error("找不到文件或文件路径错误, 文件:{}", filePath);
}finally {
try {
if(writer != null){
writer.finish();
}
if(outputStream != null){
outputStream.close();
}
} catch (IOException e) {
log.error("excel文件导出失败, 失败原因:{}", e);
}
}
}
/**
* 导出方法,生成多Sheet的excle
* @param filePath 绝对路径, 如:/home/chenmingjian/Downloads/aaa.xlsx
* @param multipleSheelPropetys
*/
public static void writeWithMultipleSheel(String filePath,List<MultipleSheelPropety> multipleSheelPropetys){
if(CollectionUtils.isEmpty(multipleSheelPropetys)){
return;
}
OutputStream outputStream = null;
ExcelWriter writer = null;
try {
outputStream = new FileOutputStream(filePath);
writer = EasyExcelFactory.getWriter(outputStream);
for (MultipleSheelPropety multipleSheelPropety : multipleSheelPropetys) {
Sheet sheet = multipleSheelPropety.getSheet() != null ? multipleSheelPropety.getSheet() : initSheet;
if(!CollectionUtils.isEmpty(multipleSheelPropety.getData())){
sheet.setClazz(multipleSheelPropety.getData().get(0).getClass());
}
writer.write(multipleSheelPropety.getData(), sheet);
}
} catch (FileNotFoundException e) {
log.error("找不到文件或文件路径错误, 文件:{}", filePath);
}finally {
try {
if(writer != null){
writer.finish();
}
if(outputStream != null){
outputStream.close();
}
} catch (IOException e) {
log.error("excel文件导出失败, 失败原因:{}", e);
}
}
}
/*********************匿名内部类开始,可以提取出去******************************/
@Data
public static class MultipleSheelPropety{
private List<? extends BaseRowModel> data;
private Sheet sheet;
}
/**
* 解析监听器,读取大于一千行的数据需要传入次参数
* 每解析一行会回调invoke()方法。
* 整个excel解析结束会执行doAfterAllAnalysed()方法
*
* @author: chenmingjian
* @date: 19-4-3 14:11
*/
@Data
public static class ExcelListenerPlus extends AnalysisEventListener {
private List<Object> datas = new ArrayList<>();
/**
* 逐行解析
* object : 当前行的数据
*/
@Override
public void invoke(Object object, AnalysisContext context) {
//当前行
// context.getCurrentRowNum()
if (object != null) {
datas.add(object);
}
}
/**
* 解析完所有数据后会调用该方法
*/
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
//解析结束销毁不用的资源
}
}
/****************************************************************************/
}
4、测试案例
package com.xxx.xxxutils;
import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.metadata.Table;
import com.xxx.xxxutils.domain.XxxInfo;
import com.xxx.xxxutils.model.MultiLineHeadExcelModelTest1;
import com.xxx.xxxutils.model.TableHeaderExcelProperty;
import com.xxx.xxxutils.model.User;
import com.xxx.xxxutils.utils.ExcelUtil;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.util.ResourceUtils;
import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static com.xxx.xxxutils.utils.ExcelToolUtils.createTestListObject;
import static com.xxx.xxxutils.utils.ExcelToolUtils.createTestListStringHead2;
@RunWith(SpringRunner.class)
@SpringBootTest
public class UtaxExcelSaleTest {
/**
* 07版本excel读数据量少于1千行数据自动转成javamodel,内部采用回调方法.
*
* @throws IOException 简单抛出异常,真实环境需要catch异常,同时在finally中关闭流
*/
@Test
//导入
public void simpleReadJavaModelV2007() throws IOException {
/*InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("d://台账信息" +
".xlsx");*/
//
//ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
//InputStream inputStream = resolver.getResource("D:\\台账信息.xlsx").getInputStream();
InputStream inputStream = new FileInputStream("D:\\台账信息.xlsx");
List<Object> data = EasyExcelFactory.read(inputStream, new Sheet(1, 2, xxxInfo.class));
inputStream.close();
Xxx xxx= new Xxx();
for (int i = 0;i<data.size();i++){
xxx= (Xxx) data.get(i);
}
//print(data);
System.out.println(data);
}
@Test
//导出
public void writeV2007() throws IOException {
Long startTime = System.currentTimeMillis();
//文件输出位置
OutputStream out = new FileOutputStream("D:\\outTest.xlsx");
ExcelWriter writer = EasyExcelFactory.getWriter(out);
//写第一个sheet, sheet1 数据全是List<String> 无模型映射关系
//MultiLineHeadExcelModelTest1是写入excel的数据模型对象
Sheet sheet1 = new Sheet(1,3, MultiLineHeadExcelModelTest1.class,"第一个sheet",null);
//sheet1.setSheetName("testOne");
//设置列宽 设置每列的宽度
/*Map columnWidth = new HashMap();
columnWidth.put(0,10000);
columnWidth.put(1,40000);columnWidth.put(2,10000);columnWidth.put(3,10000);
sheet1.setColumnWidthMap(columnWidth);
sheet1.setHead(createTestListStringHead2());*/
//or 设置自适应宽度
//sheet1.setAutoWidth(Boolean.TRUE);
//参数一:写入的数据(要写入的结果集,list集合),参数二:写入的目标sheet
writer.write1(createTestListObject(), sheet1);
//将上下文中的最终OutputStream写入到指定文件中
writer.finish();
//关闭流
out.close();
Long endTime = System.currentTimeMillis();
Long time = endTime - startTime;
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
System.out.println("excel导出共花费 "+time/1000+"秒");
}
@Test
//动态生成表头(导出)
public void writeV2() throws IOException {
Long startTime = System.currentTimeMillis();
//文件输出位置
OutputStream out = new FileOutputStream("outTest2.xlsx");
ExcelWriter writer = EasyExcelFactory.getWriter(out);
//写第一个sheet, sheet1 数据全是List<String> 无模型映射关系
Sheet sheet1 = new Sheet(1, 0);
sheet1.setSheetName("第一个sheet");
//创建一个表格,用于sheet中使用
Table table1 = new Table(1);
//设置列宽 设置每列的宽度
/*Map columnWidth = new HashMap();
columnWidth.put(0,10000);
columnWidth.put(1,40000);
columnWidth.put(2,10000);
columnWidth.put(3,10000);
sheet1.setColumnWidthMap(columnWidth);*/
table1.setHead(createTestListStringHead2());
//or 设置自适应宽度
//sheet1.setAutoWidth(Boolean.TRUE);
//参数一:写入的数据(要写入的结果集,list集合),参数二:写入的目标sheet
writer.write1(createTestListObject(), sheet1,table1);
//合并单元格
writer.merge(5,6,0,4);
//将上下文中的最终OutputStream写入到指定文件中
writer.finish();
//关闭流
out.close();
Long endTime = System.currentTimeMillis();
Long time = endTime - startTime;
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
System.out.println("excel导出共花费 "+time/1000+"秒");
}
@Test
//导入
public void testRead(){
try (FileInputStream inputStream = new FileInputStream(ResourceUtils.getFile("classpath:excels/2003.xls"))) {
List<User> users = ExcelUtil.readExcel(new BufferedInputStream(inputStream), User.class);
System.out.println(users);
} catch (IOException e) {
e.printStackTrace();
}
}
//========================================================================
/**
* 读取少于1000行的excle(导入)
*/
@Test
public void readLessThan1000Row(){
String filePath = "outTest2.xlsx";
List<Object> objects = ExcelUtil.readLessThan1000Row(filePath);
objects.forEach(System.out::println);
}
/**
* 读取少于1000行的excle,可以指定sheet和从几行读起(导入)
*/
@Test
public void readLessThan1000RowBySheet(){
String filePath = "outTest2.xlsx";
Sheet sheet = new Sheet(1, 1);
List<Object> objects = ExcelUtil.readLessThan1000RowBySheet(filePath,sheet);
objects.forEach(System.out::println);
}
/**
* 读取大于1000行的excle
* 带sheet参数的方法可参照测试方法readLessThan1000RowBySheet(),导入
*/
@Test
public void readMoreThan1000Row(){
String filePath = "outTest2.xlsx";
List<Object> objects = ExcelUtil.readMoreThan1000Row(filePath);
objects.forEach(System.out::println);
}
/**
* 生成excle
* 带sheet参数的方法可参照测试方法readLessThan1000RowBySheet(),导出
*/
@Test
public void writeBySimple(){
String filePath = "outTest1.xlsx";
List<List<Object>> data = new ArrayList<>();
data.add(Arrays.asList("111","222","333"));
data.add(Arrays.asList("111","222","333"));
data.add(Arrays.asList("111","222","333"));
List<String> head = Arrays.asList("表头1", "表头2", "表头3");
ExcelUtil.writeBySimple(filePath,data,head);
}
/**
* 生成excle, 带用模型
* 带sheet参数的方法可参照测试方法readLessThan1000RowBySheet(),导出
*/
@Test
public void writeWithTemplate(){
String filePath = "outTest4.xlsx";
ArrayList<TableHeaderExcelProperty> data = new ArrayList<>();
for(int i = 0; i < 4; i++){
/*TableHeaderExcelProperty tableHeaderExcelProperty = new TableHeaderExcelProperty();
tableHeaderExcelProperty.setName("cmj" + i);
tableHeaderExcelProperty.setAge(22 + i);
tableHeaderExcelProperty.setSchool("清华大学" + i);*/
TableHeaderExcelProperty tableHeaderExcelProperty = TableHeaderExcelProperty
.builder()
.name("cmj" + i).age(22 + i).school("清华大学" + i)
.build();
data.add(tableHeaderExcelProperty);
}
ExcelUtil.writeWithTemplate(filePath,data);
}
/**
* 生成excle, 带用模型,带多个sheet,导出
*/
@Test
public void writeWithMultipleSheel(){
ArrayList<ExcelUtil.MultipleSheelPropety> list1 = new ArrayList<>();
for(int j = 1; j < 4; j++){
ArrayList<TableHeaderExcelProperty> list = new ArrayList<>();
for(int i = 0; i < 4; i++){
/*TableHeaderExcelProperty tableHeaderExcelProperty = new TableHeaderExcelProperty();
tableHeaderExcelProperty.setName("cmj" + i);
tableHeaderExcelProperty.setAge(22 + i);
tableHeaderExcelProperty.setSchool("清华大学" + i);*/
TableHeaderExcelProperty tableHeaderExcelProperty = TableHeaderExcelProperty.
builder()
.name("cmj" + i).age(22 + i).school("清华大学" + i)
.build();
list.add(tableHeaderExcelProperty);
}
Sheet sheet = new Sheet(j, 0);
sheet.setSheetName("sheet" + j);
ExcelUtil.MultipleSheelPropety multipleSheelPropety = new ExcelUtil.MultipleSheelPropety();
multipleSheelPropety.setData(list);
multipleSheelPropety.setSheet(sheet);
list1.add(multipleSheelPropety);
}
ExcelUtil.writeWithMultipleSheel("outTest5.xlsx",list1);
}
@Test
//遍历文件夹下文件
public void testFiles() throws FileNotFoundException {
//File file = ResourceUtils.getFile("classpath:templates/b_dfd.txt");
File file = ResourceUtils.getFile("classpath:excels");
if(file.exists()){
File[] files = file.listFiles();
if(files != null){
for(File childFile:files){
System.out.println(childFile.getName());
}
}
}
}
}
5、表头的添加
动态添加表头方法
package com.xxx.xxxutils.utils;
import com.alibaba.excel.metadata.Font;
import com.alibaba.excel.metadata.TableStyle;
import org.apache.poi.ss.usermodel.IndexedColors;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
*@ClassName: ExcelToolUtils
*@Description: 无注解模式,动态添加表头,也可自由组合复杂表头
**/
public class ExcelToolUtils {
/**
*@Description: 无注解模式,动态添加表头1,也可自由组合复杂表头
**/
public static List<List<String>> createTestListStringHead(){
//写sheet3 模型上没有注解,表头数据动态传入
List<List<String>> head = new ArrayList<List<String>>();
List<String> headCoulumn1 = new ArrayList<String>();
List<String> headCoulumn2 = new ArrayList<String>();
List<String> headCoulumn3 = new ArrayList<String>();
List<String> headCoulumn4 = new ArrayList<String>();
List<String> headCoulumn5 = new ArrayList<String>();
headCoulumn1.add("第一列");headCoulumn1.add("第一列");headCoulumn1.add("第一列");
headCoulumn2.add("第一列");headCoulumn2.add("第一列");headCoulumn2.add("第一列");
headCoulumn3.add("第二列");headCoulumn3.add("第二列");headCoulumn3.add("第二列");
headCoulumn4.add("第三列");headCoulumn4.add("第三列2");headCoulumn4.add("第三列2");
headCoulumn5.add("第一列");headCoulumn5.add("第3列");headCoulumn5.add("第4列");
head.add(headCoulumn1);
head.add(headCoulumn2);
head.add(headCoulumn3);
head.add(headCoulumn4);
head.add(headCoulumn5);
return head;
}
/**
*@Description: 无注解模式,动态添加表头2,也可自由组合复杂表头
**/
public static List<List<String>> createTestListStringHead2(){
List<List<String>> head = new ArrayList<List<String>>();
List<String> headCoulumn1 = new ArrayList<String>();
List<String> headCoulumn2 = new ArrayList<String>();
List<String> headCoulumn3 = new ArrayList<String>();
List<String> headCoulumn4 = new ArrayList<String>();
List<String> headCoulumn5 = new ArrayList<String>();
List<String> headCoulumn6 = new ArrayList<String>();
List<String> headCoulumn7 = new ArrayList<String>();
//如果行列里面都是一样的数据就直接合并为一个单元格
//第一列的第一行
headCoulumn1.add("第一列");
//第一列的第二行
headCoulumn1.add("第一列");
//第一列的第三行
headCoulumn1.add("第一列");
//第一列的第四行
headCoulumn1.add("22");
//第二列的第一行
headCoulumn2.add("第一列");
//第二列的第二行
headCoulumn2.add("第一列");
//第二列的第三行
headCoulumn2.add("第一列");
//第二列的第四行
headCoulumn2.add("33");
headCoulumn3.add("第二列");
headCoulumn3.add("第二列");
headCoulumn3.add("第二列");
headCoulumn3.add("第二列");
headCoulumn4.add("第三列");
headCoulumn4.add("第三列2");
headCoulumn4.add("第三列2");
headCoulumn4.add("第三列3");
headCoulumn5.add("第四列");
headCoulumn5.add("41");
headCoulumn5.add("42");
headCoulumn5.add("43");
headCoulumn6.add("第N列");
headCoulumn6.add("第3列");
headCoulumn6.add("第99列");
headCoulumn6.add("第100列");
headCoulumn7.add("第N列");
headCoulumn7.add("第3列");
headCoulumn7.add("第101列");
headCoulumn7.add("第102列");
head.add(headCoulumn1);
head.add(headCoulumn2);
head.add(headCoulumn3);
head.add(headCoulumn4);
head.add(headCoulumn5);
head.add(headCoulumn6);
head.add(headCoulumn7);
return head;
}
/**
*@Description: 往表格添加数据
**/
public static List<List<Object>> createTestListObject() {
List<List<Object>> object = new ArrayList<List<Object>>();
for (int i = 0; i < 1000; i++) {
List<Object> da = new ArrayList<Object>();
da.add("字符串"+i);
da.add(Long.valueOf(187837834l+i));
da.add(Integer.valueOf(2233+i));
da.add(Double.valueOf(2233.00+i));
da.add(Float.valueOf(2233.0f+i));
da.add(new Date());
da.add(new BigDecimal("3434343433554545"+i));
da.add(Short.valueOf((short)i));
object.add(da);
}
return object;
}
/**
*@Description: 设置表格样式
**/
public static TableStyle createTableStyle(){
TableStyle tableStyle = new TableStyle();
//设置表头样式
Font headFont = new Font();
//字体是否加粗
headFont.setBold(true);
//字体大小
headFont.setFontHeightInPoints((short)12);
//字体
headFont.setFontName("楷体");
tableStyle.setTableHeadFont(headFont);
//背景色
tableStyle.setTableContentBackGroundColor(IndexedColors.BLUE);
//设置表格主题样式
Font contentFont = new Font();
contentFont.setBold(true);
contentFont.setFontHeightInPoints((short)12);
contentFont.setFontName("黑体");
tableStyle.setTableContentFont(contentFont);
tableStyle.setTableContentBackGroundColor(IndexedColors.GREEN);
return tableStyle;
}
}
通过注解方式添加表头
package com.xxx.xxxutils.model;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @ClassName: MultiLineHeadExcelModelTest1
* @Description: 复杂表头实体类
* ExayExcel 提供注解的方式, 来方便的定义 Excel 需要的数据模型
* ①:首先,定义的写入模型必须要继承自 BaseRowModel
* ②:通过 @ExcelProperty 注解来指定每个字段的列名称,以及下标位置;
**/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class MultiLineHeadExcelModelTest1 extends BaseReadModel{
//如果行列里面都是一样的数据就直接合并为一个单元格
//---------------------第一列的第一行,第一列的第二行,第一列的第三行
@ExcelProperty(value = {"表头1","表头1","表头31"},index = 0)
private String p1;
//---------------------第二列的第一行,第二列的第二行,第二列的第三行
@ExcelProperty(value = {"表头1","表头1","表头32"},index = 1)
private String p2;
@ExcelProperty(value = {"表头3","表头3","表头3"},index = 2)
private int p3;
@ExcelProperty(value = {"表头4","表头4","表头4"},index = 3)
private long p4;
@ExcelProperty(value = {"表头5","表头51","表头52"},index = 4)
private String p5;
@ExcelProperty(value = {"表头6","表头61","表头611"},index = 5)
private String p6;
@ExcelProperty(value = {"表头6","表头61","表头612"},index = 6)
private String p7;
@ExcelProperty(value = {"表头6","表头62","表头621"},index = 7)
private String p8;
@ExcelProperty(value = {"表头6","表头62","表头622"},index = 8)
private String p9;
}
生成表头效果
6、总结
ddd博客参考:史上最全的Excel导入导出(easyexcel版)
easyexcel官方文档:easyexcel/README.md at master · alibaba/easyexcel · GitHub
easyexcel官方源码: GitHub - alibaba/easyexcel: 快速、简单避免OOM的java处理Excel工具
easyexcel博客参考:1、史上最全的Excel导入导出之easyexcel_点缀星空-CSDN博客_easyexcel
2、Java解析excel工具easyexcel 助你快速简单避免OOM_成长中的巨人-CSDN博客_excel解析
3、阿里开源的 5.7k star Excel工具实战!快速简单避免内存溢出。
动态表头的添加如果以日常操作excel的思维来理解还是很好弄懂的。