成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

想在Java中實(shí)現(xiàn)Excel和Csv的導(dǎo)出嗎?看這就對(duì)了

olle / 656人閱讀

摘要:將查詢到的結(jié)果生成和文件,再以字節(jié)流的形式返回給前端。則是用于創(chuàng)建字節(jié)輸出流,在導(dǎo)出文件的代碼結(jié)尾,通過(guò)工具類中的復(fù)制文件函數(shù)將字節(jié)流寫入到輸出流中,從而將文件以字節(jié)流的形式返回給客戶端。

title: 想在Java中實(shí)現(xiàn)Excel和Csv的導(dǎo)出嗎?看這就對(duì)了
date: 2019-03-01 20:07:07
tags: Java
keywords: Java導(dǎo)出Excel和Csv

description: 前言

最近在項(xiàng)目中遇到一個(gè)需求,需要后端提供一個(gè)下載Csv和Excel表格的接口。這個(gè)接口接收前端的查詢參數(shù),針對(duì)這些參數(shù)對(duì)數(shù)據(jù)庫(kù)做查詢操作。將查詢到的結(jié)果生成Excel和Csv文件,再以字節(jié)流的形式返回給前端。

前端拿到這個(gè)流文件之后,最開(kāi)始用ajax來(lái)接收,但是前端發(fā)送的請(qǐng)求卻被瀏覽器cancel掉了。后來(lái)發(fā)現(xiàn),發(fā)展了如此之久的Ajax居然不支持流文件下載。后來(lái)前端換成了最原始的XMLHttpRequest,才修復(fù)了這個(gè)問(wèn)題。

首先給出項(xiàng)目源碼的地址。這是源碼,歡迎大家star或者提MR。

Csv 新建controller

先來(lái)一個(gè)簡(jiǎn)單的例子。首先在controller中新建這樣一個(gè)接口。

@GetMapping("csv")
public void csv(
        HttpServletRequest request,
        HttpServletResponse response
) throws IOException {
    String fileName = this.getFileName(request, "測(cè)試數(shù)據(jù).csv");
    response.setContentType(MediaType.APPLICATION_OCTET_STREAM.toString());
    response.setHeader("Content-Disposition", "attachment; filename="" + fileName + "";");

    LinkedHashMap header = new LinkedHashMap<>();
    LinkedHashMap body = new LinkedHashMap<>();
    header.put("1", "姓名");
    header.put("2", "年齡");
    List> 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, "測(cè)試數(shù)據(jù).csv")函數(shù)是用來(lái)獲取導(dǎo)出文件名的函數(shù)。多帶帶提出來(lái)是因?yàn)椴煌瑸g覽器使用的默認(rèn)的編碼不同。例如,如果使用默認(rèn)的UTF-8編碼。在chrome瀏覽器中下載會(huì)出現(xiàn)中文亂碼。代碼如下。

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()則是用于創(chuàng)建字節(jié)輸出流,在導(dǎo)出csv文件的controller代碼結(jié)尾,通過(guò)工具類中的復(fù)制文件函數(shù)將字節(jié)流寫入到輸出流中,從而將csv文件以字節(jié)流的形式返回給客戶端。

當(dāng)前端通過(guò)http請(qǐng)求訪問(wèn)服務(wù)器接口的時(shí)候,http中的所有的請(qǐng)求信息都會(huì)封裝在HttpServletRequest對(duì)象中。例如,你可以通過(guò)這個(gè)對(duì)象獲取到請(qǐng)求的URL地址,請(qǐng)求的方式,請(qǐng)求的客戶端IP和完整主機(jī)名,Web服務(wù)器的IP和完整主機(jī)名,請(qǐng)求行中的參數(shù),獲取請(qǐng)求頭的參數(shù)等等。

針對(duì)每一次的HTTP請(qǐng)求,服務(wù)器會(huì)自動(dòng)創(chuàng)建一個(gè)HttpServletResponse對(duì)象和請(qǐng)求對(duì)象相對(duì)應(yīng)。響應(yīng)對(duì)象可以對(duì)當(dāng)前的請(qǐng)求進(jìn)行重定向,自定義響應(yīng)體的頭部,設(shè)置返回流等等。

新建導(dǎo)出工具類

