diff --git a/src/main/java/com/alibaba/excel/annotation/write/style/ContentFontStyle.java b/src/main/java/com/alibaba/excel/annotation/write/style/ContentFontStyle.java index cb8d3c57..d593aef3 100644 --- a/src/main/java/com/alibaba/excel/annotation/write/style/ContentFontStyle.java +++ b/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 */ -@Target({ElementType.FIELD}) +@Target({ElementType.FIELD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Inherited public @interface ContentFontStyle { @@ -24,7 +24,7 @@ public @interface ContentFontStyle { /** * The name for the font (i.e. Arial) */ - String fontName(); + String fontName() default ""; /** * Height in the familiar unit of measure - points diff --git a/src/main/java/com/alibaba/excel/annotation/write/style/ContentStyle.java b/src/main/java/com/alibaba/excel/annotation/write/style/ContentStyle.java index 1cece9bb..9ef3f47e 100644 --- a/src/main/java/com/alibaba/excel/annotation/write/style/ContentStyle.java +++ b/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 */ -@Target({ElementType.FIELD}) +@Target({ElementType.FIELD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Inherited public @interface ContentStyle { /** * 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 */ - boolean hidden(); + boolean hidden() default false; /** * 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 * 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 */ - boolean quotePrefix(); + boolean quotePrefix() default false; /** * 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 true make all content visible within a * cell by displaying it on multiple lines * */ - boolean wrapped(); + boolean wrapped() default false; /** * 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. @@ -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 * applied to. */ - short rotation(); + short rotation() default -1; /** * 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 */ - BorderStyle borderLeft(); + BorderStyle borderLeft() default BorderStyle.NONE; /** * 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 */ - BorderStyle borderTop(); + BorderStyle borderTop() default BorderStyle.NONE; /** * 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 * * @see IndexedColors */ - short leftBorderColor(); + short leftBorderColor() default -1; /** * Set the color to use for the right border @@ -110,7 +110,7 @@ public @interface ContentStyle { * @see IndexedColors * */ - short rightBorderColor(); + short rightBorderColor() default -1; /** * Set the color to use for the top border @@ -118,7 +118,7 @@ public @interface ContentStyle { * @see IndexedColors * */ - short topBorderColor(); + short topBorderColor() default -1; /** * Set the color to use for the bottom border @@ -126,14 +126,14 @@ public @interface ContentStyle { * @see IndexedColors * */ - short bottomBorderColor(); + short bottomBorderColor() default -1; /** * Setting to one fills the cell with the foreground color... No idea about other values * * @see FillPatternType#SOLID_FOREGROUND */ - FillPatternType fillPatternType(); + FillPatternType fillPatternType() default FillPatternType.NO_FILL; /** * Set the background fill color. @@ -141,7 +141,7 @@ public @interface ContentStyle { * @see IndexedColors * */ - short fillBackgroundColor(); + short fillBackgroundColor() default -1; /** * Set the foreground fill color Note: Ensure Foreground color is set prior to background color. @@ -149,11 +149,11 @@ public @interface ContentStyle { * @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 */ - boolean shrinkToFit(); + boolean shrinkToFit() default false; } diff --git a/src/main/java/com/alibaba/excel/annotation/write/style/HeadFontStyle.java b/src/main/java/com/alibaba/excel/annotation/write/style/HeadFontStyle.java index 907a44b5..957e50f5 100644 --- a/src/main/java/com/alibaba/excel/annotation/write/style/HeadFontStyle.java +++ b/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 */ -@Target({ElementType.FIELD}) +@Target({ElementType.FIELD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Inherited public @interface HeadFontStyle { @@ -24,12 +24,12 @@ public @interface HeadFontStyle { /** * The name for the font (i.e. Arial) */ - String fontName(); + String fontName() default "宋体"; /** * Height in the familiar unit of measure - points */ - short fontHeightInPoints() default -1; + short fontHeightInPoints() default 14; /** * Whether to use italics or not @@ -85,5 +85,5 @@ public @interface HeadFontStyle { /** * Bold */ - boolean bold() default false; + boolean bold() default true; } diff --git a/src/main/java/com/alibaba/excel/annotation/write/style/HeadStyle.java b/src/main/java/com/alibaba/excel/annotation/write/style/HeadStyle.java index 10252a7b..d882da8f 100644 --- a/src/main/java/com/alibaba/excel/annotation/write/style/HeadStyle.java +++ b/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 */ -@Target({ElementType.FIELD}) +@Target({ElementType.FIELD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Inherited public @interface HeadStyle { @@ -36,7 +36,7 @@ public @interface HeadStyle { /** * 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 @@ -48,19 +48,19 @@ public @interface HeadStyle { /** * 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 true make all content visible within a * cell by displaying it on multiple lines * */ - boolean wrapped() default false; + boolean wrapped() default true; /** * 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. @@ -80,22 +80,22 @@ public @interface HeadStyle { /** * 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 */ - BorderStyle borderRight(); + BorderStyle borderRight() default BorderStyle.THIN; /** * 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 */ - BorderStyle borderBottom(); + BorderStyle borderBottom() default BorderStyle.THIN; /** * Set the color to use for the left border @@ -133,7 +133,7 @@ public @interface HeadStyle { * * @see FillPatternType#SOLID_FOREGROUND */ - FillPatternType fillPatternType(); + FillPatternType fillPatternType() default FillPatternType.SOLID_FOREGROUND; /** * Set the background fill color. diff --git a/src/main/java/com/alibaba/excel/converters/DefaultConverterLoader.java b/src/main/java/com/alibaba/excel/converters/DefaultConverterLoader.java index 77e8b592..01822559 100644 --- a/src/main/java/com/alibaba/excel/converters/DefaultConverterLoader.java +++ b/src/main/java/com/alibaba/excel/converters/DefaultConverterLoader.java @@ -48,56 +48,12 @@ public class DefaultConverterLoader { private static Map defaultWriteConverter; private static Map allConverter; - /** - * Load default write converter - * - * @return - */ - public static Map loadDefaultWriteConverter() { - if (defaultWriteConverter != null) { - return defaultWriteConverter; - } - defaultWriteConverter = new HashMap(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; + static { + initDefaultWriteConverter(); + initAllConverter(); } - private static void putWriteConverter(Converter converter) { - defaultWriteConverter.put(ConverterKeyBuild.buildKey(converter.supportJavaTypeKey()), converter); - } - - /** - * Load default read converter - * - * @return - */ - public static Map loadDefaultReadConverter() { - return loadAllConverter(); - } - - /** - * Load all converter - * - * @return - */ - public static Map loadAllConverter() { - if (allConverter != null) { - return allConverter; - } + private static void initAllConverter() { allConverter = new HashMap(64); putAllConverter(new BigDecimalBooleanConverter()); putAllConverter(new BigDecimalNumberConverter()); @@ -138,6 +94,55 @@ public class DefaultConverterLoader { putAllConverter(new StringNumberConverter()); putAllConverter(new StringStringConverter()); putAllConverter(new StringErrorConverter()); + } + + private static void initDefaultWriteConverter() { + defaultWriteConverter = new HashMap(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 loadDefaultWriteConverter() { + return defaultWriteConverter; + } + + private static void putWriteConverter(Converter converter) { + defaultWriteConverter.put(ConverterKeyBuild.buildKey(converter.supportJavaTypeKey()), converter); + } + + /** + * Load default read converter + * + * @return + */ + public static Map loadDefaultReadConverter() { + return loadAllConverter(); + } + + /** + * Load all converter + * + * @return + */ + public static Map loadAllConverter() { return allConverter; } diff --git a/src/main/java/com/alibaba/excel/metadata/Head.java b/src/main/java/com/alibaba/excel/metadata/Head.java index c1cea103..c578cbbc 100644 --- a/src/main/java/com/alibaba/excel/metadata/Head.java +++ b/src/main/java/com/alibaba/excel/metadata/Head.java @@ -4,6 +4,9 @@ import java.util.ArrayList; import java.util.List; 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 @@ -35,6 +38,26 @@ public class Head { * column with */ 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 headNameList, Boolean forceIndex, Boolean forceName) { @@ -95,4 +118,44 @@ public class Head { public void setForceName(Boolean 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; + } } diff --git a/src/main/java/com/alibaba/excel/metadata/property/ExcelHeadProperty.java b/src/main/java/com/alibaba/excel/metadata/property/ExcelHeadProperty.java index 782f635a..34109adc 100644 --- a/src/main/java/com/alibaba/excel/metadata/property/ExcelHeadProperty.java +++ b/src/main/java/com/alibaba/excel/metadata/property/ExcelHeadProperty.java @@ -1,7 +1,6 @@ package com.alibaba.excel.metadata.property; import java.lang.reflect.Field; -import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -12,8 +11,6 @@ import java.util.TreeMap; import org.slf4j.Logger; 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.format.DateTimeFormat; 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.enums.HeadKindEnum; import com.alibaba.excel.exception.ExcelCommonException; -import com.alibaba.excel.exception.ExcelGenerateException; import com.alibaba.excel.metadata.Head; import com.alibaba.excel.metadata.Holder; import com.alibaba.excel.util.ClassUtils; @@ -86,10 +82,10 @@ public class ExcelHeadProperty { headIndex++; } headKind = HeadKindEnum.STRING; - } else { - // convert headClazz to head - initColumnProperties(holder, convertAllFiled); } + // convert headClazz to head + initColumnProperties(holder, convertAllFiled); + initHeadRowNumber(); if (LOGGER.isDebugEnabled()) { LOGGER.debug("The initialization sheet/table 'ExcelHeadProperty' is complete , head kind is {}", headKind); @@ -163,10 +159,14 @@ public class ExcelHeadProperty { List tmpHeadList = new ArrayList(); boolean notForceName = excelProperty == null || excelProperty.value().length <= 0 || (excelProperty.value().length == 1 && StringUtils.isEmpty((excelProperty.value())[0])); - if (notForceName) { - tmpHeadList.add(field.getName()); + if (headMap.containsKey(index)) { + tmpHeadList.addAll(headMap.get(index).getHeadNameList()); } 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); ExcelContentProperty excelContentProperty = new ExcelContentProperty(); diff --git a/src/main/java/com/alibaba/excel/metadata/property/FontProperty.java b/src/main/java/com/alibaba/excel/metadata/property/FontProperty.java new file mode 100644 index 00000000..04caf9bb --- /dev/null +++ b/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; + } +} diff --git a/src/main/java/com/alibaba/excel/metadata/property/LoopMergeProperty.java b/src/main/java/com/alibaba/excel/metadata/property/LoopMergeProperty.java new file mode 100644 index 00000000..05084bf7 --- /dev/null +++ b/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; + } +} diff --git a/src/main/java/com/alibaba/excel/metadata/property/OnceAbsoluteMergeProperty.java b/src/main/java/com/alibaba/excel/metadata/property/OnceAbsoluteMergeProperty.java new file mode 100644 index 00000000..c5092192 --- /dev/null +++ b/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; + } +} diff --git a/src/main/java/com/alibaba/excel/metadata/property/StyleProperty.java b/src/main/java/com/alibaba/excel/metadata/property/StyleProperty.java new file mode 100644 index 00000000..9222b102 --- /dev/null +++ b/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 true 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 Note: Ensure Foreground color is set prior to background color. + * + * @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; + } +} diff --git a/src/main/java/com/alibaba/excel/util/WriteHandlerUtils.java b/src/main/java/com/alibaba/excel/util/WriteHandlerUtils.java index b303a31e..06dcc72b 100644 --- a/src/main/java/com/alibaba/excel/util/WriteHandlerUtils.java +++ b/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 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, Integer relativeRowIndex, Boolean isHead) { List cellDataList = new ArrayList(); diff --git a/src/main/java/com/alibaba/excel/write/executor/AbstractExcelWriteExecutor.java b/src/main/java/com/alibaba/excel/write/executor/AbstractExcelWriteExecutor.java index 1f09d47e..4eb115c5 100644 --- a/src/main/java/com/alibaba/excel/write/executor/AbstractExcelWriteExecutor.java +++ b/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.exception.ExcelDataConvertException; import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.Head; import com.alibaba.excel.metadata.property.ExcelContentProperty; +import com.alibaba.excel.util.WriteHandlerUtils; 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, - ExcelContentProperty excelContentProperty) { + ExcelContentProperty excelContentProperty, Head head, Integer relativeRowIndex) { if (value == null) { return new CellData(CellDataTypeEnum.EMPTY); } @@ -43,6 +45,7 @@ public abstract class AbstractExcelWriteExecutor implements ExcelWriteExecutor { if (cellData.getType() == null) { cellData.setType(CellDataTypeEnum.EMPTY); } + WriteHandlerUtils.afterCellDataConverted(writeContext, cellData, cell, head, relativeRowIndex, Boolean.FALSE); switch (cellData.getType()) { case STRING: cell.setCellValue(cellData.getStringValue()); diff --git a/src/main/java/com/alibaba/excel/write/executor/ExcelWriteAddExecutor.java b/src/main/java/com/alibaba/excel/write/executor/ExcelWriteAddExecutor.java index 5b0d8ae8..66878c5f 100644 --- a/src/main/java/com/alibaba/excel/write/executor/ExcelWriteAddExecutor.java +++ b/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); Object value = oneRowData.get(dataIndex); 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); } @@ -135,7 +135,7 @@ public class ExcelWriteAddExecutor extends AbstractExcelWriteExecutor { WriteHandlerUtils.afterCellCreate(writeContext, cell, head, relativeRowIndex, Boolean.FALSE); Object value = beanMap.get(name); CellData cellData = converterAndSet(currentWriteHolder, excelContentProperty.getField().getType(), cell, - value, excelContentProperty); + value, excelContentProperty, head, relativeRowIndex); WriteHandlerUtils.afterCellDispose(writeContext, cellData, cell, head, relativeRowIndex, Boolean.FALSE); beanMapHandledSet.add(name); } @@ -160,8 +160,8 @@ public class ExcelWriteAddExecutor extends AbstractExcelWriteExecutor { WriteHandlerUtils.beforeCellCreate(writeContext, row, null, cellIndex, relativeRowIndex, Boolean.FALSE); Cell cell = WorkBookUtil.createCell(row, cellIndex++); WriteHandlerUtils.afterCellCreate(writeContext, cell, null, relativeRowIndex, Boolean.FALSE); - CellData cellData = - converterAndSet(currentWriteHolder, value == null ? null : value.getClass(), cell, value, null); + CellData cellData = converterAndSet(currentWriteHolder, value == null ? null : value.getClass(), cell, + value, null, null, relativeRowIndex); WriteHandlerUtils.afterCellDispose(writeContext, cellData, cell, null, relativeRowIndex, Boolean.FALSE); } } diff --git a/src/main/java/com/alibaba/excel/write/executor/ExcelWriteFillExecutor.java b/src/main/java/com/alibaba/excel/write/executor/ExcelWriteFillExecutor.java index 495a1348..75aa6605 100644 --- a/src/main/java/com/alibaba/excel/write/executor/ExcelWriteFillExecutor.java +++ b/src/main/java/com/alibaba/excel/write/executor/ExcelWriteFillExecutor.java @@ -162,7 +162,7 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor { } Object value = dataMap.get(variable); 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); } else { StringBuilder cellValueBuild = new StringBuilder(); diff --git a/src/main/java/com/alibaba/excel/write/handler/AbstractCellWriteHandler.java b/src/main/java/com/alibaba/excel/write/handler/AbstractCellWriteHandler.java index 3f420466..b649af7a 100644 --- a/src/main/java/com/alibaba/excel/write/handler/AbstractCellWriteHandler.java +++ b/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 public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { diff --git a/src/main/java/com/alibaba/excel/write/handler/CellWriteHandler.java b/src/main/java/com/alibaba/excel/write/handler/CellWriteHandler.java index 4d981380..8701d6a0 100644 --- a/src/main/java/com/alibaba/excel/write/handler/CellWriteHandler.java +++ b/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, 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 * diff --git a/src/main/java/com/alibaba/excel/write/merge/LoopMergeStrategy.java b/src/main/java/com/alibaba/excel/write/merge/LoopMergeStrategy.java index 9c9ece17..5796dde5 100644 --- a/src/main/java/com/alibaba/excel/write/merge/LoopMergeStrategy.java +++ b/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.util.CellRangeAddress; +import com.alibaba.excel.metadata.property.LoopMergeProperty; import com.alibaba.excel.write.handler.AbstractRowWriteHandler; import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; import com.alibaba.excel.write.metadata.holder.WriteTableHolder; @@ -48,6 +49,10 @@ public class LoopMergeStrategy extends AbstractRowWriteHandler { this.columnIndex = columnIndex; } + public LoopMergeStrategy(LoopMergeProperty loopMergeProperty, Integer columnIndex) { + this(loopMergeProperty.getEachRow(), loopMergeProperty.getColumnExtend(), columnIndex); + } + @Override public void afterRowDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Integer relativeRowIndex, Boolean isHead) { diff --git a/src/main/java/com/alibaba/excel/write/merge/OnceAbsoluteMergeStrategy.java b/src/main/java/com/alibaba/excel/write/merge/OnceAbsoluteMergeStrategy.java index 71002ef7..d85781e1 100644 --- a/src/main/java/com/alibaba/excel/write/merge/OnceAbsoluteMergeStrategy.java +++ b/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 com.alibaba.excel.metadata.property.OnceAbsoluteMergeProperty; import com.alibaba.excel.write.handler.AbstractSheetWriteHandler; import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder; @@ -39,6 +40,11 @@ public class OnceAbsoluteMergeStrategy extends AbstractSheetWriteHandler { this.lastColumnIndex = lastColumnIndex; } + public OnceAbsoluteMergeStrategy(OnceAbsoluteMergeProperty onceAbsoluteMergeProperty) { + this(onceAbsoluteMergeProperty.getFirstRowIndex(), onceAbsoluteMergeProperty.getLastRowIndex(), + onceAbsoluteMergeProperty.getFirstColumnIndex(), onceAbsoluteMergeProperty.getLastColumnIndex()); + } + @Override public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) { CellRangeAddress cellRangeAddress = diff --git a/src/main/java/com/alibaba/excel/write/metadata/holder/AbstractWriteHolder.java b/src/main/java/com/alibaba/excel/write/metadata/holder/AbstractWriteHolder.java index 375602a5..00f2ef74 100644 --- a/src/main/java/com/alibaba/excel/write/metadata/holder/AbstractWriteHolder.java +++ b/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.Head; 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.util.CollectionUtils; 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.WorkbookWriteHandler; 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.WriteSheet; import com.alibaba.excel.write.metadata.WriteTable; import com.alibaba.excel.write.metadata.style.WriteCellStyle; import com.alibaba.excel.write.metadata.style.WriteFont; import com.alibaba.excel.write.property.ExcelWriteHeadProperty; +import com.alibaba.excel.write.style.AbstractVerticalCellStyleStrategy; import com.alibaba.excel.write.style.HorizontalCellStyleStrategy; import com.alibaba.excel.write.style.column.AbstractHeadColumnWidthStyleStrategy; import com.alibaba.excel.write.style.row.SimpleRowHeightStyleStrategy; @@ -279,19 +284,63 @@ public abstract class AbstractWriteHolder extends AbstractHolder implements Writ return; } Map headMap = getExcelWriteHeadProperty().getHeadMap(); - boolean hasColumnWidth = false; - for (Map.Entry entry : headMap.entrySet()) { - if (entry.getValue().getColumnWidthProperty() != null) { + boolean hasStyle = false; + + for (Head head : headMap.values()) { + if (head.getColumnWidthProperty() != null) { hasColumnWidth = true; - break; } + if (head.getHeadStyleProperty() != null || head.getHeadFontProperty() != null + || head.getContentStyleProperty() != null || head.getContentFontProperty() != null) { + hasStyle = true; + } + dealLoopMerge(handlerList, head); } if (hasColumnWidth) { dealColumnWidth(handlerList); } + + if (hasStyle) { + dealStyle(handlerList); + } + dealRowHigh(handlerList); + dealOnceAbsoluteMerge(handlerList); + + } + + private void dealStyle(List 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 handlerList, Head head) { + LoopMergeProperty loopMergeProperty = head.getLoopMergeProperty(); + if (loopMergeProperty == null) { + return; + } + handlerList.add(new LoopMergeStrategy(loopMergeProperty, head.getColumnIndex())); + } + + private void dealOnceAbsoluteMerge(List handlerList) { + OnceAbsoluteMergeProperty onceAbsoluteMergeProperty = + getExcelWriteHeadProperty().getOnceAbsoluteMergeProperty(); + if (onceAbsoluteMergeProperty == null) { + return; + } + handlerList.add(new OnceAbsoluteMergeStrategy(onceAbsoluteMergeProperty)); } private void dealRowHigh(List handlerList) { diff --git a/src/main/java/com/alibaba/excel/write/metadata/style/WriteCellStyle.java b/src/main/java/com/alibaba/excel/write/metadata/style/WriteCellStyle.java index 01786cef..81c85e83 100644 --- a/src/main/java/com/alibaba/excel/write/metadata/style/WriteCellStyle.java +++ b/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.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 * @@ -137,6 +141,79 @@ public class WriteCellStyle { */ 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() { return dataFormat; } diff --git a/src/main/java/com/alibaba/excel/write/property/ExcelWriteHeadProperty.java b/src/main/java/com/alibaba/excel/write/property/ExcelWriteHeadProperty.java index b1ba891e..8fe03497 100644 --- a/src/main/java/com/alibaba/excel/write/property/ExcelWriteHeadProperty.java +++ b/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.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.ContentStyle; +import com.alibaba.excel.annotation.write.style.HeadFontStyle; 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.DefaultConverterLoader; 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.ExcelContentProperty; 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.StyleProperty; /** * Define the header attribute of excel @@ -31,6 +41,7 @@ import com.alibaba.excel.metadata.property.RowHeightProperty; public class ExcelWriteHeadProperty extends ExcelHeadProperty { private RowHeightProperty headRowHeightProperty; private RowHeightProperty contentRowHeightProperty; + private OnceAbsoluteMergeProperty onceAbsoluteMergeProperty; public ExcelWriteHeadProperty(Holder holder, Class headClazz, List> head, Boolean convertAllFiled) { super(holder, headClazz, head, convertAllFiled); @@ -41,8 +52,15 @@ public class ExcelWriteHeadProperty extends ExcelHeadProperty { RowHeightProperty.build((HeadRowHeight)headClazz.getAnnotation(HeadRowHeight.class)); this.contentRowHeightProperty = RowHeightProperty.build((ContentRowHeight)headClazz.getAnnotation(ContentRowHeight.class)); + this.onceAbsoluteMergeProperty = + OnceAbsoluteMergeProperty.build((OnceAbsoluteMerge)headClazz.getAnnotation(OnceAbsoluteMerge.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 entry : getContentPropertyMap().entrySet()) { Integer index = entry.getKey(); ExcelContentProperty excelContentPropertyData = entry.getValue(); @@ -54,6 +72,31 @@ public class ExcelWriteHeadProperty extends ExcelHeadProperty { } 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 (excelContentPropertyData.getConverter() == null) { NumberFormat numberFormat = field.getAnnotation(NumberFormat.class); @@ -81,6 +124,14 @@ public class ExcelWriteHeadProperty extends ExcelHeadProperty { this.contentRowHeightProperty = contentRowHeightProperty; } + public OnceAbsoluteMergeProperty getOnceAbsoluteMergeProperty() { + return onceAbsoluteMergeProperty; + } + + public void setOnceAbsoluteMergeProperty(OnceAbsoluteMergeProperty onceAbsoluteMergeProperty) { + this.onceAbsoluteMergeProperty = onceAbsoluteMergeProperty; + } + /** * Calculate all cells that need to be merged * diff --git a/src/main/java/com/alibaba/excel/write/style/AbstractCellStyleStrategy.java b/src/main/java/com/alibaba/excel/write/style/AbstractCellStyleStrategy.java index 7aafc448..4790ab11 100644 --- a/src/main/java/com/alibaba/excel/write/style/AbstractCellStyleStrategy.java +++ b/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 public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { diff --git a/src/main/java/com/alibaba/excel/write/style/column/AbstractColumnWidthStyleStrategy.java b/src/main/java/com/alibaba/excel/write/style/column/AbstractColumnWidthStyleStrategy.java index 07afcfc5..005f624e 100644 --- a/src/main/java/com/alibaba/excel/write/style/column/AbstractColumnWidthStyleStrategy.java +++ b/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 org.apache.poi.ss.usermodel.Cell; -import org.apache.poi.ss.usermodel.Row; 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.AbstractCellWriteHandler; import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; import com.alibaba.excel.write.metadata.holder.WriteTableHolder; @@ -17,7 +16,7 @@ import com.alibaba.excel.write.metadata.holder.WriteTableHolder; * * @author Jiaju Zhuang */ -public abstract class AbstractColumnWidthStyleStrategy implements CellWriteHandler, NotRepeatExecutor { +public abstract class AbstractColumnWidthStyleStrategy extends AbstractCellWriteHandler implements NotRepeatExecutor { @Override public String uniqueValue() { @@ -25,15 +24,8 @@ public abstract class AbstractColumnWidthStyleStrategy implements CellWriteHandl } @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 - public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { + public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, + List cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { setColumnWidth(writeSheetHolder, cellDataList, cell, head, relativeRowIndex, isHead); } @@ -47,7 +39,7 @@ public abstract class AbstractColumnWidthStyleStrategy implements CellWriteHandl * @param relativeRowIndex * @param isHead */ - protected abstract void setColumnWidth(WriteSheetHolder writeSheetHolder, List cellDataList, Cell cell, Head head, - Integer relativeRowIndex, Boolean isHead); + protected abstract void setColumnWidth(WriteSheetHolder writeSheetHolder, List cellDataList, Cell cell, + Head head, Integer relativeRowIndex, Boolean isHead); } diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/read/DemoCellCommentsListener.java b/src/test/java/com/alibaba/easyexcel/test/demo/read/DemoCellCommentsListener.java deleted file mode 100644 index e7d8def1..00000000 --- a/src/test/java/com/alibaba/easyexcel/test/demo/read/DemoCellCommentsListener.java +++ /dev/null @@ -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 { - private static final Logger LOGGER = LoggerFactory.getLogger(DemoCellCommentsListener.class); - /** - * 每隔5条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收 - */ - private static final int BATCH_COUNT = 5; - List list = new ArrayList(); - - /** - * 在转换异常 获取其他异常下会调用本接口。抛出异常则停止读取。如果这里不抛出异常则 继续读取下一行。 - * - * @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 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("存储数据库成功!"); - } -} diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/read/DemoExtraData.java b/src/test/java/com/alibaba/easyexcel/test/demo/read/DemoExtraData.java new file mode 100644 index 00000000..e780bfa7 --- /dev/null +++ b/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; +} diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/read/DemoExtraListener.java b/src/test/java/com/alibaba/easyexcel/test/demo/read/DemoExtraListener.java new file mode 100644 index 00000000..01adfe72 --- /dev/null +++ b/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 { + 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: + } + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/read/ReadTest.java b/src/test/java/com/alibaba/easyexcel/test/demo/read/ReadTest.java index cd45f2ea..5234f052 100644 --- a/src/test/java/com/alibaba/easyexcel/test/demo/read/ReadTest.java +++ b/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.NumberFormat; import com.alibaba.excel.converters.DefaultConverterLoader; +import com.alibaba.excel.enums.CellExtraTypeEnum; import com.alibaba.excel.read.metadata.ReadSheet; import com.alibaba.fastjson.JSON; @@ -162,20 +163,28 @@ public class ReadTest { } /** - * 读取单元格批注 + * 额外信息(批注、超链接、合并单元格信息读取) + *

+ * 由于是流式读取,没法在读取到单元格数据的时候直接读取到额外信息,所以只能最后通知哪些单元格有哪些额外信息 * *

- * 1. 创建excel对应的实体对象 参照{@link DemoData} + * 1. 创建excel对应的实体对象 参照{@link DemoExtraData} *

- * 2. 由于默认异步读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoHeadDataListener} + * 2. 由于默认异步读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoExtraListener} *

* 3. 直接读即可 */ @Test - public void commentsRead() { - String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx"; + public void extraRead() { + String fileName = TestFileUtil.getPath() + "demo" + File.separator + "extra.xlsx"; // 这里 需要指定读用哪个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 public void noModleRead() { diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/write/CustomCellWriteHandler.java b/src/test/java/com/alibaba/easyexcel/test/demo/write/CustomCellWriteHandler.java index b92d44a2..b1bcb7dc 100644 --- a/src/test/java/com/alibaba/easyexcel/test/demo/write/CustomCellWriteHandler.java +++ b/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.CreationHelper; import org.apache.poi.ss.usermodel.Hyperlink; -import org.apache.poi.ss.usermodel.Row; import org.slf4j.Logger; import org.slf4j.LoggerFactory; 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.AbstractCellWriteHandler; import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; import com.alibaba.excel.write.metadata.holder.WriteTableHolder; @@ -21,22 +20,10 @@ import com.alibaba.excel.write.metadata.holder.WriteTableHolder; * * @author Jiaju Zhuang */ -public class CustomCellWriteHandler implements CellWriteHandler { +public class CustomCellWriteHandler extends AbstractCellWriteHandler { 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 public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/write/DemoMergeData.java b/src/test/java/com/alibaba/easyexcel/test/demo/write/DemoMergeData.java new file mode 100644 index 00000000..ad94321e --- /dev/null +++ b/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; +} diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/write/DemoStyleData.java b/src/test/java/com/alibaba/easyexcel/test/demo/write/DemoStyleData.java new file mode 100644 index 00000000..c73a088b --- /dev/null +++ b/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; +} diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java b/src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java index 7b7d6b35..8b5fe53c 100644 --- a/src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java +++ b/src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java @@ -270,7 +270,21 @@ public class WriteTest { } /** - * 自定义样式 + * 注解形式自定义样式 + *

+ * 1. 创建excel对应的实体对象 参照{@link DemoStyleData} + *

+ * 3. 直接写即可 + */ + @Test + public void annotationStyleWrite() { + String fileName = TestFileUtil.getPath() + "annotationStyleWrite" + System.currentTimeMillis() + ".xlsx"; + // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 + EasyExcel.write(fileName, DemoStyleData.class).sheet("模板").doWrite(data()); + } + + /** + * 拦截器形式自定义样式 *

* 1. 创建excel对应的实体对象 参照{@link DemoData} *

@@ -279,8 +293,8 @@ public class WriteTest { * 3. 直接写即可 */ @Test - public void styleWrite() { - String fileName = TestFileUtil.getPath() + "styleWrite" + System.currentTimeMillis() + ".xlsx"; + public void handlerStyleWrite() { + String fileName = TestFileUtil.getPath() + "handlerStyleWrite" + System.currentTimeMillis() + ".xlsx"; // 头的策略 WriteCellStyle headWriteCellStyle = new WriteCellStyle(); // 背景设置为红色 @@ -310,7 +324,7 @@ public class WriteTest { /** * 合并单元格 *

- * 1. 创建excel对应的实体对象 参照{@link DemoData} + * 1. 创建excel对应的实体对象 参照{@link DemoData} {@link DemoMergeData} *

* 2. 创建一个merge策略 并注册 *

@@ -318,7 +332,14 @@ public class WriteTest { */ @Test public void mergeWrite() { + // 方法1 注解 String fileName = TestFileUtil.getPath() + "mergeWrite" + System.currentTimeMillis() + ".xlsx"; + // 在DemoStyleData里面加上ContentLoopMerge注解 + // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 + EasyExcel.write(fileName, DemoMergeData.class).sheet("模板").doWrite(data()); + + // 方法2 自定义合并单元格策略 + fileName = TestFileUtil.getPath() + "mergeWrite" + System.currentTimeMillis() + ".xlsx"; // 每隔2行会合并 把eachColumn 设置成 3 也就是我们数据的长度,所以就第一列会合并。当然其他合并策略也可以自己写 LoopMergeStrategy loopMergeStrategy = new LoopMergeStrategy(2, 0); // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 @@ -414,6 +435,23 @@ public class WriteTest { .registerWriteHandler(new CustomCellWriteHandler()).sheet("模板").doWrite(data()); } + /** + * 可变标题处理(包括标题国际化等) + *

+ * 简单的说用List>的标题 但是还支持注解 + *

+ * 1. 创建excel对应的实体对象 参照{@link ConverterData} + *

+ * 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; } + private List> variableTitleHead() { + List> list = new ArrayList>(); + List head0 = new ArrayList(); + head0.add("string" + System.currentTimeMillis()); + List head1 = new ArrayList(); + head1.add("number" + System.currentTimeMillis()); + List head2 = new ArrayList(); + head2.add("date" + System.currentTimeMillis()); + list.add(head0); + list.add(head1); + list.add(head2); + return list; + } + private List> head() { List> list = new ArrayList>(); List head0 = new ArrayList(); diff --git a/src/test/resources/demo/extra.xlsx b/src/test/resources/demo/extra.xlsx new file mode 100644 index 00000000..4936b05a Binary files /dev/null and b/src/test/resources/demo/extra.xlsx differ diff --git a/update.md b/update.md index 2078a595..cdff2093 100644 --- a/update.md +++ b/update.md @@ -11,7 +11,9 @@ * 新增合并单元格注解 * 提升合并策略效率 * 兼容部分比较特殊的excel - +* 同时传入了`List>`和`class`的head,会通过index去匹配注解 +* 修复读取转换器的并发问题 +* # 2.1.4 * 新增参数`useDefaultListener` 可以排除默认对象转换