Сложный объект Java в CSV

Я пытаюсь создать файл CSV из довольно сложного объекта Java. Объект представляет собой сеанс с некоторыми атрибутами и списком строк и сообщений, которые, в свою очередь, имеют некоторые атрибуты, и список комментариев, которые имеют некоторые атрибуты.

Класс сеанса выглядит следующим образом;

public class Session {

    private Long id;

    private Date startDate;

    private Date endDate;

    private List<Message> messages;

    private List<String> participants;

    public TweetSession() {
    }  

    public TweetSession(Date startDate, List<Message> messages, List<String>     participants) {
        this.startDate = startDate;
        this.messages = messages;
        this.participants = participants;
    }

    public Long getId() {
        return id;
    }

    public Date getStartDate() {
        return startDate;
    }

    public void setStartDate(Date startDate) {
        this.startDate = startDate;
    }

    public Date getEndDate() {
        return endDate;
    }

    public void setEndDate(Date endDate) {
        this.endDate = endDate;
    }

    public List<Message> getMessages() {
        return messages;
    }

    public void setMessage(List<Message> messages) {
        this.message = message;
    }

    public List<String> getParticipants() {
        return participants;
    }

    public void setParticipants(List<String> participants) {
        this.participants = participants;
    }
}

Класс сообщения следующий;

public class Message {

    private Long id;

    private Session session;

    private Date date;

    private String participant;

    private String content;

    private List<Comment> comments;

    public Message() {
    }

    public Message(String participant, Session session, Date date, String content) {
        this.participant = participant;
        this.session = session;
        this.content = content;
        this.date = date;
        this.comments = new ArrayList<>();
    }

    public Long getId() {
        return id;
    }

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

    public String getParticipant() {
        return participant;
    }

    public void setParticipant(String participant) {
        this.participant = participant;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public List<Comment> getComments() {
        return comments;
    }

    public void setComments(List<Comment> comments) {
        this.comments = comments;
    }

    public void addComment(Comment comment) {
        this.comments.add(comment);
    }

    public Date getDate() {
        return date;
    }

    public void setDate(Date date) {
        this.date = date;
    }

    public TweetSession getSession() {
        return session;
    }

    public void setSession(TweetSession session) {
        this.session = session;
    }
}

И класс комментариев;

public class Comment {

    private Long id;

    private Message message;

    private String participant;

    private String message;

    private Date date;

    public Comment() {
    }

    public Comment(String participant, Message message, String content, Date date) {
        this.participant = participant;
        this.content = content;
        this.message = message;
        this.date = date;
    }

    public String getParticipant() {
        return participant;
    }

    public void setParticipant(String participant) {
        this.participant = participant;
    }

    public Message getMessage() {
        return message;
    }

    public void setMessage(Message message) {
        this.message = message;
    }

    public Date getDate() {
        return date;
    }

    public void setDate(Date date) {
        this.date = date;
    }

    public Long getId() {
        return id;
    }

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

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }
}   

Мне интересно, можно ли сопоставить это с файлом CSV. Когда я конвертирую объект сеанса в формат JSON и конвертирую этот JSON в CSV в онлайн-генераторе, я получаю правильный вывод, поэтому я думаю, что это должно быть возможно. Я просто не знаю как. Я пробовал использовать библиотеку net.sf.supercsv следующим образом;

public void generateCSV(Session session, HttpServletResponse response) throws IOException {
    String csvFileName = "session.csv";
    response.setContentType("text/csv");

    String headerKey = "Content-Disposition";
    String headerValue = String.format("attachment; filename=\"%s\"",
            csvFileName);
    response.setHeader(headerKey, headerValue);

    ICsvBeanWriter csvWriter = new CsvBeanWriter(response.getWriter(),
            CsvPreference.STANDARD_PREFERENCE);

    // Generate header for the CSV
    Field fields[] = session.getClass().getDeclaredFields();
    String[] header = new String[fields.length];
    for (int i = 0; i < fields.length; i++) {
        header[i] = fields[i].getName();
    }

    csvWriter.writeHeader(header);

    // Generate CSV content from data
    csvWriter.write(session, header);

    csvWriter.close();
}

Но это, конечно, не даст желаемого результата.

Может кто-то указать мне верное направление?

Заранее спасибо,

Нильс

