• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

hee9841 / excel-module / #35

25 Apr 2025 09:05AM UTC coverage: 82.791%. First build
#35

Pull #58

github

hee9841
Revert "Chore: 배포를 위한 PR template 추가 (#54)"

This reverts commit bd34b2c5e.
Pull Request #58: Release 0.0.1

105 of 168 new or added lines in 16 files covered. (62.5%)

534 of 645 relevant lines covered (82.79%)

0.83 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.62
/src/main/java/io/github/hee9841/excel/core/ExcelExporter.java
1
package io.github.hee9841.excel.core;
2

3
import io.github.hee9841.excel.exception.ExcelException;
4
import io.github.hee9841.excel.strategy.SheetStrategy;
5
import java.text.MessageFormat;
6
import java.util.List;
7

8
/**
9
 * ExcelExporter is a concrete implementation of {@link SXSSFExcelFile} that provides functionality
10
 * for exporting data to Excel files. This class uses the SXSSFWorkbook from Apache POI for
11
 * efficient
12
 * handling of large datasets by streaming data to disk.
13
 *
14
 * <p>The ExcelExporter supports two sheet management strategies:</p>
15
 * <ul>
16
 *     <li>ONE_SHEET - All data is exported to a single sheet (limited by max rows per sheet)</li>
17
 *     <li>MULTI_SHEET - Data is split across multiple sheets when exceeding max rows per sheet</li>
18
 * </ul>
19
 *
20
 * <p>Use the {@link ExcelExporterBuilder} to configure and instantiate this class.</p>
21
 *
22
 * @param <T> The type of data to be exported to Excel. The type must be annotated appropriately
23
 *            for Excel column mapping using the library's annotation system.
24
 * @see SXSSFExcelFile
25
 * @see ExcelExporterBuilder
26
 * @see SheetStrategy
27
 */
