- * 1. Map,即元素为一个Map,第一个Map的keys作为首行,剩下的行为Map的values,data表示多行
- * 2. Bean,即元素为一个Bean,第一个Bean的字段名列表会作为首行,剩下的行为Bean的字段值列表,data表示多行
- *
- *
- * @param data 数据
- * @param comparator 比较器,用于字段名的排序
- * @return this
- * @since 3.2.3
- */
- @SuppressWarnings({ "rawtypes", "unchecked" })
- public ExcelWriter write(Iterable> data, Comparator comparator) {
- Assert.isFalse(this.isClosed, "ExcelWriter has been closed!");
- boolean isFirstRow = true;
- Map, ?> map;
- for (Object obj : data) {
- if (obj instanceof Map) {
- map = new TreeMap<>(comparator);
- map.putAll((Map) obj);
- } else {
- map = BeanUtil.beanToMap(obj, new TreeMap<>(comparator), false, false);
- }
- writeRow(map, isFirstRow);
- if (isFirstRow) {
- isFirstRow = false;
- }
- }
- return this;
- }
-
- /**
- * 写出一行标题数据
- * 本方法只是将数据写入Workbook中的Sheet,并不写出到文件
- * 写出的起始行为当前行号,可使用{@link #getCurrentRow()}方法调用,根据写出的的行数,当前行号自动+1
- * 样式为默认标题样式,可使用{@link #getHeadCellStyle()}方法调用后自定义默认样式
- *
- * @param rowData 一行的数据
- * @return this
- */
- public ExcelWriter writeHeadRow(Iterable> rowData) {
- Assert.isFalse(this.isClosed, "ExcelWriter has been closed!");
- RowUtil.writeRow(this.sheet.createRow(this.currentRow.getAndIncrement()), rowData, this.styleSet, true);
- return this;
- }
-
- /**
- * 写出一行,根据rowBean数据类型不同,写出情况如下:
- *
- *
- * 1、如果为Iterable,直接写出一行
- * 2、如果为Map,isWriteKeyAsHead为true写出两行,Map的keys做为一行,values做为第二行,否则只写出一行values
- * 3、如果为Bean,转为Map写出,isWriteKeyAsHead为true写出两行,Map的keys做为一行,values做为第二行,否则只写出一行values
- *
- *
- * @param rowBean 写出的Bean
- * @param isWriteKeyAsHead 为true写出两行,Map的keys做为一行,values做为第二行,否则只写出一行values
- * @return this
- * @see #writeRow(Iterable)
- * @see #writeRow(Map, boolean)
- * @since 4.1.5
- */
- @SuppressWarnings({"rawtypes", "unchecked"})
- public ExcelWriter writeRow(Object rowBean, boolean isWriteKeyAsHead) {
- if (rowBean instanceof Iterable) {
- return writeRow((Iterable>) rowBean);
- }
- Map rowMap;
- if (rowBean instanceof Map) {
- if (MapUtil.isNotEmpty(this.headerAlias)) {
- rowMap = MapUtil.newTreeMap((Map) rowBean, getInitedAliasComparator());
- } else {
- rowMap = (Map) rowBean;
- }
- } else if (BeanUtil.isBean(rowBean.getClass())) {
- if (MapUtil.isEmpty(this.headerAlias)) {
- rowMap = BeanUtil.beanToMap(rowBean, new LinkedHashMap<>(), false, false);
- } else {
- // 别名存在情况下按照别名的添加顺序排序Bean数据
- rowMap = BeanUtil.beanToMap(rowBean, new TreeMap<>(getInitedAliasComparator()), false, false);
- }
- } else {
- // 其它转为字符串默认输出
- return writeRow(CollUtil.newArrayList(rowBean), isWriteKeyAsHead);
- }
- return writeRow(rowMap, isWriteKeyAsHead);
- }
-
- /**
- * 将一个Map写入到Excel,isWriteKeyAsHead为true写出两行,Map的keys做为一行,values做为第二行,否则只写出一行values
- * 如果rowMap为空(包括null),则写出空行
- *
- * @param rowMap 写出的Map,为空(包括null),则写出空行
- * @param isWriteKeyAsHead 为true写出两行,Map的keys做为一行,values做为第二行,否则只写出一行values
- * @return this
- */
- public ExcelWriter writeRow(Map, ?> rowMap, boolean isWriteKeyAsHead) {
- Assert.isFalse(this.isClosed, "ExcelWriter has been closed!");
- if (MapUtil.isEmpty(rowMap)) {
- // 如果写出数据为null或空,跳过当前行
- return passCurrentRow();
- }
-
- final Map, ?> aliasMap = aliasMap(rowMap);
-
- if (isWriteKeyAsHead) {
- writeHeadRow(aliasMap.keySet());
- }
- writeRow(aliasMap.values());
- return this;
- }
-
- /**
- * 写出一行数据
- * 本方法只是将数据写入Workbook中的Sheet,并不写出到文件
- * 写出的起始行为当前行号,可使用{@link #getCurrentRow()}方法调用,根据写出的的行数,当前行号自动+1
- * 样式为默认样式,可使用{@link #getCellStyle()}方法调用后自定义默认样式
- *
- * @param rowData 一行的数据
- * @return this
- */
- public ExcelWriter writeRow(Iterable> rowData) {
- Assert.isFalse(this.isClosed, "ExcelWriter has been closed!");
- RowUtil.writeRow(this.sheet.createRow(this.currentRow.getAndIncrement()), rowData, this.styleSet, false);
- return this;
- }
-
- /**
- * 给指定单元格赋值,使用默认单元格样式
- *
- * @param locationRef 单元格地址标识符,例如A11,B5
- * @param value 值
- * @return this
- * @since 5.1.4
- */
- public ExcelWriter writeCellValue(String locationRef, Object value) {
- final CellLocation cellLocation = ExcelUtil.toLocation(locationRef);
- return writeCellValue(cellLocation.getX(), cellLocation.getY(), value);
- }
-
- /**
- * 给指定单元格赋值,使用默认单元格样式
- *
- * @param x X坐标,从0计数,即列号
- * @param y Y坐标,从0计数,即行号
- * @param value 值
- * @return this
- * @since 4.0.2
- */
- public ExcelWriter writeCellValue(int x, int y, Object value) {
- final Cell cell = getOrCreateCell(x, y);
- CellUtil.setCellValue(cell, value, this.styleSet, false);
- return this;
- }
-
- /**
- * 为指定单元格创建样式
- *
- * @param x X坐标,从0计数,即列号
- * @param y Y坐标,从0计数,即行号
- * @return {@link CellStyle}
- * @since 4.0.9
- * @deprecated 请使用{@link #createCellStyle(int, int)}
- */
- @Deprecated
- public CellStyle createStyleForCell(int x, int y) {
- return createCellStyle(x, y);
- }
-
- /**
- * 设置某个单元格的样式
- * 此方法用于多个单元格共享样式的情况
- * 可以调用{@link #getOrCreateCellStyle(int, int)} 方法创建或取得一个样式对象。
- *
- *
- * 需要注意的是,共享样式会共享同一个{@link CellStyle},一个单元格样式改变,全部改变。
- *
- * @param style 单元格样式
- * @param locationRef 单元格地址标识符,例如A11,B5
- * @return this
- * @since 5.1.4
- */
- public ExcelWriter setStyle(CellStyle style, String locationRef) {
- final CellLocation cellLocation = ExcelUtil.toLocation(locationRef);
- return setStyle(style, cellLocation.getX(), cellLocation.getY());
- }
-
- /**
- * 设置某个单元格的样式
- * 此方法用于多个单元格共享样式的情况
- * 可以调用{@link #getOrCreateCellStyle(int, int)} 方法创建或取得一个样式对象。
- *
- *
- * 需要注意的是,共享样式会共享同一个{@link CellStyle},一个单元格样式改变,全部改变。
- *
- * @param style 单元格样式
- * @param x X坐标,从0计数,即列号
- * @param y Y坐标,从0计数,即行号
- * @return this
- * @since 4.6.3
- */
- public ExcelWriter setStyle(CellStyle style, int x, int y) {
- final Cell cell = getOrCreateCell(x, y);
- cell.setCellStyle(style);
- return this;
- }
-
- /**
- * 创建字体
- *
- * @return 字体
- * @since 4.1.0
- */
- public Font createFont() {
- return getWorkbook().createFont();
- }
-
- /**
- * 将Excel Workbook刷出到预定义的文件
- * 如果用户未自定义输出的文件,将抛出{@link NullPointerException}
- * 预定义文件可以通过{@link #setDestFile(File)} 方法预定义,或者通过构造定义
- *
- * @return this
- * @throws IORuntimeException IO异常
- */
- public ExcelWriter flush() throws IORuntimeException {
- return flush(this.destFile);
- }
-
- /**
- * 将Excel Workbook刷出到文件
- * 如果用户未自定义输出的文件,将抛出{@link NullPointerException}
- *
- * @param destFile 写出到的文件
- * @return this
- * @throws IORuntimeException IO异常
- * @since 4.0.6
- */
- public ExcelWriter flush(File destFile) throws IORuntimeException {
- Assert.notNull(destFile, "[destFile] is null, and you must call setDestFile(File) first or call flush(OutputStream).");
- return flush(FileUtil.getOutputStream(destFile), true);
- }
-
- /**
- * 将Excel Workbook刷出到输出流
- *
- * @param out 输出流
- * @return this
- * @throws IORuntimeException IO异常
- */
- public ExcelWriter flush(OutputStream out) throws IORuntimeException {
- return flush(out, false);
- }
-
- /**
- * 将Excel Workbook刷出到输出流
- *
- * @param out 输出流
- * @param isCloseOut 是否关闭输出流
- * @return this
- * @throws IORuntimeException IO异常
- * @since 4.4.1
- */
- public ExcelWriter flush(OutputStream out, boolean isCloseOut) throws IORuntimeException {
- Assert.isFalse(this.isClosed, "ExcelWriter has been closed!");
- try {
- this.workbook.write(out);
- out.flush();
- } catch (IOException e) {
- throw new IORuntimeException(e);
- } finally {
- if (isCloseOut) {
- IoUtil.close(out);
- }
- }
- return this;
- }
-
- /**
- * 关闭工作簿
- * 如果用户设定了目标文件,先写出目标文件后给关闭工作簿
- */
- @Override
- public void close() {
- if (null != this.destFile) {
- flush();
- }
- closeWithoutFlush();
- }
-
- /**
- * 关闭工作簿但是不写出
- */
- protected void closeWithoutFlush() {
- super.close();
-
- // 清空对象
- this.currentRow = null;
- this.styleSet = null;
- }
-
- // -------------------------------------------------------------------------- Private method start
- /**
- * 为指定的key列表添加标题别名,如果没有定义key的别名,在onlyAlias为false时使用原key
- *
- * @param rowMap 一行数据
- * @return 别名列表
- */
- private Map, ?> aliasMap(Map, ?> rowMap) {
- if (MapUtil.isEmpty(this.headerAlias)) {
- return rowMap;
- }
-
- final Map