feat(os-common): 优化 Excel导出功能

- 修改前端导入的权限,不下载模板,不更新原有数据
- 后端更新common,从ruoyi的gitee复制的

- 添加单元格样式封装,支持自定义样式
- 增加字典值和标签的互转方法
- 优化图片数据处理,支持多图片导出
- 改进下拉列表和提示信息的设置
- 修复导入导出的一些小问题
boardTest
zch 3 weeks ago
parent 50e1f3388c
commit ff83ba78ec

@ -83,11 +83,21 @@ public @interface Excel
*/
public String prompt() default "";
/**
*
*/
public boolean wrapText() default false;
/**
* .
*/
public String[] combo() default {};
/**
* combo,,dictType.
*/
public boolean comboReadDict() default false;
/**
* ,:list)
*/

@ -3,6 +3,7 @@ package com.os.common.utils;
import java.util.Collection;
import java.util.List;
import com.alibaba.fastjson2.JSONArray;
import com.os.common.utils.StringUtils;
import com.os.common.constant.CacheConstants;
import com.os.common.core.domain.entity.SysDictData;
import com.os.common.core.redis.RedisCache;
@ -56,6 +57,10 @@ public class DictUtils
*/
public static String getDictLabel(String dictType, String dictValue)
{
if (StringUtils.isEmpty(dictValue))
{
return StringUtils.EMPTY;
}
return getDictLabel(dictType, dictValue, SEPARATOR);
}
@ -68,6 +73,10 @@ public class DictUtils
*/
public static String getDictValue(String dictType, String dictLabel)
{
if (StringUtils.isEmpty(dictLabel))
{
return StringUtils.EMPTY;
}
return getDictValue(dictType, dictLabel, SEPARATOR);
}
@ -83,9 +92,10 @@ public class DictUtils
{
StringBuilder propertyString = new StringBuilder();
List<SysDictData> datas = getDictCache(dictType);
if (StringUtils.isNotNull(datas))
if (StringUtils.isNull(datas))
{
return StringUtils.EMPTY;
}
if (StringUtils.containsAny(separator, dictValue))
{
for (SysDictData dict : datas)
@ -110,7 +120,6 @@ public class DictUtils
}
}
}
}
return StringUtils.stripEnd(propertyString.toString(), separator);
}
@ -126,8 +135,11 @@ public class DictUtils
{
StringBuilder propertyString = new StringBuilder();
List<SysDictData> datas = getDictCache(dictType);
if (StringUtils.containsAny(separator, dictLabel) && StringUtils.isNotEmpty(datas))
if (StringUtils.isNull(datas))
{
return StringUtils.EMPTY;
}
if (StringUtils.containsAny(separator, dictLabel))
{
for (SysDictData dict : datas)
{
@ -154,6 +166,48 @@ public class DictUtils
return StringUtils.stripEnd(propertyString.toString(), separator);
}
/**
*
*
* @param dictType
* @return
*/
public static String getDictValues(String dictType)
{
StringBuilder propertyString = new StringBuilder();
List<SysDictData> datas = getDictCache(dictType);
if (StringUtils.isNull(datas))
{
return StringUtils.EMPTY;
}
for (SysDictData dict : datas)
{
propertyString.append(dict.getDictValue()).append(SEPARATOR);
}
return StringUtils.stripEnd(propertyString.toString(), SEPARATOR);
}
/**
*
*
* @param dictType
* @return
*/
public static String getDictLabels(String dictType)
{
StringBuilder propertyString = new StringBuilder();
List<SysDictData> datas = getDictCache(dictType);
if (StringUtils.isNull(datas))
{
return StringUtils.EMPTY;
}
for (SysDictData dict : datas)
{
propertyString.append(dict.getDictLabel()).append(SEPARATOR);
}
return StringUtils.stripEnd(propertyString.toString(), SEPARATOR);
}
/**
*
*

@ -286,6 +286,32 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils
return str.substring(start, end);
}
/**
* `open` `close`
*
* @param str
* @param open
* @param close
* @return
*/
public static String substringBetweenLast(final String str, final String open, final String close)
{
if (isEmpty(str) || isEmpty(open) || isEmpty(close))
{
return NULLSTR;
}
final int start = str.indexOf(open);
if (start != INDEX_NOT_FOUND)
{
final int end = str.lastIndexOf(close);
if (end != INDEX_NOT_FOUND)
{
return str.substring(start + open.length(), end);
}
}
return NULLSTR;
}
/**
*
*
@ -355,6 +381,18 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils
return new HashSet<String>(str2List(str, sep, true, false));
}
/**
* list
*
* @param str
* @param sep
* @return list
*/
public static final List<String> str2List(String str, String sep)
{
return str2List(str, sep, true, false);
}
/**
* list
*

@ -11,6 +11,10 @@ import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.os.common.utils.file.FileTypeUtils;
import com.os.common.utils.file.FileUploadUtils;
import com.os.common.utils.file.MimeTypeUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.ArrayUtils;
import com.os.common.config.RuoYiConfig;
@ -285,6 +289,7 @@ public class FileUtils
{
return null;
}
return FilenameUtils.getBaseName(fileName);
String baseName = FilenameUtils.getBaseName(fileName);
return baseName;
}
}

@ -1,398 +0,0 @@
package com.os.common.utils.file;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.*;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ooxml.POIXMLDocumentPart;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTMarker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.os.common.config.RuoYiConfig;
import com.os.common.utils.DateUtils;
import com.os.common.utils.StringUtils;
import com.os.common.utils.uuid.IdUtils;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
/**
* Excel
* Excel
*
* @author ruoyi
* @date 2025-01-28
*/
public class ImageExcelUtils {
private static final Logger log = LoggerFactory.getLogger(ImageExcelUtils.class);
/**
*
*/
private static final String[] SUPPORTED_IMAGE_FORMATS = {"jpg", "jpeg", "png", "gif", "bmp"};
/**
*
*/
private static final String IMAGE_BASE_PATH = RuoYiConfig.getProfile() + "/excel-images/";
static {
// 确保图片存储目录存在
try {
Files.createDirectories(Paths.get(IMAGE_BASE_PATH));
} catch (IOException e) {
log.error("创建图片存储目录失败: {}", e.getMessage());
}
}
/**
* Excel
*
* @param workbook 簿
* @param sheet
* @param row
* @param col
* @param imagePath
* @param cellWidth
* @param cellHeight
*/
public static void insertImageToCell(Workbook workbook, Sheet sheet, int row, int col,
String imagePath, int cellWidth, int cellHeight) {
try {
if (StringUtils.isEmpty(imagePath)) {
return;
}
// 获取图片数据
byte[] imageData = getImageData(imagePath);
if (imageData == null || imageData.length == 0) {
log.warn("图片数据为空: {}", imagePath);
return;
}
// 确定图片类型
int pictureType = getPictureType(imagePath);
if (pictureType == -1) {
log.warn("不支持的图片格式: {}", imagePath);
return;
}
// 添加图片到工作簿
int pictureIdx = workbook.addPicture(imageData, pictureType);
// 创建绘图对象
Drawing<?> drawing = sheet.createDrawingPatriarch();
// 创建锚点
ClientAnchor anchor = createAnchor(workbook, col, row, col + 1, row + 1);
// 插入图片
Picture picture = drawing.createPicture(anchor, pictureIdx);
// 调整图片大小以适应单元格
resizePictureToFitCell(picture, cellWidth, cellHeight);
log.debug("成功插入图片到单元格[{},{}]: {}", row, col, imagePath);
} catch (Exception e) {
log.error("插入图片到Excel失败: {}", e.getMessage(), e);
}
}
/**
* Excel
*
* @param sheet
* @param workbook 簿
* @return key: "行_列", value:
*/
public static Map<String, String> extractImagesFromSheet(Sheet sheet, Workbook workbook) {
Map<String, String> imageMap = new HashMap<>();
try {
if (workbook instanceof XSSFWorkbook) {
extractXSSFImages(sheet, (XSSFWorkbook) workbook, imageMap);
} else if (workbook instanceof HSSFWorkbook) {
extractHSSFImages(sheet, (HSSFWorkbook) workbook, imageMap);
}
} catch (Exception e) {
log.error("从Excel提取图片失败: {}", e.getMessage(), e);
}
return imageMap;
}
/**
* XLSX
*/
private static void extractXSSFImages(Sheet sheet, XSSFWorkbook workbook, Map<String, String> imageMap) {
try {
for (POIXMLDocumentPart part : ((XSSFSheet) sheet).getRelations()) {
if (part instanceof XSSFDrawing) {
XSSFDrawing drawing = (XSSFDrawing) part;
List<XSSFShape> shapes = drawing.getShapes();
for (XSSFShape shape : shapes) {
if (shape instanceof XSSFPicture) {
XSSFPicture picture = (XSSFPicture) shape;
XSSFClientAnchor anchor = picture.getPreferredSize();
CTMarker from = anchor.getFrom();
int row = from.getRow();
int col = from.getCol();
String cellKey = row + "_" + col;
// 保存图片
String savedPath = saveImageFromExcel(picture.getPictureData());
if (StringUtils.isNotEmpty(savedPath)) {
imageMap.put(cellKey, savedPath);
log.debug("提取图片从单元格[{},{}]: {}", row, col, savedPath);
}
}
}
}
}
} catch (Exception e) {
log.error("提取XLSX图片失败: {}", e.getMessage(), e);
}
}
/**
* XLS
*/
private static void extractHSSFImages(Sheet sheet, HSSFWorkbook workbook, Map<String, String> imageMap) {
try {
List<HSSFPictureData> pictures = workbook.getAllPictures();
if (pictures.isEmpty()) {
return;
}
if (sheet.getDrawingPatriarch() != null) {
HSSFPatriarch patriarch = (HSSFPatriarch) sheet.getDrawingPatriarch();
for (HSSFShape shape : patriarch.getChildren()) {
if (shape instanceof HSSFPicture) {
HSSFPicture picture = (HSSFPicture) shape;
HSSFClientAnchor anchor = (HSSFClientAnchor) shape.getAnchor();
int row = anchor.getRow1();
int col = anchor.getCol1();
String cellKey = row + "_" + col;
// 获取图片数据
int pictureIndex = picture.getPictureIndex() - 1;
if (pictureIndex >= 0 && pictureIndex < pictures.size()) {
HSSFPictureData pictureData = pictures.get(pictureIndex);
String savedPath = saveImageFromExcel(pictureData);
if (StringUtils.isNotEmpty(savedPath)) {
imageMap.put(cellKey, savedPath);
log.debug("提取图片从单元格[{},{}]: {}", row, col, savedPath);
}
}
}
}
}
} catch (Exception e) {
log.error("提取XLS图片失败: {}", e.getMessage(), e);
}
}
/**
* Excel
*/
private static String saveImageFromExcel(PictureData pictureData) {
try {
byte[] data = pictureData.getData();
if (data == null || data.length == 0) {
return null;
}
// 根据图片数据确定文件扩展名
String extension = getImageExtension(data);
// 生成唯一文件名
String fileName = DateUtils.datePath() + "/" + IdUtils.fastUUID() + "." + extension;
String fullPath = IMAGE_BASE_PATH + fileName;
// 确保目录存在
File file = new File(fullPath);
if (!file.getParentFile().exists()) {
file.getParentFile().mkdirs();
}
// 保存文件
Files.write(Paths.get(fullPath), data);
// 返回相对路径
return "/excel-images/" + fileName;
} catch (Exception e) {
log.error("保存Excel图片失败: {}", e.getMessage(), e);
return null;
}
}
/**
*
*/
private static byte[] getImageData(String imagePath) {
try {
String fullPath = null;
// 1. 处理绝对路径(包含驱动器盘符如 C:
if (imagePath.contains(":")) {
fullPath = imagePath;
}
// 2. 处理新格式的excel-images路径
else if (imagePath.startsWith("/excel-images/")) {
fullPath = RuoYiConfig.getProfile() + imagePath;
}
// 3. 处理传统的profile路径格式如 /profile/upload/...
else if (imagePath.startsWith("/profile/")) {
fullPath = RuoYiConfig.getProfile() + imagePath.substring("/profile".length());
}
// 4. 处理以/开头的其他路径
else if (imagePath.startsWith("/")) {
fullPath = RuoYiConfig.getProfile() + imagePath;
}
// 5. 处理相对路径
else {
fullPath = RuoYiConfig.getProfile() + "/" + imagePath;
}
File imageFile = new File(fullPath);
if (!imageFile.exists()) {
log.warn("图片文件不存在: {}", fullPath);
return null;
}
return Files.readAllBytes(imageFile.toPath());
} catch (Exception e) {
log.error("读取图片数据失败: {}", e.getMessage(), e);
return null;
}
}
/**
* POI
*/
private static int getPictureType(String imagePath) {
String extension = FileUtils.getFileExtendName(imagePath.getBytes()).toLowerCase();
switch (extension) {
case "jpg":
case "jpeg":
return Workbook.PICTURE_TYPE_JPEG;
case "png":
return Workbook.PICTURE_TYPE_PNG;
case "gif":
// GIF格式在POI 4.1.2中不直接支持使用JPEG作为默认
return Workbook.PICTURE_TYPE_JPEG;
case "bmp":
// BMP格式在POI 4.1.2中不直接支持使用JPEG作为默认
return Workbook.PICTURE_TYPE_JPEG;
default:
return -1;
}
}
/**
*
*/
private static String getImageExtension(byte[] imageData) {
if (imageData.length >= 4) {
// JPEG
if (imageData[0] == (byte) 0xFF && imageData[1] == (byte) 0xD8) {
return "jpg";
}
// PNG
if (imageData[0] == (byte) 0x89 && imageData[1] == (byte) 0x50 &&
imageData[2] == (byte) 0x4E && imageData[3] == (byte) 0x47) {
return "png";
}
// GIF
if (imageData[0] == (byte) 0x47 && imageData[1] == (byte) 0x49 && imageData[2] == (byte) 0x46) {
return "gif";
}
// BMP
if (imageData[0] == (byte) 0x42 && imageData[1] == (byte) 0x4D) {
return "bmp";
}
}
return "jpg"; // 默认为jpg
}
/**
*
*/
private static ClientAnchor createAnchor(Workbook workbook, int col1, int row1, int col2, int row2) {
if (workbook instanceof XSSFWorkbook || workbook instanceof SXSSFWorkbook) {
return new XSSFClientAnchor(0, 0, 0, 0, col1, row1, col2, row2);
} else {
return new HSSFClientAnchor(0, 0, 0, 0, (short) col1, row1, (short) col2, row2);
}
}
/**
*
*/
private static void resizePictureToFitCell(Picture picture, int cellWidth, int cellHeight) {
try {
// 如果没有指定尺寸,使用默认调整
if (cellWidth <= 0 || cellHeight <= 0) {
picture.resize();
} else {
// 根据指定尺寸调整
picture.resize(cellWidth / 256.0, cellHeight / 20.0);
}
} catch (Exception e) {
log.warn("调整图片尺寸失败: {}", e.getMessage());
// 使用默认调整作为后备方案
try {
picture.resize();
} catch (Exception ex) {
log.error("默认图片调整也失败: {}", ex.getMessage());
}
}
}
/**
*
*/
public static boolean isSupportedImageFormat(String fileName) {
if (StringUtils.isEmpty(fileName)) {
return false;
}
String extension = FileUtils.getFileExtendName(fileName.getBytes()).toLowerCase();
return Arrays.asList(SUPPORTED_IMAGE_FORMATS).contains(extension);
}
/**
*
*
* @param imagePaths
*/
public static void cleanupTempImages(List<String> imagePaths) {
if (imagePaths == null || imagePaths.isEmpty()) {
return;
}
for (String imagePath : imagePaths) {
try {
if (StringUtils.isNotEmpty(imagePath) && imagePath.contains("/excel-images/")) {
String fullPath = RuoYiConfig.getProfile() + imagePath;
Files.deleteIfExists(Paths.get(fullPath));
}
} catch (Exception e) {
log.warn("删除临时图片失败: {}", e.getMessage());
}
}
}
}

@ -24,6 +24,8 @@ import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletResponse;
import com.os.common.utils.poi.ExcelHandlerAdapter;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.RegExUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
@ -95,6 +97,8 @@ public class ExcelUtil<T>
{
private static final Logger log = LoggerFactory.getLogger(ExcelUtil.class);
public static final String SEPARATOR = ",";
public static final String FORMULA_REGEX_STR = "=|-|\\+|@";
public static final String[] FORMULA_STR = { "=", "-", "+", "@" };
@ -194,6 +198,11 @@ public class ExcelUtil<T>
*/
public Class<T> clazz;
/**
*
*/
public String[] includeFields;
/**
*
*/
@ -204,11 +213,20 @@ public class ExcelUtil<T>
this.clazz = clazz;
}
/**
* Excel
*
* @param fields ["name"/"id","name"]
*/
public void showColumn(String... fields)
{
this.includeFields = fields;
}
/**
* Excel
*
* @param fields ["name"/"id","name"]
* @throws Exception
*/
public void hideColumn(String... fields)
{
@ -238,8 +256,6 @@ public class ExcelUtil<T>
{
if (StringUtils.isNotEmpty(title))
{
subMergedFirstRowNum++;
subMergedLastRowNum++;
int titleLastCol = this.fields.size() - 1;
if (isSubList())
{
@ -250,7 +266,7 @@ public class ExcelUtil<T>
Cell titleCell = titleRow.createCell(0);
titleCell.setCellStyle(styles.get("title"));
titleCell.setCellValue(title);
sheet.addMergedRegion(new CellRangeAddress(titleRow.getRowNum(), titleRow.getRowNum(), titleRow.getRowNum(), titleLastCol));
sheet.addMergedRegion(new CellRangeAddress(titleRow.getRowNum(), titleRow.getRowNum(), 0, titleLastCol));
}
}
@ -261,23 +277,31 @@ public class ExcelUtil<T>
{
if (isSubList())
{
subMergedFirstRowNum++;
subMergedLastRowNum++;
Row subRow = sheet.createRow(rownum);
int excelNum = 0;
int column = 0;
int subFieldSize = subFields != null ? subFields.size() : 0;
for (Object[] objects : fields)
{
Field field = (Field) objects[0];
Excel attr = (Excel) objects[1];
Cell headCell1 = subRow.createCell(excelNum);
headCell1.setCellValue(attr.name());
headCell1.setCellStyle(styles.get(StringUtils.format("header_{}_{}", attr.headerColor(), attr.headerBackgroundColor())));
excelNum++;
}
int headFirstRow = excelNum - 1;
int headLastRow = headFirstRow + subFields.size() - 1;
if (headLastRow > headFirstRow)
if (Collection.class.isAssignableFrom(field.getType()))
{
sheet.addMergedRegion(new CellRangeAddress(rownum, rownum, headFirstRow, headLastRow));
Cell cell = subRow.createCell(column);
cell.setCellValue(attr.name());
cell.setCellStyle(styles.get(StringUtils.format("header_{}_{}", attr.headerColor(), attr.headerBackgroundColor())));
if (subFieldSize > 1)
{
CellRangeAddress cellAddress = new CellRangeAddress(rownum, rownum, column, column + subFieldSize - 1);
sheet.addMergedRegion(cellAddress);
}
column += subFieldSize;
}
else
{
Cell cell = subRow.createCell(column++);
cell.setCellValue(attr.name());
cell.setCellStyle(styles.get(StringUtils.format("header_{}_{}", attr.headerColor(), attr.headerBackgroundColor())));
}
}
rownum++;
}
@ -290,11 +314,23 @@ public class ExcelUtil<T>
* @return
*/
public List<T> importExcel(InputStream is)
{
return importExcel(is, 0);
}
/**
* excellist
*
* @param is
* @param titleNum
* @return
*/
public List<T> importExcel(InputStream is, int titleNum)
{
List<T> list = null;
try
{
list = importExcel(is, 0);
list = importExcel(StringUtils.EMPTY, is, titleNum);
}
catch (Exception e)
{
@ -308,18 +344,6 @@ public class ExcelUtil<T>
return list;
}
/**
* excellist
*
* @param is
* @param titleNum
* @return
*/
public List<T> importExcel(InputStream is, int titleNum) throws Exception
{
return importExcel(StringUtils.EMPTY, is, titleNum);
}
/**
* excellist
*
@ -340,7 +364,7 @@ public class ExcelUtil<T>
throw new IOException("文件sheet不存在");
}
boolean isXSSFWorkbook = !(wb instanceof HSSFWorkbook);
Map<String, PictureData> pictures;
Map<String, List<PictureData>> pictures = null;
if (isXSSFWorkbook)
{
pictures = getSheetPictures07((XSSFSheet) sheet, (XSSFWorkbook) wb);
@ -406,7 +430,7 @@ public class ExcelUtil<T>
if (String.class == fieldType)
{
String s = Convert.toStr(val);
if (StringUtils.endsWith(s, ".0"))
if (s.matches("^\\d+\\.0$"))
{
val = StringUtils.substringBefore(s, ".0");
}
@ -471,7 +495,12 @@ public class ExcelUtil<T>
}
else if (StringUtils.isNotEmpty(attr.dictType()))
{
val = reverseDictByExp(Convert.toStr(val), attr.dictType(), attr.separator());
if (!sysDictMap.containsKey(attr.dictType() + val))
{
String dictValue = reverseDictByExp(Convert.toStr(val), attr.dictType(), attr.separator());
sysDictMap.put(attr.dictType() + val, dictValue);
}
val = sysDictMap.get(attr.dictType() + val);
}
else if (!attr.handler().equals(ExcelHandlerAdapter.class))
{
@ -479,16 +508,15 @@ public class ExcelUtil<T>
}
else if (ColumnType.IMAGE == attr.cellType() && StringUtils.isNotEmpty(pictures))
{
PictureData image = pictures.get(row.getRowNum() + "_" + entry.getKey());
if (image == null)
StringBuilder propertyString = new StringBuilder();
List<PictureData> images = pictures.get(row.getRowNum() + "_" + entry.getKey());
for (PictureData picture : images)
{
val = "";
}
else
{
byte[] data = image.getData();
val = FileUtils.writeImportBytes(data);
byte[] data = picture.getData();
String fileName = FileUtils.writeImportBytes(data);
propertyString.append(fileName).append(SEPARATOR);
}
val = StringUtils.stripEnd(propertyString.toString(), SEPARATOR);
}
ReflectUtils.invokeSetter(entity, propertyName, val);
}
@ -706,64 +734,91 @@ public class ExcelUtil<T>
{
int startNo = index * sheetSize;
int endNo = Math.min(startNo + sheetSize, list.size());
int rowNo = (1 + rownum) - startNo;
int currentRowNum = rownum + 1; // 从标题行后开始
for (int i = startNo; i < endNo; i++)
{
rowNo = isSubList() ? (i > 1 ? rowNo + 1 : rowNo + i) : i + 1 + rownum - startNo;
row = sheet.createRow(rowNo);
// 得到导出对象.
row = sheet.createRow(currentRowNum);
T vo = (T) list.get(i);
Collection<?> subList = null;
if (isSubList())
{
if (isSubListValue(vo))
{
subList = getListCellValue(vo);
subMergedLastRowNum = subMergedLastRowNum + subList.size();
}
else
{
subMergedFirstRowNum++;
subMergedLastRowNum++;
}
}
int column = 0;
int maxSubListSize = getCurrentMaxSubListSize(vo);
for (Object[] os : fields)
{
Field field = (Field) os[0];
Excel excel = (Excel) os[1];
if (Collection.class.isAssignableFrom(field.getType()) && StringUtils.isNotNull(subList))
if (Collection.class.isAssignableFrom(field.getType()))
{
boolean subFirst = false;
for (Object obj : subList)
try
{
if (subFirst)
Collection<?> subList = (Collection<?>) getTargetValue(vo, field, excel);
if (subList != null && !subList.isEmpty())
{
rowNo++;
row = sheet.createRow(rowNo);
}
List<Field> subFields = FieldUtils.getFieldsListWithAnnotation(obj.getClass(), Excel.class);
int subIndex = 0;
for (Object subVo : subList)
{
Row subRow = sheet.getRow(currentRowNum + subIndex);
if (subRow == null)
{
subRow = sheet.createRow(currentRowNum + subIndex);
}
int subColumn = column;
for (Field subField : subFields)
{
if (subField.isAnnotationPresent(Excel.class))
{
subField.setAccessible(true);
Excel attr = subField.getAnnotation(Excel.class);
this.addCell(attr, row, (T) obj, subField, column + subIndex);
Excel subExcel = subField.getAnnotation(Excel.class);
addCell(subExcel, subRow, (T) subVo, subField, subColumn++);
}
subIndex++;
}
subFirst = true;
column += subFields.size();
}
}
catch (Exception e)
{
log.error("填充集合数据失败", e);
}
this.subMergedFirstRowNum = this.subMergedFirstRowNum + subList.size();
}
else
{
this.addCell(excel, row, vo, field, column++);
// 创建单元格并设置值
addCell(excel, row, vo, field, column);
if (maxSubListSize > 1 && excel.needMerge())
{
sheet.addMergedRegion(new CellRangeAddress(currentRowNum, currentRowNum + maxSubListSize - 1, column, column));
}
column++;
}
}
currentRowNum += maxSubListSize;
}
}
/**
*
*/
private int getCurrentMaxSubListSize(T vo)
{
int maxSubListSize = 1;
for (Object[] os : fields)
{
Field field = (Field) os[0];
if (Collection.class.isAssignableFrom(field.getType()))
{
try
{
Collection<?> subList = (Collection<?>) getTargetValue(vo, field, (Excel) os[1]);
if (subList != null && !subList.isEmpty())
{
maxSubListSize = Math.max(maxSubListSize, subList.size());
}
}
catch (Exception e)
{
log.error("获取集合大小失败", e);
}
}
}
return maxSubListSize;
}
/**
@ -898,7 +953,7 @@ public class ExcelUtil<T>
*/
public void annotationDataStyles(Map<String, CellStyle> styles, Field field, Excel excel)
{
String key = StringUtils.format("data_{}_{}_{}_{}", excel.align(), excel.color(), excel.backgroundColor(), excel.cellType());
String key = StringUtils.format("data_{}_{}_{}_{}_{}", excel.align(), excel.color(), excel.backgroundColor(), excel.cellType(), excel.wrapText());
if (!styles.containsKey(key))
{
CellStyle style = wb.createCellStyle();
@ -914,6 +969,7 @@ public class ExcelUtil<T>
style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
style.setFillForegroundColor(excel.backgroundColor().getIndex());
style.setWrapText(excel.wrapText());
Font dataFont = wb.createFont();
dataFont.setFontName("Arial");
dataFont.setFontHeightInPoints((short) 10);
@ -942,7 +998,7 @@ public class ExcelUtil<T>
if (isSubList())
{
// 填充默认样式,防止合并单元格样式失效
sheet.setDefaultColumnStyle(column, styles.get(StringUtils.format("data_{}_{}_{}_{}", attr.align(), attr.color(), attr.backgroundColor(), attr.cellType())));
sheet.setDefaultColumnStyle(column, styles.get(StringUtils.format("data_{}_{}_{}_{}_{}", attr.align(), attr.color(), attr.backgroundColor(), attr.cellType(), attr.wrapText())));
if (attr.needMerge())
{
sheet.addMergedRegion(new CellRangeAddress(rownum - 1, rownum, column, column));
@ -984,12 +1040,15 @@ public class ExcelUtil<T>
else if (ColumnType.IMAGE == attr.cellType())
{
ClientAnchor anchor = new XSSFClientAnchor(0, 0, 0, 0, (short) cell.getColumnIndex(), cell.getRow().getRowNum(), (short) (cell.getColumnIndex() + 1), cell.getRow().getRowNum() + 1);
String imagePath = Convert.toStr(value);
if (StringUtils.isNotEmpty(imagePath))
String propertyValue = Convert.toStr(value);
if (StringUtils.isNotEmpty(propertyValue))
{
List<String> imagePaths = StringUtils.str2List(propertyValue, SEPARATOR);
for (String imagePath : imagePaths)
{
byte[] data = ImageUtils.getImage(imagePath);
getDrawingPatriarch(cell.getSheet()).createPicture(anchor,
cell.getSheet().getWorkbook().addPicture(data, getImageType(data)));
getDrawingPatriarch(cell.getSheet()).createPicture(anchor, cell.getSheet().getWorkbook().addPicture(data, getImageType(data)));
}
}
}
}
@ -1037,17 +1096,28 @@ public class ExcelUtil<T>
// 设置列宽
sheet.setColumnWidth(column, (int) ((attr.width() + 0.72) * 256));
}
if (StringUtils.isNotEmpty(attr.prompt()) || attr.combo().length > 0)
if (StringUtils.isNotEmpty(attr.prompt()) || attr.combo().length > 0 || attr.comboReadDict())
{
if (attr.combo().length > 15 || StringUtils.join(attr.combo()).length() > 255)
String[] comboArray = attr.combo();
if (attr.comboReadDict())
{
if (!sysDictMap.containsKey("combo_" + attr.dictType()))
{
String labels = DictUtils.getDictLabels(attr.dictType());
sysDictMap.put("combo_" + attr.dictType(), labels);
}
String val = sysDictMap.get("combo_" + attr.dictType());
comboArray = StringUtils.split(val, DictUtils.SEPARATOR);
}
if (comboArray.length > 15 || StringUtils.join(comboArray).length() > 255)
{
// 如果下拉数大于15或字符串长度大于255则使用一个新sheet存储避免生成的模板下拉值获取不到
setXSSFValidationWithHidden(sheet, attr.combo(), attr.prompt(), 1, 100, column, column);
setXSSFValidationWithHidden(sheet, comboArray, attr.prompt(), 1, 100, column, column);
}
else
{
// 提示信息或只能选择不能输入的列内容.
setPromptOrValidation(sheet, attr.combo(), attr.prompt(), 1, 100, column, column);
setPromptOrValidation(sheet, comboArray, attr.prompt(), 1, 100, column, column);
}
}
}
@ -1069,10 +1139,12 @@ public class ExcelUtil<T>
cell = row.createCell(column);
if (isSubListValue(vo) && getListCellValue(vo).size() > 1 && attr.needMerge())
{
CellRangeAddress cellAddress = new CellRangeAddress(subMergedFirstRowNum, subMergedLastRowNum, column, column);
sheet.addMergedRegion(cellAddress);
if (subMergedLastRowNum >= subMergedFirstRowNum)
{
sheet.addMergedRegion(new CellRangeAddress(subMergedFirstRowNum, subMergedLastRowNum, column, column));
}
cell.setCellStyle(styles.get(StringUtils.format("data_{}_{}_{}_{}", attr.align(), attr.color(), attr.backgroundColor(), attr.cellType())));
}
cell.setCellStyle(styles.get(StringUtils.format("data_{}_{}_{}_{}_{}", attr.align(), attr.color(), attr.backgroundColor(), attr.cellType(), attr.wrapText())));
// 用于读取对象中的属性
Object value = getTargetValue(vo, field, attr);
@ -1082,6 +1154,7 @@ public class ExcelUtil<T>
String dictType = attr.dictType();
if (StringUtils.isNotEmpty(dateFormat) && StringUtils.isNotNull(value))
{
cell.getCellStyle().setDataFormat(this.wb.getCreationHelper().createDataFormat().getFormat(dateFormat));
cell.setCellValue(parseDateToStr(dateFormat, value));
}
else if (StringUtils.isNotEmpty(readConverterExp) && StringUtils.isNotNull(value))
@ -1220,7 +1293,7 @@ public class ExcelUtil<T>
public static String convertByExp(String propertyValue, String converterExp, String separator)
{
StringBuilder propertyString = new StringBuilder();
String[] convertSource = converterExp.split(",");
String[] convertSource = converterExp.split(SEPARATOR);
for (String item : convertSource)
{
String[] itemArray = item.split("=");
@ -1257,7 +1330,7 @@ public class ExcelUtil<T>
public static String reverseByExp(String propertyValue, String converterExp, String separator)
{
StringBuilder propertyString = new StringBuilder();
String[] convertSource = converterExp.split(",");
String[] convertSource = converterExp.split(SEPARATOR);
for (String item : convertSource)
{
String[] itemArray = item.split("=");
@ -1382,8 +1455,7 @@ public class ExcelUtil<T>
*/
public String encodingFilename(String filename)
{
filename = UUID.randomUUID() + "_" + filename + ".xlsx";
return filename;
return UUID.randomUUID() + "_" + filename + ".xlsx";
}
/**
@ -1413,6 +1485,7 @@ public class ExcelUtil<T>
*/
private Object getTargetValue(T vo, Field field, Excel excel) throws Exception
{
field.setAccessible(true);
Object o = field.get(vo);
if (StringUtils.isNotEmpty(excel.targetAttr()))
{
@ -1472,9 +1545,40 @@ public class ExcelUtil<T>
List<Field> tempFields = new ArrayList<>();
tempFields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields()));
tempFields.addAll(Arrays.asList(clazz.getDeclaredFields()));
if (StringUtils.isNotEmpty(includeFields))
{
for (Field field : tempFields)
{
if (ArrayUtils.contains(this.includeFields, field.getName()) || field.isAnnotationPresent(Excels.class))
{
addField(fields, field);
}
}
}
else if (StringUtils.isNotEmpty(excludeFields))
{
for (Field field : tempFields)
{
if (!ArrayUtils.contains(this.excludeFields, field.getName()))
{
addField(fields, field);
}
}
}
else
{
for (Field field : tempFields)
{
addField(fields, field);
}
}
return fields;
}
/**
*
*/
public void addField(List<Object[]> fields, Field field)
{
// 单注解
if (field.isAnnotationPresent(Excel.class))
@ -1482,7 +1586,6 @@ public class ExcelUtil<T>
Excel attr = field.getAnnotation(Excel.class);
if (attr != null && (attr.type() == Type.ALL || attr.type() == type))
{
field.setAccessible(true);
fields.add(new Object[] { field, attr });
}
if (Collection.class.isAssignableFrom(field.getType()))
@ -1500,19 +1603,26 @@ public class ExcelUtil<T>
Excels attrs = field.getAnnotation(Excels.class);
Excel[] excels = attrs.value();
for (Excel attr : excels)
{
if (StringUtils.isNotEmpty(includeFields))
{
if (ArrayUtils.contains(this.includeFields, field.getName() + "." + attr.targetAttr())
&& (attr != null && (attr.type() == Type.ALL || attr.type() == type)))
{
fields.add(new Object[] { field, attr });
}
}
else
{
if (!ArrayUtils.contains(this.excludeFields, field.getName() + "." + attr.targetAttr())
&& (attr != null && (attr.type() == Type.ALL || attr.type() == type)))
{
field.setAccessible(true);
fields.add(new Object[] { field, attr });
}
}
}
}
}
return fields;
}
/**
*
@ -1646,31 +1756,25 @@ public class ExcelUtil<T>
* @param workbook 簿
* @return Map key:1_1Stringvalue:PictureData
*/
public static Map<String, PictureData> getSheetPictures03(HSSFSheet sheet, HSSFWorkbook workbook)
public static Map<String, List<PictureData>> getSheetPictures03(HSSFSheet sheet, HSSFWorkbook workbook)
{
Map<String, PictureData> sheetIndexPicMap = new HashMap<String, PictureData>();
Map<String, List<PictureData>> sheetIndexPicMap = new HashMap<>();
List<HSSFPictureData> pictures = workbook.getAllPictures();
if (!pictures.isEmpty())
if (!pictures.isEmpty() && sheet.getDrawingPatriarch() != null)
{
for (HSSFShape shape : sheet.getDrawingPatriarch().getChildren())
{
HSSFClientAnchor anchor = (HSSFClientAnchor) shape.getAnchor();
if (shape instanceof HSSFPicture)
{
HSSFPicture pic = (HSSFPicture) shape;
int pictureIndex = pic.getPictureIndex() - 1;
HSSFPictureData picData = pictures.get(pictureIndex);
HSSFClientAnchor anchor = (HSSFClientAnchor) pic.getAnchor();
String picIndex = anchor.getRow1() + "_" + anchor.getCol1();
sheetIndexPicMap.put(picIndex, picData);
sheetIndexPicMap.computeIfAbsent(picIndex, k -> new ArrayList<>()).add(pic.getPictureData());
}
}
}
return sheetIndexPicMap;
}
else
{
return sheetIndexPicMap;
}
}
/**
* Excel2007
@ -1679,16 +1783,15 @@ public class ExcelUtil<T>
* @param workbook 簿
* @return Map key:1_1Stringvalue:PictureData
*/
public static Map<String, PictureData> getSheetPictures07(XSSFSheet sheet, XSSFWorkbook workbook)
public static Map<String, List<PictureData>> getSheetPictures07(XSSFSheet sheet, XSSFWorkbook workbook)
{
Map<String, PictureData> sheetIndexPicMap = new HashMap<String, PictureData>();
Map<String, List<PictureData>> sheetIndexPicMap = new HashMap<>();
for (POIXMLDocumentPart dr : sheet.getRelations())
{
if (dr instanceof XSSFDrawing)
{
XSSFDrawing drawing = (XSSFDrawing) dr;
List<XSSFShape> shapes = drawing.getShapes();
for (XSSFShape shape : shapes)
for (XSSFShape shape : drawing.getShapes())
{
if (shape instanceof XSSFPicture)
{
@ -1696,7 +1799,7 @@ public class ExcelUtil<T>
XSSFClientAnchor anchor = pic.getPreferredSize();
CTMarker ctMarker = anchor.getFrom();
String picIndex = ctMarker.getRow() + "_" + ctMarker.getCol();
sheetIndexPicMap.put(picIndex, pic.getPictureData());
sheetIndexPicMap.computeIfAbsent(picIndex, k -> new ArrayList<>()).add(pic.getPictureData());
}
}
}

@ -39,7 +39,7 @@ public class LuggageSystemPlcBufferBatteryLifecycle extends BaseEntity
private String powerSource;
/** 图片地址 */
@Excel(name = "图片地址")
@Excel(name = "图片地址", cellType = Excel.ColumnType.IMAGE, width = 100, height = 50)
private String imageAddress;
/** 备注 */

@ -39,7 +39,7 @@ public class LuggageSystemSecurityDoorBatteryLifecycle extends BaseEntity
private String batteryType;
/** 图片地址 */
@Excel(name = "图片地址")
@Excel(name = "图片地址", cellType = Excel.ColumnType.IMAGE, width = 100, height = 50)
private String imageAddress;
/** 备注 */

Loading…
Cancel
Save