Java中如何将服务类中的Excel操作共享方法迁移至工具类?
Problem Description
I have a service implementation class that handles Excel export functionality:
public class DataServiceImpl implements DataService { private static final String SHEET_TITLE = "export.permission.sheetTitle"; private XSSFWorkbook workbook; private XSSFSheet sheet; private AtomicInteger rowCount; @Override public MultipartFile export() throws IOException { createSheet(SHEET_TITLE); // Omitted code for brevity } private void createSheet(String title) { workbook = new XSSFWorkbook(); sheet = workbook.createSheet(title); rowCount = new AtomicInteger(0); } }
I want to migrate methods like createSheet to a utility class since other similar classes need to use them. However, variables like workbook, sheet, and rowCount are used by other methods in this service class, so I'm unsure whether to pass these variables to the utility method and return them, or use another approach.
Additionally, I have these methods and need advice on whether to migrate them too:
private MultipartFile createMultipartFile(String title, String extension) throws IOException { File outputFile = File.createTempFile(TextBundleUtil.read(title), extension); workbook.write(outputStream); final FileInputStream input = new FileInputStream(outputFile); final String fileName = TextBundleUtil.read(title).concat(extension); return new MockMultipartFile(fileName, fileName, CONTENT_TYPE, IOUtils.toByteArray(input)); } private static void writeTitles(Row row, List<String> titles, XSSFCellStyle style) { for (int i = 0; i < titles.size(); i++) { Cell cell = row.createCell(i); cell.setCellValue(titles.get(i)); cell.setCellStyle(style); } }
Solution
Let's break this down into manageable parts, focusing on clean state management and reusability:
1. Handling createSheet & State Variables (workbook, sheet, rowCount)
The core challenge here is that createSheet initializes state your service class relies on. Passing individual variables back and forth gets messy quickly—instead, create a context class to encapsulate all Excel-related state. This keeps your utility methods clean and makes state management consistent across multiple classes.
Step 1: Create an Excel Context Class
This class holds all the state variables and exposes getters (no setters to enforce immutability after initialization):
public class ExcelContext { private final XSSFWorkbook workbook; private final XSSFSheet sheet; private final AtomicInteger rowCount; public ExcelContext(XSSFWorkbook workbook, XSSFSheet sheet, AtomicInteger rowCount) { this.workbook = workbook; this.sheet = sheet; this.rowCount = rowCount; } // Getters for state variables public XSSFWorkbook getWorkbook() { return workbook; } public XSSFSheet getSheet() { return sheet; } public AtomicInteger getRowCount() { return rowCount; } }
Step 2: Migrate createSheet to a Utility Class
Now your utility method can return the initialized ExcelContext, which your service class can store and use for other operations:
public class ExcelExportUtil { public static ExcelContext createSheet(String title) { XSSFWorkbook workbook = new XSSFWorkbook(); XSSFSheet sheet = workbook.createSheet(title); AtomicInteger rowCount = new AtomicInteger(0); return new ExcelContext(workbook, sheet, rowCount); } }
Step 3: Update Your Service Class
Replace the individual state variables with the context:
public class DataServiceImpl implements DataService { private static final String SHEET_TITLE = "export.permission.sheetTitle"; private ExcelContext excelContext; @Override public MultipartFile export() throws IOException { excelContext = ExcelExportUtil.createSheet(SHEET_TITLE); // Use excelContext.getWorkbook(), excelContext.getSheet(), excelContext.getRowCount() in other methods } }
2. Migrating the Other Methods
writeTitles: Definitely Migrate to Utility Class
This method is static already and only depends on its input parameters (no external state). It's perfect for a utility class:
public class ExcelExportUtil { // ... existing createSheet method public static void writeTitles(Row row, List<String> titles, XSSFCellStyle style) { for (int i = 0; i < titles.size(); i++) { Cell cell = row.createCell(i); cell.setCellValue(titles.get(i)); cell.setCellStyle(style); } } }
Call it directly from your service class:
ExcelExportUtil.writeTitles(row, titles, cellStyle);
createMultipartFile: Migrate to Utility Class (with Context)
This method depends on workbook, which is part of your ExcelContext. Pass the context to the utility method to keep it reusable:
public class ExcelExportUtil { // ... existing methods public static MultipartFile createMultipartFile(ExcelContext excelContext, String title, String extension, String contentType) throws IOException { String fileNamePrefix = TextBundleUtil.read(title); File outputFile = File.createTempFile(fileNamePrefix, extension); // Use try-with-resources to auto-close streams try (FileOutputStream outputStream = new FileOutputStream(outputFile)) { excelContext.getWorkbook().write(outputStream); } try (FileInputStream input = new FileInputStream(outputFile)) { String fileName = fileNamePrefix.concat(extension); return new MockMultipartFile(fileName, fileName, contentType, IOUtils.toByteArray(input)); } } }
Call it from your service:
MultipartFile file = ExcelExportUtil.createMultipartFile(excelContext, SHEET_TITLE, ".xlsx", CONTENT_TYPE);
Key Takeaways
- Use a context class for stateful Excel operations: it avoids messy parameter lists and keeps related state organized.
- Migrate stateless methods (like
writeTitles) directly to the utility class—they're self-contained and easy to reuse. - Stateful methods (like
createMultipartFile) can be migrated by passing the context or required state as parameters, ensuring they stay flexible across different service classes.
内容的提问来源于stack exchange,提问作者Jack