Изменить:

Это пример сеанса в формате JSON:

{
    "id": 22,
    "startDate": 1447368081000,
    "endDate": null,
    "messages": [
        {
            "id": 10,
            "date": 1447368159000,
            "participant": "1",
            "content": "This is a message",
            "comments": []
        },
        {
            "id": 11,
            "date": 1447368168000,
            "participant": "1",
            "content": "This is also a message",
            "comments": []
        },
        {
            "id": 12,
            "date": 1447368179000,
            "participant": "1",
            "content": "This is another message",
            "comments": [
                {
                    "id": 10,
                    "participant": "1",
                    "message": "This is a comment",
                    "date": 1447368227000
                },
                {
                    "id": 11,
                    "participant": "1",
                    "message": "This is also a comment",
                    "date": 1447368234000
                }
            ]
        }
    ],
    "participants": [
        "1",
        "23"
    ]
}

Когда я конвертирую это в CSV, я получаю что-то вроде этого:

CSV

Действительно, начинать думать (один) CSV может быть не лучшим подходом к этой проблеме.


person Niels Masdorp    schedule 18.11.2015    source источник
comment
Мне кажется, что csv не будет подходящим форматом для реляционных данных. Формат csv больше подходит для представления таблицы данных, где каждая строка семантически похожа на другие. Если вы хотите представить тип реляционной структуры, которую вы описываете, вам придется либо дублировать большое количество данных, оставляя много столбцов пустыми для многих строк, либо вам придется создавать несколько отдельных файлов csv. Не могли бы вы предоставить нам пример того, как ваш ожидаемый конечный результат должен выглядеть в формате csv?   -  person jvalli    schedule 18.11.2015
comment
Достаточно честно, клиент хочет, чтобы данные были загружены и запрошены CSV. Может быть, я смогу убедить клиента принять другой формат. Спасибо за ваш вклад!   -  person Niels Masdorp    schedule 18.11.2015
comment
Мы создали файлы для клиента, создав CSV из списка POJO. Пожалуйста, смотрите мой ответ   -  person Mahendran Ayyarsamy Kandiar    schedule 18.11.2015
comment
Ваш POJO состоит из вложенных списков, составленных другими POJO?   -  person Niels Masdorp    schedule 18.11.2015
comment
У моего POJO есть атрибут List‹AnotherDTO›   -  person Mahendran Ayyarsamy Kandiar    schedule 18.11.2015
comment
Пример подробностей Apache Common Csv API: stackoverflow.com/a/42198895/6549532   -  person Kevin Li    schedule 13.02.2017
comment
Используйте подход beansToCsv для записи контента из bean-компонентов в csv, следуя по этой ссылке javainterviewpoint .com/   -  person DHARMENDRA SINGH    schedule 21.02.2018


Ответы (5)


Данные, которые у вас есть, имеют много зависимостей 1:n и не совсем подходят для одного CSV-файла.

