Browse Source

优化读写逻辑

developing
zhuangjiaju 5 years ago
parent
commit
b90988e194
  1. BIN
      img/readme/quickstart/write/dynamicHeadWrite.png
  2. 42
      quickstart.md
  3. 3
      src/main/java/com/alibaba/excel/annotation/write/style/ColumnWidth.java
  4. 2
      src/main/java/com/alibaba/excel/context/WriteContextImpl.java
  5. 4
      src/main/java/com/alibaba/excel/metadata/AbstractHolder.java
  6. 28
      src/main/java/com/alibaba/excel/write/ExcelBuilderImpl.java
  7. 7
      src/main/java/com/alibaba/excel/write/handler/CellWriteHandler.java
  8. 5
      src/main/java/com/alibaba/excel/write/merge/AbstractMergeStrategy.java
  9. 5
      src/main/java/com/alibaba/excel/write/style/AbstractCellStyleStrategy.java
  10. 14
      src/main/java/com/alibaba/excel/write/style/column/AbstractColumnWidthStyleStrategy.java
  11. 8
      src/main/java/com/alibaba/excel/write/style/column/AbstractHeadColumnWidthStyleStrategy.java
  12. 66
      src/main/java/com/alibaba/excel/write/style/column/LongestMatchColumnWidthStyleStrategy.java
  13. 22
      src/test/java/com/alibaba/easyexcel/test/demo/write/LongestMatchColumnWidthData.java
  14. 65
      src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java

BIN
img/readme/quickstart/write/dynamicHeadWrite.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

42
quickstart.md

