如何基于Map表头与Java对象生成CSV格式的StringBuffer
问题描述
需要生成CSV文件,规则如下:
- 表头来自一个Map:键是
MyObject类的属性名,值是CSV对应的列标题 - 数据行来自
MyObject实例列表 - 要求列顺序变更时,数据行能和表头正确对应
现有代码已通过反射生成表头,但不知如何将MyObject的属性值追加到StringBuffer生成目标CSV内容,相关代码及期望输出如下:
MyObject类定义
public class MyObject { private String name; private String email; private Integer id; private String phone; // getters and setters... }
列标题映射Map示例
Map<String, String> columnMap = new HashMap<>(); columnMap.put("id", "Id"); columnMap.put("name", "User Name"); columnMap.put("email", "User Email"); columnMap.put("phone", "User Phone");
当前实现代码
public class CopyMapToSBForFile { public static void main(String[] args) { List<MyObject> myObjects = new ArrayList<>(); MyObject myObject1 = new MyObject(); myObject1.setId(1); myObject1.setName("Name 1"); myObject1.setEmail("Email 1"); myObject1.setPhone("111-121-2121"); MyObject myObject2 = new MyObject(); myObject2.setId(2); myObject2.setName("Name 2"); myObject2.setEmail("Email 2"); myObject2.setPhone("111-121-2121"); MyObject myObject3 = new MyObject(); myObject3.setId(3); myObject3.setName("Name 3"); myObject3.setEmail("Email 3"); myObject3.setPhone("111-121-2121"); myObjects.add(myObject1); myObjects.add(myObject2); myObjects.add(myObject3); Map<String, String> columnMap = new HashMap<>(); columnMap.put("id", "Id"); columnMap.put("name", "User Name"); columnMap.put("email", "User Email"); columnMap.put("phone", "User Phone"); Field[] fields = MyObject.class.getDeclaredFields(); StringBuffer sb = new StringBuffer(); for (Field field : fields) { System.out.println(field.getName()); if (columnMap.containsKey(field.getName())) { sb.append(columnMap.get(field.getName())); sb.append(","); } } } }
期望生成的CSV格式
User Name,User Email,Id,User Phone Name 1,Email 1,1,111-121-2121 Name 2,Email 2,2,111-121-2121 Name 3,Email 3,3,111-121-2121
解决方案
核心思路是先固定列的顺序(HashMap是无序的,直接遍历会导致表头和数据行顺序不匹配),然后按该顺序分别生成表头和数据行,保证一一对应。
修改后的完整代码
import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; public class CopyMapToSBForFile { public static void main(String[] args) { List<MyObject> myObjects = new ArrayList<>(); MyObject myObject1 = new MyObject(); myObject1.setId(1); myObject1.setName("Name 1"); myObject1.setEmail("Email 1"); myObject1.setPhone("111-121-2121"); MyObject myObject2 = new MyObject(); myObject2.setId(2); myObject2.setName("Name 2"); myObject2.setEmail("Email 2"); myObject2.setPhone("111-121-2121"); MyObject myObject3 = new MyObject(); myObject3.setId(3); myObject3.setName("Name 3"); myObject3.setEmail("Email 3"); myObject3.setPhone("111-121-2121"); myObjects.add(myObject1); myObjects.add(myObject2); myObjects.add(myObject3); // 列标题映射 Map<String, String> columnMap = new HashMap<>(); columnMap.put("id", "Id"); columnMap.put("name", "User Name"); columnMap.put("email", "User Email"); columnMap.put("phone", "User Phone"); // 关键:定义属性顺序,保证表头和数据行顺序严格对应 List<String> fieldOrder = Arrays.asList("name", "email", "id", "phone"); StringBuffer sb = new StringBuffer(); // 生成表头 for (String fieldName : fieldOrder) { sb.append(columnMap.get(fieldName)); sb.append(","); } // 移除末尾多余逗号并换行 if (sb.length() > 0) { sb.setLength(sb.length() - 1); sb.append("\n"); } // 生成数据行 for (MyObject obj : myObjects) { for (String fieldName : fieldOrder) { try { Field field = MyObject.class.getDeclaredField(fieldName); field.setAccessible(true); // 允许访问私有属性 Object value = field.get(obj); // 处理空值,避免CSV中出现null字样 sb.append(value != null ? value : ""); sb.append(","); } catch (NoSuchFieldException | IllegalAccessException e) { e.printStackTrace(); } } // 移除末尾多余逗号并换行 if (sb.length() > 0) { sb.setLength(sb.length() - 1); sb.append("\n"); } } // 输出最终CSV内容 System.out.println(sb.toString()); } static class MyObject { private String name; private String email; private Integer id; private String phone; // Getters and Setters public String getName() { return name; } public void setName(String name) { this.name = name; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } } }
关键细节说明
- 列顺序控制:通过
fieldOrder列表明确指定属性顺序,不受columnMap存储顺序影响,确保表头和数据行列完全对应 - 反射访问私有属性:调用
field.setAccessible(true)突破私有属性访问限制 - 空值处理:属性值为
null时替换为空字符串,避免生成无效CSV内容 - 格式修正:自动移除每行末尾多余的逗号,保证CSV格式合规
- 可选优化:若需动态保留
columnMap的插入顺序,可将HashMap替换为LinkedHashMap,直接遍历columnMap.keySet()即可获取顺序(需保证插入顺序与期望列顺序一致)
内容的提问来源于stack exchange,提问作者Mohit224
相关产品推荐
相关产品推荐