Подходы, которые я использовал или видел для этого:

  • Один «гибридный» CSV с собственными данными Session, т. е. id, startDate, endDate в первых столбцах, а затем два столбца для сообщений и участников, напечатанные в формате JSON.

    "123", "2015-11-17", "2015-11-18", "[{id: 345, date: ...}, {id: 789, date: ...}]", "[...]"
    

    (обратите внимание, что вам нужно использовать хорошую библиотеку CSV, которая экранирует значения, содержащие , или "s)

  • Несколько файлов CSV — смоделированы так же, как если бы вы моделировали реляционную базу данных для своей структуры, т.е.

    • sessions.csv containing id, startDate, endDate
    • messages.csv, содержащий id, session_id, date, ...
    • ...

    затем заархивируйте их для загрузки одним файлом

  • Попросите вашего пользователя дать более точную спецификацию — постарайтесь выяснить, что он собирается делать с данными, а затем предоставьте ему «представление» данных в формате, который позволит им легко их читать — точно так же, как база данных просматривает и отчеты создаются, чтобы предоставить пользователям ориентированное на задачи представление данных.
person Jiri Tousek    schedule 18.11.2015
comment
Спасибо за ваш вклад, я добавил образец JSON к моему вопросу. Я думаю, вы правы, я не думаю, что мне следует использовать (один) CSV для этой проблемы. Клиент просто хочет иметь возможность легко просматривать данные в Excel или чем-то подобном. Я попытаюсь изменить его мнение. - person Niels Masdorp; 18.11.2015
comment
А еще лучше попытаться выяснить, что он хочет видеть в этих данных. Если он, например, хочет увидеть, как сообщения связаны с сеансами, вы можете дать ему CSV с одной строкой для каждого сеанса - отношение сообщения, т.е. session_id, startDate, endDate, messageId, messageDate, messageContent - точно так же, как вы подготовили бы представление для них, если бы они хотели увидеть некоторую базу данных данные. - person Jiri Tousek; 18.11.2015
comment
Я так и сделаю, хотя думаю, что смогу убедить его принять JSON или даже XML. - person Niels Masdorp; 18.11.2015

Мы использовали openCSV

com.opencsv.bean.BeanToCsv для достижения этой цели

   public void exportIronData(String destinationFilePath,
        List<ExportIronDataFileFormatDTO> dataList) throws Exception {
    try {
        if (validationUtil.isNullOrEmpty(destinationFilePath)
                || validationUtil.isNullOrEmpty(dataList)) {
            return;
        }
        ColumnPositionMappingStrategy<ExportIronDataFileFormatDTO> strategy = new ColumnPositionMappingStrategy<ExportIronDataFileFormatDTO>();
        strategy.setType(ExportIronDataFileFormatDTO.class);
        String[] columns = IlmcrCsvFileConstants.EXPORT_IRONDATA_COLUMN_HEADERS;
        strategy.setColumnMapping(columns);
        CSVWriter writer = new CSVWriter(
                new FileWriter(destinationFilePath),
                IlmcrCsvFileConstants.exportIronDataSeperator,
                CSVWriter.NO_ESCAPE_CHARACTER, System.getProperty("line.separator"));
        BeanToCsv<ExportIronDataFileFormatDTO> exportFormat = new BeanToCsv<ExportIronDataFileFormatDTO>();
        exportFormat.write(strategy, writer, dataList);
        writer.flush();
        writer.close();
    } catch (Exception e) {
        e.printStackTrace();
        throw e;
    }
}

Дай мне знать если тебе нужно что-нибудь еще

person Mahendran Ayyarsamy Kandiar    schedule 18.11.2015

Существует библиотека под названием json2flat.
Она берет сложный документ JSON и преобразует его в в формат CSV.

Итак, что вам нужно сделать, это преобразовать ваши java-объекты в формат JSON. После этого
вам нужно передать сгенерированный JSON в библиотеку, и она вернет 2D
представление JSON, вы также можете получить из него csv.

Эта библиотека не настолько зрелая, но все же она многообещающая.
Вам стоит попробовать.

person skap    schedule 01.12.2016

Вы должны использовать гибридные форматы CSV. У меня была такая же проблема, поэтому я создал легкую структуру. Вы можете скопировать исходный код или пример из: https://github.com/abhisoni96/dev-tools

Вы можете создать свой собственный модуль форматирования для каждого члена данных на основе коллекции. Пожалуйста, обратитесь к примеру по ссылке выше.

person Abhishek Soni    schedule 28.11.2016

Вместо этого я рекомендую использовать Apache Commons CSV. Мы использовали его в нескольких проектах, включая управление нашими списками рассылки.

 Reader in = new StringReader("a,b,c");
 for (CSVRecord record : CSVFormat.DEFAULT.parse(in)) {
     for (String field : record) {
         System.out.print("\"" + field + "\", ");
     }
     System.out.println();
 }

Output: "a", "b", "c", 
person johnnieb    schedule 18.11.2015
comment
Как это помогает выводить отношения 1:n в CSV? - person Jiri Tousek; 18.11.2015
comment
@MahendranAyyarsamyKandiar Да, он генерирует CSV. Я добавил вывод в свой ответ. - person johnnieb; 18.11.2015
comment
Где используется bean-компонент в качестве ввода, как спросил OP? - person Mahendran Ayyarsamy Kandiar; 18.11.2015
comment
@MahendranAyyarsamyKandiar Класс CVSPrinter в Commons CSV может обрабатывать более сложные структуры данных и bean-компоненты. См. commons.apache.org/proper/commons-csv. /архивы/1.2/апидоки/ - person johnnieb; 18.11.2015