繁体   English   中英

如何使用 OpenCSV 或任何其他库将 csv 转换为嵌套 bean?

[英]How to convert csv to nested beans using OpenCSV or any other library?

我正在进行 HTTP 调用以获取 CSV 文件,并且我正在使用 OpenCSV 将等效于 CSV 文件的字符串转换为普通的旧 java 对象。 我跳过了进行 http 调用以获取 csv 的逻辑,因为它包含敏感信息。 以下代码中转换后的 Student 对象的“collegeTiming”属性为空值。 如何从 CSV 映射此值? 有人可以建议吗? 提前致谢!

PFB 我在 pom.xml 中的依赖

    <dependency>
        <groupId>com.opencsv</groupId>
        <artifactId>opencsv</artifactId>
        <version>4.0</version>
    </dependency>

我的输入CSV

"id", "name", "monday_open_time", "monday_close_time", "tuesday_open_time", "tuesday_close_time", "wednesday_open_time", "wednesday_close_time", "thursday_open_time", "thrusday_close_time", "friday_open_time", "friday_close_time"
1, ABCD, 07.00.00,21.00.00, 08.00.00,22.00.00, 07.00.00,21.00.00, 07.00.00,21.00.00, 07.00.00,21.00.00
2, ABCD, 08.00.00,21.00.00, 07.00.00,14.00.00, 07.00.00,21.00.00, 07.00.00,21.00.00, 07.00.00,21.00.00
3, ABCD, 07.00.00,21.00.00, 10.00.00,13.00.00, 07.00.00,21.00.00, 07.00.00,21.00.00, 07.00.00,21.00.00
4, ABCD, 09.00.00,21.00.00, 11.00.00,20.00.00, 07.00.00,21.00.00, 07.00.00,21.00.00, 07.00.00,21.00.00

我想将输入的 csv 转换为以下 Student bean

{
    "id" : 1,
    "name": ABC,
    "collegeTime" : { 
                        "monday":[ 07.00.00, 21.00.00 ], 
                        "tuesday":[ 08.00.00, 22.00.00 ], 
                        "wednesday":[ 07.00.00, 21.00.00 ], 
                        "thrusday":[ 07.00.00, 21.00.00 ], 
                        "friday":[ 07.00.00, 21.00.00 ], 
                        }

}

学生.java

import java.util.List;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.opencsv.bean.CsvBindByName;

public class Student {
@CsvBindByName
@JsonProperty("id")
private String id;
@JsonProperty("name")
@CsvBindByName
private String name;
@JsonProperty("collegeTiming")
private List<CollegeTiming> collegeTimings;

public String getId() {
    return id;
}

public void setId(String id) {
    this.id = id;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public List<CollegeTiming> getCollegeTimings() {
    return collegeTimings;
}

public void setCollegeTimings(List<CollegeTiming> collegeTimings) {
    this.collegeTimings = collegeTimings;
}
}

CollegeTiming.java

import com.fasterxml.jackson.annotation.JsonProperty;

public class CollegeTiming {
@JsonProperty("collegeTime")    
private CollegeTime collegeTime;

public CollegeTime getCollegeTime() {
    return collegeTime;
}

public void setCollegeTime(CollegeTime collegeTime) {
    this.collegeTime = collegeTime;
}
}

大学时光.java

public class CollegeTime {
private String day;
private String startTime;
private String endTime;

public String getStartTime() {
    return startTime;
}

public void setStartTime(String startTime) {
    this.startTime = startTime;
}

public String getEndTime() {
    return endTime;
}

public void setEndTime(String endTime) {
    this.endTime = endTime;
}   

}

//使用 OpenCSV 将 csv 转换为 Student 对象。 注意:csvAsString 是 csv 文件的字符串表示(我进行了 HTTP 调用以获取此信息。

 HeaderColumnNameMappingStrategy<Student> strategy = new HeaderColumnNameMappingStrategy<>();
    strategy.setType(Student.class);

CsvToBean<Student> csvToBean = new CsvToBeanBuilder<Student>(new StringReader(csvAsString))
             .withType(Student.class)
             .withMappingStrategy(strategy)
             .withIgnoreLeadingWhiteSpace(true)
             .build();

 List<Student> = = csvToBean.parse();

当我打印 Student 对象时,将为 Student 对象的“collegeTiming”属性打印 null。 如何将 csv 文件映射到嵌套对象(CollegeTime)?

这似乎有些奇怪,您正在尝试将平面数据推入层次结构。 您将需要在此处进行一些自定义处理,因为您的密钥也与您要构建的模型不匹配。 我已经举例说明了如何使用CSVReader和Jackson的ObjectMapper实现该CSVReader

public class CSVMappingTest {

    static String csv = "\"id\", \"name\", \"monday_open_time\", \"monday_close_time\", \"tuesday_open_time\", \"tuesday_close_time\", \"wednesday_open_time\", \"wednesday_close_time\", \"thursday_open_time\", \"thrusday_close_time\", \"friday_open_time\", \"friday_close_time\"\n" + 
            "1, ABCD, 07.00.00,21.00.00, 08.00.00,22.00.00, 07.00.00,21.00.00, 07.00.00,21.00.00, 07.00.00,21.00.00\n" + 
            "2, ABCD, 08.00.00,21.00.00, 07.00.00,14.00.00, 07.00.00,21.00.00, 07.00.00,21.00.00, 07.00.00,21.00.00\n" + 
            "3, ABCD, 07.00.00,21.00.00, 10.00.00,13.00.00, 07.00.00,21.00.00, 07.00.00,21.00.00, 07.00.00,21.00.00\n" + 
            "4, ABCD, 09.00.00,21.00.00, 11.00.00,20.00.00, 07.00.00,21.00.00, 07.00.00,21.00.00, 07.00.00,21.00.00";

