Skip to content
Open
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.apache.fesod.excel.temp.fill;

import java.util.Map;
import lombok.Data;
import org.apache.fesod.excel.annotation.fill.DynamicColumn;

@Data
public class DynamicFillData {
private String name;
private double number;

@DynamicColumn()
private Map<String, String> qtyMap;

@DynamicColumn()
private Map<String, DynamicFillDataObj> priceMap;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.apache.fesod.excel.temp.fill;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;

@AllArgsConstructor
@Getter
@Setter
public class DynamicFillDataObj {

private String qty;
private double price;
}
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,83 @@ public void simpleFill() {
*/
}

@Test
public void dynamicFill() {
String templateFileName = "src/test/resources/fill/dynamicColumn.xlsx";
String fileName = TestFileUtil.getPath() + "dynamicColumnFill" + System.currentTimeMillis() + ".xlsx";

DynamicFillData fillData1 = new DynamicFillData();
fillData1.setName("Zhang San");
fillData1.setNumber(5.2);
HashMap<String, String> qtyMap = new HashMap<>();
qtyMap.put("2023-01-01", "100");
qtyMap.put("2023-01-02", "200");
qtyMap.put("2023-01-03", "300");
fillData1.setQtyMap(qtyMap);
HashMap<String, DynamicFillDataObj> priceMap = new HashMap<>();
priceMap.put("2023-01-01", new DynamicFillDataObj("100个", 100));
priceMap.put("2023-01-02", new DynamicFillDataObj("200个", 200));
priceMap.put("2023-01-03", new DynamicFillDataObj("300个", 300));
fillData1.setPriceMap(priceMap);

DynamicFillData fillData2 = new DynamicFillData();
fillData2.setName("Li Si");
fillData2.setNumber(6.3);
HashMap<String, String> qtyMap2 = new HashMap<>();
qtyMap2.put("2023-01-01", "100");
qtyMap2.put("2023-01-02", "200");
qtyMap2.put("2023-01-03", "300");
fillData2.setQtyMap(qtyMap2);
HashMap<String, DynamicFillDataObj> priceMap2 = new HashMap<>();
priceMap2.put("2023-01-01", new DynamicFillDataObj("100", 100));
priceMap2.put("2023-01-02", new DynamicFillDataObj("200", 200));
priceMap2.put("2023-01-03", new DynamicFillDataObj("300", 300));
fillData2.setPriceMap(priceMap2);

List<DynamicFillData> fillDataList = new ArrayList<>();
fillDataList.add(fillData1);
fillDataList.add(fillData2);

ArrayList dateList = new ArrayList<>();
dateList.add("2023-01-01");
dateList.add("2023-01-02");
dateList.add("2023-01-03");
dateList.add("2023-01-04");
dateList.add("2023-01-05");
dateList.add("2023-01-06");
dateList.add("2023-01-07");
dateList.add("2023-01-08");
dateList.add("2023-01-09");
dateList.add("2023-01-10");
dateList.add("2023-01-11");
dateList.add("2023-01-12");

ExcelWriter excelWriter =
FastExcel.write(fileName).withTemplate(templateFileName).build();
WriteSheet writeSheet = FastExcel.writerSheet().build();
excelWriter.fill(
new FillWrapper("dataList", fillDataList),
FillConfig.builder()
.forceNewRow(true)
.addDynamicInfo(dateList, 1, "qtyMap")
.addDefaultDynamicInfo(dateList, 1)
.build(),
writeSheet);
excelWriter.fill(
new FillWrapper("dataObjList", fillDataList),
FillConfig.builder()
.addDefaultDynamicInfo(dateList, 2)
.forceNewRow(true)
.build(),
writeSheet);
excelWriter.fill(
new FillWrapper("dateList", dateList),
FillConfig.builder().direction(WriteDirectionEnum.HORIZONTAL).build(),
writeSheet);
// Do not forget to close the stream
excelWriter.finish();
}

/**
* Example of filling a list of data.
*
Expand Down Expand Up @@ -205,7 +282,7 @@ public void horizontalFill() {
excelWriter.fill(data(), fillConfig, writeSheet);
excelWriter.fill(data(), fillConfig, writeSheet);

Map<String, Object> map = new HashMap<String, Object>();
Map<String, Object> map = new HashMap();
Copy link

Copilot AI Sep 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Raw type usage. Should use new HashMap<>() or new HashMap<String, Object>() for type safety.

Suggested change
Map<String, Object> map = new HashMap();
Map<String, Object> map = new HashMap<String, Object>();

Copilot uses AI. Check for mistakes.
map.put("date", "2019-10-09 13:28:28");
excelWriter.fill(map, writeSheet);

Expand Down
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.apache.fesod.excel.annotation.fill;

import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface DynamicColumn {}
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,19 @@

package org.apache.fesod.excel.write.executor;

import cn.idev.excel.support.cglib.beans.BeanMap;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.fesod.excel.annotation.fill.DynamicColumn;
import org.apache.fesod.excel.context.WriteContext;
import org.apache.fesod.excel.converters.Converter;
import org.apache.fesod.excel.converters.ConverterKeyBuild;
import org.apache.fesod.excel.converters.NullableObjectConverter;
import org.apache.fesod.excel.converters.WriteConverterContext;
import org.apache.fesod.excel.enums.CellDataTypeEnum;
import org.apache.fesod.excel.enums.WriteDirectionEnum;
import org.apache.fesod.excel.exception.ExcelWriteDataConvertException;
import org.apache.fesod.excel.metadata.data.CommentData;
import org.apache.fesod.excel.metadata.data.FormulaData;
Expand All @@ -35,13 +40,17 @@
import org.apache.fesod.excel.metadata.data.WriteCellData;
import org.apache.fesod.excel.metadata.property.ExcelContentProperty;
import org.apache.fesod.excel.support.ExcelTypeEnum;
import org.apache.fesod.excel.util.BeanMapUtils;
import org.apache.fesod.excel.util.DateUtils;
import org.apache.fesod.excel.util.FieldUtils;
import org.apache.fesod.excel.util.FileTypeUtils;
import org.apache.fesod.excel.util.ListUtils;
import org.apache.fesod.excel.util.StyleUtil;
import org.apache.fesod.excel.util.WorkBookUtil;
import org.apache.fesod.excel.util.WriteHandlerUtils;
import org.apache.fesod.excel.write.handler.context.CellWriteHandlerContext;
import org.apache.fesod.excel.write.metadata.fill.DynamicColumnInfo;
import org.apache.fesod.excel.write.metadata.fill.FillConfig;
import org.apache.poi.hssf.usermodel.HSSFClientAnchor;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.ClientAnchor;
Expand All @@ -66,12 +75,11 @@ public AbstractExcelWriteExecutor(WriteContext writeContext) {
}

/**
* Transform the data and then to set into the cell
* Transform item
*
* @param cellWriteHandlerContext context
*/
protected void converterAndSet(CellWriteHandlerContext cellWriteHandlerContext) {

* */
protected void convertAndSetItem(CellWriteHandlerContext cellWriteHandlerContext) {
WriteCellData<?> cellData = convert(cellWriteHandlerContext);
cellWriteHandlerContext.setCellDataList(ListUtils.newArrayList(cellData));
cellWriteHandlerContext.setFirstCellData(cellData);
Expand All @@ -98,6 +106,10 @@ protected void converterAndSet(CellWriteHandlerContext cellWriteHandlerContext)
cellData.setType(CellDataTypeEnum.EMPTY);
}
Cell cell = cellWriteHandlerContext.getCell();
setCellValue(cellWriteHandlerContext, cellData, cell);
}

private void setCellValue(CellWriteHandlerContext cellWriteHandlerContext, WriteCellData<?> cellData, Cell cell) {
switch (cellData.getType()) {
case STRING:
cell.setCellValue(cellData.getStringValue());
Expand Down Expand Up @@ -126,6 +138,70 @@ protected void converterAndSet(CellWriteHandlerContext cellWriteHandlerContext)
}
}

/**
* Transform the data and then to set into the cell
*
* @param cellWriteHandlerContext context
*/
protected void converterAndSet(CellWriteHandlerContext cellWriteHandlerContext) {
Object originalValue = cellWriteHandlerContext.getOriginalValue();
Field field = cellWriteHandlerContext.getExcelContentProperty().getField();
if (null != field && field.isAnnotationPresent(DynamicColumn.class)) {
Map<String, Object> dynamicColumnMap = (Map<String, Object>) originalValue;
FillConfig fillConfig = cellWriteHandlerContext.getFillConfig();
if (null == fillConfig || null == fillConfig.getDynamicColumnInfoMap()) {
throw new ExcelWriteDataConvertException(
cellWriteHandlerContext,
"DynamicColumn annotation must be used with FillConfig.dynamicColumnInfoMap");
}
DynamicColumnInfo dynamicColumnInfo = fillConfig.getDynamicColumnInfo(field.getName());
Integer columnIndex = cellWriteHandlerContext.getColumnIndex();
Integer rowIndex = cellWriteHandlerContext.getRowIndex();
for (int i = 0; i < dynamicColumnInfo.getKeys().size(); i++) {
String key = dynamicColumnInfo.getKeys().get(i);
Object o = dynamicColumnMap.get(key);
String originalVariable = cellWriteHandlerContext.getOriginalVariable();
if (originalVariable.contains(".")) {
int dotIndex = originalVariable.indexOf('.');
if (dotIndex > 0) {
key = originalVariable.substring(dotIndex + 1);
Object itemBean = o;
if (null == itemBean) {
o = null;
} else {
BeanMap beanMap = BeanMapUtils.create(itemBean);
o = beanMap.get(key);
}
}
}

Integer dynamicColumnGroupSize = dynamicColumnInfo.getGroupSize();
WriteDirectionEnum direction = fillConfig.getDirection();
int currentRowIndex = rowIndex;
int currentColumnIndex = columnIndex;
if (WriteDirectionEnum.VERTICAL.equals(direction)) {
currentColumnIndex = columnIndex + dynamicColumnGroupSize * i;
} else {
currentRowIndex = rowIndex + dynamicColumnGroupSize * i;
}

Map<String, CellWriteHandlerContext> cellMap = cellWriteHandlerContext.getCellMap();
CellWriteHandlerContext currentCellWriteHandlerContext =
cellMap.get(currentRowIndex + "_" + currentColumnIndex);
currentCellWriteHandlerContext.setOriginalValue(o);
currentCellWriteHandlerContext.setOriginalFieldClass(FieldUtils.getFieldClass(o));
convertAndSetItem(currentCellWriteHandlerContext);
if (i == 0) {
cellWriteHandlerContext.setOriginalValue(o);
cellWriteHandlerContext.setOriginalFieldClass(FieldUtils.getFieldClass(o));
convertAndSetItem(cellWriteHandlerContext);
}
}
} else {
convertAndSetItem(cellWriteHandlerContext);
}
}

private void fillFormula(CellWriteHandlerContext cellWriteHandlerContext, FormulaData formulaData) {
if (formulaData == null) {
return;
Expand Down
Loading