Commit 0187344798c2d4cb2a1b0d89a3e73dcc6bbb0a07
1 parent
a9c6ba12
Excel注解支持Image图片导出
Showing
4 changed files
with
211 additions
and
9 deletions
ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excel.java
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<T> |
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<T> |
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<T> |
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<T> |
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<T> |
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<T> |
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<T> |
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<T> |
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 | /** |
... | ... |