Загрузка очень больших результатов из запроса через Java Webapp - PullRequest
0 голосов
/ 04 марта 2020

Я размышлял над какой-то проблемой, и мне было интересно, есть ли у кого-нибудь совет. У меня есть веб-приложение, в которое мне нужно добавить раздел для отчетов. Он будет иметь t- sql запрос, построенный на основе пользовательских данных gui, выполнит и позволит пользователю загружать файл на свой компьютер через свой браузер как csv. Само по себе ничего из этого не слишком сложно. Я делал эти вещи раньше. Однако есть одна проблема, с которой я раньше не сталкивался. Результаты могут закончиться как данные нескольких ГБ. Что бы я сделал по-другому (с точки зрения кода) по сравнению с обычным, чтобы он не перегружал браузер или не работал слишком медленно? Это явно не может быть все в памяти сразу? Как я могу предотвратить это?

1 Ответ

1 голос
/ 04 марта 2020

Вы можете записать csv-данные непосредственно в OutputStream входящего запроса:

package example;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.nio.charset.StandardCharsets;

public class MyServlet extends HttpServlet {

    private final CSVCreator csvCreator;

    private MyServlet(CSVCreator csvCreator) {
        this.csvCreator = csvCreator;
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // be nice to your consumer, tell them what they get
        resp.setHeader("Content-Type", "text/comma-separated-values; charset=UTF-8");

        try (Writer writer = new OutputStreamWriter(resp.getOutputStream(), StandardCharsets.UTF_8)) {
            this.csvCreator.createCSV("some params you need to create the correct csv", writer);
        }
    }
}

Вам придется изменить поколение csv, чтобы иметь возможность записи в Writer ... например :

package example;

import java.io.IOException;

public class CSVCreator {

    public void createCSV(String someParamsYouNeedToCreateTheCSV, Appendable appendable) throws IOException {
        appendable.append("Column1,Column2,Column3\n");
        appendable.append("Row1,Row1,Row1\n");
        appendable.append("Row2,Row2,Row2\n");
    }
}

Вы также можете, например, использовать apache -commons-csv, чтобы записать CSV-файл в данный объект добавления (см .: https://javadoc.io/doc/org.apache.commons/commons-csv/latest/org/apache/commons/csv/CSVPrinter.html)

package example;

import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVPrinter;

import java.io.IOException;

public class CSVCreator {

    public void createCSV(String someParamsYouNeedToCreateTheCSV, Appendable appendable) throws IOException {
        try (CSVPrinter printer = new CSVPrinter(appendable, CSVFormat.DEFAULT)) {
            printer.printRecord("Column1", "Column2", "Column3");
            printer.printRecord("Row1", "Row1", "Row1");
            printer.printRecord("Row2", "Row2", "Row2");
        }
    }
}

РЕДАКТИРОВАТЬ:

Вы можете создать CSV-файл из ResultSet, как это:

package example;

import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVPrinter;

import java.io.IOException;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;

public class ResultSetToCSV {

    public void createCSV(ResultSet rs, Appendable appendable) throws IOException, SQLException {
        final ResultSetMetaData metaData = rs.getMetaData();
        final int columnCount = metaData.getColumnCount();

        try (CSVPrinter printer = new CSVPrinter(appendable, CSVFormat.DEFAULT)) {
            printHeaders(metaData, columnCount, printer);
            printValues(rs, columnCount, printer);
        }
    }

    private void printHeaders(ResultSetMetaData metaData, int columnCount, CSVPrinter printer) throws IOException, SQLException {
        for (int i = 1; i <= columnCount; i++) {
            printer.print(metaData.getColumnLabel(i));
        }

        printer.println();
    }

    private void printValues(ResultSet rs, int columnCount, CSVPrinter printer) throws IOException, SQLException {
        while (rs.next()) {
            printValue(rs, columnCount, printer);
        }
    }

    private void printValue(ResultSet rs, int columnCount, CSVPrinter printer) throws IOException, SQLException {
        for (int i = 1; i <= columnCount; i++) {
            printer.print(rs.getString(i));
        }

        printer.println();
    }
}

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...