Universal Java Class to Excel Export Using Reflection and Apache POI
This article demonstrates how to create a generic utility that, through Java reflection and Apache POI, can export any list of objects—regardless of their class—into a CSV/Excel file, with optional custom column names via annotations.
In this tutorial the author shows a step‑by‑step method to export arbitrary Java objects to CSV/Excel without needing to know the specific class in advance. The core idea is to use reflection to read field names and values, build a header row, and then write the data rows.
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>Utility Class: MyCsvFileUtil
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.*;
/**
* @author JCccc
* @Remark 是我
*/
@Slf4j
public class MyCsvFileUtil {
public static final String FILE_SUFFIX = ".csv";
public static final String CSV_DELIMITER = ",";
public static final String CSV_TAIL = "\r\n";
protected static final String DATE_STR_FILE_NAME = "yyyyMMddHHmmssSSS";
/**
* 将字符串转成csv文件
*/
public static void createCsvFile(String savePath, String contextStr) throws IOException {
File file = new File(savePath);
//创建文件
file.createNewFile();
//创建文件输出流
FileOutputStream fileOutputStream = new FileOutputStream(file);
//将指定字节写入此文件输出流
fileOutputStream.write(contextStr.getBytes("gbk"));
fileOutputStream.flush();
fileOutputStream.close();
}
/**
* 写文件
*
* @param fileName
* @param content
*/
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;
}
/**
* 构建excel 标题行名
*/
public static String buildCsvFileTableNames(List dataList) {
Map
map = toMap(dataList.get(0));
StringBuilder tableNames = new StringBuilder();
for (String key : map.keySet()) {
tableNames.append(key).append(MyCsvFileUtil.CSV_DELIMITER);
}
return tableNames.append(MyCsvFileUtil.CSV_TAIL).toString();
}
/**
* 构建excel内容
*/
public static String buildCsvFileBodyMap(List dataLists) {
//不管你传什么玩意,我都给你反射一手,搞成Map
List
> mapList = new ArrayList<>();
for (Object o : dataLists) {
mapList.add(toMap(o));
}
//然后利用csv格式,对着map嘎嘎一顿拼接数据
StringBuilder lineBuilder = new StringBuilder();
for (Map
rowData : mapList) {
for (String key : rowData.keySet()) {
Object value = rowData.get(key);
if (Objects.nonNull(value)) {
lineBuilder.append(value).append(MyCsvFileUtil.CSV_DELIMITER);
} else {
lineBuilder.append("--").append(MyCsvFileUtil.CSV_DELIMITER);
}
}
lineBuilder.append(MyCsvFileUtil.CSV_TAIL);
}
return lineBuilder.toString();
}
/**
* 类转map
*/
public static
Map
toMap(T entity) {
Class
bean = entity.getClass();
Field[] fields = bean.getDeclaredFields();
Map
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;
}
}Controller Test Example
@RequestMapping("/createCsvFileJcTest")
public void createCsvFileJcTest() {
//类不确定 随便怎么传都行
List
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: Custom Column Names via Annotation
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface JcExcelName {
String name() default "";
}Fields annotated with @JcExcelName will use the provided name as the column header; otherwise the field name is used.
Utility to Resolve Column Names
public static
List
resolveExcelTableName(T entity) {
List
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 myFieldAnn = field.getAnnotation(JcExcelName.class);
String annName = myFieldAnn.name();
if (StringUtils.hasLength(annName)) {
tableTitleName = annName;
}
tableNamesList.add(tableTitleName);
}
} catch (Exception e) {
log.warn("toMap() Exception={}", e.getMessage());
}
}
return tableNamesList;
}Building Header with Resolved Names
public static String buildCsvFileTableNamesNew(List
dataList) {
StringBuilder tableNames = new StringBuilder();
for (String name : dataList) {
tableNames.append(name).append(MyCsvFileUtil.CSV_DELIMITER);
}
return tableNames.append(MyCsvFileUtil.CSV_TAIL).toString();
}Demo Main Method
public static void main(String[] args) {
User user = new User();
List
nameList = MapUtils.resolveExcelTableName(user);
System.out.println(nameList.toString());
String tableNames = buildCsvFileTableNamesNew(nameList);
System.out.println(tableNames);
}The article concludes that with these utilities you can export any Java class to Excel, customize column headers via annotations, and extend the approach with additional processing such as interceptors or custom annotations.
Java Architect Essentials
Committed to sharing quality articles and tutorials to help Java programmers progress from junior to mid-level to senior architect. We curate high-quality learning resources, interview questions, videos, and projects from across the internet to help you systematically improve your Java architecture skills. Follow and reply '1024' to get Java programming resources. Learn together, grow together.
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.