簡體   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