通過(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); // ④
}
- 從數(shù)據(jù)庫(kù)中取出需要導(dǎo)入 Excel 的數(shù)據(jù)
- 方法:
exportProjectList
將數(shù)據(jù)存入POI
生成的 Excel 中,并將 Excel 轉(zhuǎn)換為字節(jié)流恍风,用來(lái)向對(duì)象存儲(chǔ)
中上傳 - 方法:
uploadWorkbook
上傳流式文件蹦狂,和文件名稱 - 輸出
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 上
,本方法適用于 aliyun
的 OSS 對(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); // ③
}
- 將輸出流轉(zhuǎn)換為輸入流
- 保存對(duì)象的媒體信息
- 上傳至
aliyun
的OSS
對(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);
}
}