Commit 0187344798c2d4cb2a1b0d89a3e73dcc6bbb0a07

Authored by RuoYi
1 parent a9c6ba12

Excel注解支持Image图片导出

ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excel.java
... ... @@ -149,7 +149,7 @@ public @interface Excel
149 149  
150 150 public enum ColumnType
151 151 {
152   - NUMERIC(0), STRING(1);
  152 + NUMERIC(0), STRING(1), IMAGE(2);
153 153 private final int value;
154 154  
155 155 ColumnType(int value)
... ...
ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileTypeUtils.java
... ... @@ -44,4 +44,33 @@ public class FileTypeUtils
44 44 }
45 45 return fileName.substring(separatorIndex + 1).toLowerCase();
46 46 }
  47 +
  48 + /**
  49 + * 获取文件类型
  50 + *
  51 + * @param photoByte 文件字节码
  52 + * @return 后缀(不含".")
  53 + */
  54 + public static String getFileExtendName(byte[] photoByte)
  55 + {
  56 + String strFileExtendName = "JPG";
  57 + if ((photoByte[0] == 71) && (photoByte[1] == 73) && (photoByte[2] == 70) && (photoByte[3] == 56)
  58 + && ((photoByte[4] == 55) || (photoByte[4] == 57)) && (photoByte[5] == 97))
  59 + {
  60 + strFileExtendName = "GIF";
  61 + }
  62 + else if ((photoByte[6] == 74) && (photoByte[7] == 70) && (photoByte[8] == 73) && (photoByte[9] == 70))
  63 + {
  64 + strFileExtendName = "JPG";
  65 + }
  66 + else if ((photoByte[0] == 66) && (photoByte[1] == 77))
  67 + {
  68 + strFileExtendName = "BMP";
  69 + }
  70 + else if ((photoByte[1] == 80) && (photoByte[2] == 78) && (photoByte[3] == 71))
  71 + {
  72 + strFileExtendName = "PNG";
  73 + }
  74 + return strFileExtendName;
  75 + }
47 76 }
48 77 \ No newline at end of file
... ...
ruoyi-common/src/main/java/com/ruoyi/common/utils/file/ImageUtils.java 0 → 100644
  1 +package com.ruoyi.common.utils.file;
  2 +
  3 +import java.io.ByteArrayInputStream;
  4 +import java.io.ByteArrayOutputStream;
  5 +import java.io.FileInputStream;
  6 +import java.io.InputStream;
  7 +import java.net.URL;
  8 +import java.net.URLConnection;
  9 +import java.util.Arrays;
  10 +import org.apache.poi.util.IOUtils;
  11 +import org.slf4j.Logger;
  12 +import org.slf4j.LoggerFactory;
  13 +import com.ruoyi.common.config.RuoYiConfig;
  14 +import com.ruoyi.common.constant.Constants;
  15 +import com.ruoyi.common.utils.StringUtils;
  16 +
  17 +/**
  18 + * 图片处理工具类
  19 + *
  20 + * @author ruoyi
  21 + */
  22 +public class ImageUtils
  23 +{
  24 + private static final Logger log = LoggerFactory.getLogger(ImageUtils.class);
  25 +
  26 + public static byte[] getImage(String imagePath)
  27 + {
  28 + InputStream is = getFile(imagePath);
  29 + try
  30 + {
  31 + return IOUtils.toByteArray(is);
  32 + }
  33 + catch (Exception e)
  34 + {
  35 + log.error("图片加载异常 {}", e);
  36 + return null;
  37 + }
  38 + finally
  39 + {
  40 + IOUtils.closeQuietly(is);
  41 + }
  42 + }
  43 +
  44 + public static InputStream getFile(String imagePath)
  45 + {
  46 + try
  47 + {
  48 + byte[] result = readFile(imagePath);
  49 + result = Arrays.copyOf(result, result.length);
  50 + return new ByteArrayInputStream(result);
  51 + }
  52 + catch (Exception e)
  53 + {
  54 + log.error("获取图片异常 {}", e);
  55 + }
  56 + return null;
  57 + }
  58 +
  59 + /**
  60 + * 读取文件为字节数据
  61 + *
  62 + * @param key 地址
  63 + * @return 字节数据
  64 + */
  65 + public static byte[] readFile(String url)
  66 + {
  67 + InputStream in = null;
  68 + ByteArrayOutputStream baos = null;
  69 + try
  70 + {
  71 + if (url.startsWith("http"))
  72 + {
  73 + // 网络地址
  74 + URL urlObj = new URL(url);
  75 + URLConnection urlConnection = urlObj.openConnection();
  76 + urlConnection.setConnectTimeout(30 * 1000);
  77 + urlConnection.setReadTimeout(60 * 1000);
  78 + urlConnection.setDoInput(true);
  79 + in = urlConnection.getInputStream();
  80 + }
  81 + else
  82 + {
  83 + // 本机地址
  84 + String localPath = RuoYiConfig.getProfile();
  85 + String downloadPath = localPath + StringUtils.substringAfter(url, Constants.RESOURCE_PREFIX);
  86 + in = new FileInputStream(downloadPath);
  87 + }
  88 + return IOUtils.toByteArray(in);
  89 + }
  90 + catch (Exception e)
  91 + {
  92 + log.error("获取文件路径异常 {}", e);
  93 + return null;
  94 + }
  95 + finally
  96 + {
  97 + IOUtils.closeQuietly(baos);
  98 + }
  99 + }
  100 +}