28
public class ExcelExporter<T> extends SXSSFExcelFile<T> {
29

30
    private static final String EXCEED_MAX_ROW_MSG_2ARGS =
31
        "The data size exceeds the maximum number of rows allowed per sheet. "
32
            + "The sheet strategy is set to ONE_SHEET but the data size is larger than "
33
            + "the maximum rows per sheet (data size: {0}, maximum rows: {1} ).\n"
34
            + "Please change the sheet strategy to MULTI_SHEET or reduce the data size.";
35

36
    private static final int ROW_START_INDEX = 0;
37
    private int currentRowIndex = ROW_START_INDEX;
1✔
38

39
    private final String sheetName;
40
    private final int maxRowsPerSheet;
41

42
    private SheetStrategy sheetStrategy;
43
    private int currentSheetIndex;
44

45

46
    /**
47
     * Constructs an ExcelExporter with the specified configuration.
48
     *
49
     * <p>This constructor is not meant to be called directly. Use {@link ExcelExporterBuilder}
50
     * to create instances of ExcelExporter.</p>
51
     *
52
     * @param type            The class type of the data to be exported
53
     * @param data            The list of data objects to be exported
54
     * @param sheetStrategy   The strategy for sheet management (ONE_SHEET or MULTI_SHEET)
55
     * @param sheetName       Base name for sheets (null for default names)
56
     * @param maxRowsPerSheet Maximum number of rows allowed per sheet
57
     */
58
    ExcelExporter(
59
        Class<T> type,
60
        List<T> data,
61
        SheetStrategy sheetStrategy,
62
        String sheetName,
63
        int maxRowsPerSheet
64
    ) {
65
        super();
1✔
66
        this.maxRowsPerSheet = maxRowsPerSheet;
1✔
67
        this.sheetName = sheetName;
1✔
68
        this.currentSheetIndex = 0;
1✔
69
        setSheetStrategy(sheetStrategy);
1✔
70

71
        this.initialize(type, data);
1✔
72
        this.createExcelFile(data);
1✔
73
    }
1✔
74

75

76
    /**
77
     * Creates a new builder for configuring and instantiating an ExcelExporter.
78
     *
79
     * @param <T>  The type of data to be exported
80
     * @param type The class of the data type
81
     * @param data The list of data objects to be exported
82
     * @return A new ExcelExporterBuilder instance
83
     */
84
    public static <T> ExcelExporterBuilder<T> builder(Class<T> type, List<T> data) {
85
        return new ExcelExporterBuilder<>(type, data, supplyExcelVersion.getMaxRows());
1✔
86
    }
87

88

89
    /**
90
     * Validates the data size against the maximum rows per sheet limit.
91
     *
92
     * <p>This method checks if the data size exceeds the maximum allowed rows per sheet
93
     * when using ONE_SHEET strategy. If the limit is exceeded, an ExcelException is thrown.</p>
94
     *
95
     * @param type The class type of the data being validated
96
     * @param data The list of data objects to be validated
97
     * @throws ExcelException if data size exceeds max rows limit with ONE_SHEET strategy
98
     */
99
    @Override
100
    protected void validate(Class<?> type, List<T> data) {
101
        if (SheetStrategy.isOneSheet(sheetStrategy) && data.size() > maxRowsPerSheet - 1) {
1✔
102
            throw new ExcelException(
1✔
103
                MessageFormat.format(EXCEED_MAX_ROW_MSG_2ARGS,
1✔
104
                    data.size(), maxRowsPerSheet
1✔
105
                ), dtoTypeName);
106
        }
107
    }
1✔
108

109
    /**
110
     * Creates the Excel file with the provided data.
111
     *
112
     * <p>This method handles the creation of sheets and rows based on the data:</p>
113
     * <ul>
114
     *   <li>If the data is empty, it creates a sheet with headers only</li>
115
     *   <li>Otherwise, it creates a sheet with headers and adds all data rows</li>
116
     * </ul>
117
     *
118
     * @param data The list of data objects to be exported
119
     */
120
    @Override
121
    protected void createExcelFile(List<T> data) {
122
        // 1. If data is empty, create createHeader only.
123
        if (data.isEmpty()) {
1✔
124
            createNewSheetWithHeader();
1✔
125
            logger.warn("Empty data provided - Excel file will be created with headers only.");
1✔
126
            return;
1✔
127
        }
128

129
        //2. Add rows
130
        createNewSheetWithHeader();
1✔
131
        addRows(data);
1✔
132
    }
1✔
133

134
    /**
135
     * Adds rows to the current sheet for the provided data list.
136
     *
137
     * <p>If the number of rows exceeds the maximum allowed per sheet and the sheet strategy
138
     * is MULTI_SHEET, a new sheet will be created to continue adding rows.</p>
139
     *
140
     * <p>If the sheet strategy is ONE_SHEET and the data size exceeds the maximum rows per sheet,
141
     * an ExcelException will be thrown.</p>
142
     *
143
     * @param data The list of data objects to be added as rows
144
     * @throws ExcelException if ONE_SHEET strategy is used and data exceeds max rows limit
145
     */
146
    @Override
147
    public void addRows(List<T> data) {
148
        int leftDataSize = data.size();
1✔
149
        for (Object renderedData : data) {
1✔
150
            createBody(renderedData, currentRowIndex++);
1✔
151
            leftDataSize--;
1✔
152
            if (currentRowIndex == maxRowsPerSheet && leftDataSize > 0) {
1✔
153
                //If one sheet strategy, throw exception
154
                if (SheetStrategy.isOneSheet(sheetStrategy)) {
1✔
155
                    throw new ExcelException(
×
156
                        MessageFormat.format(EXCEED_MAX_ROW_MSG_2ARGS,
×
NEW
157
                            data.size(), maxRowsPerSheet), dtoTypeName);
×
158
                }
159

160
                //If multi sheet strategy, create new sheet
161
                createNewSheetWithHeader();
1✔
162
            }
163
        }
1✔
164
    }
1✔
165

166
    /**
167
     * Sets the sheet strategy for this exporter.
168
     *
169
     * <p>This method also configures the workbook's Zip64 mode based on the selected strategy.</p>
170
     *
171
     * @param strategy The sheet strategy to use (ONE_SHEET or MULTI_SHEET)-
172
     */
173
    private void setSheetStrategy(SheetStrategy strategy) {
174

175
        this.sheetStrategy = strategy;
1✔
176
        workbook.setZip64Mode(sheetStrategy.getZip64Mode());
1✔
177

178
        logger.debug("Set sheet strategy and Zip64Mode - strategy: {}, Zip64Mode: {}.",
1✔
179
            strategy.name(), sheetStrategy.getZip64Mode().name());
1✔
180
    }
1✔
181

182
    /**
183
     * Creates a new sheet with headers.
184
     *
185
     * <p>This method resets the current row index, creates a new sheet, and adds headers to it.
186
     * If a sheet name is provided, it will be used as a base name with an index(index starts from
187
     * 0) suffix.</p>
188
     */
189
    private void createNewSheetWithHeader() {
190
        currentRowIndex = ROW_START_INDEX;
1✔
191

192
        //If sheet name is provided, create sheet with sheet name + idx
193
        if (sheetName != null) {
1✔
194
            sheet = workbook.createSheet(String.format("%s%d", sheetName, currentSheetIndex++));
1✔
195
        } else {
196
            sheet = workbook.createSheet();
1✔
197
        }
198

199
        logger.debug("Create new Sheet : {}.", sheet.getSheetName());
1✔
200

201
        createHeaderWithNewSheet(sheet, ROW_START_INDEX);
1✔
202
        currentRowIndex++;
1✔
203
    }
1✔
204
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc