如何读取含继承类的CSV文件并映射至指定Java类?
问题解答
1. 读取CSV文件的实现方式
可以用Java原生API或第三方库实现,以下是两种常用方案:
原生Java实现
通过BufferedReader逐行读取并分割列:
import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; import java.util.List; public class CsvReader { public static List<String[]> readCsv(String filePath) throws IOException { List<String[]> rows = new ArrayList<>(); try (BufferedReader br = new BufferedReader(new FileReader(filePath))) { String line; br.readLine(); // 跳过表头 while ((line = br.readLine()) != null) { String[] columns = line.split(","); rows.add(columns); } } return rows; } }
第三方库(OpenCSV)实现
依赖Maven坐标:
<dependency> <groupId>com.opencsv</groupId> <artifactId>opencsv</artifactId> <version>5.6</version> </dependency>
读取代码:
import com.opencsv.CSVReader; import java.io.FileReader; import java.io.IOException; import java.util.List; public class OpenCsvReader { public static List<String[]> readCsv(String filePath) throws IOException { try (CSVReader reader = new CSVReader(new FileReader(filePath))) { reader.readNext(); // 跳过表头 return reader.readAll(); } } }
2. 具备可扩展性的读取方法设计
要支持所有Person子类,采用工厂+策略模式实现,核心是基于datatype字段分发解析逻辑:
步骤1:定义解析器接口
public interface PersonParser<T extends Person> { T parse(String[] columns); String getDataType(); }
步骤2:实现子类解析器
以Employee为例:
public class EmployeeParser implements PersonParser<Employee> { @Override public Employee parse(String[] columns) { Employee employee = new Employee(); // 按CSV列顺序填充属性,例如: // employee.setFirstname(columns[1]); // employee.setLastname(columns[2]); // ... 其他属性赋值 return employee; } @Override public String getDataType() { return "employee"; } }
后续新增Person子类时,只需实现对应的解析器即可。
步骤3:工厂类管理解析器
import java.util.HashMap; import java.util.Map; public class PersonParserFactory { private static final Map<String, PersonParser<? extends Person>> parsers = new HashMap<>(); static { // 注册已有的解析器 parsers.put(new EmployeeParser().getDataType(), new EmployeeParser()); } public static PersonParser<? extends Person> getParser(String dataType) { return parsers.get(dataType); } // 支持动态注册新解析器,增强扩展性 public static void registerParser(PersonParser<? extends Person> parser) { parsers.put(parser.getDataType(), parser); } }
步骤4:整合读取与解析逻辑
import java.io.IOException; import java.util.ArrayList; import java.util.List; public class ExtensiblePersonReader { public static List<Person> readPersons(String filePath) throws IOException { List<String[]> rows = OpenCsvReader.readCsv(filePath); List<Person> persons = new ArrayList<>(); for (String[] columns : rows) { String dataType = columns[0]; PersonParser<? extends Person> parser = PersonParserFactory.getParser(dataType); if (parser != null) { persons.add(parser.parse(columns)); } else { throw new IllegalArgumentException("不支持的数据类型:" + dataType); } } return persons; } }
新增Person子类时,仅需实现解析器并注册到工厂,无需修改核心读取逻辑,符合开闭原则。
3. 能否将CSV数据存储到CreatePersonCommand类?
完全可以。CreatePersonCommand的dataType字段对应CSV的datatype列,其余列可作为键值对存入params集合。
实现代码示例:
import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class CommandConverter { private static final String[] HEADERS = { "datatype", "firstname", "lastname", "identifier", "height", "weight", "email", "hiredate", "jobposition", "salary", "nameschool", "graduationyear", "major", "schoolarship" }; public static List<CreatePersonCommand> convertToCommands(String filePath) throws IOException { List<String[]> rows = OpenCsvReader.readCsv(filePath); List<CreatePersonCommand> commands = new ArrayList<>(); for (String[] columns : rows) { CreatePersonCommand command = new CreatePersonCommand(); command.setDataType(columns[0]); Map<String, String> params = new HashMap<>(); for (int i = 1; i < HEADERS.length; i++) { if (!"null".equals(columns[i])) { params.put(HEADERS[i], columns[i]); } } command.setParams(params); commands.add(command); } return commands; } }
这种方式无需关注具体Person子类,仅需按原始结构存储数据,后续可根据dataType做进一步转换,灵活性较强。
内容的提问来源于stack exchange,提问作者Mieciu
相关产品推荐
相关产品推荐

