Excel注解支持Image图片导出
This commit is contained in:
		| @@ -149,7 +149,7 @@ public @interface Excel | |||||||
|  |  | ||||||
|     public enum ColumnType |     public enum ColumnType | ||||||
|     { |     { | ||||||
|         NUMERIC(0), STRING(1); |         NUMERIC(0), STRING(1), IMAGE(2); | ||||||
|         private final int value; |         private final int value; | ||||||
|  |  | ||||||
|         ColumnType(int value) |         ColumnType(int value) | ||||||
|   | |||||||
| @@ -44,4 +44,33 @@ public class FileTypeUtils | |||||||
|         } |         } | ||||||
|         return fileName.substring(separatorIndex + 1).toLowerCase(); |         return fileName.substring(separatorIndex + 1).toLowerCase(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 获取文件类型 | ||||||
|  |      *  | ||||||
|  |      * @param photoByte 文件字节码 | ||||||
|  |      * @return 后缀(不含".") | ||||||
|  |      */ | ||||||
|  |     public static String getFileExtendName(byte[] photoByte) | ||||||
|  |     { | ||||||
|  |         String strFileExtendName = "JPG"; | ||||||
|  |         if ((photoByte[0] == 71) && (photoByte[1] == 73) && (photoByte[2] == 70) && (photoByte[3] == 56) | ||||||
|  |                 && ((photoByte[4] == 55) || (photoByte[4] == 57)) && (photoByte[5] == 97)) | ||||||
|  |         { | ||||||
|  |             strFileExtendName = "GIF"; | ||||||
|  |         } | ||||||
|  |         else if ((photoByte[6] == 74) && (photoByte[7] == 70) && (photoByte[8] == 73) && (photoByte[9] == 70)) | ||||||
|  |         { | ||||||
|  |             strFileExtendName = "JPG"; | ||||||
|  |         } | ||||||
|  |         else if ((photoByte[0] == 66) && (photoByte[1] == 77)) | ||||||
|  |         { | ||||||
|  |             strFileExtendName = "BMP"; | ||||||
|  |         } | ||||||
|  |         else if ((photoByte[1] == 80) && (photoByte[2] == 78) && (photoByte[3] == 71)) | ||||||
|  |         { | ||||||
|  |             strFileExtendName = "PNG"; | ||||||
|  |         } | ||||||
|  |         return strFileExtendName; | ||||||
|  |     } | ||||||
| } | } | ||||||
| @@ -0,0 +1,100 @@ | |||||||
|  | package com.ruoyi.common.utils.file; | ||||||
|  |  | ||||||
|  | import java.io.ByteArrayInputStream; | ||||||
|  | import java.io.ByteArrayOutputStream; | ||||||
|  | import java.io.FileInputStream; | ||||||
|  | import java.io.InputStream; | ||||||
|  | import java.net.URL; | ||||||
|  | import java.net.URLConnection; | ||||||
|  | import java.util.Arrays; | ||||||
|  | import org.apache.poi.util.IOUtils; | ||||||
|  | import org.slf4j.Logger; | ||||||
|  | import org.slf4j.LoggerFactory; | ||||||
|  | import com.ruoyi.common.config.RuoYiConfig; | ||||||
|  | import com.ruoyi.common.constant.Constants; | ||||||
|  | import com.ruoyi.common.utils.StringUtils; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * 图片处理工具类 | ||||||
|  |  * | ||||||
|  |  * @author ruoyi | ||||||
|  |  */ | ||||||
|  | public class ImageUtils | ||||||
|  | { | ||||||
|  |     private static final Logger log = LoggerFactory.getLogger(ImageUtils.class); | ||||||
|  |  | ||||||
|  |     public static byte[] getImage(String imagePath) | ||||||
|  |     { | ||||||
|  |         InputStream is = getFile(imagePath); | ||||||
|  |         try | ||||||
|  |         { | ||||||
|  |             return IOUtils.toByteArray(is); | ||||||
|  |         } | ||||||
|  |         catch (Exception e) | ||||||
|  |         { | ||||||
|  |             log.error("图片加载异常 {}", e); | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  |         finally | ||||||
|  |         { | ||||||
|  |             IOUtils.closeQuietly(is); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public static InputStream getFile(String imagePath) | ||||||
|  |     { | ||||||
|  |         try | ||||||
|  |         { | ||||||
|  |             byte[] result = readFile(imagePath); | ||||||
|  |             result = Arrays.copyOf(result, result.length); | ||||||
|  |             return new ByteArrayInputStream(result); | ||||||
|  |         } | ||||||
|  |         catch (Exception e) | ||||||
|  |         { | ||||||
|  |             log.error("获取图片异常 {}", e); | ||||||
|  |         } | ||||||
|  |         return null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 读取文件为字节数据 | ||||||
|  |      *  | ||||||
|  |      * @param key 地址 | ||||||
|  |      * @return 字节数据 | ||||||
|  |      */ | ||||||
|  |     public static byte[] readFile(String url) | ||||||
|  |     { | ||||||
|  |         InputStream in = null; | ||||||
|  |         ByteArrayOutputStream baos = null; | ||||||
|  |         try | ||||||
|  |         { | ||||||
|  |             if (url.startsWith("http")) | ||||||
|  |             { | ||||||
|  |                 // 网络地址 | ||||||
|  |                 URL urlObj = new URL(url); | ||||||
|  |                 URLConnection urlConnection = urlObj.openConnection(); | ||||||
|  |                 urlConnection.setConnectTimeout(30 * 1000); | ||||||
|  |                 urlConnection.setReadTimeout(60 * 1000); | ||||||
|  |                 urlConnection.setDoInput(true); | ||||||
|  |                 in = urlConnection.getInputStream(); | ||||||
|  |             } | ||||||
|  |             else | ||||||
|  |             { | ||||||
|  |                 // 本机地址 | ||||||
|  |                 String localPath = RuoYiConfig.getProfile(); | ||||||
|  |                 String downloadPath = localPath + StringUtils.substringAfter(url, Constants.RESOURCE_PREFIX); | ||||||
|  |                 in = new FileInputStream(downloadPath); | ||||||
|  |             } | ||||||
|  |             return IOUtils.toByteArray(in); | ||||||
|  |         } | ||||||
|  |         catch (Exception e) | ||||||
|  |         { | ||||||
|  |             log.error("获取文件路径异常 {}", e); | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  |         finally | ||||||
|  |         { | ||||||
|  |             IOUtils.closeQuietly(baos); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -22,10 +22,12 @@ import org.apache.poi.ss.usermodel.BorderStyle; | |||||||
| import org.apache.poi.ss.usermodel.Cell; | import org.apache.poi.ss.usermodel.Cell; | ||||||
| import org.apache.poi.ss.usermodel.CellStyle; | import org.apache.poi.ss.usermodel.CellStyle; | ||||||
| import org.apache.poi.ss.usermodel.CellType; | import org.apache.poi.ss.usermodel.CellType; | ||||||
|  | import org.apache.poi.ss.usermodel.ClientAnchor; | ||||||
| import org.apache.poi.ss.usermodel.DataValidation; | import org.apache.poi.ss.usermodel.DataValidation; | ||||||
| import org.apache.poi.ss.usermodel.DataValidationConstraint; | import org.apache.poi.ss.usermodel.DataValidationConstraint; | ||||||
| import org.apache.poi.ss.usermodel.DataValidationHelper; | import org.apache.poi.ss.usermodel.DataValidationHelper; | ||||||
| import org.apache.poi.ss.usermodel.DateUtil; | import org.apache.poi.ss.usermodel.DateUtil; | ||||||
|  | import org.apache.poi.ss.usermodel.Drawing; | ||||||
| import org.apache.poi.ss.usermodel.FillPatternType; | import org.apache.poi.ss.usermodel.FillPatternType; | ||||||
| import org.apache.poi.ss.usermodel.Font; | import org.apache.poi.ss.usermodel.Font; | ||||||
| import org.apache.poi.ss.usermodel.HorizontalAlignment; | import org.apache.poi.ss.usermodel.HorizontalAlignment; | ||||||
| @@ -37,6 +39,7 @@ import org.apache.poi.ss.usermodel.Workbook; | |||||||
| import org.apache.poi.ss.usermodel.WorkbookFactory; | import org.apache.poi.ss.usermodel.WorkbookFactory; | ||||||
| import org.apache.poi.ss.util.CellRangeAddressList; | import org.apache.poi.ss.util.CellRangeAddressList; | ||||||
| import org.apache.poi.xssf.streaming.SXSSFWorkbook; | import org.apache.poi.xssf.streaming.SXSSFWorkbook; | ||||||
|  | import org.apache.poi.xssf.usermodel.XSSFClientAnchor; | ||||||
| import org.apache.poi.xssf.usermodel.XSSFDataValidation; | import org.apache.poi.xssf.usermodel.XSSFDataValidation; | ||||||
| import org.slf4j.Logger; | import org.slf4j.Logger; | ||||||
| import org.slf4j.LoggerFactory; | import org.slf4j.LoggerFactory; | ||||||
| @@ -51,6 +54,8 @@ import com.ruoyi.common.exception.CustomException; | |||||||
| import com.ruoyi.common.utils.DateUtils; | import com.ruoyi.common.utils.DateUtils; | ||||||
| import com.ruoyi.common.utils.DictUtils; | import com.ruoyi.common.utils.DictUtils; | ||||||
| import com.ruoyi.common.utils.StringUtils; | import com.ruoyi.common.utils.StringUtils; | ||||||
|  | import com.ruoyi.common.utils.file.FileTypeUtils; | ||||||
|  | import com.ruoyi.common.utils.file.ImageUtils; | ||||||
| import com.ruoyi.common.utils.reflect.ReflectUtils; | import com.ruoyi.common.utils.reflect.ReflectUtils; | ||||||
|  |  | ||||||
| /** | /** | ||||||
| @@ -102,16 +107,21 @@ public class ExcelUtil<T> | |||||||
|      */ |      */ | ||||||
|     private List<Object[]> fields; |     private List<Object[]> fields; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 最大高度 | ||||||
|  |      */ | ||||||
|  |     private short maxHeight; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 统计列表 |      * 统计列表 | ||||||
|      */ |      */ | ||||||
|     private Map<Integer, Double> statistics = new HashMap<Integer, Double>(); |     private Map<Integer, Double> statistics = new HashMap<Integer, Double>(); | ||||||
|  |      | ||||||
|     /** |     /** | ||||||
|      * 数字格式 |      * 数字格式 | ||||||
|      */ |      */ | ||||||
|     private static final DecimalFormat DOUBLE_FORMAT = new DecimalFormat("######0.00"); |     private static final DecimalFormat DOUBLE_FORMAT = new DecimalFormat("######0.00"); | ||||||
|  |      | ||||||
|     /** |     /** | ||||||
|      * 实体对象 |      * 实体对象 | ||||||
|      */ |      */ | ||||||
| @@ -239,7 +249,15 @@ public class ExcelUtil<T> | |||||||
|                         } |                         } | ||||||
|                         else |                         else | ||||||
|                         { |                         { | ||||||
|                             val = Convert.toStr(val); |                             String dateFormat = field.getAnnotation(Excel.class).dateFormat(); | ||||||
|  |                             if (StringUtils.isNotEmpty(dateFormat)) | ||||||
|  |                             { | ||||||
|  |                                 val = DateUtils.parseDateToStr(dateFormat, (Date) val); | ||||||
|  |                             } | ||||||
|  |                             else | ||||||
|  |                             { | ||||||
|  |                                 val = Convert.toStr(val); | ||||||
|  |                             } | ||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
|                     else if ((Integer.TYPE == fieldType || Integer.class == fieldType) && StringUtils.isNumeric(Convert.toStr(val))) |                     else if ((Integer.TYPE == fieldType || Integer.class == fieldType) && StringUtils.isNumeric(Convert.toStr(val))) | ||||||
| @@ -521,6 +539,47 @@ public class ExcelUtil<T> | |||||||
|         { |         { | ||||||
|             cell.setCellValue(StringUtils.contains(Convert.toStr(value), ".") ? Convert.toDouble(value) : Convert.toInt(value)); |             cell.setCellValue(StringUtils.contains(Convert.toStr(value), ".") ? Convert.toDouble(value) : Convert.toInt(value)); | ||||||
|         } |         } | ||||||
|  |         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)) | ||||||
|  |             { | ||||||
|  |                 byte[] data = ImageUtils.getImage(imagePath); | ||||||
|  |                 getDrawingPatriarch(cell.getSheet()).createPicture(anchor, | ||||||
|  |                         cell.getSheet().getWorkbook().addPicture(data, getImageType(data))); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * 获取画布 | ||||||
|  |      */ | ||||||
|  |     public static Drawing<?> getDrawingPatriarch(Sheet sheet) | ||||||
|  |     { | ||||||
|  |         if (sheet.getDrawingPatriarch() == null) | ||||||
|  |         { | ||||||
|  |             sheet.createDrawingPatriarch(); | ||||||
|  |         } | ||||||
|  |         return sheet.getDrawingPatriarch(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 获取图片类型,设置图片插入类型 | ||||||
|  |      */ | ||||||
|  |     public int getImageType(byte[] value) | ||||||
|  |     { | ||||||
|  |         String type = FileTypeUtils.getFileExtendName(value); | ||||||
|  |         if ("JPG".equalsIgnoreCase(type)) | ||||||
|  |         { | ||||||
|  |             return Workbook.PICTURE_TYPE_JPEG; | ||||||
|  |         } | ||||||
|  |         else if ("PNG".equalsIgnoreCase(type)) | ||||||
|  |         { | ||||||
|  |             return Workbook.PICTURE_TYPE_PNG; | ||||||
|  |         } | ||||||
|  |         return Workbook.PICTURE_TYPE_JPEG; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @@ -536,7 +595,6 @@ public class ExcelUtil<T> | |||||||
|         { |         { | ||||||
|             // 设置列宽 |             // 设置列宽 | ||||||
|             sheet.setColumnWidth(column, (int) ((attr.width() + 0.72) * 256)); |             sheet.setColumnWidth(column, (int) ((attr.width() + 0.72) * 256)); | ||||||
|             row.setHeight((short) (attr.height() * 20)); |  | ||||||
|         } |         } | ||||||
|         // 如果设置了提示信息则鼠标放上去提示. |         // 如果设置了提示信息则鼠标放上去提示. | ||||||
|         if (StringUtils.isNotEmpty(attr.prompt())) |         if (StringUtils.isNotEmpty(attr.prompt())) | ||||||
| @@ -561,7 +619,7 @@ public class ExcelUtil<T> | |||||||
|         try |         try | ||||||
|         { |         { | ||||||
|             // 设置行高 |             // 设置行高 | ||||||
|             row.setHeight((short) (attr.height() * 20)); |             row.setHeight(maxHeight); | ||||||
|             // 根据Excel中设置情况决定是否导出,有些情况需要保持为空,希望用户填写这一列. |             // 根据Excel中设置情况决定是否导出,有些情况需要保持为空,希望用户填写这一列. | ||||||
|             if (attr.isExport()) |             if (attr.isExport()) | ||||||
|             { |             { | ||||||
| @@ -737,7 +795,7 @@ public class ExcelUtil<T> | |||||||
|         } |         } | ||||||
|         return StringUtils.stripEnd(propertyString.toString(), separator); |         return StringUtils.stripEnd(propertyString.toString(), separator); | ||||||
|     } |     } | ||||||
|  |      | ||||||
|     /** |     /** | ||||||
|      * 解析字典值 |      * 解析字典值 | ||||||
|      *  |      *  | ||||||
| @@ -763,7 +821,7 @@ public class ExcelUtil<T> | |||||||
|     { |     { | ||||||
|         return DictUtils.getDictValue(dictType, dictLabel, separator); |         return DictUtils.getDictValue(dictType, dictLabel, separator); | ||||||
|     } |     } | ||||||
|  |      | ||||||
|     /** |     /** | ||||||
|      * 合计统计信息 |      * 合计统计信息 | ||||||
|      */ |      */ | ||||||
| @@ -800,7 +858,7 @@ public class ExcelUtil<T> | |||||||
|             cell = row.createCell(0); |             cell = row.createCell(0); | ||||||
|             cell.setCellStyle(styles.get("total")); |             cell.setCellStyle(styles.get("total")); | ||||||
|             cell.setCellValue("合计"); |             cell.setCellValue("合计"); | ||||||
|  |              | ||||||
|             for (Integer key : keys) |             for (Integer key : keys) | ||||||
|             { |             { | ||||||
|                 cell = row.createCell(key); |                 cell = row.createCell(key); | ||||||
| @@ -916,6 +974,21 @@ public class ExcelUtil<T> | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         this.fields = this.fields.stream().sorted(Comparator.comparing(objects -> ((Excel) objects[1]).sort())).collect(Collectors.toList()); |         this.fields = this.fields.stream().sorted(Comparator.comparing(objects -> ((Excel) objects[1]).sort())).collect(Collectors.toList()); | ||||||
|  |         this.maxHeight = getRowHeight(); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * 根据注解获取最大行高 | ||||||
|  |      */ | ||||||
|  |     public short getRowHeight() | ||||||
|  |     { | ||||||
|  |         double maxHeight = 0; | ||||||
|  |         for (Object[] os : this.fields) | ||||||
|  |         { | ||||||
|  |             Excel excel = (Excel) os[1]; | ||||||
|  |             maxHeight = maxHeight > excel.height() ? maxHeight : excel.height(); | ||||||
|  |         } | ||||||
|  |         return (short) (maxHeight * 20); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user