我們新建一個(gè)導(dǎo)出工具類,來(lái)專門負(fù)責(zé)導(dǎo)出各種格式的文件。代碼如下。

public class ExportUtil {

    public static byte[] exportCSV(List> exportData) {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        BufferedWriter buffCvsWriter = null;
        try {
            buffCvsWriter = new BufferedWriter(new OutputStreamWriter(out, StandardCharsets.UTF_8));
            // 將body數(shù)據(jù)寫入表格
            for (Iterator> 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 propertyIterator = row.entrySet().iterator(); propertyIterator.hasNext(); ) {
            propertyEntry = propertyIterator.next();
            buffCvsWriter.write(""" + propertyEntry.getValue().toString() + """);
            if (propertyIterator.hasNext()) {
                buffCvsWriter.write(",");
            }
        }
    }
}

fillDataToCsv主要是抽離出來(lái)為csv填充一行一行的數(shù)據(jù)的。

運(yùn)行

然后運(yùn)行項(xiàng)目,調(diào)用http://localhost:8080/csv,就可以下載示例的csv文件。示例如下。

Excel 新建controller

新建下載xlsx文件的接口。

@GetMapping("xlsx")
public void xlsx(
        HttpServletRequest request,
        HttpServletResponse response
) throws IOException {
    String fileName = this.getFileName(request, "測(cè)試數(shù)據(jù).xlsx");
    response.setContentType(MediaType.APPLICATION_OCTET_STREAM.toString());
    response.setHeader("Content-Disposition", "attachment; filename="" + fileName + "";");

    List> datas = new ArrayList<>();
    LinkedHashMap 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>> tableData = new HashMap<>();
    tableData.put("日?qǐng)?bào)表", datas);
    tableData.put("周報(bào)表", datas);
    tableData.put("月報(bào)表", datas);

    FileCopyUtils.copy(ExportUtil.exportXlsx(tableData), response.getOutputStream());
}
補(bǔ)充工具類

上面新建的導(dǎo)出工具類中,只有導(dǎo)出csv的函數(shù),接下來(lái)我們要添加導(dǎo)出xlsx的函數(shù)。

public static byte[] exportXlsx(Map>> tableData) {
    ByteArrayOutputStream out = new ByteArrayOutputStream();

    try {
        HSSFWorkbook workbook = new HSSFWorkbook();
        // 創(chuàng)建多個(gè)sheet
        for (Map.Entry>> entry : tableData.entrySet()) {
            fillDataToXlsx(workbook.createSheet(entry.getKey()), entry.getValue());
        }

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

/**
 * 將linkedHashMap中的數(shù)據(jù),寫入xlsx表格中
 *
 * @param sheet
 * @param data
 */
private static void fillDataToXlsx(HSSFSheet sheet, List> data) {
    HSSFRow currRow;
    HSSFCell cell;
    LinkedHashMap row;
    Map.Entry propertyEntry;
    int rowIndex = 0;
    int cellIndex = 0;
    for (Iterator> iterator = data.iterator(); iterator.hasNext(); ) {
        row = iterator.next();
        currRow = sheet.createRow(rowIndex++);
        for (Iterator 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文件的每一行刷上數(shù)據(jù)。

運(yùn)行

然后運(yùn)行項(xiàng)目,調(diào)用http://localhost:8080/xlsx,就可以下載示例的csv文件。示例如下。

項(xiàng)目地址

最后再次給出項(xiàng)目地址,大家如果沒(méi)有理解到其中的一些地方,不妨把項(xiàng)目clone下來(lái),自己親自操作一波。

參考

這是在解決請(qǐng)求被瀏覽器cancel掉的過(guò)程中,很重要的一個(gè)參考,分享給大家。

https://www.cnblogs.com/cdemo...

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/73642.html

相關(guān)文章

  • 【HTML5版】導(dǎo)出Table數(shù)據(jù)并保存為Excel

    摘要:首發(fā)我的博客最近接到這么個(gè)需求,要把顯示的數(shù)據(jù)導(dǎo)出成表。之,發(fā)現(xiàn)又成了一座分水嶺。后來(lái)開(kāi)放標(biāo)準(zhǔn),可以導(dǎo)出格式的文件,就有了用武之地,導(dǎo)出數(shù)據(jù)并保存為有了更好的選擇。輸出內(nèi)容套用模版之后,我們就有了完整的表格數(shù)據(jù)。至此,此項(xiàng)功能宣告圓滿。 首發(fā)我的博客 http://blog.meathill.com/tech/js/export-table-data-into-a-excel-f...

    abson 評(píng)論0 收藏0
  • Vue 2019開(kāi)發(fā)者圖譜

    摘要:為了便于您更清晰的理解的體系架構(gòu),在這里我將為您展示年開(kāi)發(fā)者知識(shí)圖譜,它包含了所有開(kāi)發(fā)過(guò)程中的關(guān)鍵部分。在數(shù)據(jù)展示前端導(dǎo)入導(dǎo)出圖表面板數(shù)據(jù)綁定等場(chǎng)景無(wú)需大量代碼開(kāi)發(fā)和測(cè)試,可極大節(jié)省企業(yè)研發(fā)成本并降低交付風(fēng)險(xiǎn)。 作為 Vue 的初學(xué)者,您或許已經(jīng)聽(tīng)過(guò)很多關(guān)于它的專業(yè)術(shù)語(yǔ)了,例如:?jiǎn)雾?yè)面應(yīng)用程序、異步組件、服務(wù)器端呈現(xiàn)等,您可能還聽(tīng)過(guò)和Vue經(jīng)常一起被提到的工具和庫(kù),如Vuex、Webp...

    cgspine 評(píng)論0 收藏0
  • 在 Laravel 5 中使用 Laravel Excel 實(shí)現(xiàn) Excel/CSV 文件導(dǎo)入導(dǎo)出

    摘要:本文非原創(chuàng),基于學(xué)院在中使用實(shí)現(xiàn)文件導(dǎo)入導(dǎo)出功能這篇文章在實(shí)際中測(cè)試調(diào)整。簡(jiǎn)介在中集成套件中的,從而方便我們以優(yōu)雅的富有表現(xiàn)力的代碼實(shí)現(xiàn)文件的導(dǎo)入和導(dǎo)出。 本文非原創(chuàng),基于laravel 學(xué)院《在 Laravel 5 中使用 Laravel Excel 實(shí)現(xiàn) Excel/CSV 文件導(dǎo)入導(dǎo)出功能》 這篇文章在實(shí)際中測(cè)試調(diào)整。 showImg(https://segmentfault.c...

    XFLY 評(píng)論0 收藏0
  • JavaScript中錯(cuò)誤正確處理方式,你用對(duì)了

    摘要:?jiǎn)卧獪y(cè)試會(huì)體現(xiàn)出以上錯(cuò)誤處理程序的作用如果出現(xiàn)問(wèn)題,錯(cuò)誤處理程序就會(huì)返回。同時(shí)錯(cuò)誤會(huì)展開(kāi)堆棧,這對(duì)調(diào)試非常有幫助。展開(kāi)堆棧處理異常的一種方式是在調(diào)用堆棧的頂部加入。確保你的錯(cuò)誤處理處在相同域中,這樣會(huì)保留原始消息,堆棧和自定義錯(cuò)誤對(duì)象。 JavaScript的事件驅(qū)動(dòng)范式增添了豐富的語(yǔ)言,也是讓使用JavaScript編程變得更加多樣化。如果將瀏覽器設(shè)想為JavaScript的事件驅(qū)動(dòng)...

    chaos_G 評(píng)論0 收藏0
  • PHP高效導(dǎo)出Excel(CSV)

    摘要:,是逗號(hào)分隔值的英文縮寫,通常都是純文本文件。如果你導(dǎo)出的沒(méi)有什么高級(jí)用法的話,只是做導(dǎo)出數(shù)據(jù)用那么建議使用本方法要比要高效的多。二十萬(wàn)數(shù)據(jù)導(dǎo)出大概需要到秒。 CSV,是Comma Separated Value(逗號(hào)分隔值)的英文縮寫,通常都是純文本文件。如果你導(dǎo)出的Excel沒(méi)有什么高級(jí)用法的話,只是做導(dǎo)出數(shù)據(jù)用那么建議使用本方法,要比PHPexcel要高效的多。二十萬(wàn)數(shù)據(jù)導(dǎo)出大概...

    DoINsiSt 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<