JAVA连接Excel最好用的开源项目EasyExcel,官方使用文档及.jar包下载
EasyExcel是一个基于Java的简单、省内存的读写Excel的开源项目。在尽可能节约内存的情况下支持读写百M的Excel。
github地址:https://github.com/alibaba/easyexcel
开源项目不容易,如果觉得本项目对您的工作还是有帮助的话,请在帮忙在github star点个★Star。
我使用后,觉得阿里确实很用心,使用简单,速度还快,这个⭐可以给。
如果以下内容还是看不懂,给他们点个小星星,然后我教你,嘻嘻。
jar下载地址:https://share.weiyun.com/5ADw1oz
读excel的DEMO文档
package com.alibaba.easyexcel.test.demo.read;
import java.io.File;
import java.util.List;
import java.util.Map;
import org.junit.Ignore;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.easyexcel.test.util.TestFileUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.format.DateTimeFormat;
import com.alibaba.excel.annotation.format.NumberFormat;
import com.alibaba.excel.converters.DefaultConverterLoader;
import com.alibaba.excel.enums.CellExtraTypeEnum;
import com.alibaba.excel.read.metadata.ReadSheet;
import com.alibaba.fastjson.JSON;
/**
* 读的常见写法
*
* @author Jiaju Zhuang
*/
@Ignore
public class ReadTest {
private static final Logger LOGGER = LoggerFactory.getLogger(ReadTest.class);
/**
* 最简单的读
* <p>
* 1. 创建excel对应的实体对象 参照{@link DemoData}
* <p>
* 2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoDataListener}
* <p>
* 3. 直接读即可
*/
@Test
public void simpleRead() {
// 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去
// 写法1:
String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";
// 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭
EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).sheet().doRead();
// 写法2:
fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";
ExcelReader excelReader = EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).build();
ReadSheet readSheet = EasyExcel.readSheet(0).build();
excelReader.read(readSheet);
// 这里千万别忘记关闭,读的时候会创建临时文件,到时磁盘会崩的
excelReader.finish();
}
/**
* 指定列的下标或者列名
*
* <p>
* 1. 创建excel对应的实体对象,并使用{@link ExcelProperty}注解. 参照{@link IndexOrNameData}
* <p>
* 2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器,参照{@link IndexOrNameDataListener}
* <p>
* 3. 直接读即可
*/
@Test
public void indexOrNameRead() {
String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";
// 这里默认读取第一个sheet
EasyExcel.read(fileName, IndexOrNameData.class, new IndexOrNameDataListener()).sheet().doRead();
}
/**
* 读多个或者全部sheet,这里注意一个sheet不能读取多次,多次读取需要重新读取文件
* <p>
* 1. 创建excel对应的实体对象 参照{@link DemoData}
* <p>
* 2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoDataListener}
* <p>
* 3. 直接读即可
*/
@Test
public void repeatedRead() {
String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";
// 读取全部sheet
// 这里需要注意 DemoDataListener的doAfterAllAnalysed 会在每个sheet读取完毕后调用一次。然后所有sheet都会往同一个DemoDataListener里面写
EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).doReadAll();
// 读取部分sheet
fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";
ExcelReader excelReader = EasyExcel.read(fileName).build();
// 这里为了简单 所以注册了 同样的head 和Listener 自己使用功能必须不同的Listener
ReadSheet readSheet1 =
EasyExcel.readSheet(0).head(DemoData.class).registerReadListener(new DemoDataListener()).build();
ReadSheet readSheet2 =
EasyExcel.readSheet(1).head(DemoData.class).registerReadListener(new DemoDataListener()).build();
// 这里注意 一定要把sheet1 sheet2 一起传进去,不然有个问题就是03版的excel 会读取多次,浪费性能
excelReader.read(readSheet1, readSheet2);
// 这里千万别忘记关闭,读的时候会创建临时文件,到时磁盘会崩的
excelReader.finish();
}
/**
* 日期、数字或者自定义格式转换
* <p>
* 默认读的转换器{@link DefaultConverterLoader#loadDefaultReadConverter()}
* <p>
* 1. 创建excel对应的实体对象 参照{@link ConverterData}.里面可以使用注解{@link DateTimeFormat}、{@link NumberFormat}或者自定义注解
* <p>
* 2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器,参照{@link ConverterDataListener}
* <p>
* 3. 直接读即可
*/
@Test
public void converterRead() {
String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";
// 这里 需要指定读用哪个class去读,然后读取第一个sheet
EasyExcel.read(fileName, ConverterData.class, new ConverterDataListener())
// 这里注意 我们也可以registerConverter来指定自定义转换器, 但是这个转换变成全局了, 所有java为string,excel为string的都会用这个转换器。
// 如果就想单个字段使用请使用@ExcelProperty 指定converter
// .registerConverter(new CustomStringStringConverter())
// 读取sheet
.sheet().doRead();
}
/**
* 多行头
*
* <p>
* 1. 创建excel对应的实体对象 参照{@link DemoData}
* <p>
* 2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoDataListener}
* <p>
* 3. 设置headRowNumber参数,然后读。 这里要注意headRowNumber如果不指定, 会根据你传入的class的{@link ExcelProperty#value()}里面的表头的数量来决定行数,
* 如果不传入class则默认为1.当然你指定了headRowNumber不管是否传入class都是以你传入的为准。
*/
@Test
public void complexHeaderRead() {
String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";
// 这里 需要指定读用哪个class去读,然后读取第一个sheet
EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).sheet()
// 这里可以设置1,因为头就是一行。如果多行头,可以设置其他值。不传入也可以,因为默认会根据DemoData 来解析,他没有指定头,也就是默认1行
.headRowNumber(1).doRead();
}
/**
* 读取表头数据
*
* <p>
* 1. 创建excel对应的实体对象 参照{@link DemoData}
* <p>
* 2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoHeadDataListener}
* <p>
* 3. 直接读即可
*/
@Test
public void headerRead() {
String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";
// 这里 需要指定读用哪个class去读,然后读取第一个sheet
EasyExcel.read(fileName, DemoData.class, new DemoHeadDataListener()).sheet().doRead();
}
/**
* 额外信息(批注、超链接、合并单元格信息读取)
* <p>
* 由于是流式读取,没法在读取到单元格数据的时候直接读取到额外信息,所以只能最后通知哪些单元格有哪些额外信息
*
* <p>
* 1. 创建excel对应的实体对象 参照{@link DemoExtraData}
* <p>
* 2. 由于默认异步读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoExtraListener}
* <p>
* 3. 直接读即可
*
* @since 2.2.0-beat1
*/
@Test
public void extraRead() {
String fileName = TestFileUtil.getPath() + "demo" + File.separator + "extra.xlsx";
// 这里 需要指定读用哪个class去读,然后读取第一个sheet
EasyExcel.read(fileName, DemoExtraData.class, new DemoExtraListener())
// 需要读取批注 默认不读取
.extraRead(CellExtraTypeEnum.COMMENT)
// 需要读取超链接 默认不读取
.extraRead(CellExtraTypeEnum.HYPERLINK)
// 需要读取合并单元格信息 默认不读取
.extraRead(CellExtraTypeEnum.MERGE).sheet().doRead();
}
/**
* 读取公式和单元格类型
*
* <p>
* 1. 创建excel对应的实体对象 参照{@link CellDataReadDemoData}
* <p>
* 2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoHeadDataListener}
* <p>
* 3. 直接读即可
*
* @since 2.2.0-beat1
*/
@Test
public void cellDataRead() {
String fileName = TestFileUtil.getPath() + "demo" + File.separator + "cellDataDemo.xlsx";
// 这里 需要指定读用哪个class去读,然后读取第一个sheet
EasyExcel.read(fileName, CellDataReadDemoData.class, new CellDataDemoHeadDataListener()).sheet().doRead();
}
/**
* 数据转换等异常处理
*
* <p>
* 1. 创建excel对应的实体对象 参照{@link ExceptionDemoData}
* <p>
* 2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoExceptionListener}
* <p>
* 3. 直接读即可
*/
@Test
public void exceptionRead() {
String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";
// 这里 需要指定读用哪个class去读,然后读取第一个sheet
EasyExcel.read(fileName, ExceptionDemoData.class, new DemoExceptionListener()).sheet().doRead();
}
/**
* 同步的返回,不推荐使用,如果数据量大会把数据放到内存里面
*/
@Test
public void synchronousRead() {
String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";
// 这里 需要指定读用哪个class去读,然后读取第一个sheet 同步读取会自动finish
List<DemoData> list = EasyExcel.read(fileName).head(DemoData.class).sheet().doReadSync();
for (DemoData data : list) {
LOGGER.info("读取到数据:{}", JSON.toJSONString(data));
}
// 这里 也可以不指定class,返回一个list,然后读取第一个sheet 同步读取会自动finish
List<Map<Integer, String>> listMap = EasyExcel.read(fileName).sheet().doReadSync();
for (Map<Integer, String> data : listMap) {
// 返回每条数据的键值对 表示所在的列 和所在列的值
LOGGER.info("读取到数据:{}", JSON.toJSONString(data));
}
}
/**
* 不创建对象的读
*/
@Test
public void noModelRead() {
String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";
// 这里 只要,然后读取第一个sheet 同步读取会自动finish
EasyExcel.read(fileName, new NoModelDataListener()).sheet().doRead();
}
}
写excel的DEMO文档
package com.alibaba.easyexcel.test.demo.write;
import java.io.File;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.junit.Ignore;
import org.junit.Test;
import com.alibaba.easyexcel.test.util.TestFileUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.format.DateTimeFormat;
import com.alibaba.excel.annotation.format.NumberFormat;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.alibaba.excel.annotation.write.style.ContentRowHeight;
import com.alibaba.excel.annotation.write.style.HeadRowHeight;
import com.alibaba.excel.util.FileUtils;
import com.alibaba.excel.write.merge.LoopMergeStrategy;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.WriteTable;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
/**
* 写的常见写法
*
* @author Jiaju Zhuang
*/
@Ignore
public class WriteTest {
/**
* 最简单的写
* <p>
* 1. 创建excel对应的实体对象 参照{@link DemoData}
* <p>
* 2. 直接写即可
*/
@Test
public void simpleWrite() {
// 写法1
String fileName = TestFileUtil.getPath() + "simpleWrite" + System.currentTimeMillis() + ".xlsx";
// 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
// 如果这里想使用03 则 传入excelType参数即可
EasyExcel.write(fileName, DemoData.class).sheet("模板").doWrite(data());
// 写法2
fileName = TestFileUtil.getPath() + "simpleWrite" + System.currentTimeMillis() + ".xlsx";
// 这里 需要指定写用哪个class去写
ExcelWriter excelWriter = EasyExcel.write(fileName, DemoData.class).build();
WriteSheet writeSheet = EasyExcel.writerSheet("模板").build();
excelWriter.write(data(), writeSheet);
/// 千万别忘记finish 会帮忙关闭流
excelWriter.finish();
}
/**
* 根据参数只导出指定列
* <p>
* 1. 创建excel对应的实体对象 参照{@link DemoData}
* <p>
* 2. 根据自己或者排除自己需要的列
* <p>
* 3. 直接写即可
*
* @since 2.1.1
*/
@Test
public void excludeOrIncludeWrite() {
String fileName = TestFileUtil.getPath() + "excludeOrIncludeWrite" + System.currentTimeMillis() + ".xlsx";
// 根据用户传入字段 假设我们要忽略 date
Set<String> excludeColumnFiledNames = new HashSet<String>();
excludeColumnFiledNames.add("date");
// 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
EasyExcel.write(fileName, DemoData.class).excludeColumnFiledNames(excludeColumnFiledNames).sheet("模板")
.doWrite(data());
fileName = TestFileUtil.getPath() + "excludeOrIncludeWrite" + System.currentTimeMillis() + ".xlsx";
// 根据用户传入字段 假设我们只要导出 date
Set<String> includeColumnFiledNames = new HashSet<String>();
includeColumnFiledNames.add("date");
// 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
EasyExcel.write(fileName, DemoData.class).includeColumnFiledNames(includeColumnFiledNames).sheet("模板")
.doWrite(data());
}
/**
* 指定写入的列
* <p>
* 1. 创建excel对应的实体对象 参照{@link IndexData}
* <p>
* 2. 使用{@link ExcelProperty}注解指定写入的列
* <p>
* 3. 直接写即可
*/
@Test
public void indexWrite() {
String fileName = TestFileUtil.getPath() + "indexWrite" + System.currentTimeMillis() + ".xlsx";
// 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
EasyExcel.write(fileName, IndexData.class).sheet("模板").doWrite(data());
}
/**
* 复杂头写入
* <p>
* 1. 创建excel对应的实体对象 参照{@link ComplexHeadData}
* <p>
* 2. 使用{@link ExcelProperty}注解指定复杂的头
* <p>
* 3. 直接写即可
*/
@Test
public void complexHeadWrite() {
String fileName = TestFileUtil.getPath() + "complexHeadWrite" + System.currentTimeMillis() + ".xlsx";
// 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
EasyExcel.write(fileName, ComplexHeadData.class).sheet("模板").doWrite(data());
}
/**
* 重复多次写入
* <p>
* 1. 创建excel对应的实体对象 参照{@link ComplexHeadData}
* <p>
* 2. 使用{@link ExcelProperty}注解指定复杂的头
* <p>
* 3. 直接调用二次写入即可
*/
@Test
public void repeatedWrite() {
// 方法1 如果写到同一个sheet
String fileName = TestFileUtil.getPath() + "repeatedWrite" + System.currentTimeMillis() + ".xlsx";
// 这里 需要指定写用哪个class去写
ExcelWriter excelWriter = EasyExcel.write(fileName, DemoData.class).build();
// 这里注意 如果同一个sheet只要创建一次
WriteSheet writeSheet = EasyExcel.writerSheet("模板").build();
// 去调用写入,这里我调用了五次,实际使用时根据数据库分页的总的页数来
for (int i = 0; i < 5; i++) {
// 分页去数据库查询数据 这里可以去数据库查询每一页的数据
List<DemoData> data = data();
excelWriter.write(data, writeSheet);
}
/// 千万别忘记finish 会帮忙关闭流
excelWriter.finish();
// 方法2 如果写到不同的sheet 同一个对象
fileName = TestFileUtil.getPath() + "repeatedWrite" + System.currentTimeMillis() + ".xlsx";
// 这里 指定文件
excelWriter = EasyExcel.write(fileName, DemoData.class).build();
// 去调用写入,这里我调用了五次,实际使用时根据数据库分页的总的页数来。这里最终会写到5个sheet里面
for (int i = 0; i < 5; i++) {
// 每次都要创建writeSheet 这里注意必须指定sheetNo 而且sheetName必须不一样
writeSheet = EasyExcel.writerSheet(i, "模板" + i).build();
// 分页去数据库查询数据 这里可以去数据库查询每一页的数据
List<DemoData> data = data();
excelWriter.write(data, writeSheet);
}
/// 千万别忘记finish 会帮忙关闭流
excelWriter.finish();
// 方法3 如果写到不同的sheet 不同的对象
fileName = TestFileUtil.getPath() + "repeatedWrite" + System.currentTimeMillis() + ".xlsx";
// 这里 指定文件
excelWriter = EasyExcel.write(fileName).build();
// 去调用写入,这里我调用了五次,实际使用时根据数据库分页的总的页数来。这里最终会写到5个sheet里面
for (int i = 0; i < 5; i++) {
// 每次都要创建writeSheet 这里注意必须指定sheetNo 而且sheetName必须不一样。这里注意DemoData.class 可以每次都变,我这里为了方便 所以用的同一个class 实际上可以一直变
writeSheet = EasyExcel.writerSheet(i, "模板" + i).head(DemoData.class).build();
// 分页去数据库查询数据 这里可以去数据库查询每一页的数据
List<DemoData> data = data();
excelWriter.write(data, writeSheet);
}
/// 千万别忘记finish 会帮忙关闭流
excelWriter.finish();
}
/**
* 日期、数字或者自定义格式转换
* <p>
* 1. 创建excel对应的实体对象 参照{@link ConverterData}
* <p>
* 2. 使用{@link ExcelProperty}配合使用注解{@link DateTimeFormat}、{@link NumberFormat}或者自定义注解
* <p>
* 3. 直接写即可
*/
@Test
public void converterWrite() {
String fileName = TestFileUtil.getPath() + "converterWrite" + System.currentTimeMillis() + ".xlsx";
// 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
EasyExcel.write(fileName, ConverterData.class).sheet("模板").doWrite(data());
}
/**
* 图片导出
* <p>
* 1. 创建excel对应的实体对象 参照{@link ImageData}
* <p>
* 2. 直接写即可
*/
@Test
public void imageWrite() throws Exception {
String fileName = TestFileUtil.getPath() + "imageWrite" + System.currentTimeMillis() + ".xlsx";
// 如果使用流 记得关闭
InputStream inputStream = null;
try {
List<ImageData> list = new ArrayList<ImageData>();
ImageData imageData = new ImageData();
list.add(imageData);
String imagePath = TestFileUtil.getPath() + "converter" + File.separator + "img.jpg";
// 放入五种类型的图片 实际使用只要选一种即可
imageData.setByteArray(FileUtils.readFileToByteArray(new File(imagePath)));
imageData.setFile(new File(imagePath));
imageData.setString(imagePath);
inputStream = FileUtils.openInputStream(new File(imagePath));
imageData.setInputStream(inputStream);
imageData.setUrl(new URL(
"https://raw.githubusercontent.com/alibaba/easyexcel/master/src/test/resources/converter/img.jpg"));
EasyExcel.write(fileName, ImageData.class).sheet().doWrite(list);
} finally {
if (inputStream != null) {
inputStream.close();
}
}
}
/**
* 根据模板写入
* <p>
* 1. 创建excel对应的实体对象 参照{@link IndexData}
* <p>
* 2. 使用{@link ExcelProperty}注解指定写入的列
* <p>
* 3. 使用withTemplate 写取模板
* <p>
* 4. 直接写即可
*/
@Test
public void templateWrite() {
String templateFileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";
String fileName = TestFileUtil.getPath() + "templateWrite" + System.currentTimeMillis() + ".xlsx";
// 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
EasyExcel.write(fileName, DemoData.class).withTemplate(templateFileName).sheet().doWrite(data());
}
/**
* 列宽、行高
* <p>
* 1. 创建excel对应的实体对象 参照{@link WidthAndHeightData}
* <p>
* 2. 使用注解{@link ColumnWidth}、{@link HeadRowHeight}、{@link ContentRowHeight}指定宽度或高度
* <p>
* 3. 直接写即可
*/
@Test
public void widthAndHeightWrite() {
String fileName = TestFileUtil.getPath() + "widthAndHeightWrite" + System.currentTimeMillis() + ".xlsx";
// 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
EasyExcel.write(fileName, WidthAndHeightData.class).sheet("模板").doWrite(data());
}
/**
* 注解形式自定义样式
* <p>
* 1. 创建excel对应的实体对象 参照{@link DemoStyleData}
* <p>
* 3. 直接写即可
*
* @since 2.2.0-beta1
*/
@Test
public void annotationStyleWrite() {
String fileName = TestFileUtil.getPath() + "annotationStyleWrite" + System.currentTimeMillis() + ".xlsx";
// 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
EasyExcel.write(fileName, DemoStyleData.class).sheet("模板").doWrite(data());
}
/**
* 拦截器形式自定义样式
* <p>
* 1. 创建excel对应的实体对象 参照{@link DemoData}
* <p>
* 2. 创建一个style策略 并注册
* <p>
* 3. 直接写即可
*/
@Test
public void handlerStyleWrite() {
String fileName = TestFileUtil.getPath() + "handlerStyleWrite" + 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());
}
/**
* 合并单元格
* <p>
* 1. 创建excel对应的实体对象 参照{@link DemoData} {@link DemoMergeData}
* <p>
* 2. 创建一个merge策略 并注册
* <p>
* 3. 直接写即可
*
* @since 2.2.0-beta1
*/
@Test
public void mergeWrite() {
// 方法1 注解
String fileName = TestFileUtil.getPath() + "mergeWrite" + System.currentTimeMillis() + ".xlsx";
// 在DemoStyleData里面加上ContentLoopMerge注解
// 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
EasyExcel.write(fileName, DemoMergeData.class).sheet("模板").doWrite(data());
// 方法2 自定义合并单元格策略
fileName = TestFileUtil.getPath() + "mergeWrite" + System.currentTimeMillis() + ".xlsx";
// 每隔2行会合并 把eachColumn 设置成 3 也就是我们数据的长度,所以就第一列会合并。当然其他合并策略也可以自己写
LoopMergeStrategy loopMergeStrategy = new LoopMergeStrategy(2, 0);
// 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
EasyExcel.write(fileName, DemoData.class).registerWriteHandler(loopMergeStrategy).sheet("模板").doWrite(data());
}
/**
* 使用table去写入
* <p>
* 1. 创建excel对应的实体对象 参照{@link DemoData}
* <p>
* 2. 然后写入table即可
*/
@Test
public void tableWrite() {
String fileName = TestFileUtil.getPath() + "tableWrite" + System.currentTimeMillis() + ".xlsx";
// 这里直接写多个table的案例了,如果只有一个 也可以直一行代码搞定,参照其他案例
// 这里 需要指定写用哪个class去写
ExcelWriter excelWriter = EasyExcel.write(fileName, DemoData.class).build();
// 把sheet设置为不需要头 不然会输出sheet的头 这样看起来第一个table 就有2个头了
WriteSheet writeSheet = EasyExcel.writerSheet("模板").needHead(Boolean.FALSE).build();
// 这里必须指定需要头,table 会继承sheet的配置,sheet配置了不需要,table 默认也是不需要
WriteTable writeTable0 = EasyExcel.writerTable(0).needHead(Boolean.TRUE).build();
WriteTable writeTable1 = EasyExcel.writerTable(1).needHead(Boolean.TRUE).build();
// 第一次写入会创建头
excelWriter.write(data(), writeSheet, writeTable0);
// 第二次写如也会创建头,然后在第一次的后面写入数据
excelWriter.write(data(), writeSheet, writeTable1);
/// 千万别忘记finish 会帮忙关闭流
excelWriter.finish();
}
/**
* 动态头,实时生成头写入
* <p>
* 思路是这样子的,先创建List<String>头格式的sheet仅仅写入头,然后通过table 不写入头的方式 去写入数据
*
* <p>
* 1. 创建excel对应的实体对象 参照{@link DemoData}
* <p>
* 2. 然后写入table即可
*/
@Test
public void dynamicHeadWrite() {
String fileName = TestFileUtil.getPath() + "dynamicHeadWrite" + System.currentTimeMillis() + ".xlsx";
EasyExcel.write(fileName)
// 这里放入动态头
.head(head()).sheet("模板")
// 当然这里数据也可以用 List<List<String>> 去传入
.doWrite(data());
}
/**
* 自动列宽(不太精确)
* <p>
* 这个目前不是很好用,比如有数字就会导致换行。而且长度也不是刚好和实际长度一致。 所以需要精确到刚好列宽的慎用。 当然也可以自己参照
* {@link LongestMatchColumnWidthStyleStrategy}重新实现.
* <p>
* poi 自带{@link SXSSFSheet#autoSizeColumn(int)} 对中文支持也不太好。目前没找到很好的算法。 有的话可以推荐下。
*
* <p>
* 1. 创建excel对应的实体对象 参照{@link LongestMatchColumnWidthData}
* <p>
* 2. 注册策略{@link LongestMatchColumnWidthStyleStrategy}
* <p>
* 3. 直接写即可
*/
@Test
public void longestMatchColumnWidthWrite() {
String fileName =
TestFileUtil.getPath() + "longestMatchColumnWidthWrite" + System.currentTimeMillis() + ".xlsx";
// 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
EasyExcel.write(fileName, LongestMatchColumnWidthData.class)
.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).sheet("模板").doWrite(dataLong());
}
/**
* 下拉,超链接等自定义拦截器(上面几点都不符合但是要对单元格进行操作的参照这个)
* <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());
}
/**
* 插入批注
* <p>
* 1. 创建excel对应的实体对象 参照{@link DemoData}
* <p>
* 2. 注册拦截器 {@link CommentWriteHandler}
* <p>
* 2. 直接写即可
*/
@Test
public void commentWrite() {
String fileName = TestFileUtil.getPath() + "commentWrite" + System.currentTimeMillis() + ".xlsx";
// 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
// 这里要注意inMemory 要设置为true,才能支持批注。目前没有好的办法解决 不在内存处理批注。这个需要自己选择。
EasyExcel.write(fileName, DemoData.class).inMemory(Boolean.TRUE).registerWriteHandler(new CommentWriteHandler())
.sheet("模板").doWrite(data());
}
/**
* 可变标题处理(包括标题国际化等)
* <p>
* 简单的说用List<List<String>>的标题 但是还支持注解
* <p>
* 1. 创建excel对应的实体对象 参照{@link ConverterData}
* <p>
* 2. 直接写即可
*/
@Test
public void variableTitleWrite() {
// 写法1
String fileName = TestFileUtil.getPath() + "variableTitleWrite" + System.currentTimeMillis() + ".xlsx";
// 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
EasyExcel.write(fileName, ConverterData.class).head(variableTitleHead()).sheet("模板").doWrite(data());
}
/**
* 不创建对象的写
*/
@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<LongestMatchColumnWidthData> dataLong() {
List<LongestMatchColumnWidthData> list = new ArrayList<LongestMatchColumnWidthData>();
for (int i = 0; i < 10; i++) {
LongestMatchColumnWidthData data = new LongestMatchColumnWidthData();
data.setString("测试很长的字符串测试很长的字符串测试很长的字符串" + i);
data.setDate(new Date());
data.setDoubleData(1000000000000.0);
list.add(data);
}
return list;
}
private List<List<String>> variableTitleHead() {
List<List<String>> list = new ArrayList<List<String>>();
List<String> head0 = new ArrayList<String>();
head0.add("string" + System.currentTimeMillis());
List<String> head1 = new ArrayList<String>();
head1.add("number" + System.currentTimeMillis());
List<String> head2 = new ArrayList<String>();
head2.add("date" + System.currentTimeMillis());
list.add(head0);
list.add(head1);
list.add(head2);
return list;
}
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;
}
private List<DemoData> data() {
List<DemoData> list = new ArrayList<DemoData>();
for (int i = 0; i < 10; i++) {
DemoData data = new DemoData();
data.setString("字符串" + i);
data.setDate(new Date());
data.setDoubleData(0.56);
list.add(data);
}
return list;
}
}
写在最后:
我叫风骨散人,名字的意思是我多想可以不低头的自由生活,可现实却不是这样。家境贫寒,总得向这个世界低头,所以我一直在奋斗,想改变我的命运给亲人好的生活,希望同样被生活绑架的你可以通过自己的努力改变现状,深知成年人的世界里没有容易二字。目前是一名在校大学生,预计考研,热爱编程,热爱技术,喜欢分享,知识无界,希望我的分享可以帮到你!
如果有什么想看的,可以私信我,如果在能力范围内,我会发布相应的博文!
感谢大家的阅读!JAVA连接Excel最好用的开源项目EasyExcel,官方使用文档及.jar包下载的更多相关文章
- maven 项目 pom.xml文件中配置的jar包下载报错
[ERROR] [ERROR] Some problems were encountered while processing the POMs:[ERROR] 'dependencies.depen ...
- Java 使用poi导入excel,结合xml文件进行数据验证的例子(增加了jar包)
ava 使用poi导入excel,结合xml文件进行数据验证的例子(增加了jar包) 假设现在要做一个通用的导入方法: 要求: 1.xml的只定义数据库表中的column字段,字段类型,是否非空等条件 ...
- JAVA之旅(十一)——RuntimeException,异常的总结,Package,jar包,多线程概述
JAVA之旅(十一)--RuntimeException,异常的总结,Package,jar包,多程序概述 继续JAVA之旅 一.RuntimeException 在Exception种有一个特殊的子 ...
- 项目 插件 -下载- 使用,jar包-下载
插件 -下载- 使用 BootCDN前端开源项目https://www.bootcdn.cn/all/ bootstrap:HTML.CSS 和 JS 框架 插件https://v3.bootc ...
- Jar包下载 开源网站 模板下载
在日常的java学习和开发中,总是遇到各种jar包下载,但是CSDN这种坑爹网站,各位码农们都想挣点C币,一个开源的免费的东西就这么变了味,我这里收集 了一些好用的工具,日常开发中需要用的请自取,毕竟 ...
- Oracle调用Java方法(上)如何使用LoadJava命令和如何将简单的Jar包封装成Oracle方法
最近在工作中遇到了遇到了一个需求需要将TIPTOP中的数据导出成XML并上传到FTP主机中,但是4GL这方面的文档比较少最终决定使用Oracle调用Java的方法,在使用的过程中发现有很多的坑,大部分 ...
- C#开源组件DocX处理Word文档基本操作(二)
上一篇 C#开源组件DocX处理Word文档基本操作(一) 介绍了DocX的段落.表格及图片的处理,本篇介绍页眉页脚的处理. 示例代码所用DocX版本为:1.3.0.0.关于版本的区别,请参见上篇,而 ...
- 2022最新版超详细的Maven下载配置教程、IDEA中集成maven(包含图解过程)、以及导入项目时jar包下载不成功的问题解决
文章目录 1.maven下载 2.maven环境变量的配置 3.查看maven是否配置成功 4.配置文件的修改 5.IDEA集成maven 6.导入项目时jar包下载不成功的问题解决 maven教程: ...
- Java Annotation 及几个常用开源项目注解原理简析
PDF 版: Java Annotation.pdf, PPT 版:Java Annotation.pptx, Keynote 版:Java Annotation.key 一.Annotation 示 ...
随机推荐
- 浅谈 PCA与SVD
前言 在用数据对模型进行训练时,通常会遇到维度过高,也就是数据的特征太多的问题,有时特征之间还存在一定的相关性,这时如果还使用原数据训练模型,模型的精度会大大下降,因此要降低数据的维度,同时新数据的特 ...
- Wirte-up:攻防世界Web解题过程新手区01-06
文章更新于:2020-02-18 说明:为了标识图片边界,有些图片加了红线以增强观感. 注1: web 环境搭建参见: Windows&linux使用集成环境搭建 web 服务器 注2:DVW ...
- 使用ping命令探测系统
什么是ping命令 ping命令是测试网络连接.信息发送和接收状况的实用型工具,是系统内置的探测性工具.它的原理是:每台网络上的主机都有唯一确定的IP地址,用户给目标IP发送一个数据报,对方就要返回一 ...
- hadoop(七)集群配置同步(hadoop完全分布式四)|9
前置配置:rsync远程同步|xsync集群分发(hadoop完全分布式准备三)|9 1. 分布式集群分配原则 部署分配原则 说明Namenode和secondarynamenode占用内存较大,建议 ...
- 《深入理解 Java 虚拟机》笔记整理
正文 一.Java 内存区域与内存溢出异常 1.运行时数据区域 程序计数器:当前线程所执行的字节码的行号指示器.线程私有. Java 虚拟机栈:Java 方法执行的内存模型.线程私有. 本地方法栈:N ...
- Git应用详解第七讲:Git refspec与远程分支的重要操作
前言 前情提要:Git应用详解第六讲:Git协作与Git pull常见问题 这一节来介绍本地仓库与远程仓库的分支映射关系:git refspec.彻底弄清楚本地仓库到底是如何与远程仓库进行联系的. 一 ...
- JVM崩溃的原因及解决!
JVM崩溃的原因及解决! 前些天,搞JNI的时候,报了个JVM崩溃的错.错误信息如下: # # An unexpected error has been detected by HotSpot Vir ...
- JS中的offsetWidth/offsetHeight/offsetTop/offsetLeft、clientWidth/clientHeight/clientTop/clientLeft、scrollWidth/scrollHeight/scrollTop/scrollLeft
这是一组非常容易弄混的参数!都是描述某个盒子元素的宽度.高度以及上或左的距离偏移量. 1. offsetWidth / offsetHeight(不包括外边距) offsetWidth:返回元素的宽度 ...
- 谁说.NET不适合搞大数据,机器学习、人工智能
SciSharp Stack SciSharp STACK: https://scisharp.github.io/SciSharp/ 基于.NET的开源生态系统,用于数据科学.机器学习和AI. Sc ...
- JS生成随机颜色(rgb)
/*随机获取颜色*/ function getRandomColor() { var r = Math.floor(Math.random() * 256); var g = Math.floor(M ...