通過(guò) POI 將數(shù)據(jù)庫(kù)中的數(shù)據(jù)上傳至 OSS 對(duì)象存儲(chǔ)

通過(guò) POI 將數(shù)據(jù)庫(kù)中的數(shù)據(jù)上傳至 OSS 對(duì)象存儲(chǔ)

`我愛(ài)你扬绪,第一句是假的赴穗,第二句也是假的疏咐。`

表格的具體樣式可以參考 第三章

我們以 aliyun 的 OSS 為例上傳 上傳方法

一伺通、準(zhǔn)備工作

第一步:引入 Apache POI 的依賴

<!-- Maven 方式 -->

<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>4.0.0</version>
</dependency>
<!-- Gradle 方式 -->

compile group: 'org.apache.poi', name: 'poi', version: '4.0.0'

第二步:引入 JUnit 測(cè)試狂秦,這里就不做贅述了关带。

二、講解測(cè)試用例

Test方法

我們先從測(cè)試方法著手褥傍,再逐步講解測(cè)試中所用到的方法儡嘶。

@Autowired
private UserService userService;

@Test
public void upload(){
    List<User> users = userService.findAll(); // ①

    final ByteArrayOutputStream stream = exportProjectList(users); // ②

    String uri = uploadWorkbook(stream, "學(xué)生數(shù)據(jù)表.xlsx"); // ③

    System.out.println(uri); // ④
}
  1. 從數(shù)據(jù)庫(kù)中取出需要導(dǎo)入 Excel 的數(shù)據(jù)
  2. 方法:exportProjectList 將數(shù)據(jù)存入 POI 生成的 Excel 中,并將 Excel 轉(zhuǎn)換為字節(jié)流恍风,用來(lái)向對(duì)象存儲(chǔ)中上傳
  3. 方法:uploadWorkbook 上傳流式文件蹦狂,和文件名稱
  4. 輸出 aliyun 返回的地址,用于業(yè)務(wù)的實(shí)現(xiàn)朋贬,比如 保存至數(shù)據(jù)庫(kù) 等凯楔。

exportProjectList方法

作用:接收從數(shù)據(jù)庫(kù)查詢出來(lái)的對(duì)象集合,將其插入到 Workbook 中锦募,并生成二進(jìn)制的輸出流 ByteArrayOutputStream

表格的具體樣式可以參考 第三章

private ByteArrayOutputStream exportProjectList(User[] users) throws IOException {
        // Workbook 工作區(qū)
        final XSSFWorkbook workbook = new XSSFWorkbook();

        // 單字體居中樣式
        final XSSFCellStyle centerStyle = workbook.createCellStyle();
        centerStyle.setAlignment(HorizontalAlignment.CENTER);

        // 字體居中加粗樣式
        final XSSFCellStyle headerStyle = workbook.createCellStyle();
        headerStyle.setAlignment(HorizontalAlignment.CENTER);

        final XSSFFont font = workbook.createFont();
        font.setBold(true);
        headerStyle.setFont(font);

        // Sheet 分頁(yè)
        final XSSFSheet sheet = workbook.createSheet("Sheet Name");

        final String[] strings = new String[]{"序號(hào)", "學(xué)號(hào)", "姓名", "年齡", "院系", "班級(jí)"};

        // 首行內(nèi)容填充摆屯,以及設(shè)置樣式
        setFirstRow(sheet, strings, headerStyle);

        int rowSign = 0;
        for (user user : users) {

            // Row 行
            final XSSFRow row = sheet.createRow(++rowSign);

            // Cell 單元格
            final XSSFCell firstCell = row.createCell(0);
            firstCell.setCellValue(rowSign);
            firstCell.setCellStyle(centerStyle);

            final XSSFCell secondCell = row.createCell(1);
            secondCell.setCellValue(user.getStuNo());
            secondCell.setCellStyle(centerStyle);

            final XSSFCell thirdCell = row.createCell(2);
            thirdCell.setCellValue(user.getName());
            thirdCell.setCellStyle(centerStyle);

            final XSSFCell fourthCell = row.createCell(3);
            fourthCell.setCellValue(user.getAge());
            fourthCell.setCellStyle(centerStyle);

            final XSSFCell fifthCell = row.createCell(4);
            fifthCell.setCellValue(user.getCollege());
            fifthCell.setCellStyle(centerStyle);

            final XSSFCell sixthCell = row.createCell(5);
            sixthCell.setCellValue(user.getClass());
            sixthCell.setCellStyle(centerStyle);
        }

        // 寬度自適應(yīng)
        for (int s = 0; s < strings.length; s++) {
            sheet.autoSizeColumn(s);
            sheet.setColumnWidth(s, sheet.getColumnWidth(s) * 17 / 10);
        }

        final ByteArrayOutputStream stream = new ByteArrayOutputStream();

        workbook.write(stream);

        return stream;
    }

