Browse Source

同时传入了`List<List<String>>`和`class`的head,会通过index去匹配注解

pull/1159/head
Jiaju Zhuang 5 years ago
parent
commit
754c5d8dca
  1. 4
      src/main/java/com/alibaba/excel/annotation/write/style/ContentFontStyle.java
  2. 44
      src/main/java/com/alibaba/excel/annotation/write/style/ContentStyle.java
  3. 8
      src/main/java/com/alibaba/excel/annotation/write/style/HeadFontStyle.java
  4. 20
      src/main/java/com/alibaba/excel/annotation/write/style/HeadStyle.java
  5. 101
      src/main/java/com/alibaba/excel/converters/DefaultConverterLoader.java
  6. 63
      src/main/java/com/alibaba/excel/metadata/Head.java
  7. 20
      src/main/java/com/alibaba/excel/metadata/property/ExcelHeadProperty.java
  8. 180
      src/main/java/com/alibaba/excel/metadata/property/FontProperty.java
  9. 47
      src/main/java/com/alibaba/excel/metadata/property/LoopMergeProperty.java
  10. 74
      src/main/java/com/alibaba/excel/metadata/property/OnceAbsoluteMergeProperty.java
  11. 377
      src/main/java/com/alibaba/excel/metadata/property/StyleProperty.java
  12. 15
      src/main/java/com/alibaba/excel/util/WriteHandlerUtils.java
  13. 5
      src/main/java/com/alibaba/excel/write/executor/AbstractExcelWriteExecutor.java
  14. 8
      src/main/java/com/alibaba/excel/write/executor/ExcelWriteAddExecutor.java
  15. 2
      src/main/java/com/alibaba/excel/write/executor/ExcelWriteFillExecutor.java
  16. 6
      src/main/java/com/alibaba/excel/write/handler/AbstractCellWriteHandler.java
  17. 19
      src/main/java/com/alibaba/excel/write/handler/CellWriteHandler.java
  18. 5
      src/main/java/com/alibaba/excel/write/merge/LoopMergeStrategy.java
  19. 6
      src/main/java/com/alibaba/excel/write/merge/OnceAbsoluteMergeStrategy.java
  20. 57
      src/main/java/com/alibaba/excel/write/metadata/holder/AbstractWriteHolder.java
  21. 77
      src/main/java/com/alibaba/excel/write/metadata/style/WriteCellStyle.java
  22. 51
      src/main/java/com/alibaba/excel/write/property/ExcelWriteHeadProperty.java
  23. 6
      src/main/java/com/alibaba/excel/write/style/AbstractCellStyleStrategy.java
  24. 20
      src/main/java/com/alibaba/excel/write/style/column/AbstractColumnWidthStyleStrategy.java
  25. 77
      src/test/java/com/alibaba/easyexcel/test/demo/read/DemoCellCommentsListener.java
  26. 14
      src/test/java/com/alibaba/easyexcel/test/demo/read/DemoExtraData.java
  27. 58
      src/test/java/com/alibaba/easyexcel/test/demo/read/DemoExtraListener.java
  28. 23
      src/test/java/com/alibaba/easyexcel/test/demo/read/ReadTest.java
  29. 17
      src/test/java/com/alibaba/easyexcel/test/demo/write/CustomCellWriteHandler.java
  30. 27
      src/test/java/com/alibaba/easyexcel/test/demo/write/DemoMergeData.java
  31. 44
      src/test/java/com/alibaba/easyexcel/test/demo/write/DemoStyleData.java
  32. 60
      src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java
  33. BIN
      src/test/resources/demo/extra.xlsx
  34. 4
      update.md

4
src/main/java/com/alibaba/excel/annotation/write/style/ContentFontStyle.java

@ -16,7 +16,7 @@ import org.apache.poi.ss.usermodel.IndexedColors;
* *
* @author Jiaju Zhuang * @author Jiaju Zhuang
*/ */
@Target({ElementType.FIELD}) @Target({ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Inherited @Inherited
public @interface ContentFontStyle { public @interface ContentFontStyle {
@ -24,7 +24,7 @@ public @interface ContentFontStyle {
/** /**
* The name for the font (i.e. Arial) * The name for the font (i.e. Arial)
*/ */
String fontName(); String fontName() default "";
/** /**
* Height in the familiar unit of measure - points * Height in the familiar unit of measure - points

44
src/main/java/com/alibaba/excel/annotation/write/style/ContentStyle.java

@ -19,48 +19,48 @@ import org.apache.poi.ss.usermodel.VerticalAlignment;
* *
* @author Jiaju Zhuang * @author Jiaju Zhuang
*/ */
@Target({ElementType.FIELD}) @Target({ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Inherited @Inherited
public @interface ContentStyle { public @interface ContentStyle {
/** /**
* Set the data format (must be a valid format). Built in formats are defined at {@link BuiltinFormats}. * Set the data format (must be a valid format). Built in formats are defined at {@link BuiltinFormats}.
*/ */
short dataFormat(); short dataFormat() default -1;
/** /**
* Set the cell's using this style to be hidden * Set the cell's using this style to be hidden
*/ */
boolean hidden(); boolean hidden() default false;
/** /**
* Set the cell's using this style to be locked * Set the cell's using this style to be locked
*/ */
boolean locked(); boolean locked() default false;
/** /**
* Turn on or off "Quote Prefix" or "123 Prefix" for the style, which is used to tell Excel that the thing which * Turn on or off "Quote Prefix" or "123 Prefix" for the style, which is used to tell Excel that the thing which
* looks like a number or a formula shouldn't be treated as on. Turning this on is somewhat (but not completely, see * looks like a number or a formula shouldn't be treated as on. Turning this on is somewhat (but not completely, see
* {@link IgnoredErrorType}) like prefixing the cell value with a ' in Excel * {@link IgnoredErrorType}) like prefixing the cell value with a ' in Excel
*/ */
boolean quotePrefix(); boolean quotePrefix() default false;
/** /**
* Set the type of horizontal alignment for the cell * Set the type of horizontal alignment for the cell
*/ */
HorizontalAlignment horizontalAlignment(); HorizontalAlignment horizontalAlignment() default HorizontalAlignment.GENERAL;
/** /**
* Set whether the text should be wrapped. Setting this flag to <code>true</code> make all content visible within a * Set whether the text should be wrapped. Setting this flag to <code>true</code> make all content visible within a
* cell by displaying it on multiple lines * cell by displaying it on multiple lines
* *
*/ */
boolean wrapped(); boolean wrapped() default false;
/** /**
* Set the type of vertical alignment for the cell * Set the type of vertical alignment for the cell
*/ */
VerticalAlignment verticalAlignment(); VerticalAlignment verticalAlignment() default VerticalAlignment.CENTER;
/** /**
* Set the degree of rotation for the text in the cell. * Set the degree of rotation for the text in the cell.
@ -70,39 +70,39 @@ public @interface ContentStyle {
* getter is returning values in the range mandated by the current type of Excel file-format that this CellStyle is * getter is returning values in the range mandated by the current type of Excel file-format that this CellStyle is
* applied to. * applied to.
*/ */
short rotation(); short rotation() default -1;
/** /**
* Set the number of spaces to indent the text in the cell * Set the number of spaces to indent the text in the cell
*/ */
short indent(); short indent() default -1;
/** /**
* Set the type of border to use for the left border of the cell * Set the type of border to use for the left border of the cell
*/ */
BorderStyle borderLeft(); BorderStyle borderLeft() default BorderStyle.NONE;
/** /**
* Set the type of border to use for the right border of the cell * Set the type of border to use for the right border of the cell
*/ */
BorderStyle borderRight(); BorderStyle borderRight() default BorderStyle.NONE;
/** /**
* Set the type of border to use for the top border of the cell * Set the type of border to use for the top border of the cell
*/ */
BorderStyle borderTop(); BorderStyle borderTop() default BorderStyle.NONE;
/** /**
* Set the type of border to use for the bottom border of the cell * Set the type of border to use for the bottom border of the cell
*/ */
BorderStyle borderBottom(); BorderStyle borderBottom() default BorderStyle.NONE;
/** /**
* Set the color to use for the left border * Set the color to use for the left border
* *
* @see IndexedColors * @see IndexedColors
*/ */
short leftBorderColor(); short leftBorderColor() default -1;
/** /**
* Set the color to use for the right border * Set the color to use for the right border
@ -110,7 +110,7 @@ public @interface ContentStyle {
* @see IndexedColors * @see IndexedColors
* *
*/ */
short rightBorderColor(); short rightBorderColor() default -1;
/** /**
* Set the color to use for the top border * Set the color to use for the top border
@ -118,7 +118,7 @@ public @interface ContentStyle {
* @see IndexedColors * @see IndexedColors
* *
*/ */
short topBorderColor(); short topBorderColor() default -1;
/** /**
* Set the color to use for the bottom border * Set the color to use for the bottom border
@ -126,14 +126,14 @@ public @interface ContentStyle {
* @see IndexedColors * @see IndexedColors
* *
*/ */
short bottomBorderColor(); short bottomBorderColor() default -1;
/** /**
* Setting to one fills the cell with the foreground color... No idea about other values * Setting to one fills the cell with the foreground color... No idea about other values
* *
* @see FillPatternType#SOLID_FOREGROUND * @see FillPatternType#SOLID_FOREGROUND
*/ */
FillPatternType fillPatternType(); FillPatternType fillPatternType() default FillPatternType.NO_FILL;
/** /**
* Set the background fill color. * Set the background fill color.
@ -141,7 +141,7 @@ public @interface ContentStyle {
* @see IndexedColors * @see IndexedColors
* *
*/ */
short fillBackgroundColor(); short fillBackgroundColor() default -1;
/** /**
* Set the foreground fill color <i>Note: Ensure Foreground color is set prior to background color.</i> * Set the foreground fill color <i>Note: Ensure Foreground color is set prior to background color.</i>
@ -149,11 +149,11 @@ public @interface ContentStyle {
* @see IndexedColors * @see IndexedColors
* *
*/ */
short fillForegroundColor(); short fillForegroundColor() default -1;
/** /**
* Controls if the Cell should be auto-sized to shrink to fit if the text is too long * Controls if the Cell should be auto-sized to shrink to fit if the text is too long
*/ */
boolean shrinkToFit(); boolean shrinkToFit() default false;
} }

8
src/main/java/com/alibaba/excel/annotation/write/style/HeadFontStyle.java

@ -16,7 +16,7 @@ import org.apache.poi.ss.usermodel.IndexedColors;
* *
* @author Jiaju Zhuang * @author Jiaju Zhuang
*/ */
@Target({ElementType.FIELD}) @Target({ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Inherited @Inherited
public @interface HeadFontStyle { public @interface HeadFontStyle {
@ -24,12 +24,12 @@ public @interface HeadFontStyle {
/** /**
* The name for the font (i.e. Arial) * The name for the font (i.e. Arial)
*/ */
String fontName(); String fontName() default "宋体";
/** /**
* Height in the familiar unit of measure - points * Height in the familiar unit of measure - points
*/ */
short fontHeightInPoints() default -1; short fontHeightInPoints() default 14;
/** /**
* Whether to use italics or not * Whether to use italics or not
@ -85,5 +85,5 @@ public @interface HeadFontStyle {
/** /**
* Bold * Bold
*/ */
boolean bold() default false; boolean bold() default true;
} }

20
src/main/java/com/alibaba/excel/annotation/write/style/HeadStyle.java

@ -19,7 +19,7 @@ import org.apache.poi.ss.usermodel.VerticalAlignment;
* *
* @author Jiaju Zhuang * @author Jiaju Zhuang
*/ */
@Target({ElementType.FIELD}) @Target({ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Inherited @Inherited
public @interface HeadStyle { public @interface HeadStyle {
@ -36,7 +36,7 @@ public @interface HeadStyle {
/** /**
* Set the cell's using this style to be locked * Set the cell's using this style to be locked
*/ */
boolean locked() default false; boolean locked() default true;
/** /**
* Turn on or off "Quote Prefix" or "123 Prefix" for the style, which is used to tell Excel that the thing which * Turn on or off "Quote Prefix" or "123 Prefix" for the style, which is used to tell Excel that the thing which
@ -48,19 +48,19 @@ public @interface HeadStyle {
/** /**
* Set the type of horizontal alignment for the cell * Set the type of horizontal alignment for the cell
*/ */
HorizontalAlignment horizontalAlignment(); HorizontalAlignment horizontalAlignment() default HorizontalAlignment.CENTER;
/** /**
* Set whether the text should be wrapped. Setting this flag to <code>true</code> make all content visible within a * Set whether the text should be wrapped. Setting this flag to <code>true</code> make all content visible within a
* cell by displaying it on multiple lines * cell by displaying it on multiple lines
* *
*/ */
boolean wrapped() default false; boolean wrapped() default true;
/** /**
* Set the type of vertical alignment for the cell * Set the type of vertical alignment for the cell
*/ */
VerticalAlignment verticalAlignment(); VerticalAlignment verticalAlignment() default VerticalAlignment.CENTER;
/** /**
* Set the degree of rotation for the text in the cell. * Set the degree of rotation for the text in the cell.
@ -80,22 +80,22 @@ public @interface HeadStyle {
/** /**
* Set the type of border to use for the left border of the cell * Set the type of border to use for the left border of the cell
*/ */
BorderStyle borderLeft(); BorderStyle borderLeft() default BorderStyle.THIN;
/** /**
* Set the type of border to use for the right border of the cell * Set the type of border to use for the right border of the cell
*/ */
BorderStyle borderRight(); BorderStyle borderRight() default BorderStyle.THIN;
/** /**
* Set the type of border to use for the top border of the cell * Set the type of border to use for the top border of the cell
*/ */
BorderStyle borderTop(); BorderStyle borderTop() default BorderStyle.THIN;
/** /**
* Set the type of border to use for the bottom border of the cell * Set the type of border to use for the bottom border of the cell
*/ */
BorderStyle borderBottom(); BorderStyle borderBottom() default BorderStyle.THIN;
/** /**
* Set the color to use for the left border * Set the color to use for the left border
@ -133,7 +133,7 @@ public @interface HeadStyle {
* *
* @see FillPatternType#SOLID_FOREGROUND * @see FillPatternType#SOLID_FOREGROUND
*/ */
FillPatternType fillPatternType(); FillPatternType fillPatternType() default FillPatternType.SOLID_FOREGROUND;
/** /**
* Set the background fill color. * Set the background fill color.

101
src/main/java/com/alibaba/excel/converters/DefaultConverterLoader.java

@ -48,56 +48,12 @@ public class DefaultConverterLoader {
private static Map<String, Converter> defaultWriteConverter; private static Map<String, Converter> defaultWriteConverter;
private static Map<String, Converter> allConverter; private static Map<String, Converter> allConverter;
/** static {
* Load default write converter initDefaultWriteConverter();
* initAllConverter();
* @return
*/
public static Map<String, Converter> loadDefaultWriteConverter() {
if (defaultWriteConverter != null) {
return defaultWriteConverter;
}
defaultWriteConverter = new HashMap<String, Converter>(32);
putWriteConverter(new BigDecimalNumberConverter());
putWriteConverter(new BooleanBooleanConverter());
putWriteConverter(new ByteNumberConverter());
putWriteConverter(new DateStringConverter());
putWriteConverter(new DoubleNumberConverter());
putWriteConverter(new FloatNumberConverter());
putWriteConverter(new IntegerNumberConverter());
putWriteConverter(new LongNumberConverter());
putWriteConverter(new ShortNumberConverter());
putWriteConverter(new StringStringConverter());
putWriteConverter(new FileImageConverter());
putWriteConverter(new InputStreamImageConverter());
putWriteConverter(new ByteArrayImageConverter());
putWriteConverter(new BoxingByteArrayImageConverter());
putWriteConverter(new UrlImageConverter());
return defaultWriteConverter;
} }
private static void putWriteConverter(Converter converter) { private static void initAllConverter() {
defaultWriteConverter.put(ConverterKeyBuild.buildKey(converter.supportJavaTypeKey()), converter);
}
/**
* Load default read converter
*
* @return
*/
public static Map<String, Converter> loadDefaultReadConverter() {
return loadAllConverter();
}
/**
* Load all converter
*
* @return
*/
public static Map<String, Converter> loadAllConverter() {
if (allConverter != null) {
return allConverter;
}
allConverter = new HashMap<String, Converter>(64); allConverter = new HashMap<String, Converter>(64);
putAllConverter(new BigDecimalBooleanConverter()); putAllConverter(new BigDecimalBooleanConverter());
putAllConverter(new BigDecimalNumberConverter()); putAllConverter(new BigDecimalNumberConverter());
@ -138,6 +94,55 @@ public class DefaultConverterLoader {
putAllConverter(new StringNumberConverter()); putAllConverter(new StringNumberConverter());
putAllConverter(new StringStringConverter()); putAllConverter(new StringStringConverter());
putAllConverter(new StringErrorConverter()); putAllConverter(new StringErrorConverter());
}
private static void initDefaultWriteConverter() {
defaultWriteConverter = new HashMap<String, Converter>(32);
putWriteConverter(new BigDecimalNumberConverter());
putWriteConverter(new BooleanBooleanConverter());
putWriteConverter(new ByteNumberConverter());
putWriteConverter(new DateStringConverter());
putWriteConverter(new DoubleNumberConverter());
putWriteConverter(new FloatNumberConverter());
putWriteConverter(new IntegerNumberConverter());
putWriteConverter(new LongNumberConverter());
putWriteConverter(new ShortNumberConverter());
putWriteConverter(new StringStringConverter());
putWriteConverter(new FileImageConverter());
putWriteConverter(new InputStreamImageConverter());
putWriteConverter(new ByteArrayImageConverter());
putWriteConverter(new BoxingByteArrayImageConverter());
putWriteConverter(new UrlImageConverter());
}
/**
* Load default write converter
*
* @return
*/
public static Map<String, Converter> loadDefaultWriteConverter() {
return defaultWriteConverter;
}
private static void putWriteConverter(Converter converter) {
defaultWriteConverter.put(ConverterKeyBuild.buildKey(converter.supportJavaTypeKey()), converter);
}
/**
* Load default read converter
*
* @return
*/
public static Map<String, Converter> loadDefaultReadConverter() {
return loadAllConverter();
}
/**
* Load all converter
*
* @return
*/
public static Map<String, Converter> loadAllConverter() {
return allConverter; return allConverter;
} }

63
src/main/java/com/alibaba/excel/metadata/Head.java

@ -4,6 +4,9 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import com.alibaba.excel.metadata.property.ColumnWidthProperty; import com.alibaba.excel.metadata.property.ColumnWidthProperty;
import com.alibaba.excel.metadata.property.FontProperty;
import com.alibaba.excel.metadata.property.LoopMergeProperty;
import com.alibaba.excel.metadata.property.StyleProperty;
/** /**
* excel head * excel head
@ -35,6 +38,26 @@ public class Head {
* column with * column with
*/ */
private ColumnWidthProperty columnWidthProperty; private ColumnWidthProperty columnWidthProperty;
/**
* Loop merge
*/
private LoopMergeProperty loopMergeProperty;
/**
* Head style
*/
private StyleProperty headStyleProperty;
/**
* Content style
*/
private StyleProperty contentStyleProperty;
/**
* Head font
*/
private FontProperty headFontProperty;
/**
* Content font
*/
private FontProperty contentFontProperty;
public Head(Integer columnIndex, String fieldName, List<String> headNameList, Boolean forceIndex, public Head(Integer columnIndex, String fieldName, List<String> headNameList, Boolean forceIndex,
Boolean forceName) { Boolean forceName) {
@ -95,4 +118,44 @@ public class Head {
public void setForceName(Boolean forceName) { public void setForceName(Boolean forceName) {
this.forceName = forceName; this.forceName = forceName;
} }
public LoopMergeProperty getLoopMergeProperty() {
return loopMergeProperty;
}
public void setLoopMergeProperty(LoopMergeProperty loopMergeProperty) {
this.loopMergeProperty = loopMergeProperty;
}
public StyleProperty getHeadStyleProperty() {
return headStyleProperty;
}
public void setHeadStyleProperty(StyleProperty headStyleProperty) {
this.headStyleProperty = headStyleProperty;
}
public StyleProperty getContentStyleProperty() {
return contentStyleProperty;
}
public void setContentStyleProperty(StyleProperty contentStyleProperty) {
this.contentStyleProperty = contentStyleProperty;
}
public FontProperty getHeadFontProperty() {
return headFontProperty;
}
public void setHeadFontProperty(FontProperty headFontProperty) {
this.headFontProperty = headFontProperty;
}
public FontProperty getContentFontProperty() {
return contentFontProperty;
}
public void setContentFontProperty(FontProperty contentFontProperty) {
this.contentFontProperty = contentFontProperty;
}
} }

20
src/main/java/com/alibaba/excel/metadata/property/ExcelHeadProperty.java

@ -1,7 +1,6 @@
package com.alibaba.excel.metadata.property; package com.alibaba.excel.metadata.property;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
@ -12,8 +11,6 @@ import java.util.TreeMap;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.format.DateTimeFormat; import com.alibaba.excel.annotation.format.DateTimeFormat;
import com.alibaba.excel.annotation.format.NumberFormat; import com.alibaba.excel.annotation.format.NumberFormat;
@ -21,7 +18,6 @@ import com.alibaba.excel.converters.AutoConverter;
import com.alibaba.excel.converters.Converter; import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.HeadKindEnum; import com.alibaba.excel.enums.HeadKindEnum;
import com.alibaba.excel.exception.ExcelCommonException; import com.alibaba.excel.exception.ExcelCommonException;
import com.alibaba.excel.exception.ExcelGenerateException;
import com.alibaba.excel.metadata.Head; import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.Holder; import com.alibaba.excel.metadata.Holder;
import com.alibaba.excel.util.ClassUtils; import com.alibaba.excel.util.ClassUtils;
@ -86,10 +82,10 @@ public class ExcelHeadProperty {
headIndex++; headIndex++;
} }
headKind = HeadKindEnum.STRING; headKind = HeadKindEnum.STRING;
} else {
// convert headClazz to head
initColumnProperties(holder, convertAllFiled);
} }
// convert headClazz to head
initColumnProperties(holder, convertAllFiled);
initHeadRowNumber(); initHeadRowNumber();
if (LOGGER.isDebugEnabled()) { if (LOGGER.isDebugEnabled()) {
LOGGER.debug("The initialization sheet/table 'ExcelHeadProperty' is complete , head kind is {}", headKind); LOGGER.debug("The initialization sheet/table 'ExcelHeadProperty' is complete , head kind is {}", headKind);
@ -163,10 +159,14 @@ public class ExcelHeadProperty {
List<String> tmpHeadList = new ArrayList<String>(); List<String> tmpHeadList = new ArrayList<String>();
boolean notForceName = excelProperty == null || excelProperty.value().length <= 0 boolean notForceName = excelProperty == null || excelProperty.value().length <= 0
|| (excelProperty.value().length == 1 && StringUtils.isEmpty((excelProperty.value())[0])); || (excelProperty.value().length == 1 && StringUtils.isEmpty((excelProperty.value())[0]));
if (notForceName) { if (headMap.containsKey(index)) {
tmpHeadList.add(field.getName()); tmpHeadList.addAll(headMap.get(index).getHeadNameList());
} else { } else {
Collections.addAll(tmpHeadList, excelProperty.value()); if (notForceName) {
tmpHeadList.add(field.getName());
} else {
Collections.addAll(tmpHeadList, excelProperty.value());
}
} }
Head head = new Head(index, field.getName(), tmpHeadList, forceIndex, !notForceName); Head head = new Head(index, field.getName(), tmpHeadList, forceIndex, !notForceName);
ExcelContentProperty excelContentProperty = new ExcelContentProperty(); ExcelContentProperty excelContentProperty = new ExcelContentProperty();

180
src/main/java/com/alibaba/excel/metadata/property/FontProperty.java

@ -0,0 +1,180 @@
package com.alibaba.excel.metadata.property;
import org.apache.poi.common.usermodel.fonts.FontCharset;
import org.apache.poi.hssf.usermodel.HSSFPalette;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.IndexedColors;
import com.alibaba.excel.annotation.write.style.ContentFontStyle;
import com.alibaba.excel.annotation.write.style.HeadFontStyle;
/**
* Configuration from annotations
*
* @author Jiaju Zhuang
*/
public class FontProperty {
/**
* The name for the font (i.e. Arial)
*/
private String fontName;
/**
* Height in the familiar unit of measure - points
*/
private Short fontHeightInPoints;
/**
* Whether to use italics or not
*/
private Boolean italic;
/**
* Whether to use a strikeout horizontal line through the text or not
*/
private Boolean strikeout;
/**
* The color for the font
*
* @see Font#COLOR_NORMAL
* @see Font#COLOR_RED
* @see HSSFPalette#getColor(short)
* @see IndexedColors
*/
private Short color;
/**
* Set normal,super or subscript.
*
* @see Font#SS_NONE
* @see Font#SS_SUPER
* @see Font#SS_SUB
*/
private Short typeOffset;
/**
* set type of text underlining to use
*
* @see Font#U_NONE
* @see Font#U_SINGLE
* @see Font#U_DOUBLE
* @see Font#U_SINGLE_ACCOUNTING
* @see Font#U_DOUBLE_ACCOUNTING
*/
private Byte underline;
/**
* Set character-set to use.
*
* @see FontCharset
* @see Font#ANSI_CHARSET
* @see Font#DEFAULT_CHARSET
* @see Font#SYMBOL_CHARSET
*/
private Integer charset;
/**
* Bold
*/
private Boolean bold;
public static FontProperty build(HeadFontStyle headFontStyle) {
if (headFontStyle == null) {
return null;
}
FontProperty styleProperty = new FontProperty();
styleProperty.setFontName(headFontStyle.fontName());
styleProperty.setFontHeightInPoints(headFontStyle.fontHeightInPoints());
styleProperty.setItalic(headFontStyle.italic());
styleProperty.setStrikeout(headFontStyle.strikeout());
styleProperty.setColor(headFontStyle.color());
styleProperty.setTypeOffset(headFontStyle.typeOffset());
styleProperty.setUnderline(headFontStyle.underline());
styleProperty.setCharset(headFontStyle.charset());
styleProperty.setBold(headFontStyle.bold());
return styleProperty;
}
public static FontProperty build(ContentFontStyle contentFontStyle) {
if (contentFontStyle == null) {
return null;
}
FontProperty styleProperty = new FontProperty();
styleProperty.setFontName(contentFontStyle.fontName());
styleProperty.setFontHeightInPoints(contentFontStyle.fontHeightInPoints());
styleProperty.setItalic(contentFontStyle.italic());
styleProperty.setStrikeout(contentFontStyle.strikeout());
styleProperty.setColor(contentFontStyle.color());
styleProperty.setTypeOffset(contentFontStyle.typeOffset());
styleProperty.setUnderline(contentFontStyle.underline());
styleProperty.setCharset(contentFontStyle.charset());
styleProperty.setBold(contentFontStyle.bold());
return styleProperty;
}
public String getFontName() {
return fontName;
}
public void setFontName(String fontName) {
this.fontName = fontName;
}
public Short getFontHeightInPoints() {
return fontHeightInPoints;
}
public void setFontHeightInPoints(Short fontHeightInPoints) {
this.fontHeightInPoints = fontHeightInPoints;
}
public Boolean getItalic() {
return italic;
}
public void setItalic(Boolean italic) {
this.italic = italic;
}
public Boolean getStrikeout() {
return strikeout;
}
public void setStrikeout(Boolean strikeout) {
this.strikeout = strikeout;
}
public Short getColor() {
return color;
}
public void setColor(Short color) {
this.color = color;
}
public Short getTypeOffset() {
return typeOffset;
}
public void setTypeOffset(Short typeOffset) {
this.typeOffset = typeOffset;
}
public Byte getUnderline() {
return underline;
}
public void setUnderline(Byte underline) {
this.underline = underline;
}
public Integer getCharset() {
return charset;
}
public void setCharset(Integer charset) {
this.charset = charset;
}
public Boolean getBold() {
return bold;
}
public void setBold(Boolean bold) {
this.bold = bold;
}
}

47
src/main/java/com/alibaba/excel/metadata/property/LoopMergeProperty.java

@ -0,0 +1,47 @@
package com.alibaba.excel.metadata.property;
import com.alibaba.excel.annotation.write.style.ContentLoopMerge;
/**
* Configuration from annotations
*
* @author Jiaju Zhuang
*/
public class LoopMergeProperty {
/**
* Each row
*/
private int eachRow;
/**
* Extend column
*/
private int columnExtend;
public LoopMergeProperty(int eachRow, int columnExtend) {
this.eachRow = eachRow;
this.columnExtend = columnExtend;
}
public static LoopMergeProperty build(ContentLoopMerge contentLoopMerge) {
if (contentLoopMerge == null) {
return null;
}
return new LoopMergeProperty(contentLoopMerge.eachRow(), contentLoopMerge.columnExtend());
}
public int getEachRow() {
return eachRow;
}
public void setEachRow(int eachRow) {
this.eachRow = eachRow;
}
public int getColumnExtend() {
return columnExtend;
}
public void setColumnExtend(int columnExtend) {
this.columnExtend = columnExtend;
}
}

74
src/main/java/com/alibaba/excel/metadata/property/OnceAbsoluteMergeProperty.java

@ -0,0 +1,74 @@
package com.alibaba.excel.metadata.property;
import com.alibaba.excel.annotation.write.style.OnceAbsoluteMerge;
/**
* Configuration from annotations
*
* @author Jiaju Zhuang
*/
public class OnceAbsoluteMergeProperty {
/**
* First row
*/
private int firstRowIndex;
/**
* Last row
*/
private int lastRowIndex;
/**
* First column
*/
private int firstColumnIndex;
/**
* Last row
*/
private int lastColumnIndex;
public OnceAbsoluteMergeProperty(int firstRowIndex, int lastRowIndex, int firstColumnIndex, int lastColumnIndex) {
this.firstRowIndex = firstRowIndex;
this.lastRowIndex = lastRowIndex;
this.firstColumnIndex = firstColumnIndex;
this.lastColumnIndex = lastColumnIndex;
}
public static OnceAbsoluteMergeProperty build(OnceAbsoluteMerge onceAbsoluteMerge) {
if (onceAbsoluteMerge == null) {
return null;
}
return new OnceAbsoluteMergeProperty(onceAbsoluteMerge.firstRowIndex(), onceAbsoluteMerge.lastRowIndex(),
onceAbsoluteMerge.firstColumnIndex(), onceAbsoluteMerge.lastColumnIndex());
}
public int getFirstRowIndex() {
return firstRowIndex;
}
public void setFirstRowIndex(int firstRowIndex) {
this.firstRowIndex = firstRowIndex;
}
public int getLastRowIndex() {
return lastRowIndex;
}
public void setLastRowIndex(int lastRowIndex) {
this.lastRowIndex = lastRowIndex;
}
public int getFirstColumnIndex() {
return firstColumnIndex;
}
public void setFirstColumnIndex(int firstColumnIndex) {
this.firstColumnIndex = firstColumnIndex;
}
public int getLastColumnIndex() {
return lastColumnIndex;
}
public void setLastColumnIndex(int lastColumnIndex) {
this.lastColumnIndex = lastColumnIndex;
}
}

377
src/main/java/com/alibaba/excel/metadata/property/StyleProperty.java

@ -0,0 +1,377 @@
package com.alibaba.excel.metadata.property;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.BuiltinFormats;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IgnoredErrorType;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import com.alibaba.excel.annotation.write.style.ContentStyle;
import com.alibaba.excel.annotation.write.style.HeadStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
/**
* Configuration from annotations
*
* @author Jiaju Zhuang
*/
public class StyleProperty {
/**
* Set the data format (must be a valid format). Built in formats are defined at {@link BuiltinFormats}.
*/
private Short dataFormat;
/**
* Set the font for this style
*/
private WriteFont writeFont;
/**
* Set the cell's using this style to be hidden
*/
private Boolean hidden;
/**
* Set the cell's using this style to be locked
*/
private Boolean locked;
/**
* Turn on or off "Quote Prefix" or "123 Prefix" for the style, which is used to tell Excel that the thing which
* looks like a number or a formula shouldn't be treated as on. Turning this on is somewhat (but not completely, see
* {@link IgnoredErrorType}) like prefixing the cell value with a ' in Excel
*/
private Boolean quotePrefix;
/**
* Set the type of horizontal alignment for the cell
*/
private HorizontalAlignment horizontalAlignment;
/**
* Set whether the text should be wrapped. Setting this flag to <code>true</code> make all content visible within a
* cell by displaying it on multiple lines
*
*/
private Boolean wrapped;
/**
* Set the type of vertical alignment for the cell
*/
private VerticalAlignment verticalAlignment;
/**
* Set the degree of rotation for the text in the cell.
*
* Note: HSSF uses values from -90 to 90 degrees, whereas XSSF uses values from 0 to 180 degrees. The
* implementations of this method will map between these two value-ranges accordingly, however the corresponding
* getter is returning values in the range mandated by the current type of Excel file-format that this CellStyle is
* applied to.
*/
private Short rotation;
/**
* Set the number of spaces to indent the text in the cell
*/
private Short indent;
/**
* Set the type of border to use for the left border of the cell
*/
private BorderStyle borderLeft;
/**
* Set the type of border to use for the right border of the cell
*/
private BorderStyle borderRight;
/**
* Set the type of border to use for the top border of the cell
*/
private BorderStyle borderTop;
/**
* Set the type of border to use for the bottom border of the cell
*/
private BorderStyle borderBottom;
/**
* Set the color to use for the left border
*
* @see IndexedColors
*/
private Short leftBorderColor;
/**
* Set the color to use for the right border
*
* @see IndexedColors
*
*/
private Short rightBorderColor;
/**
* Set the color to use for the top border
*
* @see IndexedColors
*
*/
private Short topBorderColor;
/**
* Set the color to use for the bottom border
*
* @see IndexedColors
*
*/
private Short bottomBorderColor;
/**
* Setting to one fills the cell with the foreground color... No idea about other values
*
* @see FillPatternType#SOLID_FOREGROUND
*/
private FillPatternType fillPatternType;
/**
* Set the background fill color.
*
* @see IndexedColors
*
*/
private Short fillBackgroundColor;
/**
* Set the foreground fill color <i>Note: Ensure Foreground color is set prior to background color.</i>
*
* @see IndexedColors
*
*/
private Short fillForegroundColor;
/**
* Controls if the Cell should be auto-sized to shrink to fit if the text is too long
*/
private Boolean shrinkToFit;
public static StyleProperty build(HeadStyle headStyle) {
if (headStyle == null) {
return null;
}
StyleProperty styleProperty = new StyleProperty();
styleProperty.setDataFormat(headStyle.dataFormat());
styleProperty.setHidden(headStyle.hidden());
styleProperty.setLocked(headStyle.locked());
styleProperty.setQuotePrefix(headStyle.quotePrefix());
styleProperty.setHorizontalAlignment(headStyle.horizontalAlignment());
styleProperty.setWrapped(headStyle.wrapped());
styleProperty.setVerticalAlignment(headStyle.verticalAlignment());
styleProperty.setRotation(headStyle.rotation());
styleProperty.setIndent(headStyle.indent());
styleProperty.setBorderLeft(headStyle.borderLeft());
styleProperty.setBorderRight(headStyle.borderRight());
styleProperty.setBorderTop(headStyle.borderTop());
styleProperty.setBorderBottom(headStyle.borderBottom());
styleProperty.setLeftBorderColor(headStyle.leftBorderColor());
styleProperty.setRightBorderColor(headStyle.rightBorderColor());
styleProperty.setTopBorderColor(headStyle.topBorderColor());
styleProperty.setBottomBorderColor(headStyle.bottomBorderColor());
styleProperty.setFillPatternType(headStyle.fillPatternType());
styleProperty.setFillBackgroundColor(headStyle.fillBackgroundColor());
styleProperty.setFillForegroundColor(headStyle.fillForegroundColor());
styleProperty.setShrinkToFit(headStyle.shrinkToFit());
return styleProperty;
}
public static StyleProperty build(ContentStyle contentStyle) {
if (contentStyle == null) {
return null;
}
StyleProperty styleProperty = new StyleProperty();
styleProperty.setDataFormat(contentStyle.dataFormat());
styleProperty.setHidden(contentStyle.hidden());
styleProperty.setLocked(contentStyle.locked());
styleProperty.setQuotePrefix(contentStyle.quotePrefix());
styleProperty.setHorizontalAlignment(contentStyle.horizontalAlignment());
styleProperty.setWrapped(contentStyle.wrapped());
styleProperty.setVerticalAlignment(contentStyle.verticalAlignment());
styleProperty.setRotation(contentStyle.rotation());
styleProperty.setIndent(contentStyle.indent());
styleProperty.setBorderLeft(contentStyle.borderLeft());
styleProperty.setBorderRight(contentStyle.borderRight());
styleProperty.setBorderTop(contentStyle.borderTop());
styleProperty.setBorderBottom(contentStyle.borderBottom());
styleProperty.setLeftBorderColor(contentStyle.leftBorderColor());
styleProperty.setRightBorderColor(contentStyle.rightBorderColor());
styleProperty.setTopBorderColor(contentStyle.topBorderColor());
styleProperty.setBottomBorderColor(contentStyle.bottomBorderColor());
styleProperty.setFillPatternType(contentStyle.fillPatternType());
styleProperty.setFillBackgroundColor(contentStyle.fillBackgroundColor());
styleProperty.setFillForegroundColor(contentStyle.fillForegroundColor());
styleProperty.setShrinkToFit(contentStyle.shrinkToFit());
return styleProperty;
}
public Short getDataFormat() {
return dataFormat;
}
public void setDataFormat(Short dataFormat) {
this.dataFormat = dataFormat;
}
public WriteFont getWriteFont() {
return writeFont;
}
public void setWriteFont(WriteFont writeFont) {
this.writeFont = writeFont;
}
public Boolean getHidden() {
return hidden;
}
public void setHidden(Boolean hidden) {
this.hidden = hidden;
}
public Boolean getLocked() {
return locked;
}
public void setLocked(Boolean locked) {
this.locked = locked;
}
public Boolean getQuotePrefix() {
return quotePrefix;
}
public void setQuotePrefix(Boolean quotePrefix) {
this.quotePrefix = quotePrefix;
}
public HorizontalAlignment getHorizontalAlignment() {
return horizontalAlignment;
}
public void setHorizontalAlignment(HorizontalAlignment horizontalAlignment) {
this.horizontalAlignment = horizontalAlignment;
}
public Boolean getWrapped() {
return wrapped;
}
public void setWrapped(Boolean wrapped) {
this.wrapped = wrapped;
}
public VerticalAlignment getVerticalAlignment() {
return verticalAlignment;
}
public void setVerticalAlignment(VerticalAlignment verticalAlignment) {
this.verticalAlignment = verticalAlignment;
}
public Short getRotation() {
return rotation;
}
public void setRotation(Short rotation) {
this.rotation = rotation;
}
public Short getIndent() {
return indent;
}
public void setIndent(Short indent) {
this.indent = indent;
}
public BorderStyle getBorderLeft() {
return borderLeft;
}
public void setBorderLeft(BorderStyle borderLeft) {
this.borderLeft = borderLeft;
}
public BorderStyle getBorderRight() {
return borderRight;
}
public void setBorderRight(BorderStyle borderRight) {
this.borderRight = borderRight;
}
public BorderStyle getBorderTop() {
return borderTop;
}
public void setBorderTop(BorderStyle borderTop) {
this.borderTop = borderTop;
}
public BorderStyle getBorderBottom() {
return borderBottom;
}
public void setBorderBottom(BorderStyle borderBottom) {
this.borderBottom = borderBottom;
}
public Short getLeftBorderColor() {
return leftBorderColor;
}
public void setLeftBorderColor(Short leftBorderColor) {
this.leftBorderColor = leftBorderColor;
}
public Short getRightBorderColor() {
return rightBorderColor;
}
public void setRightBorderColor(Short rightBorderColor) {
this.rightBorderColor = rightBorderColor;
}
public Short getTopBorderColor() {
return topBorderColor;
}
public void setTopBorderColor(Short topBorderColor) {
this.topBorderColor = topBorderColor;
}
public Short getBottomBorderColor() {
return bottomBorderColor;
}
public void setBottomBorderColor(Short bottomBorderColor) {
this.bottomBorderColor = bottomBorderColor;
}
public FillPatternType getFillPatternType() {
return fillPatternType;
}
public void setFillPatternType(FillPatternType fillPatternType) {
this.fillPatternType = fillPatternType;
}
public Short getFillBackgroundColor() {
return fillBackgroundColor;
}
public void setFillBackgroundColor(Short fillBackgroundColor) {
this.fillBackgroundColor = fillBackgroundColor;
}
public Short getFillForegroundColor() {
return fillForegroundColor;
}
public void setFillForegroundColor(Short fillForegroundColor) {
this.fillForegroundColor = fillForegroundColor;
}
public Boolean getShrinkToFit() {
return shrinkToFit;
}
public void setShrinkToFit(Boolean shrinkToFit) {
this.shrinkToFit = shrinkToFit;
}
}

15
src/main/java/com/alibaba/excel/util/WriteHandlerUtils.java

@ -123,6 +123,21 @@ public class WriteHandlerUtils {
} }
} }
public static void afterCellDataConverted(WriteContext writeContext, CellData cellData, Cell cell, Head head,
Integer relativeRowIndex, Boolean isHead) {
List<WriteHandler> handlerList =
writeContext.currentWriteHolder().writeHandlerMap().get(CellWriteHandler.class);
if (handlerList == null || handlerList.isEmpty()) {
return;
}
for (WriteHandler writeHandler : handlerList) {
if (writeHandler instanceof CellWriteHandler) {
((CellWriteHandler)writeHandler).afterCellDataConverted(writeContext.writeSheetHolder(),
writeContext.writeTableHolder(), cellData, cell, head, relativeRowIndex, isHead);
}
}
}
public static void afterCellDispose(WriteContext writeContext, CellData cellData, Cell cell, Head head, public static void afterCellDispose(WriteContext writeContext, CellData cellData, Cell cell, Head head,
Integer relativeRowIndex, Boolean isHead) { Integer relativeRowIndex, Boolean isHead) {
List<CellData> cellDataList = new ArrayList<CellData>(); List<CellData> cellDataList = new ArrayList<CellData>();

5
src/main/java/com/alibaba/excel/write/executor/AbstractExcelWriteExecutor.java

@ -13,7 +13,9 @@ import com.alibaba.excel.converters.ConverterKeyBuild;
import com.alibaba.excel.enums.CellDataTypeEnum; import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.exception.ExcelDataConvertException; import com.alibaba.excel.exception.ExcelDataConvertException;
import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.property.ExcelContentProperty; import com.alibaba.excel.metadata.property.ExcelContentProperty;
import com.alibaba.excel.util.WriteHandlerUtils;
import com.alibaba.excel.write.metadata.holder.WriteHolder; import com.alibaba.excel.write.metadata.holder.WriteHolder;
/** /**
@ -29,7 +31,7 @@ public abstract class AbstractExcelWriteExecutor implements ExcelWriteExecutor {
} }
protected CellData converterAndSet(WriteHolder currentWriteHolder, Class clazz, Cell cell, Object value, protected CellData converterAndSet(WriteHolder currentWriteHolder, Class clazz, Cell cell, Object value,
ExcelContentProperty excelContentProperty) { ExcelContentProperty excelContentProperty, Head head, Integer relativeRowIndex) {
if (value == null) { if (value == null) {
return new CellData(CellDataTypeEnum.EMPTY); return new CellData(CellDataTypeEnum.EMPTY);
} }
@ -43,6 +45,7 @@ public abstract class AbstractExcelWriteExecutor implements ExcelWriteExecutor {
if (cellData.getType() == null) { if (cellData.getType() == null) {
cellData.setType(CellDataTypeEnum.EMPTY); cellData.setType(CellDataTypeEnum.EMPTY);
} }
WriteHandlerUtils.afterCellDataConverted(writeContext, cellData, cell, head, relativeRowIndex, Boolean.FALSE);
switch (cellData.getType()) { switch (cellData.getType()) {
case STRING: case STRING:
cell.setCellValue(cellData.getStringValue()); cell.setCellValue(cellData.getStringValue());

8
src/main/java/com/alibaba/excel/write/executor/ExcelWriteAddExecutor.java

@ -105,7 +105,7 @@ public class ExcelWriteAddExecutor extends AbstractExcelWriteExecutor {
WriteHandlerUtils.afterCellCreate(writeContext, cell, head, relativeRowIndex, Boolean.FALSE); WriteHandlerUtils.afterCellCreate(writeContext, cell, head, relativeRowIndex, Boolean.FALSE);
Object value = oneRowData.get(dataIndex); Object value = oneRowData.get(dataIndex);
CellData cellData = converterAndSet(writeContext.currentWriteHolder(), value == null ? null : value.getClass(), CellData cellData = converterAndSet(writeContext.currentWriteHolder(), value == null ? null : value.getClass(),
cell, value, null); cell, value, null, head, relativeRowIndex);
WriteHandlerUtils.afterCellDispose(writeContext, cellData, cell, head, relativeRowIndex, Boolean.FALSE); WriteHandlerUtils.afterCellDispose(writeContext, cellData, cell, head, relativeRowIndex, Boolean.FALSE);
} }
@ -135,7 +135,7 @@ public class ExcelWriteAddExecutor extends AbstractExcelWriteExecutor {
WriteHandlerUtils.afterCellCreate(writeContext, cell, head, relativeRowIndex, Boolean.FALSE); WriteHandlerUtils.afterCellCreate(writeContext, cell, head, relativeRowIndex, Boolean.FALSE);
Object value = beanMap.get(name); Object value = beanMap.get(name);
CellData cellData = converterAndSet(currentWriteHolder, excelContentProperty.getField().getType(), cell, CellData cellData = converterAndSet(currentWriteHolder, excelContentProperty.getField().getType(), cell,
value, excelContentProperty); value, excelContentProperty, head, relativeRowIndex);
WriteHandlerUtils.afterCellDispose(writeContext, cellData, cell, head, relativeRowIndex, Boolean.FALSE); WriteHandlerUtils.afterCellDispose(writeContext, cellData, cell, head, relativeRowIndex, Boolean.FALSE);
beanMapHandledSet.add(name); beanMapHandledSet.add(name);
} }
@ -160,8 +160,8 @@ public class ExcelWriteAddExecutor extends AbstractExcelWriteExecutor {
WriteHandlerUtils.beforeCellCreate(writeContext, row, null, cellIndex, relativeRowIndex, Boolean.FALSE); WriteHandlerUtils.beforeCellCreate(writeContext, row, null, cellIndex, relativeRowIndex, Boolean.FALSE);
Cell cell = WorkBookUtil.createCell(row, cellIndex++); Cell cell = WorkBookUtil.createCell(row, cellIndex++);
WriteHandlerUtils.afterCellCreate(writeContext, cell, null, relativeRowIndex, Boolean.FALSE); WriteHandlerUtils.afterCellCreate(writeContext, cell, null, relativeRowIndex, Boolean.FALSE);
CellData cellData = CellData cellData = converterAndSet(currentWriteHolder, value == null ? null : value.getClass(), cell,
converterAndSet(currentWriteHolder, value == null ? null : value.getClass(), cell, value, null); value, null, null, relativeRowIndex);
WriteHandlerUtils.afterCellDispose(writeContext, cellData, cell, null, relativeRowIndex, Boolean.FALSE); WriteHandlerUtils.afterCellDispose(writeContext, cellData, cell, null, relativeRowIndex, Boolean.FALSE);
} }
} }

2
src/main/java/com/alibaba/excel/write/executor/ExcelWriteFillExecutor.java

@ -162,7 +162,7 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor {
} }
Object value = dataMap.get(variable); Object value = dataMap.get(variable);
CellData cellData = converterAndSet(writeSheetHolder, value == null ? null : value.getClass(), cell, CellData cellData = converterAndSet(writeSheetHolder, value == null ? null : value.getClass(), cell,
value, fieldNameContentPropertyMap.get(variable)); value, fieldNameContentPropertyMap.get(variable), null, relativeRowIndex);
WriteHandlerUtils.afterCellDispose(writeContext, cellData, cell, null, relativeRowIndex, Boolean.FALSE); WriteHandlerUtils.afterCellDispose(writeContext, cellData, cell, null, relativeRowIndex, Boolean.FALSE);
} else { } else {
StringBuilder cellValueBuild = new StringBuilder(); StringBuilder cellValueBuild = new StringBuilder();

6
src/main/java/com/alibaba/excel/write/handler/AbstractCellWriteHandler.java

@ -29,6 +29,12 @@ public abstract class AbstractCellWriteHandler implements CellWriteHandler {
} }
@Override
public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder,
CellData cellData, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
}
@Override @Override
public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder,
List<CellData> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { List<CellData> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {

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

@ -52,6 +52,25 @@ public interface CellWriteHandler extends WriteHandler {
void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head,
Integer relativeRowIndex, Boolean isHead); Integer relativeRowIndex, Boolean isHead);
/**
* Called after the cell data is converted
*
* @param writeSheetHolder
* @param writeTableHolder
* Nullable.It is null without using table writes.
* @param cell
* @param head
* Nullable.It is null in the case of fill data and without head.
* @param cellData
* Nullable.It is null in the case of add header.
* @param relativeRowIndex
* Nullable.It is null in the case of fill data.
* @param isHead
* It will always be false when fill data.
*/
void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, CellData cellData,
Cell cell, Head head, Integer relativeRowIndex, Boolean isHead);
/** /**
* Called after all operations on the cell have been completed * Called after all operations on the cell have been completed
* *

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

@ -3,6 +3,7 @@ package com.alibaba.excel.write.merge;
import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.ss.util.CellRangeAddress;
import com.alibaba.excel.metadata.property.LoopMergeProperty;
import com.alibaba.excel.write.handler.AbstractRowWriteHandler; import com.alibaba.excel.write.handler.AbstractRowWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder; import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
@ -48,6 +49,10 @@ public class LoopMergeStrategy extends AbstractRowWriteHandler {
this.columnIndex = columnIndex; this.columnIndex = columnIndex;
} }
public LoopMergeStrategy(LoopMergeProperty loopMergeProperty, Integer columnIndex) {
this(loopMergeProperty.getEachRow(), loopMergeProperty.getColumnExtend(), columnIndex);
}
@Override @Override
public void afterRowDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, public void afterRowDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row,
Integer relativeRowIndex, Boolean isHead) { Integer relativeRowIndex, Boolean isHead) {

6
src/main/java/com/alibaba/excel/write/merge/OnceAbsoluteMergeStrategy.java

@ -2,6 +2,7 @@ package com.alibaba.excel.write.merge;
import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.ss.util.CellRangeAddress;
import com.alibaba.excel.metadata.property.OnceAbsoluteMergeProperty;
import com.alibaba.excel.write.handler.AbstractSheetWriteHandler; import com.alibaba.excel.write.handler.AbstractSheetWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder; import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
@ -39,6 +40,11 @@ public class OnceAbsoluteMergeStrategy extends AbstractSheetWriteHandler {
this.lastColumnIndex = lastColumnIndex; this.lastColumnIndex = lastColumnIndex;
} }
public OnceAbsoluteMergeStrategy(OnceAbsoluteMergeProperty onceAbsoluteMergeProperty) {
this(onceAbsoluteMergeProperty.getFirstRowIndex(), onceAbsoluteMergeProperty.getLastRowIndex(),
onceAbsoluteMergeProperty.getFirstColumnIndex(), onceAbsoluteMergeProperty.getLastColumnIndex());
}
@Override @Override
public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) { public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
CellRangeAddress cellRangeAddress = CellRangeAddress cellRangeAddress =

57
src/main/java/com/alibaba/excel/write/metadata/holder/AbstractWriteHolder.java

@ -22,6 +22,8 @@ import com.alibaba.excel.metadata.AbstractHolder;
import com.alibaba.excel.metadata.Font; import com.alibaba.excel.metadata.Font;
import com.alibaba.excel.metadata.Head; import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.TableStyle; import com.alibaba.excel.metadata.TableStyle;
import com.alibaba.excel.metadata.property.LoopMergeProperty;
import com.alibaba.excel.metadata.property.OnceAbsoluteMergeProperty;
import com.alibaba.excel.metadata.property.RowHeightProperty; import com.alibaba.excel.metadata.property.RowHeightProperty;
import com.alibaba.excel.util.CollectionUtils; import com.alibaba.excel.util.CollectionUtils;
import com.alibaba.excel.write.handler.CellWriteHandler; import com.alibaba.excel.write.handler.CellWriteHandler;
@ -30,12 +32,15 @@ import com.alibaba.excel.write.handler.RowWriteHandler;
import com.alibaba.excel.write.handler.SheetWriteHandler; import com.alibaba.excel.write.handler.SheetWriteHandler;
import com.alibaba.excel.write.handler.WorkbookWriteHandler; import com.alibaba.excel.write.handler.WorkbookWriteHandler;
import com.alibaba.excel.write.handler.WriteHandler; import com.alibaba.excel.write.handler.WriteHandler;
import com.alibaba.excel.write.merge.LoopMergeStrategy;
import com.alibaba.excel.write.merge.OnceAbsoluteMergeStrategy;
import com.alibaba.excel.write.metadata.WriteBasicParameter; import com.alibaba.excel.write.metadata.WriteBasicParameter;
import com.alibaba.excel.write.metadata.WriteSheet; import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.WriteTable; import com.alibaba.excel.write.metadata.WriteTable;
import com.alibaba.excel.write.metadata.style.WriteCellStyle; import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont; import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.property.ExcelWriteHeadProperty; import com.alibaba.excel.write.property.ExcelWriteHeadProperty;
import com.alibaba.excel.write.style.AbstractVerticalCellStyleStrategy;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy; import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.alibaba.excel.write.style.column.AbstractHeadColumnWidthStyleStrategy; import com.alibaba.excel.write.style.column.AbstractHeadColumnWidthStyleStrategy;
import com.alibaba.excel.write.style.row.SimpleRowHeightStyleStrategy; import com.alibaba.excel.write.style.row.SimpleRowHeightStyleStrategy;
@ -279,19 +284,63 @@ public abstract class AbstractWriteHolder extends AbstractHolder implements Writ
return; return;
} }
Map<Integer, Head> headMap = getExcelWriteHeadProperty().getHeadMap(); Map<Integer, Head> headMap = getExcelWriteHeadProperty().getHeadMap();
boolean hasColumnWidth = false; boolean hasColumnWidth = false;
for (Map.Entry<Integer, Head> entry : headMap.entrySet()) { boolean hasStyle = false;
if (entry.getValue().getColumnWidthProperty() != null) {
for (Head head : headMap.values()) {
if (head.getColumnWidthProperty() != null) {
hasColumnWidth = true; hasColumnWidth = true;
break;
} }
if (head.getHeadStyleProperty() != null || head.getHeadFontProperty() != null
|| head.getContentStyleProperty() != null || head.getContentFontProperty() != null) {
hasStyle = true;
}
dealLoopMerge(handlerList, head);
} }
if (hasColumnWidth) { if (hasColumnWidth) {
dealColumnWidth(handlerList); dealColumnWidth(handlerList);
} }
if (hasStyle) {
dealStyle(handlerList);
}
dealRowHigh(handlerList); dealRowHigh(handlerList);
dealOnceAbsoluteMerge(handlerList);
}
private void dealStyle(List<WriteHandler> handlerList) {
WriteHandler styleStrategy = new AbstractVerticalCellStyleStrategy() {
@Override
protected WriteCellStyle headCellStyle(Head head) {
return WriteCellStyle.build(head.getHeadStyleProperty(), head.getHeadFontProperty());
}
@Override
protected WriteCellStyle contentCellStyle(Head head) {
return WriteCellStyle.build(head.getContentStyleProperty(), head.getContentFontProperty());
}
};
handlerList.add(styleStrategy);
}
private void dealLoopMerge(List<WriteHandler> handlerList, Head head) {
LoopMergeProperty loopMergeProperty = head.getLoopMergeProperty();
if (loopMergeProperty == null) {
return;
}
handlerList.add(new LoopMergeStrategy(loopMergeProperty, head.getColumnIndex()));
}
private void dealOnceAbsoluteMerge(List<WriteHandler> handlerList) {
OnceAbsoluteMergeProperty onceAbsoluteMergeProperty =
getExcelWriteHeadProperty().getOnceAbsoluteMergeProperty();
if (onceAbsoluteMergeProperty == null) {
return;
}
handlerList.add(new OnceAbsoluteMergeStrategy(onceAbsoluteMergeProperty));
} }
private void dealRowHigh(List<WriteHandler> handlerList) { private void dealRowHigh(List<WriteHandler> handlerList) {

77
src/main/java/com/alibaba/excel/write/metadata/style/WriteCellStyle.java

@ -8,6 +8,10 @@ import org.apache.poi.ss.usermodel.IgnoredErrorType;
import org.apache.poi.ss.usermodel.IndexedColors; import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.VerticalAlignment; import org.apache.poi.ss.usermodel.VerticalAlignment;
import com.alibaba.excel.metadata.property.FontProperty;
import com.alibaba.excel.metadata.property.StyleProperty;
import com.alibaba.excel.util.StringUtils;
/** /**
* Cell style when writing * Cell style when writing
* *
@ -137,6 +141,79 @@ public class WriteCellStyle {
*/ */
private Boolean shrinkToFit; private Boolean shrinkToFit;
public static WriteCellStyle build(StyleProperty styleProperty, FontProperty fontProperty) {
if (styleProperty == null && fontProperty == null) {
return null;
}
WriteCellStyle writeCellStyle = new WriteCellStyle();
if (styleProperty != null) {
if (styleProperty.getDataFormat() >= 0) {
writeCellStyle.setDataFormat(styleProperty.getDataFormat());
}
writeCellStyle.setHidden(styleProperty.getHidden());
writeCellStyle.setLocked(styleProperty.getLocked());
writeCellStyle.setQuotePrefix(styleProperty.getQuotePrefix());
writeCellStyle.setHorizontalAlignment(styleProperty.getHorizontalAlignment());
writeCellStyle.setWrapped(styleProperty.getWrapped());
writeCellStyle.setVerticalAlignment(styleProperty.getVerticalAlignment());
if (styleProperty.getRotation() >= 0) {
writeCellStyle.setRotation(styleProperty.getRotation());
}
if (styleProperty.getIndent() >= 0) {
writeCellStyle.setIndent(styleProperty.getIndent());
}
writeCellStyle.setBorderLeft(styleProperty.getBorderLeft());
writeCellStyle.setBorderRight(styleProperty.getBorderRight());
writeCellStyle.setBorderTop(styleProperty.getBorderTop());
writeCellStyle.setBorderBottom(styleProperty.getBorderBottom());
if (styleProperty.getLeftBorderColor() >= 0) {
writeCellStyle.setLeftBorderColor(styleProperty.getLeftBorderColor());
}
if (styleProperty.getRightBorderColor() >= 0) {
writeCellStyle.setRightBorderColor(styleProperty.getRightBorderColor());
}
if (styleProperty.getTopBorderColor() >= 0) {
writeCellStyle.setTopBorderColor(styleProperty.getTopBorderColor());
}
if (styleProperty.getBottomBorderColor() >= 0) {
writeCellStyle.setBottomBorderColor(styleProperty.getBottomBorderColor());
}
writeCellStyle.setFillPatternType(styleProperty.getFillPatternType());
if (styleProperty.getFillBackgroundColor() >= 0) {
writeCellStyle.setFillBackgroundColor(styleProperty.getFillBackgroundColor());
}
if (styleProperty.getFillForegroundColor() >= 0) {
writeCellStyle.setFillForegroundColor(styleProperty.getFillForegroundColor());
}
writeCellStyle.setShrinkToFit(styleProperty.getShrinkToFit());
}
if (fontProperty != null) {
WriteFont writeFont = new WriteFont();
writeCellStyle.setWriteFont(writeFont);
if (!StringUtils.isEmpty(fontProperty.getFontName())) {
writeFont.setFontName(fontProperty.getFontName());
}
writeFont.setFontHeightInPoints(fontProperty.getFontHeightInPoints());
writeFont.setItalic(fontProperty.getItalic());
writeFont.setStrikeout(fontProperty.getStrikeout());
if (fontProperty.getColor() >= 0) {
writeFont.setColor(fontProperty.getColor());
}
if (fontProperty.getTypeOffset() >= 0) {
writeFont.setTypeOffset(fontProperty.getTypeOffset());
}
if (fontProperty.getUnderline() >= 0) {
writeFont.setUnderline(fontProperty.getUnderline());
}
if (fontProperty.getCharset() >= 0) {
writeFont.setCharset(fontProperty.getCharset());
}
writeFont.setBold(fontProperty.getBold());
}
return writeCellStyle;
}
public Short getDataFormat() { public Short getDataFormat() {
return dataFormat; return dataFormat;
} }

51
src/main/java/com/alibaba/excel/write/property/ExcelWriteHeadProperty.java

@ -9,8 +9,14 @@ import java.util.Set;
import com.alibaba.excel.annotation.format.NumberFormat; import com.alibaba.excel.annotation.format.NumberFormat;
import com.alibaba.excel.annotation.write.style.ColumnWidth; import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.alibaba.excel.annotation.write.style.ContentFontStyle;
import com.alibaba.excel.annotation.write.style.ContentLoopMerge;
import com.alibaba.excel.annotation.write.style.ContentRowHeight; import com.alibaba.excel.annotation.write.style.ContentRowHeight;
import com.alibaba.excel.annotation.write.style.ContentStyle;
import com.alibaba.excel.annotation.write.style.HeadFontStyle;
import com.alibaba.excel.annotation.write.style.HeadRowHeight; import com.alibaba.excel.annotation.write.style.HeadRowHeight;
import com.alibaba.excel.annotation.write.style.HeadStyle;
import com.alibaba.excel.annotation.write.style.OnceAbsoluteMerge;
import com.alibaba.excel.converters.ConverterKeyBuild; import com.alibaba.excel.converters.ConverterKeyBuild;
import com.alibaba.excel.converters.DefaultConverterLoader; import com.alibaba.excel.converters.DefaultConverterLoader;
import com.alibaba.excel.enums.CellDataTypeEnum; import com.alibaba.excel.enums.CellDataTypeEnum;
@ -21,7 +27,11 @@ import com.alibaba.excel.metadata.Holder;
import com.alibaba.excel.metadata.property.ColumnWidthProperty; import com.alibaba.excel.metadata.property.ColumnWidthProperty;
import com.alibaba.excel.metadata.property.ExcelContentProperty; import com.alibaba.excel.metadata.property.ExcelContentProperty;
import com.alibaba.excel.metadata.property.ExcelHeadProperty; import com.alibaba.excel.metadata.property.ExcelHeadProperty;
import com.alibaba.excel.metadata.property.FontProperty;
import com.alibaba.excel.metadata.property.LoopMergeProperty;
import com.alibaba.excel.metadata.property.OnceAbsoluteMergeProperty;
import com.alibaba.excel.metadata.property.RowHeightProperty; import com.alibaba.excel.metadata.property.RowHeightProperty;
import com.alibaba.excel.metadata.property.StyleProperty;
/** /**
* Define the header attribute of excel * Define the header attribute of excel
@ -31,6 +41,7 @@ import com.alibaba.excel.metadata.property.RowHeightProperty;
public class ExcelWriteHeadProperty extends ExcelHeadProperty { public class ExcelWriteHeadProperty extends ExcelHeadProperty {
private RowHeightProperty headRowHeightProperty; private RowHeightProperty headRowHeightProperty;
private RowHeightProperty contentRowHeightProperty; private RowHeightProperty contentRowHeightProperty;
private OnceAbsoluteMergeProperty onceAbsoluteMergeProperty;
public ExcelWriteHeadProperty(Holder holder, Class headClazz, List<List<String>> head, Boolean convertAllFiled) { public ExcelWriteHeadProperty(Holder holder, Class headClazz, List<List<String>> head, Boolean convertAllFiled) {
super(holder, headClazz, head, convertAllFiled); super(holder, headClazz, head, convertAllFiled);
@ -41,8 +52,15 @@ public class ExcelWriteHeadProperty extends ExcelHeadProperty {
RowHeightProperty.build((HeadRowHeight)headClazz.getAnnotation(HeadRowHeight.class)); RowHeightProperty.build((HeadRowHeight)headClazz.getAnnotation(HeadRowHeight.class));
this.contentRowHeightProperty = this.contentRowHeightProperty =
RowHeightProperty.build((ContentRowHeight)headClazz.getAnnotation(ContentRowHeight.class)); RowHeightProperty.build((ContentRowHeight)headClazz.getAnnotation(ContentRowHeight.class));
this.onceAbsoluteMergeProperty =
OnceAbsoluteMergeProperty.build((OnceAbsoluteMerge)headClazz.getAnnotation(OnceAbsoluteMerge.class));
ColumnWidth parentColumnWidth = (ColumnWidth)headClazz.getAnnotation(ColumnWidth.class); ColumnWidth parentColumnWidth = (ColumnWidth)headClazz.getAnnotation(ColumnWidth.class);
HeadStyle parentHeadStyle = (HeadStyle)headClazz.getAnnotation(HeadStyle.class);
HeadFontStyle parentHeadFontStyle = (HeadFontStyle)headClazz.getAnnotation(HeadFontStyle.class);
ContentStyle parentContentStyle = (ContentStyle)headClazz.getAnnotation(ContentStyle.class);
ContentFontStyle parentContentFontStyle = (ContentFontStyle)headClazz.getAnnotation(ContentFontStyle.class);
for (Map.Entry<Integer, ExcelContentProperty> entry : getContentPropertyMap().entrySet()) { for (Map.Entry<Integer, ExcelContentProperty> entry : getContentPropertyMap().entrySet()) {
Integer index = entry.getKey(); Integer index = entry.getKey();
ExcelContentProperty excelContentPropertyData = entry.getValue(); ExcelContentProperty excelContentPropertyData = entry.getValue();
@ -54,6 +72,31 @@ public class ExcelWriteHeadProperty extends ExcelHeadProperty {
} }
headData.setColumnWidthProperty(ColumnWidthProperty.build(columnWidth)); headData.setColumnWidthProperty(ColumnWidthProperty.build(columnWidth));
HeadStyle headStyle = field.getAnnotation(HeadStyle.class);
if (headStyle == null) {
headStyle = parentHeadStyle;
}
headData.setHeadStyleProperty(StyleProperty.build(headStyle));
HeadFontStyle headFontStyle = field.getAnnotation(HeadFontStyle.class);
if (headFontStyle == null) {
headFontStyle = parentHeadFontStyle;
}
headData.setHeadFontProperty(FontProperty.build(headFontStyle));
ContentStyle contentStyle = field.getAnnotation(ContentStyle.class);
if (contentStyle == null) {
contentStyle = parentContentStyle;
}
headData.setContentStyleProperty(StyleProperty.build(contentStyle));
ContentFontStyle contentFontStyle = field.getAnnotation(ContentFontStyle.class);
if (contentFontStyle == null) {
contentFontStyle = parentContentFontStyle;
}
headData.setContentFontProperty(FontProperty.build(contentFontStyle));
headData.setLoopMergeProperty(LoopMergeProperty.build(field.getAnnotation(ContentLoopMerge.class)));
// If have @NumberFormat, 'NumberStringConverter' is specified by default // If have @NumberFormat, 'NumberStringConverter' is specified by default
if (excelContentPropertyData.getConverter() == null) { if (excelContentPropertyData.getConverter() == null) {
NumberFormat numberFormat = field.getAnnotation(NumberFormat.class); NumberFormat numberFormat = field.getAnnotation(NumberFormat.class);
@ -81,6 +124,14 @@ public class ExcelWriteHeadProperty extends ExcelHeadProperty {
this.contentRowHeightProperty = contentRowHeightProperty; this.contentRowHeightProperty = contentRowHeightProperty;
} }
public OnceAbsoluteMergeProperty getOnceAbsoluteMergeProperty() {
return onceAbsoluteMergeProperty;
}
public void setOnceAbsoluteMergeProperty(OnceAbsoluteMergeProperty onceAbsoluteMergeProperty) {
this.onceAbsoluteMergeProperty = onceAbsoluteMergeProperty;
}
/** /**
* Calculate all cells that need to be merged * Calculate all cells that need to be merged
* *

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

@ -40,6 +40,12 @@ public abstract class AbstractCellStyleStrategy implements CellWriteHandler, She
} }
@Override
public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder,
CellData cellData, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
}
@Override @Override
public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder,
List<CellData> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { List<CellData> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {

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

@ -3,12 +3,11 @@ package com.alibaba.excel.write.style.column;
import java.util.List; import java.util.List;
import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import com.alibaba.excel.event.NotRepeatExecutor; import com.alibaba.excel.event.NotRepeatExecutor;
import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head; import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.handler.CellWriteHandler; import com.alibaba.excel.write.handler.AbstractCellWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder; import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
@ -17,7 +16,7 @@ import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
* *
* @author Jiaju Zhuang * @author Jiaju Zhuang
*/ */
public abstract class AbstractColumnWidthStyleStrategy implements CellWriteHandler, NotRepeatExecutor { public abstract class AbstractColumnWidthStyleStrategy extends AbstractCellWriteHandler implements NotRepeatExecutor {
@Override @Override
public String uniqueValue() { public String uniqueValue() {
@ -25,15 +24,8 @@ public abstract class AbstractColumnWidthStyleStrategy implements CellWriteHandl
} }
@Override @Override
public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder,
Head head, Integer columnIndex, Integer relativeRowIndex, Boolean isHead) {} List<CellData> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
@Override
public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell,
Head head, Integer relativeRowIndex, Boolean isHead) {}
@Override
public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<CellData> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
setColumnWidth(writeSheetHolder, cellDataList, cell, head, relativeRowIndex, isHead); setColumnWidth(writeSheetHolder, cellDataList, cell, head, relativeRowIndex, isHead);
} }
@ -47,7 +39,7 @@ public abstract class AbstractColumnWidthStyleStrategy implements CellWriteHandl
* @param relativeRowIndex * @param relativeRowIndex
* @param isHead * @param isHead
*/ */
protected abstract void setColumnWidth(WriteSheetHolder writeSheetHolder, List<CellData> cellDataList, Cell cell, Head head, protected abstract void setColumnWidth(WriteSheetHolder writeSheetHolder, List<CellData> cellDataList, Cell cell,
Integer relativeRowIndex, Boolean isHead); Head head, Integer relativeRowIndex, Boolean isHead);
} }

77
src/test/java/com/alibaba/easyexcel/test/demo/read/DemoCellCommentsListener.java

@ -1,77 +0,0 @@
package com.alibaba.easyexcel.test.demo.read;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.exception.ExcelDataConvertException;
import com.alibaba.fastjson.JSON;
/**
* 读取单元格的批注
*
* @author: kaiux
* @date: 2019-10-23 14:10
**/
public class DemoCellCommentsListener extends AnalysisEventListener<DemoData> {
private static final Logger LOGGER = LoggerFactory.getLogger(DemoCellCommentsListener.class);
/**
* 每隔5条存储数据库实际使用中可以3000条然后清理list 方便内存回收
*/
private static final int BATCH_COUNT = 5;
List<DemoData> list = new ArrayList<DemoData>();
/**
* 在转换异常 获取其他异常下会调用本接口抛出异常则停止读取如果这里不抛出异常则 继续读取下一行
*
* @param exception
* @param context
* @throws Exception
*/
@Override
public void onException(Exception exception, AnalysisContext context) {
LOGGER.error("解析失败,但是继续解析下一行:{}", exception.getMessage());
if (exception instanceof ExcelDataConvertException) {
ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException)exception;
LOGGER.error("第{}行,第{}列解析异常", excelDataConvertException.getRowIndex(),
excelDataConvertException.getColumnIndex());
}
}
/**
* 这里会一行行的返回头
*
* @param headMap
* @param context
*/
@Override
public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {}
@Override
public void invoke(DemoData data, AnalysisContext context) {
LOGGER.info("解析到一条数据:{}", JSON.toJSONString(data));
if (list.size() >= BATCH_COUNT) {
saveData();
list.clear();
}
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
saveData();
LOGGER.info("所有数据解析完成!");
}
/**
* 加上存储数据库
*/
private void saveData() {
LOGGER.info("{}条数据,开始存储数据库!", list.size());
LOGGER.info("存储数据库成功!");
}
}

14
src/test/java/com/alibaba/easyexcel/test/demo/read/DemoExtraData.java

@ -0,0 +1,14 @@
package com.alibaba.easyexcel.test.demo.read;
import lombok.Data;
/**
* @author Jiaju Zhuang
*/
@Data
public class DemoExtraData {
private String row1;
private String row2;
}

58
src/test/java/com/alibaba/easyexcel/test/demo/read/DemoExtraListener.java

@ -0,0 +1,58 @@
package com.alibaba.easyexcel.test.demo.read;
import org.junit.Assert;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.metadata.CellExtra;
import com.alibaba.fastjson.JSON;
/**
* 读取单元格的批注
*
* @author: kaiux
* @date: 2019-10-23 14:10
**/
public class DemoExtraListener extends AnalysisEventListener<DemoExtraData> {
private static final Logger LOGGER = LoggerFactory.getLogger(DemoDataListener.class);
@Override
public void invoke(DemoExtraData data, AnalysisContext context) {}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {}
@Override
public void extra(CellExtra extra, AnalysisContext context) {
LOGGER.info("读取到了一条额外信息:{}", JSON.toJSONString(extra));
switch (extra.getType()) {
case COMMENT:
LOGGER.info("额外信息是批注,在rowIndex:{},columnIndex;{},内容是:{}", extra.getRowIndex(), extra.getColumnIndex(),
extra.getText());
break;
case HYPERLINK:
if ("Sheet1!A1".equals(extra.getText())) {
LOGGER.info("额外信息是超链接,在rowIndex:{},columnIndex;{},内容是:{}", extra.getRowIndex(),
extra.getColumnIndex(), extra.getText());
} else if ("Sheet2!A1".equals(extra.getText())) {
LOGGER.info(
"额外信息是超链接,而且覆盖了一个区间,在firstRowIndex:{},firstColumnIndex;{},lastRowIndex:{},lastColumnIndex:{},"
+ "内容是:{}",
extra.getFirstRowIndex(), extra.getFirstColumnIndex(), extra.getLastRowIndex(),
extra.getLastColumnIndex(), extra.getText());
} else {
Assert.fail("Unknown hyperlink!");
}
break;
case MERGE:
LOGGER.info(
"额外信息是超链接,而且覆盖了一个区间,在firstRowIndex:{},firstColumnIndex;{},lastRowIndex:{},lastColumnIndex:{}",
extra.getFirstRowIndex(), extra.getFirstColumnIndex(), extra.getLastRowIndex(),
extra.getLastColumnIndex());
break;
default:
}
}
}

23
src/test/java/com/alibaba/easyexcel/test/demo/read/ReadTest.java

@ -16,6 +16,7 @@ import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.format.DateTimeFormat; import com.alibaba.excel.annotation.format.DateTimeFormat;
import com.alibaba.excel.annotation.format.NumberFormat; import com.alibaba.excel.annotation.format.NumberFormat;
import com.alibaba.excel.converters.DefaultConverterLoader; import com.alibaba.excel.converters.DefaultConverterLoader;
import com.alibaba.excel.enums.CellExtraTypeEnum;
import com.alibaba.excel.read.metadata.ReadSheet; import com.alibaba.excel.read.metadata.ReadSheet;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
@ -162,20 +163,28 @@ public class ReadTest {
} }
/** /**
* 读取单元格批注 * 额外信息批注超链接合并单元格信息读取
* <p>
* 由于是流式读取没法在读取到单元格数据的时候直接读取到额外信息所以只能最后通知哪些单元格有哪些额外信息
* *
* <p> * <p>
* 1. 创建excel对应的实体对象 参照{@link DemoData} * 1. 创建excel对应的实体对象 参照{@link DemoExtraData}
* <p> * <p>
* 2. 由于默认异步读取excel所以需要创建excel一行一行的回调监听器参照{@link DemoHeadDataListener} * 2. 由于默认异步读取excel所以需要创建excel一行一行的回调监听器参照{@link DemoExtraListener}
* <p> * <p>
* 3. 直接读即可 * 3. 直接读即可
*/ */
@Test @Test
public void commentsRead() { public void extraRead() {
String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx"; String fileName = TestFileUtil.getPath() + "demo" + File.separator + "extra.xlsx";
// 这里 需要指定读用哪个class去读,然后读取第一个sheet // 这里 需要指定读用哪个class去读,然后读取第一个sheet
EasyExcel.read(fileName, DemoData.class, new DemoCellCommentsListener()).sheet().doRead(); EasyExcel.read(fileName, DemoExtraData.class, new DemoExtraListener())
// 需要读取批注 默认不读取
.extraRead(CellExtraTypeEnum.COMMENT)
// 需要读取超链接 默认不读取
.extraRead(CellExtraTypeEnum.HYPERLINK)
// 需要读取合并单元格信息 默认不读取
.extraRead(CellExtraTypeEnum.MERGE).sheet().doRead();
} }
/** /**
@ -233,7 +242,7 @@ public class ReadTest {
} }
/** /**
* 不创建对象的读不是特别推荐使用都用String接收对日期的支持不是很好 * 不创建对象的读
*/ */
@Test @Test
public void noModleRead() { public void noModleRead() {

17
src/test/java/com/alibaba/easyexcel/test/demo/write/CustomCellWriteHandler.java

@ -6,13 +6,12 @@ import org.apache.poi.common.usermodel.HyperlinkType;
import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CreationHelper; import org.apache.poi.ss.usermodel.CreationHelper;
import org.apache.poi.ss.usermodel.Hyperlink; import org.apache.poi.ss.usermodel.Hyperlink;
import org.apache.poi.ss.usermodel.Row;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head; import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.handler.CellWriteHandler; import com.alibaba.excel.write.handler.AbstractCellWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder; import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
@ -21,22 +20,10 @@ import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
* *
* @author Jiaju Zhuang * @author Jiaju Zhuang
*/ */
public class CustomCellWriteHandler implements CellWriteHandler { public class CustomCellWriteHandler extends AbstractCellWriteHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(CustomCellWriteHandler.class); private static final Logger LOGGER = LoggerFactory.getLogger(CustomCellWriteHandler.class);
@Override
public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row,
Head head, Integer columnIndex, Integer relativeRowIndex, Boolean isHead) {
}
@Override
public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell,
Head head, Integer relativeRowIndex, Boolean isHead) {
}
@Override @Override
public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder,
List<CellData> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { List<CellData> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {

27
src/test/java/com/alibaba/easyexcel/test/demo/write/DemoMergeData.java

@ -0,0 +1,27 @@
package com.alibaba.easyexcel.test.demo.write;
import java.util.Date;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ContentLoopMerge;
import lombok.Data;
/**
* 样式的数据类
*
* @author Jiaju Zhuang
**/
@Data
// 将第6-7行的2-3列合并成一个单元格
// @OnceAbsoluteMerge(firstRowIndex = 5, lastRowIndex = 6, firstColumnIndex = 1, lastColumnIndex = 2)
public class DemoMergeData {
// 这一列 每隔2行 合并单元格
@ContentLoopMerge(eachRow = 2)
@ExcelProperty("字符串标题")
private String string;
@ExcelProperty("日期标题")
private Date date;
@ExcelProperty("数字标题")
private Double doubleData;
}

44
src/test/java/com/alibaba/easyexcel/test/demo/write/DemoStyleData.java

@ -0,0 +1,44 @@
package com.alibaba.easyexcel.test.demo.write;
import java.util.Date;
import org.apache.poi.ss.usermodel.FillPatternType;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ContentFontStyle;
import com.alibaba.excel.annotation.write.style.ContentStyle;
import com.alibaba.excel.annotation.write.style.HeadFontStyle;
import com.alibaba.excel.annotation.write.style.HeadStyle;
import lombok.Data;
/**
* 样式的数据类
*
* @author Jiaju Zhuang
**/
@Data
// 头背景设置成红色 IndexedColors.RED.getIndex()
@HeadStyle(fillPatternType = FillPatternType.SOLID_FOREGROUND, fillForegroundColor = 10)
// 头字体设置成20
@HeadFontStyle(fontHeightInPoints = 20)
// 内容的背景设置成绿色 IndexedColors.GREEN.getIndex()
@ContentStyle(fillPatternType = FillPatternType.SOLID_FOREGROUND, fillForegroundColor = 17)
// 内容字体设置成20
@ContentFontStyle(fontHeightInPoints = 20)
public class DemoStyleData {
// 字符串的头背景设置成粉红 IndexedColors.PINK.getIndex()
@HeadStyle(fillPatternType = FillPatternType.SOLID_FOREGROUND, fillForegroundColor = 14)
// 字符串的头字体设置成20
@HeadFontStyle(fontHeightInPoints = 30)
// 字符串的内容的背景设置成天蓝 IndexedColors.SKY_BLUE.getIndex()
@ContentStyle(fillPatternType = FillPatternType.SOLID_FOREGROUND, fillForegroundColor = 40)
// 字符串的内容字体设置成20
@ContentFontStyle(fontHeightInPoints = 30)
@ExcelProperty("字符串标题")
private String string;
@ExcelProperty("日期标题")
private Date date;
@ExcelProperty("数字标题")
private Double doubleData;
}

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

@ -270,7 +270,21 @@ public class WriteTest {
} }
/** /**
* 自定义样式 * 注解形式自定义样式
* <p>
* 1. 创建excel对应的实体对象 参照{@link DemoStyleData}
* <p>
* 3. 直接写即可
*/
@Test
public void annotationStyleWrite() {
String fileName = TestFileUtil.getPath() + "annotationStyleWrite" + System.currentTimeMillis() + ".xlsx";
// 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
EasyExcel.write(fileName, DemoStyleData.class).sheet("模板").doWrite(data());
}
/**
* 拦截器形式自定义样式
* <p> * <p>
* 1. 创建excel对应的实体对象 参照{@link DemoData} * 1. 创建excel对应的实体对象 参照{@link DemoData}
* <p> * <p>
@ -279,8 +293,8 @@ public class WriteTest {
* 3. 直接写即可 * 3. 直接写即可
*/ */
@Test @Test
public void styleWrite() { public void handlerStyleWrite() {
String fileName = TestFileUtil.getPath() + "styleWrite" + System.currentTimeMillis() + ".xlsx"; String fileName = TestFileUtil.getPath() + "handlerStyleWrite" + System.currentTimeMillis() + ".xlsx";
// 头的策略 // 头的策略
WriteCellStyle headWriteCellStyle = new WriteCellStyle(); WriteCellStyle headWriteCellStyle = new WriteCellStyle();
// 背景设置为红色 // 背景设置为红色
@ -310,7 +324,7 @@ public class WriteTest {
/** /**
* 合并单元格 * 合并单元格
* <p> * <p>
* 1. 创建excel对应的实体对象 参照{@link DemoData} * 1. 创建excel对应的实体对象 参照{@link DemoData} {@link DemoMergeData}
* <p> * <p>
* 2. 创建一个merge策略 并注册 * 2. 创建一个merge策略 并注册
* <p> * <p>
@ -318,7 +332,14 @@ public class WriteTest {
*/ */
@Test @Test
public void mergeWrite() { public void mergeWrite() {
// 方法1 注解
String fileName = TestFileUtil.getPath() + "mergeWrite" + System.currentTimeMillis() + ".xlsx"; 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 也就是我们数据的长度,所以就第一列会合并。当然其他合并策略也可以自己写 // 每隔2行会合并 把eachColumn 设置成 3 也就是我们数据的长度,所以就第一列会合并。当然其他合并策略也可以自己写
LoopMergeStrategy loopMergeStrategy = new LoopMergeStrategy(2, 0); LoopMergeStrategy loopMergeStrategy = new LoopMergeStrategy(2, 0);
// 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
@ -414,6 +435,23 @@ public class WriteTest {
.registerWriteHandler(new CustomCellWriteHandler()).sheet("模板").doWrite(data()); .registerWriteHandler(new CustomCellWriteHandler()).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());
}
/** /**
* 不创建对象的写 * 不创建对象的写
*/ */
@ -437,6 +475,20 @@ public class WriteTest {
return list; 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() { private List<List<String>> head() {
List<List<String>> list = new ArrayList<List<String>>(); List<List<String>> list = new ArrayList<List<String>>();
List<String> head0 = new ArrayList<String>(); List<String> head0 = new ArrayList<String>();

BIN
src/test/resources/demo/extra.xlsx

Binary file not shown.

4
update.md

@ -11,7 +11,9 @@
* 新增合并单元格注解 * 新增合并单元格注解
* 提升合并策略效率 * 提升合并策略效率
* 兼容部分比较特殊的excel * 兼容部分比较特殊的excel
* 同时传入了`List<List<String>>`和`class`的head,会通过index去匹配注解
* 修复读取转换器的并发问题
*
# 2.1.4 # 2.1.4
* 新增参数`useDefaultListener` 可以排除默认对象转换 * 新增参数`useDefaultListener` 可以排除默认对象转换

Loading…
Cancel
Save