@ -21,6 +21,7 @@ DEMO代码地址:[https://github.com/alibaba/easyexcel/blob/master/src/test/ja
* [自定义样式](#styleWrite)
* [合并单元格](#mergeWrite)
* [使用table去写入](#tableWrite)
* [动态头,实时生成头写入](#dynamicHeadWrite)
* [web中的写](#webWrite)
## 读excel样例
@ -697,6 +698,47 @@ public class WidthAndHeightData {
}
```
### <span id="tableWrite" />动态头,实时生成头写入
##### excel示例
![img](img/readme/quickstart/write/dynamicHeadWrite.png)
##### 对象
参照:[对象](#simpleWriteObject)
##### 代码
```java
/**
* 动态头,实时生成头写入
* <p>
* 思路是这样子的,先创建List<String>头格式的sheet仅仅写入头,然后通过table 不写入头的方式 去写入数据
*
* <li>1. 创建excel对应的实体对象 参照{@link DemoData}
* <li>2. 然后写入table即可
*/
@Test
public void dynamicHeadWrite() {
String fileName = TestFileUtil.getPath() + "dynamicHeadWrite" + System.currentTimeMillis() + ".xlsx";
// write的时候 不传入 class 在table的时候传入
EasyExcelFactory.write(fileName)
// 这里放入动态头
.head(head()).sheet("模板")
// table的时候 传入class 并且设置needHead =false
.table().head(DemoData.class).needHead(Boolean.FALSE).doWrite(data());
}
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;
}
```
### <span id="webWrite" />web中的写
##### 示例代码
DEMO代码地址:[https://github.com/alibaba/easyexcel/blob/master/src/test/java/com/alibaba/easyexcel/test/demo/web/WebTest.java](/src/test/java/com/alibaba/easyexcel/test/demo/web/WebTest.java)

3
src/main/java/com/alibaba/excel/annotation/write/style/ColumnWidth.java

@ -15,10 +15,11 @@ import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface ColumnWidth {
/**
* Column width
* <p>
* -1 mean the auto set width
* -1 means the default column width is used
*/
int value() default -1;
}

2
src/main/java/com/alibaba/excel/context/WriteContextImpl.java

@ -275,7 +275,7 @@ public class WriteContextImpl implements WriteContext {
}
for (WriteHandler writeHandler : handlerList) {
if (writeHandler instanceof CellWriteHandler) {
((CellWriteHandler)writeHandler).afterCellCreate(writeSheetHolder, writeTableHolder, cell, head,
((CellWriteHandler)writeHandler).afterCellCreate(writeSheetHolder, writeTableHolder, null, cell, head,
relativeRowIndex, true);
}
}

4
src/main/java/com/alibaba/excel/metadata/AbstractHolder.java

@ -36,12 +36,12 @@ public abstract class AbstractHolder implements ConfigurationHolder {
public AbstractHolder(BasicParameter basicParameter, AbstractHolder prentAbstractHolder) {
this.newInitialization = Boolean.TRUE;
if (basicParameter.getHead() == null && prentAbstractHolder != null) {
if (basicParameter.getHead() == null && basicParameter.getClazz() == null && prentAbstractHolder != null) {
this.head = prentAbstractHolder.getHead();
} else {
this.head = basicParameter.getHead();
}
if (basicParameter.getClazz() == null && prentAbstractHolder != null) {
if (basicParameter.getHead() == null && basicParameter.getClazz() == null && prentAbstractHolder != null) {
this.clazz = prentAbstractHolder.getClazz();
} else {
this.clazz = basicParameter.getClazz();

28
src/main/java/com/alibaba/excel/write/ExcelBuilderImpl.java

@ -179,8 +179,8 @@ public class ExcelBuilderImpl implements ExcelBuilder {
beforeCellCreate(row, head, relativeRowIndex);
Cell cell = WorkBookUtil.createCell(row, cellIndex);
Object value = oneRowData.get(dataIndex);
converterAndSet(context.currentWriteHolder(), value.getClass(), cell, value, null);
afterCellCreate(head, cell, relativeRowIndex);
CellData cellData = converterAndSet(context.currentWriteHolder(), value.getClass(), cell, value, null);
afterCellCreate(head, cellData, cell, relativeRowIndex);
}
private void addJavaObjectToExcel(Object oneRowData, Row row, int relativeRowIndex, List<Field> fieldList) {
@ -202,9 +202,9 @@ public class ExcelBuilderImpl implements ExcelBuilder {
beforeCellCreate(row, head, relativeRowIndex);
Cell cell = WorkBookUtil.createCell(row, cellIndex);
Object value = beanMap.get(name);
converterAndSet(currentWriteHolder, excelContentProperty.getField().getType(), cell, value,
excelContentProperty);
afterCellCreate(head, cell, relativeRowIndex);
CellData cellData = converterAndSet(currentWriteHolder, excelContentProperty.getField().getType(), cell,
value, excelContentProperty);
afterCellCreate(head, cellData, cell, relativeRowIndex);
beanMapHandledSet.add(name);
}
// Finish
@ -229,8 +229,8 @@ public class ExcelBuilderImpl implements ExcelBuilder {
}
beforeCellCreate(row, null, relativeRowIndex);
Cell cell = WorkBookUtil.createCell(row, cellIndex++);
converterAndSet(currentWriteHolder, value.getClass(), cell, value, null);
afterCellCreate(null, cell, relativeRowIndex);
CellData cellData = converterAndSet(currentWriteHolder, value.getClass(), cell, value, null);
afterCellCreate(null, cellData, cell, relativeRowIndex);
}
}
@ -261,7 +261,7 @@ public class ExcelBuilderImpl implements ExcelBuilder {
}
private void afterCellCreate(Head head, Cell cell, int relativeRowIndex) {
private void afterCellCreate(Head head, CellData cellData, Cell cell, int relativeRowIndex) {
List<WriteHandler> handlerList = context.currentWriteHolder().writeHandlerMap().get(CellWriteHandler.class);
if (handlerList == null || handlerList.isEmpty()) {
return;
@ -269,7 +269,7 @@ public class ExcelBuilderImpl implements ExcelBuilder {
for (WriteHandler writeHandler : handlerList) {
if (writeHandler instanceof CellWriteHandler) {
((CellWriteHandler)writeHandler).afterCellCreate(context.writeSheetHolder(), context.writeTableHolder(),
cell, head, relativeRowIndex, false);
cellData, cell, head, relativeRowIndex, false);
}
}
if (null != context.writeWorkbookHolder().getWriteWorkbook().getWriteHandler()) {
@ -277,10 +277,10 @@ public class ExcelBuilderImpl implements ExcelBuilder {
}
}
private void converterAndSet(WriteHolder currentWriteHolder, Class clazz, Cell cell, Object value,
private CellData converterAndSet(WriteHolder currentWriteHolder, Class clazz, Cell cell, Object value,
ExcelContentProperty excelContentProperty) {
if (value == null) {
return;
return null;
}
if (value instanceof String && currentWriteHolder.globalConfiguration().getAutoTrim()) {
value = ((String)value).trim();
@ -296,13 +296,13 @@ public class ExcelBuilderImpl implements ExcelBuilder {
switch (cellData.getType()) {
case STRING:
cell.setCellValue(cellData.getStringValue());
return;
return cellData;
case BOOLEAN:
cell.setCellValue(cellData.getBooleanValue());
return;
return cellData;
case NUMBER:
cell.setCellValue(cellData.getDoubleValue());
return;
return cellData;
default:
throw new ExcelDataConvertException("Not supported data:" + value + " return type:" + cell.getCellType()
+ "at row:" + cell.getRow().getRowNum());

7
src/main/java/com/alibaba/excel/write/handler/CellWriteHandler.java

@ -3,6 +3,7 @@ package com.alibaba.excel.write.handler;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
@ -36,9 +37,11 @@ public interface CellWriteHandler extends WriteHandler {
* Nullable
* @param cell
* @param head
* @param cellData
* Nullable.
* @param relativeRowIndex
* @param isHead
*/
void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head,
int relativeRowIndex, boolean isHead);
void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, CellData cellData,
Cell cell, Head head, int relativeRowIndex, boolean isHead);
}

5
src/main/java/com/alibaba/excel/write/merge/AbstractMergeStrategy.java

@ -4,6 +4,7 @@ import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
@ -22,8 +23,8 @@ public abstract class AbstractMergeStrategy implements CellWriteHandler {
}
@Override
public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell,
Head head, int relativeRowIndex, boolean isHead) {
public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, CellData cellData, Cell cell,
Head head, int relativeRowIndex, boolean isHead) {
if (isHead) {
return;
}

5
src/main/java/com/alibaba/excel/write/style/AbstractCellStyleStrategy.java

@ -5,6 +5,7 @@ import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Workbook;
import com.alibaba.excel.event.NotRepeatExecutor;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.handler.SheetWriteHandler;
@ -46,8 +47,8 @@ public abstract class AbstractCellStyleStrategy implements CellWriteHandler, She
}
@Override
public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell,
Head head, int relativeRowIndex, boolean isHead) {
public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, CellData cellData,
Cell cell, Head head, int relativeRowIndex, boolean isHead) {
if (isHead) {
setHeadCellStyle(cell, head, relativeRowIndex);
} else {

14
src/main/java/com/alibaba/excel/write/style/column/AbstractColumnWidthStyleStrategy.java

@ -2,9 +2,9 @@ package com.alibaba.excel.write.style.column;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import com.alibaba.excel.event.NotRepeatExecutor;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
@ -29,20 +29,22 @@ public abstract class AbstractColumnWidthStyleStrategy implements CellWriteHandl
}
@Override
public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell,
Head head, int relativeRowIndex, boolean isHead) {
setColumnWidth(writeSheetHolder.getSheet(), cell, head, relativeRowIndex, isHead);
public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, CellData cellData,
Cell cell, Head head, int relativeRowIndex, boolean isHead) {
setColumnWidth(writeSheetHolder, cellData, cell, head, relativeRowIndex, isHead);
}
/**
* Sets the column width when head create
*
* @param sheet
* @param writeSheetHolder
* @param cellData
* @param cell
* @param head
* @param relativeRowIndex
* @param isHead
*/
protected abstract void setColumnWidth(Sheet sheet, Cell cell, Head head, int relativeRowIndex, boolean isHead);
protected abstract void setColumnWidth(WriteSheetHolder writeSheetHolder, CellData cellData, Cell cell, Head head,
int relativeRowIndex, boolean isHead);
}

8
src/main/java/com/alibaba/excel/write/style/column/AbstractHeadColumnWidthStyleStrategy.java

@ -1,9 +1,10 @@
package com.alibaba.excel.write.style.column;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Sheet;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
/**
* Returns the column width according to each column header
@ -12,14 +13,15 @@ import com.alibaba.excel.metadata.Head;
*/
public abstract class AbstractHeadColumnWidthStyleStrategy extends AbstractColumnWidthStyleStrategy {
@Override
protected void setColumnWidth(Sheet sheet, Cell cell, Head head, int relativeRowIndex, boolean isHead) {
protected void setColumnWidth(WriteSheetHolder writeSheetHolder, CellData cellData, Cell cell, Head head,
int relativeRowIndex, boolean isHead) {
if (!isHead && relativeRowIndex != 0) {
return;
}
Integer width = columnWidth(head);
if (width != null) {
width = width * 256;
sheet.setColumnWidth(cell.getColumnIndex(), width);
writeSheetHolder.getSheet().setColumnWidth(cell.getColumnIndex(), width);
}
}

66
src/main/java/com/alibaba/excel/write/style/column/LongestMatchColumnWidthStyleStrategy.java

@ -0,0 +1,66 @@
package com.alibaba.excel.write.style.column;
import java.util.HashMap;
import java.util.Map;
import org.apache.poi.ss.usermodel.Cell;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
/**
* Take the width of the longest column as the width.
* <p>
* This is not very useful at the moment, for example if you have Numbers it will cause a newline.And the length is not
* exactly the same as the actual length.
*
* @author Jiaju Zhuang
*/
public class LongestMatchColumnWidthStyleStrategy extends AbstractColumnWidthStyleStrategy {
private static final int MAX_COLUMN_WIDTH = 256;
Map<Integer, Map<Integer, Integer>> cache = new HashMap<Integer, Map<Integer, Integer>>(8);
@Override
protected void setColumnWidth(WriteSheetHolder writeSheetHolder, CellData cellData, Cell cell, Head head,
int relativeRowIndex, boolean isHead) {
if (!isHead && cellData == null) {
return;
}
Map<Integer, Integer> maxColumnWidthMap = cache.get(writeSheetHolder.getSheetNo());
if (maxColumnWidthMap == null) {
maxColumnWidthMap = new HashMap<Integer, Integer>(16);
cache.put(writeSheetHolder.getSheetNo(), maxColumnWidthMap);
}
Integer columnWidth = dataLength(cellData, cell, isHead);
if (columnWidth < 0) {
return;
}
if (columnWidth > MAX_COLUMN_WIDTH) {
columnWidth = MAX_COLUMN_WIDTH;
}
Integer maxColumnWidth = maxColumnWidthMap.get(head.getColumnIndex());
if (maxColumnWidth == null || columnWidth > maxColumnWidth) {
maxColumnWidthMap.put(head.getColumnIndex(), columnWidth);
writeSheetHolder.getSheet().setColumnWidth(head.getColumnIndex(), columnWidth * 256);
}
}
private Integer dataLength(CellData cellData, Cell cell, boolean isHead) {
if (isHead) {
return cell.getStringCellValue().getBytes().length;
}
switch (cellData.getType()) {
case STRING:
return cellData.getStringValue().getBytes().length;
case BOOLEAN:
return cellData.getBooleanValue().toString().getBytes().length;
case NUMBER:
return cellData.getDoubleValue().toString().getBytes().length;
default:
return -1;
}
}
}

22
src/test/java/com/alibaba/easyexcel/test/demo/write/LongestMatchColumnWidthData.java

@ -0,0 +1,22 @@
package com.alibaba.easyexcel.test.demo.write;
import java.util.Date;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
/**
* 基础数据类
*
* @author Jiaju Zhuang
**/
@Data
public class LongestMatchColumnWidthData {
@ExcelProperty("字符串标题")
private String string;
@ExcelProperty("日期标题很长日期标题很长日期标题很长很长")
private Date date;
@ExcelProperty("数字")
private Double doubleData;
}

65
src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java

@ -25,6 +25,7 @@ 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;
/**
* 写的常见写法
@ -218,6 +219,70 @@ public class WriteTest {
excelWriter.finish();
}
/**
* 动态头实时生成头写入
* <p>
* 思路是这样子的先创建List<String>头格式的sheet仅仅写入头,然后通过table 不写入头的方式 去写入数据
*
* <li>1. 创建excel对应的实体对象 参照{@link DemoData}
* <li>2. 然后写入table即可
*/
@Test
public void dynamicHeadWrite() {
String fileName = TestFileUtil.getPath() + "dynamicHeadWrite" + System.currentTimeMillis() + ".xlsx";
// write的时候 不传入 class 在table的时候传入
EasyExcelFactory.write(fileName)
// 这里放入动态头
.head(head()).sheet("模板")
// table的时候 传入class 并且设置needHead =false
.table().head(DemoData.class).needHead(Boolean.FALSE).doWrite(data());
}
/**
* 自动列宽(不太精确)
* <p>
* 这个目前不是很好用比如有数字就会导致换行而且长度也不是刚好和实际长度一致 所以需要精确到刚好列宽的慎用 当然也可以自己参照
* {@link LongestMatchColumnWidthStyleStrategy}重新实现.
*
* <li>1. 创建excel对应的实体对象 参照{@link DemoData}
* <li>3. 注册策略{@link LongestMatchColumnWidthStyleStrategy}
* <li>2. 直接写即可
*/
@Test
public void longestMatchColumnWidthWrite() {
String fileName =
TestFileUtil.getPath() + "longestMatchColumnWidthWrite" + System.currentTimeMillis() + ".xlsx";
// 这里 需要指定写用哪个class去读,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
EasyExcelFactory.write(fileName, LongestMatchColumnWidthData.class)
.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).sheet("模板").doWrite(dataLong());
}
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>> 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<DemoData> data() {
List<DemoData> list = new ArrayList<DemoData>();
for (int i = 0; i < 10; i++) {

Loading…
Cancel
Save