需要注意的是,每一個(gè)單元格 (Cell) 都是不能為空的御滩。

我們將設(shè)置頭標(biāo)題的方法抽離出來(lái)鸥拧,可供其他設(shè)置的方法使用党远。

/**
 * 設(shè)置第一行的頭標(biāo)題
 */
private void setFirstRow(Sheet sheet, String[] cellTitles, XSSFCellStyle headerStyle) {
    final Row row = sheet.createRow(0);

    int cellSign = 0;

    for (String cellName : cellTitles) {
        final Cell cell = row.createCell(cellSign++);
        cell.setCellValue(cellName);
        cell.setCellStyle(headerStyle);
    }
}

在做完前面的工作之后削解,我們就可以開(kāi)始寫(xiě)測(cè)試方法了

uploadWorkbook方法

該方法用于:接收 Workbook 生成的流富弦,并將其保存至 OSS 上,本方法適用于 aliyunOSS 對(duì)象存儲(chǔ)氛驮,其他的具體實(shí)現(xiàn)都可以從官方API中查到腕柜。

private String uploadWorkbook(ByteArrayOutputStream stream, String fileId) throws IOException {
    final ByteArrayInputStream inputStream = new ByteArrayInputStream(stream.toByteArray()); // ①

    ObjectMetadata objectMetadata = new ObjectMetadata();
    objectMetadata.setContentLength(stream.size());
    objectMetadata.setContentEncoding("utf-8");
    objectMetadata.setCacheControl("no-cache");
    objectMetadata.setHeader("Pragma", "no-cache");
    objectMetadata.setContentDisposition("inline;filename=" + "學(xué)生表數(shù)據(jù).xlsx"); // ②

    return ossCore.uploadByStream(fileId, objectMetadata, inputStream); // ③
}
  1. 將輸出流轉(zhuǎn)換為輸入流
  2. 保存對(duì)象的媒體信息
  3. 上傳至 aliyunOSS 對(duì)象存儲(chǔ),具體實(shí)現(xiàn)可以看 第四部分

三矫废、設(shè)置Excel單元格樣式

創(chuàng)建sheet

HSSFCellStyle cellStyle = wb.createCellStyle();  

一盏缤、設(shè)置背景色:

cellStyle.setFillForegroundColor((short) 13);// 設(shè)置背景色  
cellStyle.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);  

二、設(shè)置邊框:

cellStyle.setBorderBottom(HSSFCellStyle.BORDER_THIN); //下邊框  
cellStyle.setBorderLeft(HSSFCellStyle.BORDER_THIN);//左邊框  
cellStyle.setBorderTop(HSSFCellStyle.BORDER_THIN);//上邊框  
cellStyle.setBorderRight(HSSFCellStyle.BORDER_THIN);//右邊框  

三蓖扑、設(shè)置居中:

cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER); // 居中  

四唉铜、設(shè)置字體:

HSSFFont font = wb.createFont();  
font.setFontName("黑體");  
font.setFontHeightInPoints((short) 16);//設(shè)置字體大小  
  
HSSFFont font2 = wb.createFont();  
font2.setFontName("仿宋_GB2312");  
font2.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);//粗體顯示  
font2.setFontHeightInPoints((short) 12);  
  
cellStyle.setFont(font);//選擇需要用到的字體格式  

五、設(shè)置列寬:

sheet.setColumnWidth(0, 3766); //第一個(gè)參數(shù)代表列id(從0開(kāi)始),第2個(gè)參數(shù)代表寬度值  參考 :"2012-08-10"的寬度為2500  

六律杠、設(shè)置自動(dòng)換行:

cellStyle.setWrapText(true);//設(shè)置自動(dòng)換行  

七潭流、合并單元格:

Region region1 = new Region(0, (short) 0, 0, (short) 6);//參數(shù)1:行號(hào) 參數(shù)2:起始列號(hào) 參數(shù)3:行號(hào) 參數(shù)4:終止列號(hào)
//此方法在POI3.8中已經(jīng)被廢棄,建議使用下面一個(gè)  
或者用

CellRangeAddress region1 = new CellRangeAddress(rowNumber, rowNumber, (short) 0, (short) 11);

//參數(shù)1:起始行 參數(shù)2:終止行 參數(shù)3:起始列 參數(shù)4:終止列
但應(yīng)注意兩個(gè)構(gòu)造方法的參數(shù)不是一樣的柜去,具體使用哪個(gè)取決于POI的不同版本灰嫉。


sheet.addMergedRegion(region1);

四、上傳至OSS等對(duì)象存儲(chǔ)

作用:上傳 stream流 至 OSS

public String uploadByStream(String fileId, ObjectMetadata metadata, InputStream in) {
        String ossUrl = null;
        OSSClient ossClient = new OSSClient(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET);
        ossClientMap.put(fileId, ossClient);
        try {
            putUploadProgress(fileId, 0);
            PutObjectRequest req = new PutObjectRequest(OssConnectionUtil.getBucketName(), fileId, in, metadata);
            req.setProgressListener(new UploadProgressListener(req));
            PutObjectResult putResult = ossClient.putObject(req);
            if (putResult.getETag() != null) {
                ossUrl =  getOssURL(ossClient, fileId);
            }
            return ossUrl;
        } catch(ClientException ce) {
            return null;
        } catch (Exception e) {
            return null;
        } finally {
            ossClient.shutdown();
            ossClientMap.remove(fileId);
        }
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末嗓奢,一起剝皮案震驚了整個(gè)濱河市讼撒,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌股耽,老刑警劉巖根盒,帶你破解...
    沈念sama閱讀 221,820評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異物蝙,居然都是意外死亡郑象,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,648評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)茬末,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)厂榛,“玉大人,你說(shuō)我怎么就攤上這事丽惭』髂蹋” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,324評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵责掏,是天一觀的道長(zhǎng)柜砾。 經(jīng)常有香客問(wèn)我,道長(zhǎng)换衬,這世上最難降的妖魔是什么痰驱? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,714評(píng)論 1 297
  • 正文 為了忘掉前任证芭,我火速辦了婚禮,結(jié)果婚禮上担映,老公的妹妹穿的比我還像新娘废士。我一直安慰自己,他們只是感情好蝇完,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,724評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布官硝。 她就那樣靜靜地躺著,像睡著了一般短蜕。 火紅的嫁衣襯著肌膚如雪氢架。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,328評(píng)論 1 310
  • 那天朋魔,我揣著相機(jī)與錄音岖研,去河邊找鬼。 笑死警检,一個(gè)胖子當(dāng)著我的面吹牛孙援,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播解滓,決...
    沈念sama閱讀 40,897評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼赃磨,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了洼裤?” 一聲冷哼從身側(cè)響起邻辉,我...
    開(kāi)封第一講書(shū)人閱讀 39,804評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎腮鞍,沒(méi)想到半個(gè)月后值骇,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,345評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡移国,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,431評(píng)論 3 340
  • 正文 我和宋清朗相戀三年吱瘩,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片迹缀。...
    茶點(diǎn)故事閱讀 40,561評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡使碾,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出祝懂,到底是詐尸還是另有隱情票摇,我是刑警寧澤,帶...
    沈念sama閱讀 36,238評(píng)論 5 350
  • 正文 年R本政府宣布砚蓬,位于F島的核電站矢门,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜祟剔,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,928評(píng)論 3 334
  • 文/蒙蒙 一隔躲、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧物延,春花似錦宣旱、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,417評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)驾霜。三九已至案训,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間粪糙,已是汗流浹背强霎。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,528評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蓉冈,地道東北人城舞。 一個(gè)月前我還...
    沈念sama閱讀 48,983評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像寞酿,于是被迫代替她去往敵國(guó)和親家夺。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,573評(píng)論 2 359