... ...
ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java
... ... @@ -22,10 +22,12 @@ import org.apache.poi.ss.usermodel.BorderStyle;
22 22 import org.apache.poi.ss.usermodel.Cell;
23 23 import org.apache.poi.ss.usermodel.CellStyle;
24 24 import org.apache.poi.ss.usermodel.CellType;
  25 +import org.apache.poi.ss.usermodel.ClientAnchor;
25 26 import org.apache.poi.ss.usermodel.DataValidation;
26 27 import org.apache.poi.ss.usermodel.DataValidationConstraint;
27 28 import org.apache.poi.ss.usermodel.DataValidationHelper;
28 29 import org.apache.poi.ss.usermodel.DateUtil;
  30 +import org.apache.poi.ss.usermodel.Drawing;
29 31 import org.apache.poi.ss.usermodel.FillPatternType;
30 32 import org.apache.poi.ss.usermodel.Font;
31 33 import org.apache.poi.ss.usermodel.HorizontalAlignment;
... ... @@ -37,6 +39,7 @@ import org.apache.poi.ss.usermodel.Workbook;
37 39 import org.apache.poi.ss.usermodel.WorkbookFactory;
38 40 import org.apache.poi.ss.util.CellRangeAddressList;
39 41 import org.apache.poi.xssf.streaming.SXSSFWorkbook;
  42 +import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
40 43 import org.apache.poi.xssf.usermodel.XSSFDataValidation;
41 44 import org.slf4j.Logger;
42 45 import org.slf4j.LoggerFactory;
... ... @@ -51,6 +54,8 @@ import com.ruoyi.common.exception.CustomException;
51 54 import com.ruoyi.common.utils.DateUtils;
52 55 import com.ruoyi.common.utils.DictUtils;
53 56 import com.ruoyi.common.utils.StringUtils;
  57 +import com.ruoyi.common.utils.file.FileTypeUtils;
  58 +import com.ruoyi.common.utils.file.ImageUtils;
54 59 import com.ruoyi.common.utils.reflect.ReflectUtils;
55 60  
56 61 /**
... ... @@ -103,15 +108,20 @@ public class ExcelUtil<T>
103 108 private List<Object[]> fields;
104 109  
105 110 /**
  111 + * 最大高度
  112 + */
  113 + private short maxHeight;
  114 +
  115 + /**
106 116 * 统计列表
107 117 */
108 118 private Map<Integer, Double> statistics = new HashMap<Integer, Double>();
109   -
  119 +
110 120 /**
111 121 * 数字格式
112 122 */
113 123 private static final DecimalFormat DOUBLE_FORMAT = new DecimalFormat("######0.00");
114   -
  124 +
115 125 /**
116 126 * 实体对象
117 127 */
... ... @@ -239,7 +249,15 @@ public class ExcelUtil&lt;T&gt;
239 249 }
240 250 else
241 251 {
242   - val = Convert.toStr(val);
  252 + String dateFormat = field.getAnnotation(Excel.class).dateFormat();
  253 + if (StringUtils.isNotEmpty(dateFormat))
  254 + {
  255 + val = DateUtils.parseDateToStr(dateFormat, (Date) val);
  256 + }
  257 + else
  258 + {
  259 + val = Convert.toStr(val);
  260 + }
243 261 }
244 262 }
245 263 else if ((Integer.TYPE == fieldType || Integer.class == fieldType) && StringUtils.isNumeric(Convert.toStr(val)))
... ... @@ -521,6 +539,47 @@ public class ExcelUtil&lt;T&gt;
521 539 {
522 540 cell.setCellValue(StringUtils.contains(Convert.toStr(value), ".") ? Convert.toDouble(value) : Convert.toInt(value));
523 541 }
  542 + else if (ColumnType.IMAGE == attr.cellType())
  543 + {
  544 + ClientAnchor anchor = new XSSFClientAnchor(0, 0, 0, 0, (short) cell.getColumnIndex(), cell.getRow().getRowNum(), (short) (cell.getColumnIndex() + 1),
  545 + cell.getRow().getRowNum() + 1);
  546 + String imagePath = Convert.toStr(value);
  547 + if (StringUtils.isNotEmpty(imagePath))
  548 + {
  549 + byte[] data = ImageUtils.getImage(imagePath);
  550 + getDrawingPatriarch(cell.getSheet()).createPicture(anchor,
  551 + cell.getSheet().getWorkbook().addPicture(data, getImageType(data)));
  552 + }
  553 + }
  554 + }
  555 +
  556 + /**
  557 + * 获取画布
  558 + */
  559 + public static Drawing<?> getDrawingPatriarch(Sheet sheet)
  560 + {
  561 + if (sheet.getDrawingPatriarch() == null)
  562 + {
  563 + sheet.createDrawingPatriarch();
  564 + }
  565 + return sheet.getDrawingPatriarch();
  566 + }
  567 +
  568 + /**
  569 + * 获取图片类型,设置图片插入类型
  570 + */
  571 + public int getImageType(byte[] value)
  572 + {
  573 + String type = FileTypeUtils.getFileExtendName(value);
  574 + if ("JPG".equalsIgnoreCase(type))
  575 + {
  576 + return Workbook.PICTURE_TYPE_JPEG;
  577 + }
  578 + else if ("PNG".equalsIgnoreCase(type))
  579 + {
  580 + return Workbook.PICTURE_TYPE_PNG;
  581 + }
  582 + return Workbook.PICTURE_TYPE_JPEG;
524 583 }
525 584  
526 585 /**
... ... @@ -536,7 +595,6 @@ public class ExcelUtil&lt;T&gt;
536 595 {
537 596 // 设置列宽
538 597 sheet.setColumnWidth(column, (int) ((attr.width() + 0.72) * 256));
539   - row.setHeight((short) (attr.height() * 20));
540 598 }
541 599 // 如果设置了提示信息则鼠标放上去提示.
542 600 if (StringUtils.isNotEmpty(attr.prompt()))
... ... @@ -561,7 +619,7 @@ public class ExcelUtil&lt;T&gt;
561 619 try
562 620 {
563 621 // 设置行高
564   - row.setHeight((short) (attr.height() * 20));
  622 + row.setHeight(maxHeight);
565 623 // 根据Excel中设置情况决定是否导出,有些情况需要保持为空,希望用户填写这一列.
566 624 if (attr.isExport())
567 625 {
... ... @@ -737,7 +795,7 @@ public class ExcelUtil&lt;T&gt;
737 795 }
738 796 return StringUtils.stripEnd(propertyString.toString(), separator);
739 797 }
740   -
  798 +
741 799 /**
742 800 * 解析字典值
743 801 *
... ... @@ -763,7 +821,7 @@ public class ExcelUtil&lt;T&gt;
763 821 {
764 822 return DictUtils.getDictValue(dictType, dictLabel, separator);
765 823 }
766   -
  824 +
767 825 /**
768 826 * 合计统计信息
769 827 */
... ... @@ -800,7 +858,7 @@ public class ExcelUtil&lt;T&gt;
800 858 cell = row.createCell(0);
801 859 cell.setCellStyle(styles.get("total"));
802 860 cell.setCellValue("合计");
803   -
  861 +
804 862 for (Integer key : keys)
805 863 {
806 864 cell = row.createCell(key);
... ... @@ -916,6 +974,21 @@ public class ExcelUtil&lt;T&gt;
916 974 }
917 975 }
918 976 this.fields = this.fields.stream().sorted(Comparator.comparing(objects -> ((Excel) objects[1]).sort())).collect(Collectors.toList());
  977 + this.maxHeight = getRowHeight();
  978 + }
  979 +
  980 + /**
  981 + * 根据注解获取最大行高
  982 + */
  983 + public short getRowHeight()
  984 + {
  985 + double maxHeight = 0;
  986 + for (Object[] os : this.fields)
  987 + {
  988 + Excel excel = (Excel) os[1];
  989 + maxHeight = maxHeight > excel.height() ? maxHeight : excel.height();
  990 + }
  991 + return (short) (maxHeight * 20);
919 992 }
920 993  
921 994 /**
... ...