POI java 處理excel上傳圖片
阿新 • • 發佈:2019-02-10
在最近的專案開發中,遇到這樣一個需求,使用者匯入帶圖片的excel,excel批量匯入功能已做過很多了,帶圖片的是第一次嘗試,大概的要求有以下幾點:
- 所有excel中的圖片不能超出單元格,即必須在單元格內
- 所有圖片單個大小必須在1M以內
- 其中一列的單元格放入的圖片不能多於5張
- 其中一列的單元格為無限數量的圖片與不多於2000的字元
核心思路:獲取所有的圖片放入Map
/**
* 獲取Excel2003圖片
*
* @param sheet 當前sheet物件
* @param workbook 工作簿物件
* @return Map key:圖片左上角-右下角單元格索引+uuid(leftRow,leftCol_rightRow,rightCol_uuid)String,value:圖片流PictureData
*/
private Map<String, PictureData> getSheetPictrues03(HSSFSheet sheet, HSSFWorkbook workbook) {
Map<String, PictureData> sheetIndexPicMap = new HashMap<String, PictureData>();
// 獲取excel上所有的圖片
List<HSSFPictureData> pictures = workbook.getAllPictures();
if (pictures.size() != 0) {
HSSFPatriarch hp = sheet.getDrawingPatriarch();
List<HSSFShape> shapeList = hp.getChildren();
for (HSSFShape shape : shapeList) {
HSSFClientAnchor anchor = (HSSFClientAnchor) shape.getAnchor();
if (shape instanceof HSSFPicture) {
HSSFPicture pic = (HSSFPicture) shape;
int pictureIndex = pic.getPictureIndex() - 1;
HSSFPictureData picData = pictures.get(pictureIndex);
String picIndex = String.valueOf(anchor.getRow1()) + "," + String.valueOf(anchor.getCol1()) + "_"
+ anchor.getRow2() + "," + String.valueOf(anchor.getCol2()) + "_"
+ UUID.randomUUID();
// Map key:圖片左上角-右下角單元格索引+uuid(1,2_3,4_uuid),左上右下定位一張圖片
// leftRow,leftCol_rightRow,rightCol_uuid ,放入返回的Map時,拼接uuid標示唯一的圖片
sheetIndexPicMap.put(picIndex, picData);
}
}
}
return sheetIndexPicMap;
}
驗證關鍵程式碼
// 宣告的存放同一單元的圖片,方便後面判斷同一單元格圖片是否超過5張
Map<String, String> numTempMap = new HashMap<String, String>();
Object key[] = sheetIndexPicMap.keySet().toArray();
for (int i = 0; i < sheetIndexPicMap.size(); i++) {
String keyTemp = key[i].toString();
// 圖片左上角所在的行列
String leftTop = keyTemp.substring(0, keyTemp.indexOf("_"));
// 圖片右下角所在的行列
String rightBottom = keyTemp.substring(keyTemp.indexOf("_") + 1, keyTemp.lastIndexOf("_"));
int leftRow = Integer.parseInt(leftTop.substring(0, leftTop.indexOf(",")));
int leftCol = Integer.parseInt(leftTop.substring(leftTop.indexOf(",") + 1));
int rightRow = Integer.parseInt(rightBottom.substring(0, rightBottom.indexOf(",")));
int rightCol = Integer.parseInt(rightBottom.substring(rightBottom.indexOf(",") + 1));
int currentCol = leftCol;
int currentRow = leftRow;
// 左上角行與右下角行不相同 或 左上角列與右下角列不相同,即為圖片超出單元格
if (leftRow != rightRow || leftCol != rightCol) {
throw bizExceptions.create(CatalogError.ERROR_10001610, "圖片超出單元格!");
}
// 為使邏輯更清晰,分開兩種寫超出單元格的判斷,圖片不在4、5列的也為超出單元格
// 這裡我的實際需求是,只有第4、5列才能上傳圖片
if (!(leftCol == 4 || leftCol == 5)) {
throw bizExceptions.create(CatalogError.ERROR_10001610, "圖片超出單元格!");
}
PictureData pic = sheetIndexPicMap.get(key[i]);
byte[] data = pic.getData();
if (data.length / 1024.0 / 1024.0 > 3) {
throw bizExceptions.create(CatalogError.ERROR_10001608, "推薦描述圖片大小超過3M!");
}
// 這裡迴圈所有的圖片,同一單元的圖片放入同一key的Map中,後續根據判斷單元格的數量
if (!numTempMap.containsKey(currentRow + "")) {
for (int k = 0; k < sheetIndexPicMap.size(); k++) {
String keyTempk = key[k].toString();
String leftTopk = keyTempk.substring(0, keyTempk.indexOf("_"));
int currentRowk = Integer.parseInt(leftTopk.substring(0, leftTopk.indexOf(",")));
int currentColk = Integer.parseInt(leftTopk.substring(leftTopk.indexOf(",") + 1));
if (currentRow == currentRowk && currentColk == startCellNum) {
String productImgNumStr = numTempMap.get(currentRow + "");
int productImgNum = 0;
if (null != productImgNumStr) {
productImgNum = Integer.parseInt(productImgNumStr) + 1;
}
numTempMap.put(currentRow + "", productImgNum + "");
}
}
}
}
}
Object keyNum[] = numTempMap.keySet().toArray();
for (int i = 0; i < numTempMap.size(); i++) {
String productImgs = numTempMap.get(keyNum[i]);
if (null != productImgs && Integer.parseInt(productImgs) >= 5) {
throw bizExceptions.create(CatalogError.ERROR_10001609, "產品圖片數量超過5張!");
}
}
這種方式,個人覺得還是有點太消耗效能,本來就是批量匯入,一次性將所有圖片放入Map中,然後迴圈key,實際處理中應該是很慢的,筆者供職外包,無法檢視線上實際情況。………….