Apache Fesod: High-Performance Java Excel Library with Streaming & Spring Boot Integration
Apache Fesod (Incubating) is a high-performance, memory-efficient Java library for reading and writing Excel files, featuring streaming APIs, simple annotation-driven mapping, Spring Boot integration, and SXSSF-based large-file writing with optional temp-file compression.
Introduction
Apache Fesod (Incubating) is a high-performance, memory-efficient Java library for reading and writing spreadsheet files. The name stands for "fast easy spreadsheet and other documents" (pronounced /ˈfɛsɒd/). It aims to simplify development while ensuring reliability, with plans for future feature enhancements.
Key Features
High-performance read/write: Optimized for large-scale spreadsheet data, significantly reducing memory consumption compared to traditional libraries.
Simple API: Intuitive, annotation-driven mapping for easy integration into projects, from simple operations to complex data processing.
Streaming operations: Supports streaming reads to minimize memory footprint when processing hundreds of thousands or millions of rows.
Environment
Spring Boot 3.5.0, Java 1.8+ (latest LTS recommended).
Dependency Configuration
Currently, Apache Fesod uses POI as the underlying package. If your project already includes POI components, you must manually exclude POI-related JARs.
<dependency>
<groupId>org.apache.fesod</groupId>
<artifactId>fesod-sheet</artifactId>
<version>2.0.2-incubating</version>
</dependency>Quick Start
Reading Excel
Define a listener implementing ReadListener<User>:
public class UserDataListener implements ReadListener<User> {
@Override
public void invoke(User user, AnalysisContext context) {
System.out.println("解析数据: %s".formatted(user));
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
System.out.println("所有数据解析完成!");
}
}Read the file:
String fileName = "f:/user.xlsx";
FesodSheet.read(fileName, User.class, new UserDataListener())
.sheet()
.doRead();Output example:
解析数据: User [id=1, name=张三, age=22, [email protected]]
解析数据: User [id=2, name=李四, age=33, [email protected]]
解析数据: User [id=3, name=王五, age=44, [email protected]]
所有数据解析完成!Writing Excel
Model class with annotations:
public class User {
@ExcelProperty("编号")
private Long id;
@ExcelProperty("姓名")
private String name;
@ExcelProperty("年龄")
private Integer age;
@ExcelProperty("邮箱")
private String email;
@ExcelIgnore
private String profile;
}Write data:
private static List<User> data() {
List<User> list = new ArrayList<>();
for (int i = 4; i <= 10; i++) {
User user = new User(
i + 0L,
"姓名 - " + i,
new Random().nextInt(100),
i + "@qq.com",
"profile - " + i
);
list.add(user);
}
return list;
}
public static void main(String[] args) {
String fileName = "f:/user.xlsx";
FesodSheet.write(fileName, User.class)
.sheet("Template")
.doWrite(data());
}Spring Boot Integration
Upload Excel
public class UploadUserListener extends AnalysisEventListener<User> {
private static final Logger log = LoggerFactory.getLogger(UploadUserListener.class);
private final List<User> list = new ArrayList<>();
@Override
public void invoke(User user, AnalysisContext context) {
list.add(user);
// For large data, perform batch saves here
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
log.info("所有数据读取完成!");
// Save to database here
}
}
@PostMapping("/upload")
public ResponseEntity<String> upload(@RequestParam("file") MultipartFile file) {
if (file.isEmpty()) {
return ResponseEntity.badRequest().body("请选择一个文件上传!");
}
try {
FesodSheet.read(file.getInputStream(), User.class, new UploadUserListener())
.sheet()
.doRead();
return ResponseEntity.ok("文件上传并处理成功!");
} catch (IOException e) {
e.printStackTrace();
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("文件处理失败!");
}
}Download Excel
@GetMapping("/download")
public void download(HttpServletResponse response) throws IOException {
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
String fileName = URLEncoder.encode("user", "UTF-8").replaceAll("\\+", "%20");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
FesodSheet.write(response.getOutputStream(), User.class)
.sheet("Sheet")
.doWrite(data());
}Large File Writing
Exporting large datasets (database dumps, log analysis) can exhaust memory if all rows are loaded at once. Fesod internally uses Apache POI's streaming API (SXSSF), but temporary XML files may consume significant disk space. Enabling compression reduces disk usage at the cost of slightly higher CPU consumption.
@Test
public void largeFileWrite() {
String fileName = "largeFile" + System.currentTimeMillis() + ".xlsx";
try (ExcelWriter excelWriter = FesodSheet.write(fileName, User.class)
.registerWriteHandler(new WorkbookWriteHandler() {
@Override
public void afterWorkbookCreate(WorkbookWriteHandlerContext context) {
Workbook workbook = context.getWriteWorkbookHolder().getWorkbook();
if (workbook instanceof SXSSFWorkbook) {
((SXSSFWorkbook) workbook).setCompressTempFiles(true);
}
}
}).build()) {
WriteSheet writeSheet = FesodSheet.writerSheet("模板").build();
// Batch write — each data() call returns one batch
for (int i = 0; i < 1000; i++) {
excelWriter.write(data(), writeSheet);
}
}
}Architecture
Data (in-memory, batched) Fesod POI/SXSSF
│ │ │
├─ 100-row batch ──────────▶ write() ─────▶ Temp XML (compressed)
├─ 100-row batch ──────────▶ write() ─────▶ Temp XML (appended)
│ ... (1000 batches) │ │
└─ close() ────────────────▶ Finish ──────▶ Final .xlsxPerformance Recommendations
Use ExcelWriter (try-with-resources) for batched writes instead of loading all data via doWrite().
Enable temp-file compression in disk-constrained environments.
Tune batch size (e.g., 100 rows) based on row width and available memory.
Monitor temp directory size via FileUtils.getPoiFilesPath().
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
