Хотите реализовать экспорт Excel и Csv в Java? Смотри, это правильно

Java

предисловие

Недавно я столкнулся с требованием в проекте, которое требует, чтобы серверная часть предоставляла интерфейс для загрузки таблиц Csv и Excel. Этот интерфейс получает параметры запроса внешнего интерфейса и выполняет операции запроса к базе данных в соответствии с этими параметрами. Результаты запроса генерируются в файлы Excel и Csv, а затем возвращаются во внешний интерфейс в виде потоков байтов.

После того, как внешний интерфейс получил потоковый файл, он изначально был получен с помощью ajax, но запрос, отправленный внешним интерфейсом, был отменен браузером. Позже выяснилось, что Ajax, который так долго разрабатывался, не поддерживает потоковую загрузку файлов. Позже фронтенд заменили на максимально примитивный XMLHttpRequest, что устранило эту проблему.

Сначала дайте адрес исходного кода проекта. Этоисходный код, Добро пожаловать, чтобы отметить или упомянуть MR.

Csv

новый контроллер

Начнем с простого примера. Сначала создайте такой интерфейс в контроллере.

@GetMapping("csv")
public void csv(
        HttpServletRequest request,
        HttpServletResponse response
) throws IOException {
    String fileName = this.getFileName(request, "测试数据.csv");
    response.setContentType(MediaType.APPLICATION_OCTET_STREAM.toString());
    response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\";");

    LinkedHashMap<String, Object> header = new LinkedHashMap<>();
    LinkedHashMap<String, Object> body = new LinkedHashMap<>();
    header.put("1", "姓名");
    header.put("2", "年龄");
    List<LinkedHashMap<String, Object>> data = new ArrayList<>();
    body.put("1", "小明");
    body.put("2", "小王");
    data.add(header);
    data.add(body);
    data.add(body);
    data.add(body);
    FileCopyUtils.copy(ExportUtil.exportCSV(data), response.getOutputStream());
}

вthis.getFileName(request, "测试数据.csv")function — это функция, используемая для получения имени экспортируемого файла. Он поднимается отдельно, потому что разные браузеры используют разные кодировки по умолчанию. Например, при использовании кодировки UTF-8 по умолчанию. При загрузке в браузере Chrome появляются искаженные китайские символы. код показывает, как показано ниже.

private String getFileName(HttpServletRequest request, String name) throws UnsupportedEncodingException {
    String userAgent = request.getHeader("USER-AGENT");
    return userAgent.contains("Mozilla") ? new String(name.getBytes(), "ISO8859-1") : name;
}

response.getOutputStream()Он используется для создания потока вывода байтов.В конце кода контроллера, который экспортирует файл csv, поток байтов записывается в поток вывода через функцию копирования файла в классе инструмента, так что файл csv возвращается в вид потока байтов на выходной поток.клиент.

Когда внешний интерфейс обращается к интерфейсу сервера через http-запрос, вся информация запроса в http будет инкапсулирована вHttpServletRequestв объекте. Например, вы можете использовать этот объект для получения URL-адреса запроса, метода запроса, запрошенного IP-адреса клиента и полного имени хоста, IP-адреса и полного имени хоста веб-сервера, параметров в строке запроса, параметры для получения заголовка запроса и т.д.

Для каждого HTTP-запроса сервер автоматически создаетHttpServletResponseОбъект соответствует объекту запроса. Объект ответа может перенаправить текущий запрос, настроить заголовок тела ответа, задать поток возврата и т. д.

Новый класс инструментов экспорта

Мы создаем новый класс инструмента экспорта, который будет отвечать за экспорт файлов в различные форматы. код показывает, как показано ниже.

public class ExportUtil {

    public static byte[] exportCSV(List<LinkedHashMap<String, Object>> exportData) {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        BufferedWriter buffCvsWriter = null;
        try {
            buffCvsWriter = new BufferedWriter(new OutputStreamWriter(out, StandardCharsets.UTF_8));
            // 将body数据写入表格
            for (Iterator<LinkedHashMap<String, Object>> iterator = exportData.iterator(); iterator.hasNext(); ) {
                fillDataToCsv(buffCvsWriter, iterator.next());
                if (iterator.hasNext()) {
                    buffCvsWriter.newLine();
                }
            }
            // 刷新缓冲
            buffCvsWriter.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 释放资源
            if (buffCvsWriter != null) {
                try {
                    buffCvsWriter.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return out.toByteArray();
    }

    private static void fillDataToCsv(BufferedWriter buffCvsWriter, LinkedHashMap row) throws IOException {
        Map.Entry propertyEntry;
        for (Iterator<Map.Entry> propertyIterator = row.entrySet().iterator(); propertyIterator.hasNext(); ) {
            propertyEntry = propertyIterator.next();
            buffCvsWriter.write("\"" + propertyEntry.getValue().toString() + "\"");
            if (propertyIterator.hasNext()) {
                buffCvsWriter.write(",");
            }
        }
    }
}

fillDataToCsvВ основном извлекается и заполняется данными построчно для csv.

бегать

Затем запустите проект и вызовите http://localhost:8080/csv, чтобы загрузить пример CSV-файла. Примеры следующие.

Excel

новый контроллер

Создайте новый интерфейс для загрузки файлов xlsx.

@GetMapping("xlsx")
public void xlsx(
        HttpServletRequest request,
        HttpServletResponse response
) throws IOException {
    String fileName = this.getFileName(request, "测试数据.xlsx");
    response.setContentType(MediaType.APPLICATION_OCTET_STREAM.toString());
    response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\";");

    List<LinkedHashMap<String, Object>> datas = new ArrayList<>();
    LinkedHashMap<String, Object> data = new LinkedHashMap<>();
    data.put("1", "姓名");
    data.put("2", "年龄");
    datas.add(data);
    for (int i = 0; i < 5; i++) {
        data = new LinkedHashMap<>();
        data.put("1", "小青");
        data.put("2", "小白");
        datas.add(data);
    }

    Map<String, List<LinkedHashMap<String, Object>>> tableData = new HashMap<>();
    tableData.put("日报表", datas);
    tableData.put("周报表", datas);
    tableData.put("月报表", datas);

    FileCopyUtils.copy(ExportUtil.exportXlsx(tableData), response.getOutputStream());
}

Дополнительные инструменты

В новом классе инструментов экспорта выше есть только функция для экспорта в csv, а затем нам нужно добавить функцию для экспорта в xlsx.

public static byte[] exportXlsx(Map<String, List<LinkedHashMap<String, Object>>> tableData) {
    ByteArrayOutputStream out = new ByteArrayOutputStream();

    try {
        HSSFWorkbook workbook = new HSSFWorkbook();
        // 创建多个sheet
        for (Map.Entry<String, List<LinkedHashMap<String, Object>>> entry : tableData.entrySet()) {
            fillDataToXlsx(workbook.createSheet(entry.getKey()), entry.getValue());
        }

        workbook.write(out);
    } catch (IOException e) {
        e.printStackTrace();
    }
    return out.toByteArray();
}

/**
 * 将linkedHashMap中的数据,写入xlsx表格中
 *
 * @param sheet
 * @param data
 */
private static void fillDataToXlsx(HSSFSheet sheet, List<LinkedHashMap<String, Object>> data) {
    HSSFRow currRow;
    HSSFCell cell;
    LinkedHashMap row;
    Map.Entry propertyEntry;
    int rowIndex = 0;
    int cellIndex = 0;
    for (Iterator<LinkedHashMap<String, Object>> iterator = data.iterator(); iterator.hasNext(); ) {
        row = iterator.next();
        currRow = sheet.createRow(rowIndex++);
        for (Iterator<Map.Entry> propertyIterator = row.entrySet().iterator(); propertyIterator.hasNext(); ) {
            propertyEntry = propertyIterator.next();
            if (propertyIterator.hasNext()) {
                String value = String.valueOf(propertyEntry.getValue());
                cell = currRow.createCell(cellIndex++);
                cell.setCellValue(value);
            } else {
                String value = String.valueOf(propertyEntry.getValue());
                cell = currRow.createCell(cellIndex++);
                cell.setCellValue(value);
                break;
            }
        }
        if (iterator.hasNext()) {
            cellIndex = 0;
        }
    }
}

fillDataToXlsxЦель та же, что и у csv, очищая данные для каждой строки файла xlsx.

бегать

Затем запустите проект и вызовите http://localhost:8080/xlsx, чтобы загрузить образец CSV-файла. Примеры следующие.

адрес проекта

Наконец, дайте сноваадрес проекта, Если мы не понимаем в некоторых местах, которые, возможно, пожелают клонировать проект вниз, лично управляйте волной.

Ссылаться на

Это очень важная ссылка в процессе решения запроса, отменяемого браузером, и я поделюсь ею с вами.

  • https://www.cnblogs.com/cdemo/p/5225848.html