    public static void main(String[] args) throws IOException {
        CSVReader reader = new CSVReader(new StringReader(csv));
        ObjectMapper mapper = new ObjectMapper();

        String[] keys = reader.readNext(); // headers
        String[] values = reader.readNext();
        while(values != null) {
            Student convertValue = mapper.convertValue(csvToMap(keys, values), Student.class);
            System.err.println(mapper.writeValueAsString(convertValue));
            values = reader.readNext();
        }
    }

    public static Map<String, String> csvToMap(final String[] headers, final String[] vals) {
        if(headers == null || vals == null) {
            throw new NullPointerException("Empty input for csv to map");
        }
        if(headers.length != vals.length) { 
            throw new IllegalArgumentException("Header and value count do not match for csv to map");
        }
        Map<String, String> res = new HashMap<>();
        IntStream.range(0, vals.length).forEach( i -> res.put(headers[i], vals[i]));
        return res;
    }

    public static class Student { 
        @JsonProperty("id")
        String id;
        @JsonProperty("name")
        String name;
        @JsonProperty
        Map<String, String> studentTimings = new HashMap<>();

        @JsonAnySetter
        public void setTime(String key, String value) { 
            studentTimings.put(key, value);
        }
    }
}

说明:

我只使用CSVReader来检索行。

然后,我使用csvToMap创建标头值的映射。

然后,我在jackson上使用转换方法来自动创建我想要的bean。

重要的一点在这里:

    @JsonAnySetter
    public void setTime(String key, String value) { 
        studentTimings.put(key, value);
    }

这告诉杰克逊,任何未直接包装的属性都将发送到此处。 在这里您可以处理时间,然后将其手动分组到所需的任何存储桶中。 我看不到任何其他选择,因为您的平面输入与您尝试创建的属性不匹配。

OpenCSV和Jackson都不是处理器。 他们不负责转换您的数据,其目的很简单,例如“找到密钥并呼叫设置程序”。 您可以使用任何形式的自定义序列化程序来告诉它如何创建所需的对象,但是默认设置与上面的语句一样简单。

我确定也有一个OpenCSV方法,但是我不知道:)

希望对您有所帮助,

阿图尔

附言:我没有复制您的整个模型,而是将值推入地图。 这样,我的解析输出将是:

{
  "id": "3",
  "name": " ABCD",
  "studentTimings": {
    "friday_close_time": "21.00.00",
    "friday_open_time": " 07.00.00",
    "monday_close_time": "21.00.00",
    "monday_open_time": " 07.00.00",
    "thrusday_close_time": "21.00.00",
    "thursday_open_time": " 07.00.00",
    "tuesday_close_time": "13.00.00",
    "tuesday_open_time": " 10.00.00",
    "wednesday_close_time": "21.00.00",
    "wednesday_open_time": " 07.00.00"
  }
}
 BufferedReader br = null; List<Student> objLst = new ArrayList<Student>(); InputStreamReader inStreamReader = null; inStreamReader = new InputStreamReader(ReadAccountsUtil.class.getClassLoader().getResourceAsStream("someFile.csv")); CsvReader csvReader = new CsvReader(inStreamReader); String objStr[] = {}; JavaPojoClass id = new Id(); try { while (csvReader.readRecord()) { objStr = csvReader.getRawRecord().split(","); student = new Student(); student.setRollNo(new Short(objStr[0])); student.setName(new String(objStr[1])); student.setAdd(new String(objStr[2])); student.setEmail(new String(objStr[3])); objLst.add(student); } } catch (Exception ex) { if(inStreamReader != null){ try { inStreamReader.close(); } catch (IOException e) { LOGGER.error("Error in closing the input streams"+ e.getMessage()); } } LOGGER.error("Error in reading the Student file"+ ex.getMessage()); } return objLst; } 
 public static void main(String[] args) throws IOException{
 String fileName = "c:\\test.csv";
 char separator = ';';

 List<TestDTO> obj= new CsvToBeanBuilder(new 
 FileReader(fileName)).withSeparator(separator)
                .withType(TestDTO.class)
                .build()
                .parse();

        obj.forEach(System.out::println);

}


import com.opencsv.bean.CsvBindByName;
import lombok.*;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@ToString

public class TestDTO {
  @CsvBindByName(column = "EXTERNAL_ID")
  private String externalId;
  @CsvBindByName(column = "ID_TYPE")
  private String idType;
  @CsvBindByName(column = "STUDY_ID")
  private String studyId;
  @CsvBindByName(column = "STUDY_NAME")
  private String studyName;

}

pom.xml

<dependency>
  <groupId>com.opencsv</groupId>
  <artifactId>opencsv</artifactId>
  <version>5.3</version>
</dependency>

更多详情请访问openscv

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM