Export Any Java Object to CSV/Excel with Reflection – A Universal Utility
This tutorial demonstrates how to create a universal CSV/Excel export utility in Java that can handle objects of any class by using reflection to generate headers and rows, leveraging Apache POI and Spring Boot for seamless file generation.
Introduction
In this article we show how to export objects of any class to a CSV/Excel file without limiting the type of the class, using Java reflection and Apache POI.
Core Idea
The class type is unknown (User, Student, District, etc.). The utility iterates a list of such objects, extracts field names via reflection for the header row, and writes field values to the CSV body.
Implementation Steps
1. Dependencies
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.15</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-scratchpad</artifactId>
<version>3.15</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.69</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>2. Utility Class
The MyCsvFileUtil class provides methods to create CSV files, write files, build file names, generate header rows, convert objects to maps, and assemble the CSV body.
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import java.io.*;
import java.lang.reflect.*;
import java.text.SimpleDateFormat;
import java.util.*;
@Slf4j
public class MyCsvFileUtil {
public static final String FILE_SUFFIX = ".csv";
public static final String CSV_DELIMITER = ",";
public static final String CSV_TAIL = "
";
protected static final String DATE_STR_FILE_NAME = "yyyyMMddHHmmssSSS";
public static void createCsvFile(String savePath, String contextStr) throws IOException {
File file = new File(savePath);
file.createNewFile();
FileOutputStream fos = new FileOutputStream(file);
fos.write(contextStr.getBytes("gbk"));
fos.flush();
fos.close();
}
public static void writeFile(String fileName, String content) {
FileOutputStream fos = null;
OutputStreamWriter writer = null;
try {
fos = new FileOutputStream(fileName, true);
writer = new OutputStreamWriter(fos, "GBK");
writer.write(content);
writer.flush();
} catch (Exception e) {
log.error("写文件异常|{}", e);
} finally {
if (fos != null) IOUtils.closeQuietly(fos);
if (writer != null) IOUtils.closeQuietly(writer);
}
}
public static String buildCsvFileFileName(List dataList) {
return dataList.get(0).getClass().getSimpleName() + new SimpleDateFormat(DATE_STR_FILE_NAME).format(new Date()) + FILE_SUFFIX;
}
public static String buildCsvFileTableNames(List dataList) {
Map<String, Object> map = toMap(dataList.get(0));
StringBuilder tableNames = new StringBuilder();
for (String key : map.keySet()) {
tableNames.append(key).append(CSV_DELIMITER);
}
return tableNames.append(CSV_TAIL).toString();
}
public static String buildCsvFileBodyMap(List dataLists) {
List<Map<String, Object>> mapList = new ArrayList<>();
for (Object o : dataLists) {
mapList.add(toMap(o));
}
StringBuilder lineBuilder = new StringBuilder();
for (Map<String, Object> rowData : mapList) {
for (String key : rowData.keySet()) {
Object value = rowData.get(key);
if (Objects.nonNull(value)) {
lineBuilder.append(value).append(CSV_DELIMITER);
} else {
lineBuilder.append("--").append(CSV_DELIMITER);
}
}
lineBuilder.append(CSV_TAIL);
}
return lineBuilder.toString();
}
public static <T> Map<String, Object> toMap(T entity) {
Class<?> bean = entity.getClass();
Field[] fields = bean.getDeclaredFields();
Map<String, Object> map = new HashMap<>(fields.length);
for (Field field : fields) {
try {
if (!"serialVersionUID".equals(field.getName())) {
String methodName = "get" + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1);
Method method = bean.getDeclaredMethod(methodName);
Object fieldValue = method.invoke(entity);
map.put(field.getName(), fieldValue);
}
} catch (Exception e) {
log.warn("toMap() Exception={}", e.getMessage());
}
}
return map;
}
}3. Usage Example
A Spring MVC controller method demonstrates how to export a list of District objects.
@RequestMapping("/createCsvFileJcTest")
public void createCsvFileJcTest() {
List<District> districts = districtService.queryByParentCodes(Arrays.asList("110100"));
String fileName = "D:\\mycsv\\" + MyCsvFileUtil.buildCsvFileFileName(districts);
String tableNames = MyCsvFileUtil.buildCsvFileTableNames(districts);
MyCsvFileUtil.writeFile(fileName, tableNames);
String contentBody = MyCsvFileUtil.buildCsvFileBodyMap(districts);
MyCsvFileUtil.writeFile(fileName, contentBody);
}Extension with Custom Annotation
Define @JcExcelName to specify custom column titles, and use resolveExcelTableName to retrieve them.
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface JcExcelName {
String name() default "";
}
public static <T> List<String> resolveExcelTableName(T entity) {
List<String> tableNamesList = new ArrayList<>();
Class<?> bean = entity.getClass();
Field[] fields = bean.getDeclaredFields();
for (Field field : fields) {
try {
if (!"serialVersionUID".equals(field.getName())) {
String tableTitleName = field.getName();
JcExcelName ann = field.getAnnotation(JcExcelName.class);
if (ann != null && StringUtils.hasLength(ann.name())) {
tableTitleName = ann.name();
}
tableNamesList.add(tableTitleName);
}
} catch (Exception e) {
log.warn("toMap() Exception={}", e.getMessage());
}
}
return tableNamesList;
}Combine the custom titles with the CSV builder to produce a nicely formatted Excel file.
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.
Java Backend Technology
Focus on Java-related technologies: SSM, Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading. Occasionally cover DevOps tools like Jenkins, Nexus, Docker, and ELK. Also share technical insights from time to time, committed to Java full-stack development!
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.
