本文将在导入Excel时获取其浮动在单元格内的图片(嵌入单元格获取不到),并下载到本地。导出也是浮动式图片。这里只提供导入图片部分的代码,仅供参考。与导入图片无关的代码部分已进行删除,如报错请忽略,关注导入图片业务即可。
业务层代码
/**
* 导出Excel XSSFWorkbook
*
* @param workbook 工作簿 XSSFWorkbook格式
* @param dataList 数据集合
* @param fieldList 字段集合
* @param sheetName 工作表名称
*/
public Result> importExcel(HttpServletRequest request, HttpServletResponse response, String processDefinitionKey) {
long startTime = System.currentTimeMillis();
LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
try {
formFieldList = listFormFields(formType, processDefinition.getFormId(), null);
} catch (Exception e) {
log.error(e.getMessage(), e);
return Result.error("查询表单字段失败!");
}
// 文件处理
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
List errorMessageList = new ArrayList<>();
Map fileMap = multipartRequest.getFileMap();
for (Map.Entry entity : fileMap.entrySet()) {
MultipartFile file = entity.getValue();
try {
// 读取excel
ExcelReader reader = ExcelUtil.getReader(file.getInputStream());
List
importSingleProcessInstance
/**
* 导入单个流程实例
*
* @param processDefinitionKey 流程定义key
* @param user 登录用户
* @param processDefinition 流程定义
* @param formType 表单类型
* @param formId 表单id
* @param formFieldList 表单字段
* @param pictureDataList 图片数据
* @param map excel数据
* @param num 行数
*/
@Transactional(rollbackFor = Exception.class)
public void importSingleProcessInstance(String processDefinitionKey, LoginUser user, BpmProcessDefinitionExtDO processDefinition, Integer formType, String formId, List> formFieldList, List>> pictureDataList, Map map, int num) throws Exception {
Map form = new HashMap<>();
// 列索引
int columnNum = 0;
// 定义图片路径列表
List picPathList = new ArrayList<>();
try {
for (Map.Entry entry : map.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
for (Map formField : formFieldList) {
// 如果是必填字段,去掉excel表头中的*号并判断数据是否为空,为空则抛出异常
if (null != formField.get("mustFlag") && formField.get("mustFlag").equals("1")) {
key = key.replace("*", "");
}
if (key.equals(formField.get("name"))) {
// mustFlag为1表示必填字段,如果为空则抛出异常
boolean isMustField = null != formField.get("mustFlag") && "1".equals(formField.get("mustFlag"));
boolean isValueEmpty = value == null || "".equals(value);
if (isMustField && isValueEmpty) {
throw new JeecgBootException(formField.get("name") + "不能为空");
}
String code = formField.get("code");
// 图片处理
if (CollUtil.isNotEmpty(pictureDataList) && pictureDataList.size() > 0) {
String picPath = ExcelHutoolUtil.readPic(pictureDataList, num, columnNum);
if (StrUtil.isNotEmpty(picPath)) {
value = picPath;
// 保存图片路径
String[] split = picPath.split(",");
for (String s : split) {
picPathList.add(s);
}
}
}
form.put(code, value);
break;
}
}
columnNum++;
}
if (form.size() == 0) {
throw new JeecgBootException("第" + num + "行数据不符合规范!");
}
} catch (Exception e) {
e.printStackTrace();
// 删除图片,判断picPathList是否为空,不为空则删除图片
if (CollUtil.isNotEmpty(picPathList)) {
picPathList.stream().map(picPath -> excelHutoolUtil.getPicObjectName(picPath)).forEach(picObjectName -> MinioUtil.removeObject(MinioUtil.getBucketName(), picObjectName));
}
throw new JeecgBootException(e.getMessage());
}
}
ExcelUtil
/**
* 读取图片
*
* @param pictureDataList 图片集合
* @param rowIndex 图片所在单元格的行
* @param columnIndex 图片所在单元格的列
* @return String 图片路径
* @throws Exception
*/
public static String readPic(List>> pictureDataList, int rowIndex, int columnIndex) throws Exception {
if (pictureDataList == null || pictureDataList.isEmpty()) {
return null;
}
String key = rowIndex + "-" + columnIndex;
for (Map> map : pictureDataList) {
if (map.containsKey(key)) {
List pictureList = map.get(key);
String[] filePaths = new String[pictureList.size()];
for (int i = 0; i < pictureList.size(); i++) {
PictureData picture = pictureList.get(i);
byte[] imageData = picture.getData();
String fileExtension = picture.suggestFileExtension();
InputStream inputStream = new ByteArrayInputStream(imageData);
String fileName = UUID.randomUUID().toString().replaceAll("-", "");
fileName = fileName + "." + fileExtension;
MultipartFile multipartFile = new MockMultipartFile(fileName, fileName, ContentType.APPLICATION_OCTET_STREAM.toString(), inputStream);
String filePath = MinioUtil.upload(multipartFile, "temp");
filePaths[i] = filePath;
}
// 匹配成功,去掉图片数据
map.remove(key);
return String.join(",", filePaths);
}
}
return null;
}
/**
* 获取工作表Sheet的所有图片,并设置key为图片所在单元格的行索引+列索引,value为图数据
*
* @param sheet 工作表
* @return List>> 图片集合
*/
public static List>> listSheetPicture(Sheet sheet) {
List>> pictureList = new ArrayList<>();
Workbook workbook = sheet.getWorkbook();
ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
if (workbook instanceof HSSFWorkbook) {
HSSFSheet hssfSheet = (HSSFSheet) sheet;
HSSFPatriarch drawingPatriarch = hssfSheet.getDrawingPatriarch();
if (null == drawingPatriarch) {
return pictureList;
}
List hssfShapeList = drawingPatriarch.getChildren();
ConcurrentHashMap> map = new ConcurrentHashMap<>();
for (HSSFShape shape : hssfShapeList) {
if (shape instanceof HSSFPicture) {
executor.submit(() -> {
HSSFClientAnchor anchor = (HSSFClientAnchor) shape.getAnchor();
HSSFPicture picture = (HSSFPicture) shape;
HSSFPictureData pictureData = picture.getPictureData();
String key = anchor.getRow1() + "-" + anchor.getCol1();
if (map.containsKey(key)) {
map.get(key).add(pictureData);
} else {
List dataList = new ArrayList<>();
dataList.add(pictureData);
map.put(key, dataList);
}
});
}
}
executor.shutdown();
try {
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (!map.isEmpty()) {
pictureList.add(map);
}
} else if (workbook instanceof XSSFWorkbook) {
XSSFSheet xssfSheet = (XSSFSheet) sheet;
XSSFDrawing drawingPatriarch = xssfSheet.getDrawingPatriarch();
if (null == drawingPatriarch) {
return pictureList;
}
List xssfShapeList = drawingPatriarch.getShapes();
ConcurrentHashMap> map = new ConcurrentHashMap<>();
for (XSSFShape shape : xssfShapeList) {
if (shape instanceof XSSFPicture) {
executor.submit(() -> {
XSSFClientAnchor anchor = (XSSFClientAnchor) shape.getAnchor();
XSSFPicture picture = (XSSFPicture) shape;
XSSFPictureData pictureData = picture.getPictureData();
String key = anchor.getRow1() + "-" + anchor.getCol1();
if (map.containsKey(key)) {
map.get(key).add(pictureData);
} else {
List dataList = new ArrayList<>();
dataList.add(pictureData);
map.put(key, dataList);
}
});
}
}
executor.shutdown();
try {
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (!map.isEmpty()) {
pictureList.add(map);
}
}
return pictureList;
}
/**
* 下载图片
*
* @param pic 图片路径
* @return 图片数据
*/
private byte[] downloadAndProcessImage(String pic) {
// 根据图片路径获取图片对象名称
String objectName = getPicObjectName(pic);
return minioService.downloadFile(objectName);
}
/**
* 根据图片路径获取图片对象名称
* Minio
*
* @param pic 图片路径
* @return 图片对象名称
*/
public String getPicObjectName(String pic) {
String minioUrl = minioPrevUrl;
if (!minioUrl.endsWith("/")) {
minioUrl = minioUrl + "/";
}
int startIndex = pic.indexOf(minioUrl);
int endIndex = pic.indexOf("/", startIndex + minioUrl.length());
String url = pic.substring(0, endIndex + 1);
String objectName = pic.replace(url, "");
return objectName;
}
/**
* 设置图片
*
* @param sheet 工作表
* @param picPaths 图片路径,多个图片用逗号隔开
* @param rowIndex 行索引
* @param columnIndex 列索引
*/
public void setPictures(Sheet sheet, String picPaths, int rowIndex, int columnIndex) {
String[] pics = picPaths.split(",");
sheet.setColumnWidth(columnIndex, 4800);
sheet.getRow(rowIndex).setHeight((short) (1000 * pics.length));
HSSFPatriarch drawing = (HSSFPatriarch) sheet.createDrawingPatriarch();
int mar = 5 + 5 + (pics.length - 1) * 5;
int ave = (255 - mar) / pics.length;
for (int i = 0; i < pics.length; i++) {
String pic = pics[i];
// 根据图片路径下载图片
byte[] imageData = downloadAndProcessImage(pic);
// 处理图片,将图片写入工作簿
String suffix = pic.substring(pic.lastIndexOf(".") + 1);
HSSFClientAnchor anchor = new HSSFClientAnchor();
anchor.setDx1(20);
anchor.setDy1(5 * (i + 1) + ave * i);
anchor.setDx2(1003);
anchor.setDy2((5 + ave) * (i + 1));
anchor.setCol1(columnIndex);
anchor.setRow1(rowIndex);
anchor.setCol2(columnIndex);
anchor.setRow2(rowIndex);
if ("jpg".equals(suffix) || "jpeg".equals(suffix)) {
drawing.createPicture(anchor, sheet.getWorkbook().addPicture(imageData, HSSFWorkbook.PICTURE_TYPE_JPEG));
} else if ("png".equals(suffix)) {
drawing.createPicture(anchor, sheet.getWorkbook().addPicture(imageData, HSSFWorkbook.PICTURE_TYPE_PNG));
}
}
}
注意:导出图片时,只有将工作簿设置成HSSFWorkbook 才有效,具体原因未知。