From 476f1340d41a2d08d664319fad04df188cd9b449 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Fri, 15 Jan 2021 09:43:36 +0800 Subject: [PATCH 001/161] =?UTF-8?q?fix=20office2016=E6=8F=90=E7=A4=BA?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D/xl/worksheets/sheet1.xml=E9=83=A8=E5=88=86?= =?UTF-8?q?=E7=9A=84=E6=A0=BC=E5=BC=8F=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/ibiz/excel/picture/support/module/Sheet1.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/ibiz/excel/picture/support/module/Sheet1.java b/src/main/java/com/ibiz/excel/picture/support/module/Sheet1.java index 1d92601..7a65fbc 100644 --- a/src/main/java/com/ibiz/excel/picture/support/module/Sheet1.java +++ b/src/main/java/com/ibiz/excel/picture/support/module/Sheet1.java @@ -14,8 +14,8 @@ public class Sheet1 { @AutoFile(subDir = "worksheets", fileName = "sheet1.xml", alias = Alias.SHEET1, xmlEnd = AutoXmlHeadEndContent.SHEET1_END) String content = "" + - "" + - ""; + "xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\" mc:Ignorable=\"x14ac\" xmlns:x14ac=\"http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac\" " + + ">" + + "" + + ""; } -- Gitee From 902041af62e01250b5cea37011b8b7b9bd31a981 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Fri, 15 Jan 2021 10:20:19 +0800 Subject: [PATCH 002/161] =?UTF-8?q?add=20dev=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 5 + .../com/ibiz/excel/picture/support/User.java | 2 +- .../excel/picture/support/UserPicture.java | 141 ++++++++++++++++++ 3 files changed, 147 insertions(+), 1 deletion(-) create mode 100644 src/test/java/com/ibiz/excel/picture/support/UserPicture.java diff --git a/pom.xml b/pom.xml index fc73582..64b5d42 100644 --- a/pom.xml +++ b/pom.xml @@ -28,6 +28,11 @@ ant 1.10.5 + + cn.hutool + hutool-all + 5.5.5 + org.springframework.boot spring-boot-starter-test diff --git a/src/test/java/com/ibiz/excel/picture/support/User.java b/src/test/java/com/ibiz/excel/picture/support/User.java index b1069ae..14f48cd 100644 --- a/src/test/java/com/ibiz/excel/picture/support/User.java +++ b/src/test/java/com/ibiz/excel/picture/support/User.java @@ -163,4 +163,4 @@ public class User { public void setPicture3(String picture3) { this.picture3 = picture3; } -} +} \ No newline at end of file diff --git a/src/test/java/com/ibiz/excel/picture/support/UserPicture.java b/src/test/java/com/ibiz/excel/picture/support/UserPicture.java new file mode 100644 index 0000000..889424f --- /dev/null +++ b/src/test/java/com/ibiz/excel/picture/support/UserPicture.java @@ -0,0 +1,141 @@ +package com.ibiz.excel.picture.support; + +import com.ibiz.excel.picture.support.annotation.ExportModel; + +/** + * @auther 喻场 + * @date 2020/7/813:41 + */ +public class UserPicture { + + public UserPicture() { + } + + @ExportModel(title = "姓名", mergeMaster = true) + private String name; + @ExportModel(sort = 1, title = "年龄") + private Integer age; + @ExportModel(sort = 2, title = "部门", merge = true) + private String department; + @ExportModel(sort = 3, isPicture = true, title = "图片1") + private String picture; + @ExportModel(sort = 4, isPicture = true, title = "图片2") + private String picture1; + @ExportModel(sort = 5, isPicture = true, title = "图片3") + private String picture2; + @ExportModel(sort = 6, isPicture = true, title = "图片4") + private String picture3; + @ExportModel(sort = 7, isPicture = true, title = "图片5") + private String picture4; + @ExportModel(sort = 8, isPicture = true, title = "图片6") + private String picture5; + @ExportModel(sort = 9, isPicture = true, title = "图片7") + private String picture6; + @ExportModel(sort = 10, isPicture = true, title = "图片8") + private String picture7; + @ExportModel(sort = 11, isPicture = true, title = "图片9") + private String picture8; + + public String getPicture4() { + return picture4; + } + + public void setPicture4(String picture4) { + this.picture4 = picture4; + } + + public String getPicture5() { + return picture5; + } + + public void setPicture5(String picture5) { + this.picture5 = picture5; + } + + public String getPicture6() { + return picture6; + } + + public void setPicture6(String picture6) { + this.picture6 = picture6; + } + + public String getPicture7() { + return picture7; + } + + public void setPicture7(String picture7) { + this.picture7 = picture7; + } + + public String getPicture8() { + return picture8; + } + + public void setPicture8(String picture8) { + this.picture8 = picture8; + } + + public UserPicture(String name, Integer age, String department, String picture) { + this.name = name; + this.age = age; + this.department = department; + this.picture = picture; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getAge() { + return age; + } + + public void setAge(Integer age) { + this.age = age; + } + + public String getDepartment() { + return department; + } + + public void setDepartment(String department) { + this.department = department; + } + + public String getPicture() { + return picture; + } + + public void setPicture(String picture) { + this.picture = picture; + } + + public String getPicture1() { + return picture1; + } + + public void setPicture1(String picture1) { + this.picture1 = picture1; + } + + public String getPicture2() { + return picture2; + } + + public void setPicture2(String picture2) { + this.picture2 = picture2; + } + + public String getPicture3() { + return picture3; + } + + public void setPicture3(String picture3) { + this.picture3 = picture3; + } +} -- Gitee From 4f703ca4fb4dd23b01bccab26fc4bcf961792c98 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Fri, 15 Jan 2021 11:34:43 +0800 Subject: [PATCH 003/161] =?UTF-8?q?add=20=E5=A4=9A=E5=9B=BE=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../excel/picture/support/DemoPicture.java | 88 +++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 src/test/java/com/ibiz/excel/picture/support/DemoPicture.java diff --git a/src/test/java/com/ibiz/excel/picture/support/DemoPicture.java b/src/test/java/com/ibiz/excel/picture/support/DemoPicture.java new file mode 100644 index 0000000..c997c26 --- /dev/null +++ b/src/test/java/com/ibiz/excel/picture/support/DemoPicture.java @@ -0,0 +1,88 @@ +package com.ibiz.excel.picture.support; + +import cn.hutool.core.io.FileUtil; +import com.ibiz.excel.picture.support.model.Sheet; +import com.ibiz.excel.picture.support.model.Workbook; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.Date; +import java.util.UUID; + +/** + * 多图片导入测试 + * + * @author MinWeikai + * @date 2021-01-15 09:46:32 + */ +public class DemoPicture { + static final String CURRENT_PATH = "E:\\test\\"; + + private final static String IMG_PATH = "E:\\test\\img\\"; + + private static Integer SUM = 0; + private static Integer N = 0; + private static Integer _COUNT = 0; + + public static void main(String[] args) throws IOException { + Date start = new Date(); + Workbook workBook = Workbook.getInstance(1); + Sheet sheet = workBook.createSheet("测试"); + File[] files = FileUtil.ls(IMG_PATH); + SUM = files.length; + UserPicture u1; + for (int r = 0; r < 10; r++) { + if (N == 0) { + _COUNT = 0; + } + u1 = new UserPicture(); + u1.setAge(15); + u1.setName("测试-" + r); + u1.setPicture(files[getIndex(N, 0)].getAbsolutePath()); + u1.setPicture1(files[getIndex(N, 1)].getAbsolutePath()); + u1.setPicture2(files[getIndex(N, 2)].getAbsolutePath()); + u1.setPicture3(files[getIndex(N, 3)].getAbsolutePath()); + u1.setPicture4(files[getIndex(N, 4)].getAbsolutePath()); + u1.setPicture5(files[getIndex(N, 5)].getAbsolutePath()); + u1.setPicture6(files[getIndex(N, 6)].getAbsolutePath()); + u1.setPicture7(files[getIndex(N, 7)].getAbsolutePath()); + u1.setPicture8(files[getIndex(N, 8)].getAbsolutePath()); + sheet.createRow(u1); + + _COUNT++; + N = _COUNT * 9; + } + + File file = createFile(); + OutputStream os = new FileOutputStream(file); + workBook.write(os); + workBook.close(); + Date end = new Date(); + System.out.println("file capital :" + (file.length() / 1024 / 1024) + "M name :" + file.getName()); + System.out.println("file cost time :" + (end.getTime() - start.getTime())); + os.close(); + } + + private static int getIndex(int i, int i1) { + int count = i + i1; + if (count >= SUM) { + N = 0; + count = 0; + _COUNT = 0; + } + return count; + } + + private static File createFile() { + String dir = CURRENT_PATH + "excel/"; + File file = new File(dir); + if (!file.exists()) { + file.mkdir(); + } + String name = CURRENT_PATH + "excel/" + UUID.randomUUID() + ".xlsx"; + return new File(name); + } + +} -- Gitee From b7b7de80be75a57a3c39812bb658aa3f7481c973 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Fri, 15 Jan 2021 18:35:32 +0800 Subject: [PATCH 004/161] =?UTF-8?q?add=20=E8=87=AA=E5=AE=9A=E4=B9=89?= =?UTF-8?q?=E6=A0=87=E9=A2=98=E5=AF=BC=E5=87=BA=E6=B5=8B=E8=AF=95=E6=96=B9?= =?UTF-8?q?=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../excel/picture/support/model/Cell.java | 5 ++ .../picture/support/CustomTitleDemo.java | 82 +++++++++++++++++++ .../{DemoPicture.java => PicturesDemo.java} | 2 +- 3 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 src/test/java/com/ibiz/excel/picture/support/CustomTitleDemo.java rename src/test/java/com/ibiz/excel/picture/support/{DemoPicture.java => PicturesDemo.java} (98%) diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Cell.java b/src/main/java/com/ibiz/excel/picture/support/model/Cell.java index 170b879..d7cd946 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Cell.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Cell.java @@ -58,6 +58,11 @@ public class Cell { this(0,cellNumber); } + public Cell(int cellNumber, String value) { + this.cellNumber = cellNumber; + this.value = value; + } + public int getCellNumber() { return cellNumber; } diff --git a/src/test/java/com/ibiz/excel/picture/support/CustomTitleDemo.java b/src/test/java/com/ibiz/excel/picture/support/CustomTitleDemo.java new file mode 100644 index 0000000..8b0fbdb --- /dev/null +++ b/src/test/java/com/ibiz/excel/picture/support/CustomTitleDemo.java @@ -0,0 +1,82 @@ +package com.ibiz.excel.picture.support; + +import com.ibiz.excel.picture.support.constants.WorkbookConstant; +import com.ibiz.excel.picture.support.model.*; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.UUID; + +/** + * 自定义标题,填入文本和图片 + * + * @author MinWeikai + * @date 2021-01-15 15:19:44 + */ +public class CustomTitleDemo { + static final String CURRENT_PATH = "E:\\test\\"; + + private final static String IMG_PATH = CURRENT_PATH + "img\\"; + + private final static String IMG_PATH_1 = IMG_PATH + "ia_1900002528.jpeg"; + private final static String IMG_PATH_2 = IMG_PATH + "ia_1200000645.jpg"; + + + public static void main(String[] args) throws IOException { + Date start = new Date(); + Workbook workBook = Workbook.getInstance(1); + Sheet sheet = workBook.createSheet("测试"); + + // 第一行放标题 + Row row = sheet.createRow(0); + String[] excelName = {"文本1", "文本2", "图片1", "图片2", "图片3"}; + List nameCells = new ArrayList<>(); + for (int i = 0; i < excelName.length; i++) { + nameCells.add(new Cell(i, excelName[i])); + } + row.setCells(nameCells); + + // 第二行放文本图片 + row = sheet.createRow(1); + List valueCells = new ArrayList<>(); + List pictures = sheet.getPictures(); + for (int i = 0; i < excelName.length; i++) { + if (i < 2) { + valueCells.add(new Cell(i, "文本")); + } else { + //有图片的行,行高设置为100 + row.setHeight(WorkbookConstant.PICTURE_ROW_HEIGHT); + //增加图片 + pictures.add(new Picture(row.getRowNumber(), i, IMG_PATH_1)); + } + } + row.setCells(valueCells); + + + File file = createFile(); + OutputStream os = new FileOutputStream(file); + workBook.write(os); + workBook.close(); + Date end = new Date(); + System.out.println("file capital :" + (file.length() / 1024 / 1024) + "M name :" + file.getName()); + System.out.println("file cost time :" + (end.getTime() - start.getTime())); + os.close(); + } + + + private static File createFile() { + String dir = CURRENT_PATH + "excel/"; + File file = new File(dir); + if (!file.exists()) { + file.mkdir(); + } + String name = CURRENT_PATH + "excel/" + UUID.randomUUID() + ".xlsx"; + return new File(name); + } + +} diff --git a/src/test/java/com/ibiz/excel/picture/support/DemoPicture.java b/src/test/java/com/ibiz/excel/picture/support/PicturesDemo.java similarity index 98% rename from src/test/java/com/ibiz/excel/picture/support/DemoPicture.java rename to src/test/java/com/ibiz/excel/picture/support/PicturesDemo.java index c997c26..03290fc 100644 --- a/src/test/java/com/ibiz/excel/picture/support/DemoPicture.java +++ b/src/test/java/com/ibiz/excel/picture/support/PicturesDemo.java @@ -17,7 +17,7 @@ import java.util.UUID; * @author MinWeikai * @date 2021-01-15 09:46:32 */ -public class DemoPicture { +public class PicturesDemo { static final String CURRENT_PATH = "E:\\test\\"; private final static String IMG_PATH = "E:\\test\\img\\"; -- Gitee From c4189d9113c2d2144f788c25c7877f88e3478cb5 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Sat, 16 Jan 2021 09:37:10 +0800 Subject: [PATCH 005/161] =?UTF-8?q?Apply:=20add=20=E8=87=AA=E5=AE=9A?= =?UTF-8?q?=E4=B9=89=E6=A0=87=E9=A2=98=E5=AF=BC=E5=87=BA=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/ibiz/excel/picture/support/model/Cell.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Cell.java b/src/main/java/com/ibiz/excel/picture/support/model/Cell.java index 170b879..d7cd946 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Cell.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Cell.java @@ -58,6 +58,11 @@ public class Cell { this(0,cellNumber); } + public Cell(int cellNumber, String value) { + this.cellNumber = cellNumber; + this.value = value; + } + public int getCellNumber() { return cellNumber; } -- Gitee From 2f1c6766a82839e12bd109c589db4866be94efe5 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Sat, 16 Jan 2021 17:12:01 +0800 Subject: [PATCH 006/161] =?UTF-8?q?fix=20wps=E6=89=93=E5=BC=80=E6=B2=A1?= =?UTF-8?q?=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/ibiz/excel/picture/support/model/Cell.java | 8 ++------ .../com/ibiz/excel/picture/support/CustomTitleDemo.java | 4 ++-- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Cell.java b/src/main/java/com/ibiz/excel/picture/support/model/Cell.java index d7cd946..6e6035f 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Cell.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Cell.java @@ -50,19 +50,15 @@ public class Cell { return value; } - public void setValue(String value) { + public Cell setValue(String value) { this.value = value; + return this; } public Cell(int cellNumber) { this(0,cellNumber); } - public Cell(int cellNumber, String value) { - this.cellNumber = cellNumber; - this.value = value; - } - public int getCellNumber() { return cellNumber; } diff --git a/src/test/java/com/ibiz/excel/picture/support/CustomTitleDemo.java b/src/test/java/com/ibiz/excel/picture/support/CustomTitleDemo.java index 8b0fbdb..790cc8b 100644 --- a/src/test/java/com/ibiz/excel/picture/support/CustomTitleDemo.java +++ b/src/test/java/com/ibiz/excel/picture/support/CustomTitleDemo.java @@ -37,7 +37,7 @@ public class CustomTitleDemo { String[] excelName = {"文本1", "文本2", "图片1", "图片2", "图片3"}; List nameCells = new ArrayList<>(); for (int i = 0; i < excelName.length; i++) { - nameCells.add(new Cell(i, excelName[i])); + nameCells.add(new Cell(0, i).setValue(excelName[i])); } row.setCells(nameCells); @@ -47,7 +47,7 @@ public class CustomTitleDemo { List pictures = sheet.getPictures(); for (int i = 0; i < excelName.length; i++) { if (i < 2) { - valueCells.add(new Cell(i, "文本")); + valueCells.add(new Cell(1, i).setValue("文本")); } else { //有图片的行,行高设置为100 row.setHeight(WorkbookConstant.PICTURE_ROW_HEIGHT); -- Gitee From 91a599dcfbd1adedb9635ac78496616e69225a5e Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Mon, 18 Jan 2021 16:33:55 +0800 Subject: [PATCH 007/161] =?UTF-8?q?fix=20=E6=96=9C=E6=9D=A0=E8=B7=AF?= =?UTF-8?q?=E5=BE=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 2 +- .../support/constants/WorkbookConstant.java | 2 +- src/main/resources/image/image1.png | Bin 50647 -> 0 bytes src/main/resources/image/image2.png | Bin 51704 -> 0 bytes src/main/resources/image/image3.png | Bin 52335 -> 0 bytes src/main/resources/image/image4.png | Bin 50895 -> 0 bytes src/main/resources/image/image5.png | Bin 51523 -> 0 bytes 7 files changed, 2 insertions(+), 2 deletions(-) delete mode 100644 src/main/resources/image/image1.png delete mode 100644 src/main/resources/image/image2.png delete mode 100644 src/main/resources/image/image3.png delete mode 100644 src/main/resources/image/image4.png delete mode 100644 src/main/resources/image/image5.png diff --git a/pom.xml b/pom.xml index 64b5d42..afced53 100644 --- a/pom.xml +++ b/pom.xml @@ -30,7 +30,7 @@ cn.hutool - hutool-all + hutool-core 5.5.5 diff --git a/src/main/java/com/ibiz/excel/picture/support/constants/WorkbookConstant.java b/src/main/java/com/ibiz/excel/picture/support/constants/WorkbookConstant.java index 9b7fc32..9bf98ce 100644 --- a/src/main/java/com/ibiz/excel/picture/support/constants/WorkbookConstant.java +++ b/src/main/java/com/ibiz/excel/picture/support/constants/WorkbookConstant.java @@ -6,7 +6,7 @@ package com.ibiz.excel.picture.support.constants; */ public class WorkbookConstant { public static final String AUTO_DIR = System.getProperty("java.io.tmpdir"); - public static final String FILE_SEPARATOR = "\\"; + public static final String FILE_SEPARATOR = "/"; public static final String DEST_FILE_NAME_SUFFIX = ".xlsx"; public static final String MEDIA_IMAGE_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"; /**有图片的行高设置为100*/ diff --git a/src/main/resources/image/image1.png b/src/main/resources/image/image1.png deleted file mode 100644 index f684908bcf28561e2d768462c4d986e3f28622e3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 50647 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

LUDHW9Gr!h8jHHeTThym$86f>XD=n&p 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

L6v=8jW{E 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 Q5&!@I07*qoM6N<$f^?)>%>V!Z -- Gitee From f9b00f03161b2d523855913a97f3f0185daad459 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Mon, 18 Jan 2021 16:33:55 +0800 Subject: [PATCH 008/161] =?UTF-8?q?fix=20=E6=96=9C=E6=9D=A0=E8=B7=AF?= =?UTF-8?q?=E5=BE=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 5 +++++ .../support/constants/WorkbookConstant.java | 2 +- src/main/resources/image/image1.png | Bin 50647 -> 0 bytes src/main/resources/image/image2.png | Bin 51704 -> 0 bytes src/main/resources/image/image3.png | Bin 52335 -> 0 bytes src/main/resources/image/image4.png | Bin 50895 -> 0 bytes src/main/resources/image/image5.png | Bin 51523 -> 0 bytes 7 files changed, 6 insertions(+), 1 deletion(-) delete mode 100644 src/main/resources/image/image1.png delete mode 100644 src/main/resources/image/image2.png delete mode 100644 src/main/resources/image/image3.png delete mode 100644 src/main/resources/image/image4.png delete mode 100644 src/main/resources/image/image5.png diff --git a/pom.xml b/pom.xml index fc73582..afced53 100644 --- a/pom.xml +++ b/pom.xml @@ -28,6 +28,11 @@ ant 1.10.5 + + cn.hutool + hutool-core + 5.5.5 + org.springframework.boot spring-boot-starter-test diff --git a/src/main/java/com/ibiz/excel/picture/support/constants/WorkbookConstant.java b/src/main/java/com/ibiz/excel/picture/support/constants/WorkbookConstant.java index 9b7fc32..9bf98ce 100644 --- a/src/main/java/com/ibiz/excel/picture/support/constants/WorkbookConstant.java +++ b/src/main/java/com/ibiz/excel/picture/support/constants/WorkbookConstant.java @@ -6,7 +6,7 @@ package com.ibiz.excel.picture.support.constants; */ public class WorkbookConstant { public static final String AUTO_DIR = System.getProperty("java.io.tmpdir"); - public static final String FILE_SEPARATOR = "\\"; + public static final String FILE_SEPARATOR = "/"; public static final String DEST_FILE_NAME_SUFFIX = ".xlsx"; public static final String MEDIA_IMAGE_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"; /**有图片的行高设置为100*/ diff --git a/src/main/resources/image/image1.png b/src/main/resources/image/image1.png deleted file mode 100644 index f684908bcf28561e2d768462c4d986e3f28622e3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 50647 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

LUDHW9Gr!h8jHHeTThym$86f>XD=n&p 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

L6v=8jW{E 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 Q5&!@I07*qoM6N<$f^?)>%>V!Z -- Gitee From 22f64857b52dfb81df955dbd4c4cea0afb336bf6 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Sat, 16 Jan 2021 16:13:04 +0800 Subject: [PATCH 009/161] =?UTF-8?q?add=20=E5=86=85=E5=AD=98=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../excel/picture/support/model/Cell.java | 3 +- .../excel/picture/support/model/Workbook.java | 7 +- .../picture/support/util/CompressorUtil.java | 4 +- .../excel/picture/support/util/FileUtil.java | 8 +- .../picture/support/CustomTitleDemo.java | 85 +++++++++++++++++++ 5 files changed, 96 insertions(+), 11 deletions(-) create mode 100644 src/test/java/com/ibiz/excel/picture/support/CustomTitleDemo.java diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Cell.java b/src/main/java/com/ibiz/excel/picture/support/model/Cell.java index d7cd946..a8d7027 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Cell.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Cell.java @@ -50,8 +50,9 @@ public class Cell { return value; } - public void setValue(String value) { + public Cell setValue(String value) { this.value = value; + return this; } public Cell(int cellNumber) { diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Workbook.java b/src/main/java/com/ibiz/excel/picture/support/model/Workbook.java index d978c1d..ddfcf4e 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Workbook.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Workbook.java @@ -1,12 +1,13 @@ package com.ibiz.excel.picture.support.model; +import cn.hutool.core.util.ZipUtil; import com.ibiz.excel.picture.support.constants.WorkbookConstant; import com.ibiz.excel.picture.support.util.FileUtil; -import com.ibiz.excel.picture.support.util.CompressorUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.*; +import java.io.File; +import java.io.OutputStream; import java.util.*; /** @@ -81,7 +82,7 @@ public class Workbook { } sheets.forEach(Sheet::close); //把文件打包成xlsx - CompressorUtil.compress(filePath, destPath); + ZipUtil.zip(filePath, destPath); destFile = new File(destPath); deleteFile(filePath); logger.info("dest excel path:{}", destPath); diff --git a/src/main/java/com/ibiz/excel/picture/support/util/CompressorUtil.java b/src/main/java/com/ibiz/excel/picture/support/util/CompressorUtil.java index 25995be..ffd5936 100644 --- a/src/main/java/com/ibiz/excel/picture/support/util/CompressorUtil.java +++ b/src/main/java/com/ibiz/excel/picture/support/util/CompressorUtil.java @@ -1,11 +1,11 @@ package com.ibiz.excel.picture.support.util; -import java.io.File; - import org.apache.tools.ant.Project; import org.apache.tools.ant.taskdefs.Zip; import org.apache.tools.ant.types.FileSet; +import java.io.File; + /** * 将文件夹压缩成文件 */ diff --git a/src/main/java/com/ibiz/excel/picture/support/util/FileUtil.java b/src/main/java/com/ibiz/excel/picture/support/util/FileUtil.java index 37826f4..e1c3b95 100644 --- a/src/main/java/com/ibiz/excel/picture/support/util/FileUtil.java +++ b/src/main/java/com/ibiz/excel/picture/support/util/FileUtil.java @@ -47,14 +47,12 @@ public class FileUtil { } public static void writeToOutput(File source, OutputStream output) { - try { - byte[] buf = new byte[2048]; - FileInputStream fis = new FileInputStream(source); + byte[] buf = new byte[1024]; + try(BufferedInputStream fis = new BufferedInputStream(new FileInputStream(source))) { while (fis.read(buf) != -1) { output.write(buf); } - fis.close(); - } catch (IOException e) { + }catch (IOException e) { throw new RuntimeException("write to output error , destFile path:" + source.getAbsolutePath(), e); } } diff --git a/src/test/java/com/ibiz/excel/picture/support/CustomTitleDemo.java b/src/test/java/com/ibiz/excel/picture/support/CustomTitleDemo.java new file mode 100644 index 0000000..1adce03 --- /dev/null +++ b/src/test/java/com/ibiz/excel/picture/support/CustomTitleDemo.java @@ -0,0 +1,85 @@ +package com.ibiz.excel.picture.support; + +import cn.hutool.core.io.FileUtil; +import com.ibiz.excel.picture.support.constants.WorkbookConstant; +import com.ibiz.excel.picture.support.model.*; + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.IOException; +import java.util.*; + +/** + * 自定义标题,填入文本和图片 + * + * @author MinWeikai + * @date 2021-01-15 15:19:44 + */ +public class CustomTitleDemo { + static final String CURRENT_PATH = "E:\\test\\"; + + private final static String IMG_PATH = CURRENT_PATH + "img\\"; + + private final static String IMG_PATH_1 = IMG_PATH + "ia_1900002528.jpeg"; + private final static String IMG_PATH_2 = IMG_PATH + "ia_1200000645.jpg"; + + + public static void main(String[] args) throws IOException { + Date start = new Date(); + Workbook workBook = Workbook.getInstance(1); + Sheet sheet = workBook.createSheet("测试"); + + // 第一行放标题 + Row rowHead = sheet.createRow(0); + String[] excelName = {"文本1", "文本2", "图片1", "图片2", "图片3"}; + List nameCells = new ArrayList<>(); + int n = 0; + for (int i = 0; i < excelName.length; i++) { + nameCells.add(new Cell(0, n).setValue(excelName[i])); + if (Objects.equals(excelName[i], "图片1")) { + n = n + 9; + } + n++; + } + rowHead.setCells(nameCells); + + // 第二行放文本图片 + Row row = sheet.createRow(1); + List valueCells = new ArrayList<>(); + List pictures = sheet.getPictures(); + for (int i = 0; i < excelName.length; i++) { + if (i < 2) { + valueCells.add(new Cell(i, "文本")); + } else { + //有图片的行,行高设置为100 + row.setHeight(WorkbookConstant.PICTURE_ROW_HEIGHT); + //增加图片 + pictures.add(new Picture(row.getRowNumber(), i, IMG_PATH_1)); + } + } + row.setCells(valueCells); + + File file = createFile(); + BufferedOutputStream os = FileUtil.getOutputStream(file); + workBook.write(os); + workBook.close(); + Date end = new Date(); + System.out.println("file capital :" + (file.length() / 1024 / 1024) + "M name :" + file.getName()); + System.out.println("file cost time :" + (end.getTime() - start.getTime())); + os.close(); + } + + + + + private static File createFile() { + String dir = CURRENT_PATH + "excel/"; + File file = new File(dir); + if (!file.exists()) { + file.mkdir(); + } + String name = CURRENT_PATH + "excel/" + UUID.randomUUID() + ".xlsx"; + return new File(name); + } + +} -- Gitee From 02aa4d0534d8de3f021b2c2197a686b77a4d107a Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Sat, 16 Jan 2021 09:37:10 +0800 Subject: [PATCH 010/161] =?UTF-8?q?Apply:=20add=20=E8=87=AA=E5=AE=9A?= =?UTF-8?q?=E4=B9=89=E6=A0=87=E9=A2=98=E5=AF=BC=E5=87=BA=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit c4189d9113c2d2144f788c25c7877f88e3478cb5) --- src/main/java/com/ibiz/excel/picture/support/model/Cell.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Cell.java b/src/main/java/com/ibiz/excel/picture/support/model/Cell.java index 6e6035f..a8d7027 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Cell.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Cell.java @@ -59,6 +59,11 @@ public class Cell { this(0,cellNumber); } + public Cell(int cellNumber, String value) { + this.cellNumber = cellNumber; + this.value = value; + } + public int getCellNumber() { return cellNumber; } -- Gitee From 05bf795fc5fcfecc1f24673dba5eb27e6361d5fe Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Sat, 16 Jan 2021 16:13:04 +0800 Subject: [PATCH 011/161] =?UTF-8?q?test=20=E5=86=85=E5=AD=98=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../excel/picture/support/model/Workbook.java | 7 +++-- .../picture/support/util/CompressorUtil.java | 4 +-- .../excel/picture/support/util/FileUtil.java | 8 ++--- .../picture/support/CustomTitleDemo.java | 29 ++++++++++--------- 4 files changed, 25 insertions(+), 23 deletions(-) diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Workbook.java b/src/main/java/com/ibiz/excel/picture/support/model/Workbook.java index d978c1d..ddfcf4e 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Workbook.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Workbook.java @@ -1,12 +1,13 @@ package com.ibiz.excel.picture.support.model; +import cn.hutool.core.util.ZipUtil; import com.ibiz.excel.picture.support.constants.WorkbookConstant; import com.ibiz.excel.picture.support.util.FileUtil; -import com.ibiz.excel.picture.support.util.CompressorUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.*; +import java.io.File; +import java.io.OutputStream; import java.util.*; /** @@ -81,7 +82,7 @@ public class Workbook { } sheets.forEach(Sheet::close); //把文件打包成xlsx - CompressorUtil.compress(filePath, destPath); + ZipUtil.zip(filePath, destPath); destFile = new File(destPath); deleteFile(filePath); logger.info("dest excel path:{}", destPath); diff --git a/src/main/java/com/ibiz/excel/picture/support/util/CompressorUtil.java b/src/main/java/com/ibiz/excel/picture/support/util/CompressorUtil.java index 25995be..ffd5936 100644 --- a/src/main/java/com/ibiz/excel/picture/support/util/CompressorUtil.java +++ b/src/main/java/com/ibiz/excel/picture/support/util/CompressorUtil.java @@ -1,11 +1,11 @@ package com.ibiz.excel.picture.support.util; -import java.io.File; - import org.apache.tools.ant.Project; import org.apache.tools.ant.taskdefs.Zip; import org.apache.tools.ant.types.FileSet; +import java.io.File; + /** * 将文件夹压缩成文件 */ diff --git a/src/main/java/com/ibiz/excel/picture/support/util/FileUtil.java b/src/main/java/com/ibiz/excel/picture/support/util/FileUtil.java index 37826f4..e1c3b95 100644 --- a/src/main/java/com/ibiz/excel/picture/support/util/FileUtil.java +++ b/src/main/java/com/ibiz/excel/picture/support/util/FileUtil.java @@ -47,14 +47,12 @@ public class FileUtil { } public static void writeToOutput(File source, OutputStream output) { - try { - byte[] buf = new byte[2048]; - FileInputStream fis = new FileInputStream(source); + byte[] buf = new byte[1024]; + try(BufferedInputStream fis = new BufferedInputStream(new FileInputStream(source))) { while (fis.read(buf) != -1) { output.write(buf); } - fis.close(); - } catch (IOException e) { + }catch (IOException e) { throw new RuntimeException("write to output error , destFile path:" + source.getAbsolutePath(), e); } } diff --git a/src/test/java/com/ibiz/excel/picture/support/CustomTitleDemo.java b/src/test/java/com/ibiz/excel/picture/support/CustomTitleDemo.java index 790cc8b..1adce03 100644 --- a/src/test/java/com/ibiz/excel/picture/support/CustomTitleDemo.java +++ b/src/test/java/com/ibiz/excel/picture/support/CustomTitleDemo.java @@ -1,16 +1,13 @@ package com.ibiz.excel.picture.support; +import cn.hutool.core.io.FileUtil; import com.ibiz.excel.picture.support.constants.WorkbookConstant; import com.ibiz.excel.picture.support.model.*; +import java.io.BufferedOutputStream; import java.io.File; -import java.io.FileOutputStream; import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.UUID; +import java.util.*; /** * 自定义标题,填入文本和图片 @@ -33,21 +30,26 @@ public class CustomTitleDemo { Sheet sheet = workBook.createSheet("测试"); // 第一行放标题 - Row row = sheet.createRow(0); + Row rowHead = sheet.createRow(0); String[] excelName = {"文本1", "文本2", "图片1", "图片2", "图片3"}; List nameCells = new ArrayList<>(); + int n = 0; for (int i = 0; i < excelName.length; i++) { - nameCells.add(new Cell(0, i).setValue(excelName[i])); + nameCells.add(new Cell(0, n).setValue(excelName[i])); + if (Objects.equals(excelName[i], "图片1")) { + n = n + 9; + } + n++; } - row.setCells(nameCells); + rowHead.setCells(nameCells); // 第二行放文本图片 - row = sheet.createRow(1); + Row row = sheet.createRow(1); List valueCells = new ArrayList<>(); List pictures = sheet.getPictures(); for (int i = 0; i < excelName.length; i++) { if (i < 2) { - valueCells.add(new Cell(1, i).setValue("文本")); + valueCells.add(new Cell(i, "文本")); } else { //有图片的行,行高设置为100 row.setHeight(WorkbookConstant.PICTURE_ROW_HEIGHT); @@ -57,9 +59,8 @@ public class CustomTitleDemo { } row.setCells(valueCells); - File file = createFile(); - OutputStream os = new FileOutputStream(file); + BufferedOutputStream os = FileUtil.getOutputStream(file); workBook.write(os); workBook.close(); Date end = new Date(); @@ -69,6 +70,8 @@ public class CustomTitleDemo { } + + private static File createFile() { String dir = CURRENT_PATH + "excel/"; File file = new File(dir); -- Gitee From f68d559264956f552c3c0c03a9e0aa00aca530d2 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Mon, 18 Jan 2021 16:53:23 +0800 Subject: [PATCH 012/161] =?UTF-8?q?fix=20wps=E6=89=93=E5=BC=80=E6=B2=A1?= =?UTF-8?q?=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/ibiz/excel/picture/support/model/Cell.java | 5 ----- .../java/com/ibiz/excel/picture/support/CustomTitleDemo.java | 4 +--- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Cell.java b/src/main/java/com/ibiz/excel/picture/support/model/Cell.java index a8d7027..6e6035f 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Cell.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Cell.java @@ -59,11 +59,6 @@ public class Cell { this(0,cellNumber); } - public Cell(int cellNumber, String value) { - this.cellNumber = cellNumber; - this.value = value; - } - public int getCellNumber() { return cellNumber; } diff --git a/src/test/java/com/ibiz/excel/picture/support/CustomTitleDemo.java b/src/test/java/com/ibiz/excel/picture/support/CustomTitleDemo.java index 1adce03..d89afa0 100644 --- a/src/test/java/com/ibiz/excel/picture/support/CustomTitleDemo.java +++ b/src/test/java/com/ibiz/excel/picture/support/CustomTitleDemo.java @@ -49,7 +49,7 @@ public class CustomTitleDemo { List pictures = sheet.getPictures(); for (int i = 0; i < excelName.length; i++) { if (i < 2) { - valueCells.add(new Cell(i, "文本")); + valueCells.add(new Cell(1, i).setValue("文本")); } else { //有图片的行,行高设置为100 row.setHeight(WorkbookConstant.PICTURE_ROW_HEIGHT); @@ -70,8 +70,6 @@ public class CustomTitleDemo { } - - private static File createFile() { String dir = CURRENT_PATH + "excel/"; File file = new File(dir); -- Gitee From da331419ff93dab3087a07ac315094bb1ed46116 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Mon, 18 Jan 2021 16:57:18 +0800 Subject: [PATCH 013/161] =?UTF-8?q?fix=20wps=E6=89=93=E5=BC=80=E6=B2=A1?= =?UTF-8?q?=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/ibiz/excel/picture/support/model/Cell.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Cell.java b/src/main/java/com/ibiz/excel/picture/support/model/Cell.java index a8d7027..6e6035f 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Cell.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Cell.java @@ -59,11 +59,6 @@ public class Cell { this(0,cellNumber); } - public Cell(int cellNumber, String value) { - this.cellNumber = cellNumber; - this.value = value; - } - public int getCellNumber() { return cellNumber; } -- Gitee From 3dc9ca43bd0aa3d8ef5762e20da1db5c2c0c4e53 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Sat, 16 Jan 2021 17:12:01 +0800 Subject: [PATCH 014/161] =?UTF-8?q?fix=20wps=E6=89=93=E5=BC=80=E6=B2=A1?= =?UTF-8?q?=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/ibiz/excel/picture/support/CustomTitleDemo.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/test/java/com/ibiz/excel/picture/support/CustomTitleDemo.java b/src/test/java/com/ibiz/excel/picture/support/CustomTitleDemo.java index 1adce03..d89afa0 100644 --- a/src/test/java/com/ibiz/excel/picture/support/CustomTitleDemo.java +++ b/src/test/java/com/ibiz/excel/picture/support/CustomTitleDemo.java @@ -49,7 +49,7 @@ public class CustomTitleDemo { List pictures = sheet.getPictures(); for (int i = 0; i < excelName.length; i++) { if (i < 2) { - valueCells.add(new Cell(i, "文本")); + valueCells.add(new Cell(1, i).setValue("文本")); } else { //有图片的行,行高设置为100 row.setHeight(WorkbookConstant.PICTURE_ROW_HEIGHT); @@ -70,8 +70,6 @@ public class CustomTitleDemo { } - - private static File createFile() { String dir = CURRENT_PATH + "excel/"; File file = new File(dir); -- Gitee From b613bf0eb590f3663e7e5a70cd042521665795f3 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Tue, 19 Jan 2021 10:21:42 +0800 Subject: [PATCH 015/161] =?UTF-8?q?add=20=E5=8D=95=E5=85=83=E6=A0=BC?= =?UTF-8?q?=E5=90=88=E5=B9=B6=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../picture/support/flush/Sheet1Handler.java | 207 ++++++++++-------- .../picture/support/model/MergeCell.java | 85 +++++-- .../excel/picture/support/model/Sheet.java | 2 +- .../picture/support/ColMergeCellTest.java | 71 ++++++ .../picture/support/RowMergeCellTest.java | 65 ++++++ 5 files changed, 314 insertions(+), 116 deletions(-) create mode 100644 src/test/java/com/ibiz/excel/picture/support/ColMergeCellTest.java create mode 100644 src/test/java/com/ibiz/excel/picture/support/RowMergeCellTest.java diff --git a/src/main/java/com/ibiz/excel/picture/support/flush/Sheet1Handler.java b/src/main/java/com/ibiz/excel/picture/support/flush/Sheet1Handler.java index 7e28279..79a8e8d 100644 --- a/src/main/java/com/ibiz/excel/picture/support/flush/Sheet1Handler.java +++ b/src/main/java/com/ibiz/excel/picture/support/flush/Sheet1Handler.java @@ -5,6 +5,8 @@ import com.ibiz.excel.picture.support.model.MergeCell; import com.ibiz.excel.picture.support.model.Row; import com.ibiz.excel.picture.support.model.Sheet; import com.ibiz.excel.picture.support.util.StringUtils; +import org.springframework.util.CollectionUtils; + import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.util.List; @@ -12,106 +14,125 @@ import java.util.Set; /** * 图片 + * * @auther 喻场 * @date 2020/7/618:33 */ public class Sheet1Handler implements InvocationHandler { - private IRepository target; - public Sheet1Handler(IRepository proxy) { - this.target = proxy; - } - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - Sheet sheet = (Sheet)args[0]; - if (method.getName().equals("write")) { - List rows = sheet.getRows(); - if (!rows.isEmpty()) { - //未刷新过说明没有写入过流,这里主要为了写表头 - //如果写过了,则从脚标1开始,原因是为了对比合并单元格在row1中保存上一次刷新的最后一条数据 - int subIndex = !sheet.hasFlush() ? 0 : 1; - setMergeCell(sheet, rows); - rows.subList(subIndex, rows.size()).stream().forEach(r -> writeSheetXML(r)); - } - } else if (method.getName().equals("close")) { - setEndSheetData(); - setMergeContent(sheet); - } - return method.invoke(target, args); - } + private IRepository target; + + public Sheet1Handler(IRepository proxy) { + this.target = proxy; + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + Sheet sheet = (Sheet) args[0]; + if (method.getName().equals("write")) { + List rows = sheet.getRows(); + if (!rows.isEmpty()) { + //未刷新过说明没有写入过流,这里主要为了写表头 + //如果写过了,则从脚标1开始,原因是为了对比合并单元格在row1中保存上一次刷新的最后一条数据 + int subIndex = !sheet.hasFlush() ? 0 : 1; + setMergeCell(sheet, rows); + rows.subList(subIndex, rows.size()).stream().forEach(r -> writeSheetXML(r)); + } + } else if (method.getName().equals("close")) { + setEndSheetData(); + setMergeContent(sheet); + } + return method.invoke(target, args); + } - /** - * 增加合并列内容 - * @param sheet - */ - private void setMergeContent(Sheet sheet) { - Set colCells = sheet.getColCells(); - StringBuilder content = new StringBuilder(); - if (sheet.isAutoMergeCell() && !sheet.getMergeCells().isEmpty()) { - content.append(""); - sheet.getMergeCells().stream().forEach(m -> { - colCells.forEach(c -> { - content.append(""); - }); - }); - content.append(""); - } - target.append(content.toString()); - } + /** + * 增加合并列内容 + * + * @param sheet + */ + private void setMergeContent(Sheet sheet) { + Set colCells = sheet.getColCells(); + StringBuilder content = new StringBuilder(); + if (sheet.isAutoMergeCell() && !sheet.getMergeCells().isEmpty()) { + content.append(""); + sheet.getMergeCells().stream().forEach(m -> { + if (CollectionUtils.isEmpty(colCells)) { + //增加合并行内容 + Cell start = new Cell(m.getFirstRow(), m.getFirstCol()); + Cell end = new Cell(m.getLastRow(), m.getLastCol()); + content.append(""); + } else { + colCells.forEach(c -> content + .append("")); + } + }); + content.append(""); + } + target.append(content.toString()); + } - /** - * 列结尾 - */ - private void setEndSheetData() { - target.append(""); - } + /** + * 列结尾 + */ + private void setEndSheetData() { + target.append(""); + } - private void setMergeCell(Sheet sheet, List rows) { - String oldValue = ""; - for(int i = 0; i < rows.size(); i++){ - Row row = rows.get(i); - if(null == row){ - continue; - } - List cells = row.getCells(); - int mergeCellNumber = sheet.getMergeCellNumber(); - if(mergeCellNumber >= cells.size()){ - //合并列超出范围,不进行合并 - break; - } - Cell cell = cells.get(mergeCellNumber); - if(StringUtils.isNotBlank(oldValue) && oldValue.equals(cell.getValue())){ - MergeCell mergeCell = null; - if(!sheet.getMergeCells().isEmpty()){ - mergeCell = sheet.getMergeCells().getLast(); - } - if (null == mergeCell) { - mergeCell = new MergeCell(); - } - int endRowNumber = mergeCell.getEndRowNumber(); - if (row.getRowNumber() == endRowNumber) { - //与上一个合并对象合并 - mergeCell.endRowNumber(++endRowNumber); - } else { - mergeCell = new MergeCell().startRowNumber(row.getRowNumber()).endRowNumber(row.getRowNumber() + 1); - sheet.getMergeCells().add(mergeCell); - } - } - oldValue = StringUtils.isBlank(cell.getValue()) ? "" : cell.getValue(); - } - } + private void setMergeCell(Sheet sheet, List rows) { + String oldValue = ""; + for (int i = 0; i < rows.size(); i++) { + Row row = rows.get(i); + if (null == row) { + continue; + } + List cells = row.getCells(); + int mergeCellNumber = sheet.getMergeCellNumber(); + if (mergeCellNumber >= cells.size()) { + //合并列超出范围,不进行合并 + break; + } + Cell cell = cells.get(mergeCellNumber); + if (StringUtils.isNotBlank(oldValue) && oldValue.equals(cell.getValue())) { + MergeCell mergeCell = null; + if (!sheet.getMergeCells().isEmpty()) { + mergeCell = sheet.getMergeCells().getLast(); + } + if (null == mergeCell) { + mergeCell = new MergeCell(); + } + int endRowNumber = mergeCell.getLastRow(); + if (row.getRowNumber() == endRowNumber) { + //与上一个合并对象合并 + mergeCell.setLastRow(++endRowNumber); + } else { + mergeCell = new MergeCell().setFirstRow(row.getRowNumber()).setLastRow(row.getRowNumber() + 1); + sheet.getMergeCells().add(mergeCell); + } + } + oldValue = StringUtils.isBlank(cell.getValue()) ? "" : cell.getValue(); + } + } - private void writeSheetXML(Row row) { - StringBuilder content = new StringBuilder(); - //customHeight=1 使用自定义高度 - content.append(""); - row.getCells().forEach(c -> - content.append("") - .append("").append(c.getColDataNumber()).append("") - ); - content.append(""); - target.append(content.toString()); - } + private void writeSheetXML(Row row) { + StringBuilder content = new StringBuilder(); + //customHeight=1 使用自定义高度 + content.append(""); + row.getCells().forEach(c -> + content.append("") + .append("").append(c.getColDataNumber()).append("") + ); + content.append(""); + target.append(content.toString()); + } } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/MergeCell.java b/src/main/java/com/ibiz/excel/picture/support/model/MergeCell.java index f41b7eb..ebe3e7a 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/MergeCell.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/MergeCell.java @@ -1,29 +1,70 @@ package com.ibiz.excel.picture.support.model; /** - * @auther 喻场 - * @date 2020/7/217:36 + * 合并单元格 + * + * @author MinWeikai + * @date 2021-01-19 09:18:15 */ public class MergeCell { - private int startRowNumber; //合并单元格起始行 - private int endRowNumber; //合并单元格结束行 - - public MergeCell startRowNumber(int startRowNumber) { - this.startRowNumber = startRowNumber; - return this; - } - - public MergeCell endRowNumber(int endRowNumber) { - this.endRowNumber = endRowNumber; - return this; - } - - public int getStartRowNumber() { - return startRowNumber; - } - - public int getEndRowNumber() { - return endRowNumber; - } + + private int firstRow; + private int firstCol; + private int lastRow; + private int lastCol; + + public MergeCell() { + } + + /** + * 构造此合并单元格对象可以进行合并 + * + * @param firstRow + * @param firstCol + * @param lastRow + * @param lastCol + */ + public MergeCell(int firstRow, int firstCol, int lastRow, int lastCol) { + this.firstRow = firstRow; + this.firstCol = firstCol; + this.lastRow = lastRow; + this.lastCol = lastCol; + } + + public int getFirstRow() { + return firstRow; + } + + public MergeCell setFirstRow(int firstRow) { + this.firstRow = firstRow; + return this; + } + + public int getFirstCol() { + return firstCol; + } + + public MergeCell setFirstCol(int firstCol) { + this.firstCol = firstCol; + return this; + } + + public int getLastRow() { + return lastRow; + } + + public MergeCell setLastRow(int lastRow) { + this.lastRow = lastRow; + return this; + } + + public int getLastCol() { + return lastCol; + } + + public MergeCell setLastCol(int lastCol) { + this.lastCol = lastCol; + return this; + } } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java index 74a247c..7546453 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java @@ -37,7 +37,7 @@ public class Sheet { private String sheetName; //默认sheet1 private int drawingSequence = 1; //图片id序号 对应drawing1.xml.rels Id后的数字 private int sharedStringSequence = -1; //单元格值序号 sharedString.xml对应标签序号 - private boolean autoMergeCell = Boolean.FALSE; //是否自动合并单元格 + private boolean autoMergeCell = Boolean.TRUE; //是否自动合并单元格 private boolean hasFlush; //是否已经执行过flush private boolean hasWriteHead; //是否已经写标题 private final List closeAlias = Arrays.asList(Alias.APP, Alias.WORKBOOK_XML); diff --git a/src/test/java/com/ibiz/excel/picture/support/ColMergeCellTest.java b/src/test/java/com/ibiz/excel/picture/support/ColMergeCellTest.java new file mode 100644 index 0000000..e76cb4c --- /dev/null +++ b/src/test/java/com/ibiz/excel/picture/support/ColMergeCellTest.java @@ -0,0 +1,71 @@ +package com.ibiz.excel.picture.support; + +import cn.hutool.core.io.FileUtil; +import com.ibiz.excel.picture.support.model.*; + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.IOException; +import java.util.*; + +/** + * 横向合并列测试 + * + * @author MinWeikai + * @date 2021/1/18 17:22 + */ +public class ColMergeCellTest { + + static final String CURRENT_PATH = "E:\\test\\"; + + public static void main(String[] args) throws IOException { + Date start = new Date(); + Workbook workBook = Workbook.getInstance(1); + Sheet sheet = workBook.createSheet("测试"); + + // 第一行表头 + Row row = sheet.createRow(0); + String[] excelName = {"文本1", "文本2", "图片1", "图片2", "图片3"}; + sheet.getMergeCells().add(new MergeCell(0, 0, 0, excelName.length - 1)); + row.setCells(Collections.singletonList(new Cell(0, 0).setValue("表头"))); + + // 第二行放标题 + row = sheet.createRow(1); + List cells = new ArrayList<>(); + for (int i = 0; i < excelName.length; i++) { + Cell cell = new Cell(1, i).setValue(excelName[i]); + cells.add(cell); + } + row.setCells(cells); + + // 第三行放内容 + row = sheet.createRow(2); + cells = new ArrayList<>(); + for (int i = 0; i < excelName.length; i++) { + Cell cell = new Cell(2, i).setValue("文本" + i); + cells.add(cell); + } + row.setCells(cells); + + + File file = createFile(); + BufferedOutputStream os = FileUtil.getOutputStream(file); + workBook.write(os); + workBook.close(); + Date end = new Date(); + System.out.println("file capital :" + (file.length() / 1024 / 1024) + "M name :" + file.getName()); + System.out.println("file cost time :" + (end.getTime() - start.getTime())); + os.close(); + } + + + private static File createFile() { + String dir = CURRENT_PATH + "excel/"; + File file = new File(dir); + if (!file.exists()) { + file.mkdir(); + } + String name = CURRENT_PATH + "excel/" + UUID.randomUUID() + ".xlsx"; + return new File(name); + } +} diff --git a/src/test/java/com/ibiz/excel/picture/support/RowMergeCellTest.java b/src/test/java/com/ibiz/excel/picture/support/RowMergeCellTest.java new file mode 100644 index 0000000..396a304 --- /dev/null +++ b/src/test/java/com/ibiz/excel/picture/support/RowMergeCellTest.java @@ -0,0 +1,65 @@ +package com.ibiz.excel.picture.support; + +import cn.hutool.core.io.FileUtil; +import com.ibiz.excel.picture.support.model.*; + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.IOException; +import java.util.*; + +/** + * 纵向合并行测试 + * + * @author MinWeikai + * @date 2021/1/18 17:22 + */ +public class RowMergeCellTest { + + static final String CURRENT_PATH = "E:\\test\\"; + + public static void main(String[] args) throws IOException { + Date start = new Date(); + Workbook workBook = Workbook.getInstance(1); + Sheet sheet = workBook.createSheet("测试"); + + // 第一行放标题 + Row rowHead = sheet.createRow(0); + String[] excelName = {"文本1", "文本2", "图片1", "图片2", "图片3"}; + List nameCells = new ArrayList<>(); + + sheet.getMergeCells().add(new MergeCell().setFirstRow(1).setLastRow(3)); + sheet.setAutoMergeCell(true); + Set colCells = new HashSet<>(); + for (int i = 0; i < excelName.length; i++) { + Cell cell = new Cell(0, i).setValue(excelName[i]); + if (i == 0) { + colCells.add(cell.getCol()); + sheet.setColCells(colCells); + } + nameCells.add(cell); + } + rowHead.setCells(nameCells); + + + File file = createFile(); + BufferedOutputStream os = FileUtil.getOutputStream(file); + workBook.write(os); + workBook.close(); + Date end = new Date(); + System.out.println("file capital :" + (file.length() / 1024 / 1024) + "M name :" + file.getName()); + System.out.println("file cost time :" + (end.getTime() - start.getTime())); + os.close(); + } + + + private static File createFile() { + String dir = CURRENT_PATH + "excel/"; + File file = new File(dir); + if (!file.exists()) { + file.mkdir(); + } + String name = CURRENT_PATH + "excel/" + UUID.randomUUID() + ".xlsx"; + return new File(name); + } +} -- Gitee From a5e69be729e2aad180bc906033e6d94fbbdad642 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Tue, 19 Jan 2021 14:46:17 +0800 Subject: [PATCH 016/161] =?UTF-8?q?add=20=E8=A1=8C=E5=A1=AB=E5=85=85?= =?UTF-8?q?=E8=89=B2=E5=8A=9F=E8=83=BD=EF=BC=8C=E7=8E=B0=E9=BB=98=E8=AE=A4?= =?UTF-8?q?=E5=8F=AA=E6=9C=89=E6=B5=85=E7=BB=BF=E8=89=B2=EF=BC=8C=E5=8F=AF?= =?UTF-8?q?=E4=BB=A5=E8=87=AA=E8=A1=8C=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../picture/support/flush/Sheet1Handler.java | 20 +++-- .../picture/support/model/FgColorEnum.java | 29 ++++++++ .../ibiz/excel/picture/support/model/Row.java | 15 ++++ .../excel/picture/support/model/RowStyle.java | 30 ++++++++ .../excel/picture/support/module/Styles.java | 16 +++- .../excel/picture/support/RowFgColorTest.java | 73 +++++++++++++++++++ 6 files changed, 172 insertions(+), 11 deletions(-) create mode 100644 src/main/java/com/ibiz/excel/picture/support/model/FgColorEnum.java create mode 100644 src/main/java/com/ibiz/excel/picture/support/model/RowStyle.java create mode 100644 src/test/java/com/ibiz/excel/picture/support/RowFgColorTest.java diff --git a/src/main/java/com/ibiz/excel/picture/support/flush/Sheet1Handler.java b/src/main/java/com/ibiz/excel/picture/support/flush/Sheet1Handler.java index 79a8e8d..e071144 100644 --- a/src/main/java/com/ibiz/excel/picture/support/flush/Sheet1Handler.java +++ b/src/main/java/com/ibiz/excel/picture/support/flush/Sheet1Handler.java @@ -1,15 +1,13 @@ package com.ibiz.excel.picture.support.flush; -import com.ibiz.excel.picture.support.model.Cell; -import com.ibiz.excel.picture.support.model.MergeCell; -import com.ibiz.excel.picture.support.model.Row; -import com.ibiz.excel.picture.support.model.Sheet; +import com.ibiz.excel.picture.support.model.*; import com.ibiz.excel.picture.support.util.StringUtils; import org.springframework.util.CollectionUtils; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.util.List; +import java.util.Optional; import java.util.Set; /** @@ -127,10 +125,18 @@ public class Sheet1Handler implements InvocationHandler { //customHeight=1 使用自定义高度 content.append(""); - row.getCells().forEach(c -> - content.append("") - .append("").append(c.getColDataNumber()).append("") + row.getCells().forEach(c -> content.append("") + .append("") + .append(c.getColDataNumber()) + .append("") ); + + content.append(""); target.append(content.toString()); } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/FgColorEnum.java b/src/main/java/com/ibiz/excel/picture/support/model/FgColorEnum.java new file mode 100644 index 0000000..039da86 --- /dev/null +++ b/src/main/java/com/ibiz/excel/picture/support/model/FgColorEnum.java @@ -0,0 +1,29 @@ +package com.ibiz.excel.picture.support.model; + +/** + * 填充色枚举类 + * + * @author MinWeikai + * @date 2021/1/19 14:10 + */ +public enum FgColorEnum { + + /** + * 绿色填充色 + */ + GREEN(3); + + /** + * 填充色id + * 与对应{@link com.ibiz.excel.picture.support.module.Styles} + */ + private Integer fillId; + + FgColorEnum(Integer fillId) { + this.fillId = fillId; + } + + public Integer getFillId() { + return fillId; + } +} diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Row.java b/src/main/java/com/ibiz/excel/picture/support/model/Row.java index f97ef6a..76af5bd 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Row.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Row.java @@ -16,6 +16,12 @@ public class Row { */ private int height; //列高 private List cells = new ArrayList<>(); + + /** + * 该行样式 + */ + private RowStyle rowStyle; + public Row(){ this(1); } @@ -52,4 +58,13 @@ public class Row { public void clear(){ this.cells.clear(); } + + public RowStyle getRowStyle() { + return rowStyle; + } + + public Row setRowStyle(RowStyle rowStyle) { + this.rowStyle = rowStyle; + return this; + } } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/RowStyle.java b/src/main/java/com/ibiz/excel/picture/support/model/RowStyle.java new file mode 100644 index 0000000..7ec445b --- /dev/null +++ b/src/main/java/com/ibiz/excel/picture/support/model/RowStyle.java @@ -0,0 +1,30 @@ +package com.ibiz.excel.picture.support.model; + +/** + * 控制该行样式 + * + * @author MinWeikai + * @date 2021/1/19 14:04 + */ +public class RowStyle { + + private int fillId; + + private FgColorEnum fgColor; + + public RowStyle() { + } + + public RowStyle(FgColorEnum fgColor) { + this.fgColor = fgColor; + fillId = this.fgColor.getFillId(); + } + + public int getFillId() { + return fillId; + } + + public FgColorEnum getFgColor() { + return fgColor; + } +} diff --git a/src/main/java/com/ibiz/excel/picture/support/module/Styles.java b/src/main/java/com/ibiz/excel/picture/support/module/Styles.java index c248a1b..0232d7b 100644 --- a/src/main/java/com/ibiz/excel/picture/support/module/Styles.java +++ b/src/main/java/com/ibiz/excel/picture/support/module/Styles.java @@ -5,8 +5,10 @@ import com.ibiz.excel.picture.support.annotation.AutoWrite; import com.ibiz.excel.picture.support.constants.Alias; /** - * @auther 喻场 - * @date 2020/7/310:03 + * 电子表格样式参考处 + * http://officeopenxml.com/SSstyles.php + * @author MinWeikai + * @date 2021-01-19 14:00:55 */ @AutoWrite(dir = "xl") public class Styles { @@ -23,7 +25,10 @@ public class Styles { "" + "" + "" + - "" + + "" + + "" + + "" + // 绿色背景,后续可在此追加 + "" + "" + "" + "" + @@ -34,7 +39,10 @@ public class Styles { "" + "" + "" + - "" + + "" + + "" + + "" + // 填充色值坐标 + "" + "" + "" + ""; diff --git a/src/test/java/com/ibiz/excel/picture/support/RowFgColorTest.java b/src/test/java/com/ibiz/excel/picture/support/RowFgColorTest.java new file mode 100644 index 0000000..2816897 --- /dev/null +++ b/src/test/java/com/ibiz/excel/picture/support/RowFgColorTest.java @@ -0,0 +1,73 @@ +package com.ibiz.excel.picture.support; + +import cn.hutool.core.io.FileUtil; +import com.ibiz.excel.picture.support.model.*; + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.IOException; +import java.util.*; + +/** + * 行填充色 + * + * @author MinWeikai + * @date 2021-01-19 13:58:14 + */ +public class RowFgColorTest { + + static final String CURRENT_PATH = "E:\\test\\"; + + public static void main(String[] args) throws IOException { + Date start = new Date(); + Workbook workBook = Workbook.getInstance(1); + Sheet sheet = workBook.createSheet("测试"); + + // 第一行表头 + Row row = sheet.createRow(0); + String[] excelName = {"文本1", "文本2", "图片1", "图片2", "图片3"}; + sheet.getMergeCells().add(new MergeCell(0, 0, 0, excelName.length - 1)); + row.setCells(Collections.singletonList(new Cell(0, 0).setValue("表头"))); + + // 第二行放标题 + row = sheet.createRow(1) + //配置该行颜色,现在默认只有绿色 + .setRowStyle(new RowStyle(FgColorEnum.GREEN)); + List cells = new ArrayList<>(); + for (int i = 0; i < excelName.length; i++) { + Cell cell = new Cell(1, i).setValue(excelName[i]); + cells.add(cell); + } + row.setCells(cells); + + // 第三行放内容 + row = sheet.createRow(2); + cells = new ArrayList<>(); + for (int i = 0; i < excelName.length; i++) { + Cell cell = new Cell(2, i).setValue("文本" + i); + cells.add(cell); + } + row.setCells(cells); + + + File file = createFile(); + BufferedOutputStream os = FileUtil.getOutputStream(file); + workBook.write(os); + workBook.close(); + Date end = new Date(); + System.out.println("file capital :" + (file.length() / 1024 / 1024) + "M name :" + file.getName()); + System.out.println("file cost time :" + (end.getTime() - start.getTime())); + os.close(); + } + + + private static File createFile() { + String dir = CURRENT_PATH + "excel/"; + File file = new File(dir); + if (!file.exists()) { + file.mkdir(); + } + String name = CURRENT_PATH + "excel/" + UUID.randomUUID() + ".xlsx"; + return new File(name); + } +} -- Gitee From dbedeef9c226ad6045906d316ffbb1512dce0bd9 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Tue, 19 Jan 2021 16:01:37 +0800 Subject: [PATCH 017/161] =?UTF-8?q?add=20=E8=87=AA=E5=AE=9A=E4=B9=89?= =?UTF-8?q?=E5=88=97=E5=AE=BD=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../picture/support/flush/Sheet1Handler.java | 32 +++++++- .../picture/support/model/ColumnHelper.java | 30 ++++++++ .../excel/picture/support/model/Sheet.java | 23 ++++++ .../excel/picture/support/module/Sheet1.java | 4 +- .../excel/picture/support/CellWidthTest.java | 75 +++++++++++++++++++ 5 files changed, 159 insertions(+), 5 deletions(-) create mode 100644 src/main/java/com/ibiz/excel/picture/support/model/ColumnHelper.java create mode 100644 src/test/java/com/ibiz/excel/picture/support/CellWidthTest.java diff --git a/src/main/java/com/ibiz/excel/picture/support/flush/Sheet1Handler.java b/src/main/java/com/ibiz/excel/picture/support/flush/Sheet1Handler.java index e071144..a69528e 100644 --- a/src/main/java/com/ibiz/excel/picture/support/flush/Sheet1Handler.java +++ b/src/main/java/com/ibiz/excel/picture/support/flush/Sheet1Handler.java @@ -32,7 +32,9 @@ public class Sheet1Handler implements InvocationHandler { //未刷新过说明没有写入过流,这里主要为了写表头 //如果写过了,则从脚标1开始,原因是为了对比合并单元格在row1中保存上一次刷新的最后一条数据 int subIndex = !sheet.hasFlush() ? 0 : 1; - setMergeCell(sheet, rows); + this.setMergeCell(sheet, rows); + //设置宽度 + this.setColumnWidth(sheet, subIndex); rows.subList(subIndex, rows.size()).stream().forEach(r -> writeSheetXML(r)); } } else if (method.getName().equals("close")) { @@ -42,6 +44,32 @@ public class Sheet1Handler implements InvocationHandler { return method.invoke(target, args); } + /** + * 设置列宽度 + * + * @param sheet + * @param subIndex + */ + private void setColumnWidth(Sheet sheet, int subIndex) { + if (subIndex == 0) { + StringBuilder content = new StringBuilder(); + content.append("") + // 默认宽度 + .append(""); + // 自定义的宽度 + sheet.getColumnHelpers().stream().forEach(column -> + content.append("")); + content.append(""); + target.append(content.toString()); + } + } + /** * 增加合并列内容 * @@ -135,8 +163,6 @@ public class Sheet1Handler implements InvocationHandler { .append(c.getColDataNumber()) .append("") ); - - content.append(""); target.append(content.toString()); } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/ColumnHelper.java b/src/main/java/com/ibiz/excel/picture/support/model/ColumnHelper.java new file mode 100644 index 0000000..184baec --- /dev/null +++ b/src/main/java/com/ibiz/excel/picture/support/model/ColumnHelper.java @@ -0,0 +1,30 @@ +package com.ibiz.excel.picture.support.model; + +/** + * 单元格辅助功能类 + * + * @author MinWeikai + * @date 2021/1/19 15:41 + */ +public class ColumnHelper { + + private Integer columnIndex; + + private Integer width; + + public ColumnHelper() { + } + + public ColumnHelper(Integer columnIndex, Integer width) { + this.columnIndex = columnIndex; + this.width = width; + } + + public Integer getColumnIndex() { + return columnIndex; + } + + public Integer getWidth() { + return width; + } +} diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java index 7546453..330bacb 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java @@ -63,6 +63,11 @@ public class Sheet { * 对应excel column {"A"} A列行相同的值要合并*/ private Set colCells = new HashSet<>(); + /** + * 单元格辅助类 + */ + private List columnHelpers = new ArrayList<>(); + public List getPictures() { return pictures; } @@ -274,4 +279,22 @@ public class Sheet { pictures.clear(); } } + + /** + * 设置单元格宽度 + * @param columnIndex 坐标 + * @param width 宽度 + */ + public void setColumnWidth(int columnIndex, int width){ + this.columnHelpers = Collections.singletonList(new ColumnHelper(columnIndex, width)); + } + + public Sheet addColumnHelper(ColumnHelper columnHelper){ + this.columnHelpers.add(columnHelper); + return this; + } + + public List getColumnHelpers() { + return columnHelpers; + } } diff --git a/src/main/java/com/ibiz/excel/picture/support/module/Sheet1.java b/src/main/java/com/ibiz/excel/picture/support/module/Sheet1.java index 7a65fbc..ba92d57 100644 --- a/src/main/java/com/ibiz/excel/picture/support/module/Sheet1.java +++ b/src/main/java/com/ibiz/excel/picture/support/module/Sheet1.java @@ -16,6 +16,6 @@ public class Sheet1 { String content = "" + - "" + - ""; + ""; + } diff --git a/src/test/java/com/ibiz/excel/picture/support/CellWidthTest.java b/src/test/java/com/ibiz/excel/picture/support/CellWidthTest.java new file mode 100644 index 0000000..744f8f2 --- /dev/null +++ b/src/test/java/com/ibiz/excel/picture/support/CellWidthTest.java @@ -0,0 +1,75 @@ +package com.ibiz.excel.picture.support; + +import cn.hutool.core.io.FileUtil; +import com.ibiz.excel.picture.support.model.*; + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.IOException; +import java.util.*; + +/** + * 单元格自定义宽度 + * + * @author MinWeikai + * @date 2021-01-19 14:47:39 + */ +public class CellWidthTest { + + static final String CURRENT_PATH = "E:\\test\\"; + + public static void main(String[] args) throws IOException { + Date start = new Date(); + Workbook workBook = Workbook.getInstance(1); + Sheet sheet = workBook.createSheet("测试"); + // 设置宽度 + sheet.setColumnWidth(1, 50); + + // 第一行表头 + Row row = sheet.createRow(0); + String[] excelName = {"文本1", "文本2", "图片1", "图片2", "图片3"}; + sheet.getMergeCells().add(new MergeCell(0, 0, 0, excelName.length - 1)); + row.setCells(Collections.singletonList(new Cell(0, 0).setValue("表头"))); + + // 第二行放标题 + row = sheet.createRow(1) + //配置该行颜色,现在默认只有绿色 + .setRowStyle(new RowStyle(FgColorEnum.GREEN)); + List cells = new ArrayList<>(); + for (int i = 0; i < excelName.length; i++) { + Cell cell = new Cell(1, i).setValue(excelName[i]); + cells.add(cell); + } + row.setCells(cells); + + // 第三行放内容 + row = sheet.createRow(2); + cells = new ArrayList<>(); + for (int i = 0; i < excelName.length; i++) { + Cell cell = new Cell(2, i).setValue("文本" + i); + cells.add(cell); + } + row.setCells(cells); + + + File file = createFile(); + BufferedOutputStream os = FileUtil.getOutputStream(file); + workBook.write(os); + workBook.close(); + Date end = new Date(); + System.out.println("file capital :" + (file.length() / 1024 / 1024) + "M name :" + file.getName()); + System.out.println("file cost time :" + (end.getTime() - start.getTime())); + os.close(); + } + + + private static File createFile() { + String dir = CURRENT_PATH + "excel/"; + File file = new File(dir); + if (!file.exists()) { + file.mkdir(); + } + String name = CURRENT_PATH + "excel/" + UUID.randomUUID() + ".xlsx"; + return new File(name); + } +} -- Gitee From 47eb348d16559f2806b7ad2b5a7e82acc2bf0be6 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Tue, 19 Jan 2021 19:52:13 +0800 Subject: [PATCH 018/161] =?UTF-8?q?add=20=E5=8D=95=E5=85=83=E6=A0=BC?= =?UTF-8?q?=E5=90=8C=E5=A4=9A=E5=9B=BE=E8=AE=BE=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../support/flush/Drawing1Handler.java | 100 +++++++++++------- .../excel/picture/support/model/Picture.java | 24 +++++ .../excel/picture/support/model/Sheet.java | 6 ++ .../excel/picture/support/module/Sheet1.java | 2 +- .../picture/support/PictureCellWidthTest.java | 94 ++++++++++++++++ 5 files changed, 188 insertions(+), 38 deletions(-) create mode 100644 src/test/java/com/ibiz/excel/picture/support/PictureCellWidthTest.java diff --git a/src/main/java/com/ibiz/excel/picture/support/flush/Drawing1Handler.java b/src/main/java/com/ibiz/excel/picture/support/flush/Drawing1Handler.java index a21c254..254ac2d 100644 --- a/src/main/java/com/ibiz/excel/picture/support/flush/Drawing1Handler.java +++ b/src/main/java/com/ibiz/excel/picture/support/flush/Drawing1Handler.java @@ -2,49 +2,75 @@ package com.ibiz.excel.picture.support.flush; import com.ibiz.excel.picture.support.model.Picture; import com.ibiz.excel.picture.support.model.Sheet; + import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.util.List; -import java.util.Objects; +import java.util.Map; +import java.util.stream.Collectors; /** - * 图片 - * @auther 喻场 - * @date 2020/7/618:33 + * 适应单元格填充多图 + * + * @author MinWeikai + * @date 2021-01-19 18:53:06 */ public class Drawing1Handler implements InvocationHandler { - private IRepository target; - public Drawing1Handler(IRepository proxy) { - this.target = proxy; - } - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - if (method.getName().equals("write")) { - Sheet sheet = (Sheet)args[0]; - List pictures = sheet.getPictures(); - pictures.stream().filter(Objects::nonNull).forEach(p -> { - writerDrawingXML(p); - }); - } - return method.invoke(target, args); - } - - /** - * 写 drawing1.xml - * @param picture - * @param picture - */ - private void writerDrawingXML( - Picture picture) { - String content = "" + picture.getFromCol() +"0" + - "" + picture.getFromRow() + "0\n" + - "" + picture.getToCol() +"9525" + - "" + picture.getToRow() +"1260000" + - "" + - "\n" + - "\n" + - ""; - target.append(content); - } + private IRepository target; + + public Drawing1Handler(IRepository proxy) { + this.target = proxy; + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + if (method.getName().equals("write")) { + Sheet sheet = (Sheet) args[0]; + Map> listMap = sheet.getPictures().stream() + .collect(Collectors.groupingBy(e -> e.getFromCol() + e.getFromRow())); + + for (Map.Entry> map : listMap.entrySet()) { + this.writerDrawing(map.getValue()); + } + } + return method.invoke(target, args); + } + + private void writerDrawing(List pictures) { + Picture p; + for (int i = 0; i < pictures.size(); i++) { + p = pictures.get(i); + if (p != null) { + writerDrawingXML(p, i); + } + } + } + + /** + * 写 drawing1.xml + * + * @param picture + * @param i + */ + private void writerDrawingXML( + Picture picture, int i) { + String content = "" + + "" + picture.getFromCol() + ""; + int colOff = i * picture.getWidth(); + content = content + colOff + "" + + "" + picture.getFromRow() + "0" + + "\n" + + "" + picture.getToCol() + "" + (colOff + picture.getWidth()) + "" + + "" + picture.getToRow() + "1260000" + + "" + + "" + + "" + + "\n" + + "\n" + + "" + + "" + + ""; + target.append(content); + } } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Picture.java b/src/main/java/com/ibiz/excel/picture/support/model/Picture.java index d5e359c..4f5d34e 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Picture.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Picture.java @@ -12,6 +12,12 @@ public class Picture { private int toRow; //图片结束行 Row.rowNumber /**当前系统中图片的绝对路径*/ private String picturePath; //图片路径 + + /** + * 图片宽度 + */ + private int width; + public Picture(){ } @@ -24,6 +30,16 @@ public class Picture { this.picturePath = picturePath; } + public Picture(int fromCol, int fromRow, int width, String picturePath) { + super(); + this.fromRow = fromRow; + this.fromCol = fromCol; + this.toRow = fromRow; + this.toCol = fromCol; + this.picturePath = picturePath; + this.width = width; + } + public String getPicturePath() { return picturePath; } @@ -72,4 +88,12 @@ public class Picture { this.rembed = rembed; } + public int getWidth() { + return width; + } + + public Picture setWidth(int width) { + this.width = width; + return this; + } } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java index 330bacb..24a1adf 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java @@ -289,11 +289,17 @@ public class Sheet { this.columnHelpers = Collections.singletonList(new ColumnHelper(columnIndex, width)); } + public Sheet addColumnHelper(ColumnHelper columnHelper){ this.columnHelpers.add(columnHelper); return this; } + public Sheet addAllColumnHelper(List columnHelpers){ + this.columnHelpers.addAll(columnHelpers); + return this; + } + public List getColumnHelpers() { return columnHelpers; } diff --git a/src/main/java/com/ibiz/excel/picture/support/module/Sheet1.java b/src/main/java/com/ibiz/excel/picture/support/module/Sheet1.java index ba92d57..ad0485a 100644 --- a/src/main/java/com/ibiz/excel/picture/support/module/Sheet1.java +++ b/src/main/java/com/ibiz/excel/picture/support/module/Sheet1.java @@ -15,7 +15,7 @@ public class Sheet1 { xmlEnd = AutoXmlHeadEndContent.SHEET1_END) String content = "" + + ">" + ""; } diff --git a/src/test/java/com/ibiz/excel/picture/support/PictureCellWidthTest.java b/src/test/java/com/ibiz/excel/picture/support/PictureCellWidthTest.java new file mode 100644 index 0000000..494b7aa --- /dev/null +++ b/src/test/java/com/ibiz/excel/picture/support/PictureCellWidthTest.java @@ -0,0 +1,94 @@ +package com.ibiz.excel.picture.support; + +import cn.hutool.core.io.FileUtil; +import com.ibiz.excel.picture.support.model.*; + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.IOException; +import java.util.*; + +/** + * 图片放在一个单元格宽度 + * + * @author MinWeikai + * @date 2021-01-19 16:03:21 + */ +public class PictureCellWidthTest { + + private static final String CURRENT_PATH = "E:\\test\\"; + + private final static String IMG_PATH = CURRENT_PATH + "img\\"; + + private final static String IMG_PATH_1 = IMG_PATH + "ia_1900002528.jpeg"; + + public static void main(String[] args) throws IOException { + Date start = new Date(); + Workbook workBook = Workbook.getInstance(1); + Sheet sheet = workBook.createSheet("测试"); + + // 需要在创建行前预设宽度 + sheet.addColumnHelper(new ColumnHelper(1, 10)) + .addColumnHelper(new ColumnHelper(3, 50)) + .addColumnHelper(new ColumnHelper(4, 50)); + + // 第一行表头 + Row row = sheet.createRow(0); + String[] excelName = {"序号", "文本2", "图片1", "图片2", "图片3"}; + sheet.getMergeCells().add(new MergeCell(0, 0, 0, excelName.length - 1)); + row.setCells(Collections.singletonList(new Cell(0, 0).setValue("表头"))); + + // 第二行放标题 + row = sheet.createRow(1) + //配置该行颜色,现在默认只有绿色 + .setRowStyle(new RowStyle(FgColorEnum.GREEN)); + List cells = new ArrayList<>(); + for (int i = 0; i < excelName.length; i++) { + Cell cell = new Cell(1, i).setValue(excelName[i]); + cells.add(cell); + } + row.setCells(cells); + + // 第三行放内容和图片 + row = sheet.createRow(2); + + cells = new ArrayList<>(); + List pictures = sheet.getPictures(); + //序号 + cells.add(new Cell(2, 0).setValue("1")); + for (int i = 0; i < excelName.length; i++) { + if (i < 2) { + cells.add(new Cell(2, i).setValue("文本" + i)); + } else { + //有图片的行,行高设置为100 + row.setHeight(80); + //每个单元格增加一个图片 + //pictures.add(new Picture(i, row.getRowNumber(),1000000 , IMG_PATH_1)); + //在第三列添加多张图片 + pictures.add(new Picture(3, row.getRowNumber(), 1000000, IMG_PATH_1)); + } + } + row.setCells(cells); + + + File file = createFile(); + BufferedOutputStream os = FileUtil.getOutputStream(file); + workBook.write(os); + workBook.close(); + Date end = new Date(); + System.out.println("file capital :" + (file.length() / 1024 / 1024) + "M name :" + file.getName()); + System.out.println("file cost time :" + (end.getTime() - start.getTime())); + os.close(); + } + + + private static File createFile() { + String dir = CURRENT_PATH + "excel/"; + File file = new File(dir); + if (!file.exists()) { + file.mkdir(); + } + String name = CURRENT_PATH + "excel/" + UUID.randomUUID() + ".xlsx"; + return new File(name); + } +} -- Gitee From ac644a31c2f7ab9852551f44b4d0e31afb4f659b Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Wed, 20 Jan 2021 15:40:14 +0800 Subject: [PATCH 019/161] =?UTF-8?q?add=20=E8=AE=BE=E7=BD=AE=E5=AD=97?= =?UTF-8?q?=E4=BD=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../support/flush/DrawingXmlRelsHandler.java | 10 +- .../excel/picture/support/model/FontEnum.java | 30 ++++++ .../excel/picture/support/model/RowStyle.java | 15 +-- .../{FgColorEnum.java => StyleEnum.java} | 16 ++- .../excel/picture/support/module/Styles.java | 51 ++++++++-- .../excel/picture/support/CellWidthTest.java | 2 +- .../ibiz/excel/picture/support/FontTest.java | 99 +++++++++++++++++++ .../picture/support/PictureCellWidthTest.java | 2 +- .../excel/picture/support/RowFgColorTest.java | 2 +- 9 files changed, 198 insertions(+), 29 deletions(-) create mode 100644 src/main/java/com/ibiz/excel/picture/support/model/FontEnum.java rename src/main/java/com/ibiz/excel/picture/support/model/{FgColorEnum.java => StyleEnum.java} (66%) create mode 100644 src/test/java/com/ibiz/excel/picture/support/FontTest.java diff --git a/src/main/java/com/ibiz/excel/picture/support/flush/DrawingXmlRelsHandler.java b/src/main/java/com/ibiz/excel/picture/support/flush/DrawingXmlRelsHandler.java index 4ff6bbf..f375d03 100644 --- a/src/main/java/com/ibiz/excel/picture/support/flush/DrawingXmlRelsHandler.java +++ b/src/main/java/com/ibiz/excel/picture/support/flush/DrawingXmlRelsHandler.java @@ -1,15 +1,14 @@ package com.ibiz.excel.picture.support.flush; -import com.ibiz.excel.picture.support.util.CovertUtil; import com.ibiz.excel.picture.support.constants.Alias; import com.ibiz.excel.picture.support.constants.WorkbookConstant; import com.ibiz.excel.picture.support.model.Picture; import com.ibiz.excel.picture.support.model.Sheet; import com.ibiz.excel.picture.support.module.RelationShip; +import com.ibiz.excel.picture.support.util.CovertUtil; import com.ibiz.excel.picture.support.util.FileUtil; import com.ibiz.excel.picture.support.util.MD5Digester; import com.ibiz.excel.picture.support.util.StringUtils; -import org.apache.tools.ant.util.FileUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -17,7 +16,8 @@ import java.io.File; import java.io.IOException; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; -import java.util.*; +import java.util.List; +import java.util.Objects; /** * 图片 @@ -58,10 +58,10 @@ public class DrawingXmlRelsHandler implements InvocationHandler { File srcPicture = new File(picture.getPicturePath()); String md5 = MD5Digester.digestMD5(srcPicture); Integer drawingSequence = sheet.getWorkbook().getImageCache().get(md5); + // 已存在的图片 if (Objects.nonNull(drawingSequence)) { - RelationShip relationShip = new RelationShip("rId" + drawingSequence, WorkbookConstant.MEDIA_IMAGE_TYPE, "../media/image" + drawingSequence +".png"); + // 记录索引 picture.setRembed(drawingSequence); - target.append(CovertUtil.covert(relationShip)); return; } File media = sheet.getSheetContext().getRepositoryHolder().get(Alias.MEDIA).getFile(); diff --git a/src/main/java/com/ibiz/excel/picture/support/model/FontEnum.java b/src/main/java/com/ibiz/excel/picture/support/model/FontEnum.java new file mode 100644 index 0000000..0534c8a --- /dev/null +++ b/src/main/java/com/ibiz/excel/picture/support/model/FontEnum.java @@ -0,0 +1,30 @@ +package com.ibiz.excel.picture.support.model; + +/** + * 读取内置字体 + * + * @author MinWeikai + * @date 2021/1/20 11:57 + */ +public enum FontEnum { + + /** + * font size 20 + */ + F20(22), + + F10(3) + ; + /** + * 与对应{@link com.ibiz.excel.picture.support.module.Styles} + */ + private Integer fillId; + + FontEnum(Integer fillId) { + this.fillId = fillId; + } + + public Integer getFillId() { + return fillId; + } +} diff --git a/src/main/java/com/ibiz/excel/picture/support/model/RowStyle.java b/src/main/java/com/ibiz/excel/picture/support/model/RowStyle.java index 7ec445b..ac4319f 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/RowStyle.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/RowStyle.java @@ -10,21 +10,22 @@ public class RowStyle { private int fillId; - private FgColorEnum fgColor; + /** + * 样式 + */ + private StyleEnum styleEnum; + public RowStyle() { } - public RowStyle(FgColorEnum fgColor) { - this.fgColor = fgColor; - fillId = this.fgColor.getFillId(); + public RowStyle(StyleEnum styleEnum) { + this.styleEnum = styleEnum; + this.fillId = styleEnum.getFillId(); } public int getFillId() { return fillId; } - public FgColorEnum getFgColor() { - return fgColor; - } } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/FgColorEnum.java b/src/main/java/com/ibiz/excel/picture/support/model/StyleEnum.java similarity index 66% rename from src/main/java/com/ibiz/excel/picture/support/model/FgColorEnum.java rename to src/main/java/com/ibiz/excel/picture/support/model/StyleEnum.java index 039da86..1d4dd7f 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/FgColorEnum.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/StyleEnum.java @@ -1,17 +1,23 @@ package com.ibiz.excel.picture.support.model; /** - * 填充色枚举类 + * 样式枚举类 * * @author MinWeikai * @date 2021/1/19 14:10 */ -public enum FgColorEnum { +public enum StyleEnum { /** - * 绿色填充色 + * 绿色填充色,字体加粗 */ - GREEN(3); + GREEN_B(3), + + /** + * 字体-20 + */ + F20(4); + /** * 填充色id @@ -19,7 +25,7 @@ public enum FgColorEnum { */ private Integer fillId; - FgColorEnum(Integer fillId) { + StyleEnum(Integer fillId) { this.fillId = fillId; } diff --git a/src/main/java/com/ibiz/excel/picture/support/module/Styles.java b/src/main/java/com/ibiz/excel/picture/support/module/Styles.java index 0232d7b..e51c07b 100644 --- a/src/main/java/com/ibiz/excel/picture/support/module/Styles.java +++ b/src/main/java/com/ibiz/excel/picture/support/module/Styles.java @@ -5,6 +5,7 @@ import com.ibiz.excel.picture.support.annotation.AutoWrite; import com.ibiz.excel.picture.support.constants.Alias; /** + * 有时间可以优化 * 电子表格样式参考处 * http://officeopenxml.com/SSstyles.php * @author MinWeikai @@ -15,19 +16,48 @@ public class Styles { @AutoFile(fileName = "styles.xml", alias = Alias.STYLES) String content = "" + "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + ""+ + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + "" + "" + "" + "" + "" + "" + // 绿色背景,后续可在此追加 + "" + "" + "" + "" + @@ -39,9 +69,12 @@ public class Styles { "" + "" + "" + - "" + + "" + + "" + + "" + "" + - "" + // 填充色值坐标 + "" + // 填充色值坐标 + "" + "" + "" + "" + diff --git a/src/test/java/com/ibiz/excel/picture/support/CellWidthTest.java b/src/test/java/com/ibiz/excel/picture/support/CellWidthTest.java index 744f8f2..0328afe 100644 --- a/src/test/java/com/ibiz/excel/picture/support/CellWidthTest.java +++ b/src/test/java/com/ibiz/excel/picture/support/CellWidthTest.java @@ -34,7 +34,7 @@ public class CellWidthTest { // 第二行放标题 row = sheet.createRow(1) //配置该行颜色,现在默认只有绿色 - .setRowStyle(new RowStyle(FgColorEnum.GREEN)); + .setRowStyle(new RowStyle(StyleEnum.GREEN_B)); List cells = new ArrayList<>(); for (int i = 0; i < excelName.length; i++) { Cell cell = new Cell(1, i).setValue(excelName[i]); diff --git a/src/test/java/com/ibiz/excel/picture/support/FontTest.java b/src/test/java/com/ibiz/excel/picture/support/FontTest.java new file mode 100644 index 0000000..7ceb939 --- /dev/null +++ b/src/test/java/com/ibiz/excel/picture/support/FontTest.java @@ -0,0 +1,99 @@ +package com.ibiz.excel.picture.support; + +import cn.hutool.core.io.FileUtil; +import com.ibiz.excel.picture.support.model.*; + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.IOException; +import java.util.*; + +/** + * 字体控制 + * + * @author MinWeikai + * @date 2021/1/20 11:45 + */ +public class FontTest { + + private static final String CURRENT_PATH = "E:\\test\\"; + + private final static String IMG_PATH = CURRENT_PATH + "img\\"; + + private final static String IMG_PATH_1 = IMG_PATH + "ia_1900002528.jpeg"; + private final static String IMG_PATH_2 = IMG_PATH + "ia_1200000645.jpg"; + + public static void main(String[] args) throws IOException { + Date start = new Date(); + Workbook workBook = Workbook.getInstance(1); + Sheet sheet = workBook.createSheet("测试"); + + // 需要在创建行前预设宽度 + sheet.addColumnHelper(new ColumnHelper(1, 10)) + .addColumnHelper(new ColumnHelper(3, 50)) + .addColumnHelper(new ColumnHelper(4, 50)); + + // 第一行表头 + Row row = sheet.createRow(0) + //字体20 + .setRowStyle(new RowStyle(StyleEnum.F20)) + ; + String[] excelName = {"序号", "文本2", "图片1", "图片2", "图片3"}; + sheet.getMergeCells().add(new MergeCell(0, 0, 0, excelName.length - 1)); + row.setCells(Collections.singletonList(new Cell(0, 0).setValue("表头"))); + + // 第二行放标题 + row = sheet.createRow(1) + //配置该行颜色,现在默认只有绿色 + .setRowStyle(new RowStyle(StyleEnum.GREEN_B)); + List cells = new ArrayList<>(); + for (int i = 0; i < excelName.length; i++) { + Cell cell = new Cell(1, i).setValue(excelName[i]); + cells.add(cell); + } + row.setCells(cells); + + // 第三行放内容和图片 + row = sheet.createRow(2); + + cells = new ArrayList<>(); + List pictures = sheet.getPictures(); + //序号 + cells.add(new Cell(2, 0).setValue("1")); + for (int i = 0; i < excelName.length; i++) { + if (i < 2) { + cells.add(new Cell(2, i).setValue("文本" + i)); + } else { + //有图片的行,行高设置为100 + row.setHeight(80); + //每个单元格增加一个图片 + //pictures.add(new Picture(i, row.getRowNumber(),1000000 , IMG_PATH_1)); + //在第三列添加多张图片 + pictures.add(new Picture(3, row.getRowNumber(), 1000000, IMG_PATH_1)); + pictures.add(new Picture(2, row.getRowNumber(), 1000000, IMG_PATH_2)); + } + } + row.setCells(cells); + + + File file = createFile(); + BufferedOutputStream os = FileUtil.getOutputStream(file); + workBook.write(os); + workBook.close(); + Date end = new Date(); + System.out.println("file capital :" + (file.length() / 1024 / 1024) + "M name :" + file.getName()); + System.out.println("file cost time :" + (end.getTime() - start.getTime())); + os.close(); + } + + + private static File createFile() { + String dir = CURRENT_PATH + "excel/"; + File file = new File(dir); + if (!file.exists()) { + file.mkdir(); + } + String name = CURRENT_PATH + "excel/" + UUID.randomUUID() + ".xlsx"; + return new File(name); + } +} diff --git a/src/test/java/com/ibiz/excel/picture/support/PictureCellWidthTest.java b/src/test/java/com/ibiz/excel/picture/support/PictureCellWidthTest.java index 494b7aa..ee58f5d 100644 --- a/src/test/java/com/ibiz/excel/picture/support/PictureCellWidthTest.java +++ b/src/test/java/com/ibiz/excel/picture/support/PictureCellWidthTest.java @@ -41,7 +41,7 @@ public class PictureCellWidthTest { // 第二行放标题 row = sheet.createRow(1) //配置该行颜色,现在默认只有绿色 - .setRowStyle(new RowStyle(FgColorEnum.GREEN)); + .setRowStyle(new RowStyle(StyleEnum.GREEN_B)); List cells = new ArrayList<>(); for (int i = 0; i < excelName.length; i++) { Cell cell = new Cell(1, i).setValue(excelName[i]); diff --git a/src/test/java/com/ibiz/excel/picture/support/RowFgColorTest.java b/src/test/java/com/ibiz/excel/picture/support/RowFgColorTest.java index 2816897..17dfcc0 100644 --- a/src/test/java/com/ibiz/excel/picture/support/RowFgColorTest.java +++ b/src/test/java/com/ibiz/excel/picture/support/RowFgColorTest.java @@ -32,7 +32,7 @@ public class RowFgColorTest { // 第二行放标题 row = sheet.createRow(1) //配置该行颜色,现在默认只有绿色 - .setRowStyle(new RowStyle(FgColorEnum.GREEN)); + .setRowStyle(new RowStyle(StyleEnum.GREEN_B)); List cells = new ArrayList<>(); for (int i = 0; i < excelName.length; i++) { Cell cell = new Cell(1, i).setValue(excelName[i]); -- Gitee From ae798a36d71fe64a2184fc35f605c59743453d50 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Wed, 20 Jan 2021 16:40:53 +0800 Subject: [PATCH 020/161] =?UTF-8?q?fix=20office=E6=89=93=E5=BC=80=E6=8F=90?= =?UTF-8?q?=E7=A4=BA=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/ibiz/excel/picture/support/module/Styles.java | 2 +- .../java/com/ibiz/excel/picture/support/util/FileUtil.java | 5 +++-- src/test/java/com/ibiz/excel/picture/support/FontTest.java | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/ibiz/excel/picture/support/module/Styles.java b/src/main/java/com/ibiz/excel/picture/support/module/Styles.java index e51c07b..4d4ccba 100644 --- a/src/main/java/com/ibiz/excel/picture/support/module/Styles.java +++ b/src/main/java/com/ibiz/excel/picture/support/module/Styles.java @@ -74,7 +74,7 @@ public class Styles { "" + "" + "" + // 填充色值坐标 - "" + + "" + "" + "" + "" + diff --git a/src/main/java/com/ibiz/excel/picture/support/util/FileUtil.java b/src/main/java/com/ibiz/excel/picture/support/util/FileUtil.java index e1c3b95..61ef064 100644 --- a/src/main/java/com/ibiz/excel/picture/support/util/FileUtil.java +++ b/src/main/java/com/ibiz/excel/picture/support/util/FileUtil.java @@ -48,9 +48,10 @@ public class FileUtil { public static void writeToOutput(File source, OutputStream output) { byte[] buf = new byte[1024]; + int len; try(BufferedInputStream fis = new BufferedInputStream(new FileInputStream(source))) { - while (fis.read(buf) != -1) { - output.write(buf); + while((len = fis.read(buf)) != -1){ + output.write(buf, 0 , len); } }catch (IOException e) { throw new RuntimeException("write to output error , destFile path:" + source.getAbsolutePath(), e); diff --git a/src/test/java/com/ibiz/excel/picture/support/FontTest.java b/src/test/java/com/ibiz/excel/picture/support/FontTest.java index 7ceb939..b145eff 100644 --- a/src/test/java/com/ibiz/excel/picture/support/FontTest.java +++ b/src/test/java/com/ibiz/excel/picture/support/FontTest.java @@ -61,7 +61,7 @@ public class FontTest { //序号 cells.add(new Cell(2, 0).setValue("1")); for (int i = 0; i < excelName.length; i++) { - if (i < 2) { + if (i == 1) { cells.add(new Cell(2, i).setValue("文本" + i)); } else { //有图片的行,行高设置为100 -- Gitee From 0c5dedbc6325989b68de63fc8a4b3b5a5dab7d7b Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Thu, 21 Jan 2021 09:16:23 +0800 Subject: [PATCH 021/161] =?UTF-8?q?add=20=E8=A1=A8=E5=A4=B4=E5=AD=97?= =?UTF-8?q?=E4=BD=93=E9=A2=9C=E8=89=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/ibiz/excel/picture/support/module/Styles.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ibiz/excel/picture/support/module/Styles.java b/src/main/java/com/ibiz/excel/picture/support/module/Styles.java index 4d4ccba..2947e73 100644 --- a/src/main/java/com/ibiz/excel/picture/support/module/Styles.java +++ b/src/main/java/com/ibiz/excel/picture/support/module/Styles.java @@ -39,7 +39,7 @@ public class Styles { "" + "" + "" + - ""+ + ""+ "" + "" + "" + -- Gitee From edaca58be7ffcaf3478e1b3521a515abd3dc6138 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Sat, 16 Jan 2021 16:13:04 +0800 Subject: [PATCH 022/161] =?UTF-8?q?add=20=E5=86=85=E5=AD=98=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/ibiz/excel/picture/support/CustomTitleDemo.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/java/com/ibiz/excel/picture/support/CustomTitleDemo.java b/src/test/java/com/ibiz/excel/picture/support/CustomTitleDemo.java index d89afa0..5a661fd 100644 --- a/src/test/java/com/ibiz/excel/picture/support/CustomTitleDemo.java +++ b/src/test/java/com/ibiz/excel/picture/support/CustomTitleDemo.java @@ -70,6 +70,8 @@ public class CustomTitleDemo { } + + private static File createFile() { String dir = CURRENT_PATH + "excel/"; File file = new File(dir); -- Gitee From 7188c0babc1f7ad83996a819aa33d533187456da Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Sat, 16 Jan 2021 17:12:01 +0800 Subject: [PATCH 023/161] =?UTF-8?q?fix=20wps=E6=89=93=E5=BC=80=E6=B2=A1?= =?UTF-8?q?=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/ibiz/excel/picture/support/CustomTitleDemo.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/test/java/com/ibiz/excel/picture/support/CustomTitleDemo.java b/src/test/java/com/ibiz/excel/picture/support/CustomTitleDemo.java index 5a661fd..d89afa0 100644 --- a/src/test/java/com/ibiz/excel/picture/support/CustomTitleDemo.java +++ b/src/test/java/com/ibiz/excel/picture/support/CustomTitleDemo.java @@ -70,8 +70,6 @@ public class CustomTitleDemo { } - - private static File createFile() { String dir = CURRENT_PATH + "excel/"; File file = new File(dir); -- Gitee From 7bd6001ba3e7a043b5fd5f7ea9e4420a443ae6ed Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Fri, 22 Jan 2021 14:13:03 +0800 Subject: [PATCH 024/161] add LICENSE. --- LICENSE | 127 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..ee58399 --- /dev/null +++ b/LICENSE @@ -0,0 +1,127 @@ + 木兰宽松许可证, 第2版 + + 木兰宽松许可证, 第2版 + 2020年1月 http://license.coscl.org.cn/MulanPSL2 + + + 您对“软件”的复制、使用、修改及分发受木兰宽松许可证,第2版(“本许可证”)的如下条款的约束: + + 0. 定义 + + “软件”是指由“贡献”构成的许可在“本许可证”下的程序和相关文档的集合。 + + “贡献”是指由任一“贡献者”许可在“本许可证”下的受版权法保护的作品。 + + “贡献者”是指将受版权法保护的作品许可在“本许可证”下的自然人或“法人实体”。 + + “法人实体”是指提交贡献的机构及其“关联实体”。 + + “关联实体”是指,对“本许可证”下的行为方而言,控制、受控制或与其共同受控制的机构,此处的控制是指有受控方或共同受控方至少50%直接或间接的投票权、资金或其他有价证券。 + + 1. 授予版权许可 + + 每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的版权许可,您可以复制、使用、修改、分发其“贡献”,不论修改与否。 + + 2. 授予专利许可 + + 每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的(根据本条规定撤销除外)专利许可,供您制造、委托制造、使用、许诺销售、销售、进口其“贡献”或以其他方式转移其“贡献”。前述专利许可仅限于“贡献者”现在或将来拥有或控制的其“贡献”本身或其“贡献”与许可“贡献”时的“软件”结合而将必然会侵犯的专利权利要求,不包括对“贡献”的修改或包含“贡献”的其他结合。如果您或您的“关联实体”直接或间接地,就“软件”或其中的“贡献”对任何人发起专利侵权诉讼(包括反诉或交叉诉讼)或其他专利维权行动,指控其侵犯专利权,则“本许可证”授予您对“软件”的专利许可自您提起诉讼或发起维权行动之日终止。 + + 3. 无商标许可 + + “本许可证”不提供对“贡献者”的商品名称、商标、服务标志或产品名称的商标许可,但您为满足第4条规定的声明义务而必须使用除外。 + + 4. 分发限制 + + 您可以在任何媒介中将“软件”以源程序形式或可执行形式重新分发,不论修改与否,但您必须向接收者提供“本许可证”的副本,并保留“软件”中的版权、商标、专利及免责声明。 + + 5. 免责声明与责任限制 + + “软件”及其中的“贡献”在提供时不带任何明示或默示的担保。在任何情况下,“贡献者”或版权所有者不对任何人因使用“软件”或其中的“贡献”而引发的任何直接或间接损失承担责任,不论因何种原因导致或者基于何种法律理论,即使其曾被建议有此种损失的可能性。 + + 6. 语言 + “本许可证”以中英文双语表述,中英文版本具有同等法律效力。如果中英文版本存在任何冲突不一致,以中文版为准。 + + 条款结束 + + 如何将木兰宽松许可证,第2版,应用到您的软件 + + 如果您希望将木兰宽松许可证,第2版,应用到您的新软件,为了方便接收者查阅,建议您完成如下三步: + + 1, 请您补充如下声明中的空白,包括软件名、软件的首次发表年份以及您作为版权人的名字; + + 2, 请您在软件包的一级目录下创建以“LICENSE”为名的文件,将整个许可证文本放入该文件中; + + 3, 请将如下声明文本放入每个源文件的头部注释中。 + + Copyright (c) [Year] [name of copyright holder] + [Software Name] is licensed under Mulan PSL v2. + You can use this software according to the terms and conditions of the Mulan PSL v2. + You may obtain a copy of Mulan PSL v2 at: + http://license.coscl.org.cn/MulanPSL2 + THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + See the Mulan PSL v2 for more details. + + + Mulan Permissive Software License,Version 2 + + Mulan Permissive Software License,Version 2 (Mulan PSL v2) + January 2020 http://license.coscl.org.cn/MulanPSL2 + + Your reproduction, use, modification and distribution of the Software shall be subject to Mulan PSL v2 (this License) with the following terms and conditions: + + 0. Definition + + Software means the program and related documents which are licensed under this License and comprise all Contribution(s). + + Contribution means the copyrightable work licensed by a particular Contributor under this License. + + Contributor means the Individual or Legal Entity who licenses its copyrightable work under this License. + + Legal Entity means the entity making a Contribution and all its Affiliates. + + Affiliates means entities that control, are controlled by, or are under common control with the acting entity under this License, ‘control’ means direct or indirect ownership of at least fifty percent (50%) of the voting power, capital or other securities of controlled or commonly controlled entity. + + 1. Grant of Copyright License + + Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable copyright license to reproduce, use, modify, or distribute its Contribution, with modification or not. + + 2. Grant of Patent License + + Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable (except for revocation under this Section) patent license to make, have made, use, offer for sale, sell, import or otherwise transfer its Contribution, where such patent license is only limited to the patent claims owned or controlled by such Contributor now or in future which will be necessarily infringed by its Contribution alone, or by combination of the Contribution with the Software to which the Contribution was contributed. The patent license shall not apply to any modification of the Contribution, and any other combination which includes the Contribution. If you or your Affiliates directly or indirectly institute patent litigation (including a cross claim or counterclaim in a litigation) or other patent enforcement activities against any individual or entity by alleging that the Software or any Contribution in it infringes patents, then any patent license granted to you under this License for the Software shall terminate as of the date such litigation or activity is filed or taken. + + 3. No Trademark License + + No trademark license is granted to use the trade names, trademarks, service marks, or product names of Contributor, except as required to fulfill notice requirements in Section 4. + + 4. Distribution Restriction + + You may distribute the Software in any medium with or without modification, whether in source or executable forms, provided that you provide recipients with a copy of this License and retain copyright, patent, trademark and disclaimer statements in the Software. + + 5. Disclaimer of Warranty and Limitation of Liability + + THE SOFTWARE AND CONTRIBUTION IN IT ARE PROVIDED WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED. IN NO EVENT SHALL ANY CONTRIBUTOR OR COPYRIGHT HOLDER BE LIABLE TO YOU FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO ANY DIRECT, OR INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING FROM YOUR USE OR INABILITY TO USE THE SOFTWARE OR THE CONTRIBUTION IN IT, NO MATTER HOW IT’S CAUSED OR BASED ON WHICH LEGAL THEORY, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + + 6. Language + + THIS LICENSE IS WRITTEN IN BOTH CHINESE AND ENGLISH, AND THE CHINESE VERSION AND ENGLISH VERSION SHALL HAVE THE SAME LEGAL EFFECT. IN THE CASE OF DIVERGENCE BETWEEN THE CHINESE AND ENGLISH VERSIONS, THE CHINESE VERSION SHALL PREVAIL. + + END OF THE TERMS AND CONDITIONS + + How to Apply the Mulan Permissive Software License,Version 2 (Mulan PSL v2) to Your Software + + To apply the Mulan PSL v2 to your work, for easy identification by recipients, you are suggested to complete following three steps: + + i Fill in the blanks in following statement, including insert your software name, the year of the first publication of your software, and your name identified as the copyright owner; + + ii Create a file named “LICENSE” which contains the whole context of this License in the first directory of your software package; + + iii Attach the statement to the appropriate annotated syntax at the beginning of each source file. + + + Copyright (c) [Year] [name of copyright holder] + [Software Name] is licensed under Mulan PSL v2. + You can use this software according to the terms and conditions of the Mulan PSL v2. + You may obtain a copy of Mulan PSL v2 at: + http://license.coscl.org.cn/MulanPSL2 + THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + See the Mulan PSL v2 for more details. -- Gitee From c65b64df92cf5ee988b03f0f7b014f44a005de2c Mon Sep 17 00:00:00 2001 From: minweikai <1294608448@qq.com> Date: Sat, 23 Jan 2021 21:03:21 +0800 Subject: [PATCH 025/161] =?UTF-8?q?add=20jar=E5=8C=85=E5=8F=91=E5=B8=83?= =?UTF-8?q?=E5=88=B0=E4=B8=AD=E5=A4=AE=E4=BB=93=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 131 +++++++++++------- .../picture/support/ExcelXApplication.java | 26 ---- .../picture/support/util/CompressorUtil.java | 39 ------ src/main/resources/application.properties | 1 - .../support/ExcelXApplicationTests.java | 14 -- 5 files changed, 78 insertions(+), 133 deletions(-) delete mode 100644 src/main/java/com/ibiz/excel/picture/support/ExcelXApplication.java delete mode 100644 src/main/java/com/ibiz/excel/picture/support/util/CompressorUtil.java delete mode 100644 src/main/resources/application.properties delete mode 100644 src/test/java/com/ibiz/excel/picture/support/ExcelXApplicationTests.java diff --git a/pom.xml b/pom.xml index afced53..f3e17e0 100644 --- a/pom.xml +++ b/pom.xml @@ -1,58 +1,83 @@ - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 2.3.1.RELEASE - - - com.ibiz - excel-x - 0.0.1-SNAPSHOT - excel-x - Demo project for Spring Boot - - - 1.8 - - - - - org.springframework.boot - spring-boot-starter - - - org.apache.ant - ant - 1.10.5 - - - cn.hutool - hutool-core - 5.5.5 - - - org.springframework.boot - spring-boot-starter-test - test - - - org.junit.vintage - junit-vintage-engine - - - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - + 4.0.0 + top.minwk + excel-x + 1.0.1 + excel-x + excel-x + https://gitee.com/mwk719/excel-batch-picture-support + + org.sonatype.oss + oss-parent + 9 + + + + 1.8 + + + + + The Apache Software License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + actable + + + + + + minwk + 1294608448@qq.com + mwk + https://minwk.top/ + + + + + https://gitee.com/mwk719/excel-batch-picture-support + https://gitee.com/mwk719/excel-batch-picture-support.git + https://gitee.com/mwk719/excel-batch-picture-support + + + + + cn.hutool + hutool-core + 5.5.5 + + + org.slf4j + slf4j-api + 1.7.30 + + + org.springframework + spring-core + 5.2.8.RELEASE + + + org.springframework + spring-beans + 5.2.8.RELEASE + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.0.0-M1 + + + -Xdoclint:none + + + + + + diff --git a/src/main/java/com/ibiz/excel/picture/support/ExcelXApplication.java b/src/main/java/com/ibiz/excel/picture/support/ExcelXApplication.java deleted file mode 100644 index 48cdf2a..0000000 --- a/src/main/java/com/ibiz/excel/picture/support/ExcelXApplication.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.ibiz.excel.picture.support; - -import com.ibiz.excel.picture.support.model.Sheet; -import com.ibiz.excel.picture.support.model.Workbook; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import java.util.stream.IntStream; - -@SpringBootApplication -public class ExcelXApplication { - - public static void main(String[] args) { - Workbook workBook = Workbook.getInstance(200); - Sheet sheet = workBook.createSheet("导出个表"); - /*User u1 = new User("z1", 12, "a1", "D:\\1.png"); - User u2 = new User("z2", 12, "a2", ""); - User u3 = new User("z3", 12, "a3", "D:\\1.png"); - User u4 = new User("z3", 12, "a3", "");*/ - IntStream.range(0, 1).forEach(r -> { - /*sheet.createRow(u1); - sheet.createRow(u2); - sheet.createRow(u3); - sheet.createRow(u4);*/ - }); - workBook.close(); - } -} diff --git a/src/main/java/com/ibiz/excel/picture/support/util/CompressorUtil.java b/src/main/java/com/ibiz/excel/picture/support/util/CompressorUtil.java deleted file mode 100644 index ffd5936..0000000 --- a/src/main/java/com/ibiz/excel/picture/support/util/CompressorUtil.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.ibiz.excel.picture.support.util; - -import org.apache.tools.ant.Project; -import org.apache.tools.ant.taskdefs.Zip; -import org.apache.tools.ant.types.FileSet; - -import java.io.File; - -/** - * 将文件夹压缩成文件 - */ -public class CompressorUtil { - /** - * - * @param src 原文件绝对路径 - * @param dest 目标文件绝对路径 - */ - public static void compress(String src, String dest) { - //目的文件 - File destFile = new File(dest); - //原文件 - File srcFile = new File(src); - if (!srcFile.exists()){ - throw new RuntimeException(src + "不存在!"); - } - Project prj = new Project(); - Zip zip = new Zip(); - zip.setProject(prj); - zip.setDestFile(destFile); - FileSet fileSet = new FileSet(); - fileSet.setProject(prj); - fileSet.setDir(srcFile); - //fileSet.setIncludes("**/*.java"); //包括哪些文件或文件夹 eg:zip.setIncludes("*.java"); - //fileSet.setExcludes(...); //排除哪些文件或文件夹 - zip.addFileset(fileSet); - zip.execute(); - } -} - diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties deleted file mode 100644 index 8b13789..0000000 --- a/src/main/resources/application.properties +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/test/java/com/ibiz/excel/picture/support/ExcelXApplicationTests.java b/src/test/java/com/ibiz/excel/picture/support/ExcelXApplicationTests.java deleted file mode 100644 index 7e76622..0000000 --- a/src/test/java/com/ibiz/excel/picture/support/ExcelXApplicationTests.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.ibiz.excel.picture.support; - -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; - -import java.io.*; - -@SpringBootTest -class ExcelXApplicationTests { - - @Test - void contextLoads() throws IOException { - } -} -- Gitee From b1be233c04b86c4923ca4db6abb0dd5f8d6175e8 Mon Sep 17 00:00:00 2001 From: minweikai <1294608448@qq.com> Date: Sat, 23 Jan 2021 22:31:57 +0800 Subject: [PATCH 026/161] =?UTF-8?q?docs=20=E4=BD=BF=E7=94=A8=E8=AF=B4?= =?UTF-8?q?=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 43 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 3b41d18..06a9f8e 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,54 @@ -## Excel支持大量图片导出 +# Excel支持大量图片导出 -**背景** +## 背景 用户在导出统计数据时需要导出大量图片.目前用的比较多的poi导出能支持批量导出大量数据(不包括自媒体).但是当需要导出大量图片时,即使设置了flushSize ,但是对于图片对象却没有效果,图片在内存中无法释放,写的图片越多,占用内存越大,导致频繁GC,甚至OOM -**思路** +### 思路 + excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, 这些组件分别对应了不同的数据单元.只要把数据分别写入对应的组件,最后构建成一个需要的excel文件. -**功能** +## 功能 + 采用流式方法写入文件,不会导致内存堆积而占用太多系统资源,有效避免频繁GC问题 + 1. 支持自动合并单元格 2. 使用流式处理,支持大量图片导出 3. 支持注解导出,在实体上添加注解,自动生成标题 -**测试** +### 测试 + 经测试,可以生成几个G的文件。(保证生成的文件没问题,文件是否能打开由使用者计算机决定) -## 下面对EXCEL的操作做具体介绍 -EXCEL由几大组件构建而成,具体部分: +## 快速使用 + +1. ### Maven导入 + + 在项目的pom.xml的dependencies中加入以下内容: + +```xml + + top.minwk + excel-x + 1.0.1 + +``` + +2. ### 示例 + + [excel含图片导出demo地址](https://gitee.com/mwk719/excel-batch-picture-support/tree/master/src/test/java/com/ibiz/excel/picture/support) + +## 组件介绍 + +EXCEL由几大组件构建而成 + +### 具体部分: ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200715114523625.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3ljaGFuZzU3Nw==,size_16,color_FFFFFF,t_70) -工作文件实例 + +### 工作文件实例 + 1. workbook代表一个excel工作文件 2. Sheet对应文件中多个sheet页 3. Row 为sheet页中的行数据,包含多个Cell单元格 -- Gitee From 88c93a833ef9a237c4822faa6ca7cef19de30dcb Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Tue, 26 Jan 2021 13:57:22 +0800 Subject: [PATCH 027/161] =?UTF-8?q?fix=20MD5=E6=97=B6=E6=9C=AA=E5=85=B3?= =?UTF-8?q?=E9=97=AD=E6=B5=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../excel/picture/support/util/MD5Digester.java | 13 +++++-------- .../com/ibiz/excel/picture/support/FontTest.java | 7 ++++--- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/ibiz/excel/picture/support/util/MD5Digester.java b/src/main/java/com/ibiz/excel/picture/support/util/MD5Digester.java index 59e1cac..0aceba0 100644 --- a/src/main/java/com/ibiz/excel/picture/support/util/MD5Digester.java +++ b/src/main/java/com/ibiz/excel/picture/support/util/MD5Digester.java @@ -24,23 +24,20 @@ public class MD5Digester { } /** * 文件流md5 - * @param is InputStream + * @param inputStream InputStream * @return md5 */ - public static String digestMD5(InputStream is) { - try { + public static String digestMD5(InputStream inputStream) { + try(InputStream is = inputStream) { MessageDigest digest = MessageDigest.getInstance("MD5"); byte[] buffer = new byte[8192]; - int len = 0; + int len; while (-1 != (len = is.read(buffer))) { digest.update(buffer, 0, len); } byte[] md5hash = digest.digest(); return encodeHexStr(md5hash); - } catch (NoSuchAlgorithmException e) { - e.printStackTrace(); - throw new RuntimeException(e); - } catch (IOException e) { + } catch (NoSuchAlgorithmException | IOException e) { e.printStackTrace(); throw new RuntimeException(e); } diff --git a/src/test/java/com/ibiz/excel/picture/support/FontTest.java b/src/test/java/com/ibiz/excel/picture/support/FontTest.java index b145eff..38726b4 100644 --- a/src/test/java/com/ibiz/excel/picture/support/FontTest.java +++ b/src/test/java/com/ibiz/excel/picture/support/FontTest.java @@ -18,10 +18,10 @@ public class FontTest { private static final String CURRENT_PATH = "E:\\test\\"; - private final static String IMG_PATH = CURRENT_PATH + "img\\"; + private final static String IMG_PATH = CURRENT_PATH + "img1\\"; - private final static String IMG_PATH_1 = IMG_PATH + "ia_1900002528.jpeg"; - private final static String IMG_PATH_2 = IMG_PATH + "ia_1200000645.jpg"; + private final static String IMG_PATH_1 = IMG_PATH + "ia_1200000644.jpg"; + private final static String IMG_PATH_2 = IMG_PATH + "ia_1700001489.jpg"; public static void main(String[] args) throws IOException { Date start = new Date(); @@ -84,6 +84,7 @@ public class FontTest { System.out.println("file capital :" + (file.length() / 1024 / 1024) + "M name :" + file.getName()); System.out.println("file cost time :" + (end.getTime() - start.getTime())); os.close(); + FileUtil.del(new File(IMG_PATH_1)); } -- Gitee From a165ce59fe1834afd05cf0a0eabf99688937bab5 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Tue, 26 Jan 2021 19:34:19 +0800 Subject: [PATCH 028/161] release 1.0.2 --- README.md | 16 +++++++++++++++- pom.xml | 2 +- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 06a9f8e..3377201 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, top.minwk excel-x - 1.0.1 + 1.0.2 ``` @@ -39,6 +39,20 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, [excel含图片导出demo地址](https://gitee.com/mwk719/excel-batch-picture-support/tree/master/src/test/java/com/ibiz/excel/picture/support) +3. ### 版本更迭 + + #### 1.0.2(2021.01.26) + + - 修复MD5时未关闭流 + + #### 1.0.1(2021.01.23) + + - 添加合并单元列值 + - 添加设置单元格背景色 + - 添加可自定义单元格宽度 + - 添加设置字体,目前有默认字体 + - 修复office打开提示需修复的问题 + ## 组件介绍 EXCEL由几大组件构建而成 diff --git a/pom.xml b/pom.xml index f3e17e0..d6fda96 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 top.minwk excel-x - 1.0.1 + 1.0.2 excel-x excel-x https://gitee.com/mwk719/excel-batch-picture-support -- Gitee From 2fa743fafd382a53298f5449c0ae67591bc1f8a0 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Tue, 26 Jan 2021 13:57:22 +0800 Subject: [PATCH 029/161] =?UTF-8?q?fix=20MD5=E6=97=B6=E6=9C=AA=E5=85=B3?= =?UTF-8?q?=E9=97=AD=E6=B5=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../excel/picture/support/util/MD5Digester.java | 13 +++++-------- .../com/ibiz/excel/picture/support/FontTest.java | 7 ++++--- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/ibiz/excel/picture/support/util/MD5Digester.java b/src/main/java/com/ibiz/excel/picture/support/util/MD5Digester.java index 59e1cac..0aceba0 100644 --- a/src/main/java/com/ibiz/excel/picture/support/util/MD5Digester.java +++ b/src/main/java/com/ibiz/excel/picture/support/util/MD5Digester.java @@ -24,23 +24,20 @@ public class MD5Digester { } /** * 文件流md5 - * @param is InputStream + * @param inputStream InputStream * @return md5 */ - public static String digestMD5(InputStream is) { - try { + public static String digestMD5(InputStream inputStream) { + try(InputStream is = inputStream) { MessageDigest digest = MessageDigest.getInstance("MD5"); byte[] buffer = new byte[8192]; - int len = 0; + int len; while (-1 != (len = is.read(buffer))) { digest.update(buffer, 0, len); } byte[] md5hash = digest.digest(); return encodeHexStr(md5hash); - } catch (NoSuchAlgorithmException e) { - e.printStackTrace(); - throw new RuntimeException(e); - } catch (IOException e) { + } catch (NoSuchAlgorithmException | IOException e) { e.printStackTrace(); throw new RuntimeException(e); } diff --git a/src/test/java/com/ibiz/excel/picture/support/FontTest.java b/src/test/java/com/ibiz/excel/picture/support/FontTest.java index b145eff..38726b4 100644 --- a/src/test/java/com/ibiz/excel/picture/support/FontTest.java +++ b/src/test/java/com/ibiz/excel/picture/support/FontTest.java @@ -18,10 +18,10 @@ public class FontTest { private static final String CURRENT_PATH = "E:\\test\\"; - private final static String IMG_PATH = CURRENT_PATH + "img\\"; + private final static String IMG_PATH = CURRENT_PATH + "img1\\"; - private final static String IMG_PATH_1 = IMG_PATH + "ia_1900002528.jpeg"; - private final static String IMG_PATH_2 = IMG_PATH + "ia_1200000645.jpg"; + private final static String IMG_PATH_1 = IMG_PATH + "ia_1200000644.jpg"; + private final static String IMG_PATH_2 = IMG_PATH + "ia_1700001489.jpg"; public static void main(String[] args) throws IOException { Date start = new Date(); @@ -84,6 +84,7 @@ public class FontTest { System.out.println("file capital :" + (file.length() / 1024 / 1024) + "M name :" + file.getName()); System.out.println("file cost time :" + (end.getTime() - start.getTime())); os.close(); + FileUtil.del(new File(IMG_PATH_1)); } -- Gitee From 80d0320505caeb0f2da7e2fc9c30881b8586d857 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Tue, 26 Jan 2021 19:34:19 +0800 Subject: [PATCH 030/161] release 1.0.2 --- README.md | 16 +++++++++++++++- pom.xml | 2 +- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 06a9f8e..3377201 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, top.minwk excel-x - 1.0.1 + 1.0.2 ``` @@ -39,6 +39,20 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, [excel含图片导出demo地址](https://gitee.com/mwk719/excel-batch-picture-support/tree/master/src/test/java/com/ibiz/excel/picture/support) +3. ### 版本更迭 + + #### 1.0.2(2021.01.26) + + - 修复MD5时未关闭流 + + #### 1.0.1(2021.01.23) + + - 添加合并单元列值 + - 添加设置单元格背景色 + - 添加可自定义单元格宽度 + - 添加设置字体,目前有默认字体 + - 修复office打开提示需修复的问题 + ## 组件介绍 EXCEL由几大组件构建而成 diff --git a/pom.xml b/pom.xml index f3e17e0..d6fda96 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 top.minwk excel-x - 1.0.1 + 1.0.2 excel-x excel-x https://gitee.com/mwk719/excel-batch-picture-support -- Gitee From 0655671cb271cecdad4e8287a81d2c1545646f13 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Fri, 5 Feb 2021 17:58:44 +0800 Subject: [PATCH 031/161] =?UTF-8?q?add=20README.md=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E5=9B=BE=E7=89=87=E8=B5=84=E6=BA=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 3377201..df5a00f 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,10 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, 2. ### 示例 - [excel含图片导出demo地址](https://gitee.com/mwk719/excel-batch-picture-support/tree/master/src/test/java/com/ibiz/excel/picture/support) + - [excel含图片导出demo地址](https://gitee.com/mwk719/excel-batch-picture-support/tree/master/src/test/java/com/ibiz/excel/picture/support) + - [微云-6767张图片共800mb资源.rar 可用于测试](https://minwk.top/big-size-img/) + + ## 组件介绍 3. ### 版本更迭 @@ -53,8 +56,6 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, - 添加设置字体,目前有默认字体 - 修复office打开提示需修复的问题 -## 组件介绍 - EXCEL由几大组件构建而成 ### 具体部分: -- Gitee From 8adfc27cfb54cd4ae2b46a10d5c52de20f502fae Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Sun, 7 Feb 2021 17:25:52 +0800 Subject: [PATCH 032/161] =?UTF-8?q?add=20=E7=AE=80=E5=8C=96=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE=E5=B9=B6=E6=B7=BB=E5=8A=A0=E7=A4=BA=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 +- .../excel/picture/support/model/Cell.java | 58 +++++++--- .../ibiz/excel/picture/support/model/Row.java | 10 ++ .../picture/support/EasyUseExample1.java | 86 +++++++++++++++ .../picture/support/EasyUseExample2.java | 90 ++++++++++++++++ .../picture/support/EasyUseExample3.java | 102 ++++++++++++++++++ 6 files changed, 331 insertions(+), 19 deletions(-) create mode 100644 src/test/java/com/ibiz/excel/picture/support/EasyUseExample1.java create mode 100644 src/test/java/com/ibiz/excel/picture/support/EasyUseExample2.java create mode 100644 src/test/java/com/ibiz/excel/picture/support/EasyUseExample3.java diff --git a/README.md b/README.md index df5a00f..c7bc7c3 100644 --- a/README.md +++ b/README.md @@ -40,8 +40,6 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, - [excel含图片导出demo地址](https://gitee.com/mwk719/excel-batch-picture-support/tree/master/src/test/java/com/ibiz/excel/picture/support) - [微云-6767张图片共800mb资源.rar 可用于测试](https://minwk.top/big-size-img/) - ## 组件介绍 - 3. ### 版本更迭 #### 1.0.2(2021.01.26) @@ -56,6 +54,8 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, - 添加设置字体,目前有默认字体 - 修复office打开提示需修复的问题 +## 组件介绍 + EXCEL由几大组件构建而成 ### 具体部分: diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Cell.java b/src/main/java/com/ibiz/excel/picture/support/model/Cell.java index 6e6035f..7669160 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Cell.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Cell.java @@ -5,13 +5,40 @@ package com.ibiz.excel.picture.support.model; * @date 2020/7/217:31 */ public class Cell { - private final String[] CELL_NUMBER_LINE = {"A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"}; + private final String[] CELL_NUMBER_LINE = {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"}; private int cellNumber;//第几列 private int rowNumber;//行号 private String colNumber = "";//列号 例 A1 B1 private String col = ""; //单元格列 例 A B AA AB private int colDataNumber; //列对应值序号 - private String value; //单元格值 + private String value; //单元格值 + + public Cell(int cellNumber) { + this.cellNumber = cellNumber; + } + + public Cell(int rowNumber, int cellNumber) { + super(); + this.rowNumber = rowNumber; + this.cellNumber = cellNumber; + this.autoSetCell(rowNumber, cellNumber); + } + + /** + * 自动设置Cell顺序 + * + * @param rowNumber + * @param cellNumber + */ + public void autoSetCell(int rowNumber, int cellNumber) { + int line = cellNumber; + if (cellNumber >= CELL_NUMBER_LINE.length) { + line = cellNumber - CELL_NUMBER_LINE.length; + colNumber += "A"; + } + col += colNumber + CELL_NUMBER_LINE[line]; + colNumber += CELL_NUMBER_LINE[line] + (rowNumber + 1); + } public String getColNumber() { return colNumber; @@ -25,21 +52,22 @@ public class Cell { this.colDataNumber = colDataNumber; } - public int getRowNumber() { + public Integer getRowNumber() { return rowNumber; } - public Cell(int rowNumber,int cellNumber) { - super(); + public void setRowNumber(int rowNumber) { this.rowNumber = rowNumber; - this.cellNumber = cellNumber; - int line = cellNumber; - if(cellNumber >= CELL_NUMBER_LINE.length){ - line = cellNumber - CELL_NUMBER_LINE.length; - colNumber += "A"; - } - col += colNumber + CELL_NUMBER_LINE[line]; - colNumber += CELL_NUMBER_LINE[line] + (rowNumber + 1); + } + + /** + * 设置RowNumber并自动排序 + * + * @param rowNumber + */ + public void autoSetRowNumber(int rowNumber) { + this.rowNumber = rowNumber; + this.autoSetCell(rowNumber, this.cellNumber); } public String getCol() { @@ -55,10 +83,6 @@ public class Cell { return this; } - public Cell(int cellNumber) { - this(0,cellNumber); - } - public int getCellNumber() { return cellNumber; } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Row.java b/src/main/java/com/ibiz/excel/picture/support/model/Row.java index 76af5bd..239ba27 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Row.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Row.java @@ -49,6 +49,16 @@ public class Row { this.cells = cells; } + /** + * 自动配置行对应的单元格 + * + * @param cells + */ + public void autoRowCells(List cells) { + cells.parallelStream().forEach(cell-> cell.autoSetRowNumber(rowNumber)); + this.cells = cells; + } + public Cell createCell(int cellNumber){ Cell cell = new Cell(rowNumber,cellNumber); cells.add(cell); diff --git a/src/test/java/com/ibiz/excel/picture/support/EasyUseExample1.java b/src/test/java/com/ibiz/excel/picture/support/EasyUseExample1.java new file mode 100644 index 0000000..549cc3e --- /dev/null +++ b/src/test/java/com/ibiz/excel/picture/support/EasyUseExample1.java @@ -0,0 +1,86 @@ +package com.ibiz.excel.picture.support; + +import cn.hutool.core.io.FileUtil; +import com.ibiz.excel.picture.support.constants.WorkbookConstant; +import com.ibiz.excel.picture.support.model.*; + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.UUID; + +/** + * 简化设置EasyUseExample1 + * 1. 需要文本列表信息 + * 2. 需要单元格填充单个图片 + * + * @author MinWeikai + * @date 2021-02-07 16:47:17 + */ +public class EasyUseExample1 { + static final String CURRENT_PATH = "E:\\test\\"; + + private final static String IMG_PATH = CURRENT_PATH + "img\\"; + + private final static String IMG_PATH_1 = IMG_PATH + "1.jpg"; + + + public static void main(String[] args) throws IOException { + Date start = new Date(); + Workbook workBook = Workbook.getInstance(1); + Sheet sheet = workBook.createSheet("测试"); + + // 第一行放标题 + String[] excelName = {"文本1", "文本2", "图片1", "图片2", "图片3"}; + //要进行合并的列 + sheet.getMergeCells().add(new MergeCell(0, 0, 0, excelName.length - 1)); + Row row = sheet.createRow(1) + //配置该行颜色,现在默认只有绿色 + .setRowStyle(new RowStyle(StyleEnum.GREEN_B)); + List cells = new ArrayList<>(); + for (int i = 0; i < excelName.length; i++) { + cells.add(new Cell(i).setValue(excelName[i])); + } + row.autoRowCells(cells); + + // 第二行放内容 + row = sheet.createRow(2); + List pictures = sheet.getPictures(); + cells = new ArrayList<>(); + for (int i = 0; i < excelName.length; i++) { + if (i < 2) { + cells.add(new Cell(i).setValue("文本")); + } else { + //有图片的行,行高设置为100 + row.setHeight(WorkbookConstant.PICTURE_ROW_HEIGHT); + //增加图片 + pictures.add(new Picture(row.getRowNumber(), i, IMG_PATH_1)); + } + } + row.autoRowCells(cells); + + File file = createFile(); + BufferedOutputStream os = FileUtil.getOutputStream(file); + workBook.write(os); + workBook.close(); + Date end = new Date(); + System.out.println("file capital :" + (file.length() / 1024 / 1024) + "M name :" + file.getName()); + System.out.println("file cost time :" + (end.getTime() - start.getTime())); + os.close(); + } + + + private static File createFile() { + String dir = CURRENT_PATH + "excel/"; + File file = new File(dir); + if (!file.exists()) { + file.mkdir(); + } + String name = CURRENT_PATH + "excel/" + UUID.randomUUID() + ".xlsx"; + return new File(name); + } + +} diff --git a/src/test/java/com/ibiz/excel/picture/support/EasyUseExample2.java b/src/test/java/com/ibiz/excel/picture/support/EasyUseExample2.java new file mode 100644 index 0000000..c88e9b9 --- /dev/null +++ b/src/test/java/com/ibiz/excel/picture/support/EasyUseExample2.java @@ -0,0 +1,90 @@ +package com.ibiz.excel.picture.support; + +import cn.hutool.core.io.FileUtil; +import com.ibiz.excel.picture.support.constants.WorkbookConstant; +import com.ibiz.excel.picture.support.model.*; + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.IOException; +import java.util.*; + +/** + * 简化设置EasyUseExample2 + * 1. 需要文本列表信息 + * 2. 需要单元格填充单个图片 + * 3. 需要表头 + * + * @author MinWeikai + * @date 2021-02-07 16:47:17 + */ +public class EasyUseExample2 { + static final String CURRENT_PATH = "E:\\test\\"; + + private final static String IMG_PATH = CURRENT_PATH + "img\\"; + + private final static String IMG_PATH_1 = IMG_PATH + "1.jpg"; + + + public static void main(String[] args) throws IOException { + Date start = new Date(); + Workbook workBook = Workbook.getInstance(1); + Sheet sheet = workBook.createSheet("测试"); + + // 第一行表头 + Row row = sheet.createRow(0) + //字体20 + .setRowStyle(new RowStyle(StyleEnum.F20)); + row.autoRowCells(Collections.singletonList(new Cell(0).setValue("表头"))); + + // 第二行放标题 + String[] excelName = {"文本1", "文本2", "图片1", "图片2", "图片3"}; + //要进行合并的列 + sheet.getMergeCells().add(new MergeCell(0, 0, 0, excelName.length - 1)); + row = sheet.createRow(1) + //配置该行颜色,现在默认只有绿色 + .setRowStyle(new RowStyle(StyleEnum.GREEN_B)); + List cells = new ArrayList<>(); + for (int i = 0; i < excelName.length; i++) { + cells.add(new Cell(i).setValue(excelName[i])); + } + row.autoRowCells(cells); + + // 第三行放内容 + row = sheet.createRow(2); + List pictures = sheet.getPictures(); + cells = new ArrayList<>(); + for (int i = 0; i < excelName.length; i++) { + if (i < 2) { + cells.add(new Cell(i).setValue("文本")); + } else { + //有图片的行,行高设置为100 + row.setHeight(WorkbookConstant.PICTURE_ROW_HEIGHT); + //增加图片 + pictures.add(new Picture(row.getRowNumber(), i, IMG_PATH_1)); + } + } + row.autoRowCells(cells); + + File file = createFile(); + BufferedOutputStream os = FileUtil.getOutputStream(file); + workBook.write(os); + workBook.close(); + Date end = new Date(); + System.out.println("file capital :" + (file.length() / 1024 / 1024) + "M name :" + file.getName()); + System.out.println("file cost time :" + (end.getTime() - start.getTime())); + os.close(); + } + + + private static File createFile() { + String dir = CURRENT_PATH + "excel/"; + File file = new File(dir); + if (!file.exists()) { + file.mkdir(); + } + String name = CURRENT_PATH + "excel/" + UUID.randomUUID() + ".xlsx"; + return new File(name); + } + +} diff --git a/src/test/java/com/ibiz/excel/picture/support/EasyUseExample3.java b/src/test/java/com/ibiz/excel/picture/support/EasyUseExample3.java new file mode 100644 index 0000000..ffcbb1c --- /dev/null +++ b/src/test/java/com/ibiz/excel/picture/support/EasyUseExample3.java @@ -0,0 +1,102 @@ +package com.ibiz.excel.picture.support; + +import cn.hutool.core.io.FileUtil; +import com.ibiz.excel.picture.support.model.*; + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.IOException; +import java.util.*; + +/** + * 简化设置EasyUseExample3 + * 1. 需要文本列表信息 + * 2. 需要单元格填充多张图片 + * 3. 需要表头 + * + * @author MinWeikai + * @date 2021-02-07 16:47:17 + */ +public class EasyUseExample3 { + static final String CURRENT_PATH = "E:\\test\\"; + + private final static String IMG_PATH = CURRENT_PATH + "img\\"; + + private final static String IMG_PATH_1 = IMG_PATH + "1.jpg"; + private final static String IMG_PATH_2 = IMG_PATH + "2.jpg"; + + + public static void main(String[] args) throws IOException { + Date start = new Date(); + Workbook workBook = Workbook.getInstance(1); + Sheet sheet = workBook.createSheet("测试"); + + // 需要在创建行前预设宽度 + sheet.addColumnHelper(new ColumnHelper(1, 10)) + .addColumnHelper(new ColumnHelper(3, 50)) + .addColumnHelper(new ColumnHelper(4, 50)) + .addColumnHelper(new ColumnHelper(5, 50)); + + // 第一行表头 + Row row = sheet.createRow(0) + //字体20 + .setRowStyle(new RowStyle(StyleEnum.F20)); + row.autoRowCells(Collections.singletonList(new Cell(0).setValue("表头"))); + + // 第二行放标题 + String[] excelName = {"文本1", "文本2", "图片1", "图片2", "图片3"}; + //要进行合并的列 + sheet.getMergeCells().add(new MergeCell(0, 0, 0, excelName.length - 1)); + row = sheet.createRow(1) + //配置该行颜色,现在默认只有绿色 + .setRowStyle(new RowStyle(StyleEnum.GREEN_B)); + List cells = new ArrayList<>(); + for (int i = 0; i < excelName.length; i++) { + cells.add(new Cell(i).setValue(excelName[i])); + } + row.autoRowCells(cells); + + // 第三行放内容 + row = sheet.createRow(2); + List pictures = sheet.getPictures(); + cells = new ArrayList<>(); + for (int i = 0; i < excelName.length; i++) { + if (i < 2) { + cells.add(new Cell(i).setValue("文本")); + } else { + //有图片的行,行高设置为100 + row.setHeight(80); + //每个单元格增加一个图片 + //pictures.add(new Picture(i, row.getRowNumber(),1000000 , IMG_PATH_1)); + + //在第二列添加多张图片 + pictures.add(new Picture(2, row.getRowNumber(), 1000000, IMG_PATH_1)); + //在第三列添加多张图片 + pictures.add(new Picture(3, row.getRowNumber(), 1000000, IMG_PATH_2)); + pictures.add(new Picture(4, row.getRowNumber(), 1000000, IMG_PATH_1)); + } + } + row.autoRowCells(cells); + + File file = createFile(); + BufferedOutputStream os = FileUtil.getOutputStream(file); + workBook.write(os); + workBook.close(); + Date end = new Date(); + System.out.println("file capital :" + (file.length() / 1024 / 1024) + "M name :" + file.getName()); + System.out.println("file cost time :" + (end.getTime() - start.getTime())); + os.close(); + } + + + private static File createFile() { + String dir = CURRENT_PATH + "excel/"; + File file = new File(dir); + if (!file.exists()) { + file.mkdir(); + } + String name = CURRENT_PATH + "excel/" + UUID.randomUUID() + ".xlsx"; + return new File(name); + } + +} -- Gitee From 53adfeb3249f53c011337b3d970369c26a07644b Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Mon, 8 Feb 2021 15:37:38 +0800 Subject: [PATCH 033/161] =?UTF-8?q?perf=20=E4=BD=BF=E7=94=A8=E7=A4=BA?= =?UTF-8?q?=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/ibiz/excel/picture/support/model/Sheet.java | 7 +++---- .../java/com/ibiz/excel/picture/support/FontTest.java | 7 +++---- .../picture/support/{ => example}/EasyUseExample1.java | 2 +- .../picture/support/{ => example}/EasyUseExample2.java | 2 +- .../picture/support/{ => example}/EasyUseExample3.java | 10 +++++----- 5 files changed, 13 insertions(+), 15 deletions(-) rename src/test/java/com/ibiz/excel/picture/support/{ => example}/EasyUseExample1.java (98%) rename src/test/java/com/ibiz/excel/picture/support/{ => example}/EasyUseExample2.java (98%) rename src/test/java/com/ibiz/excel/picture/support/{ => example}/EasyUseExample3.java (92%) diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java index 24a1adf..c3634e0 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java @@ -285,14 +285,13 @@ public class Sheet { * @param columnIndex 坐标 * @param width 宽度 */ - public void setColumnWidth(int columnIndex, int width){ - this.columnHelpers = Collections.singletonList(new ColumnHelper(columnIndex, width)); + public Sheet setColumnWidth(int columnIndex, int width){ + return this.addColumnHelper(new ColumnHelper(columnIndex, width)); } public Sheet addColumnHelper(ColumnHelper columnHelper){ - this.columnHelpers.add(columnHelper); - return this; + return this.addAllColumnHelper(Collections.singletonList(columnHelper)); } public Sheet addAllColumnHelper(List columnHelpers){ diff --git a/src/test/java/com/ibiz/excel/picture/support/FontTest.java b/src/test/java/com/ibiz/excel/picture/support/FontTest.java index 38726b4..34063f8 100644 --- a/src/test/java/com/ibiz/excel/picture/support/FontTest.java +++ b/src/test/java/com/ibiz/excel/picture/support/FontTest.java @@ -18,10 +18,10 @@ public class FontTest { private static final String CURRENT_PATH = "E:\\test\\"; - private final static String IMG_PATH = CURRENT_PATH + "img1\\"; + private final static String IMG_PATH = CURRENT_PATH + "img\\"; - private final static String IMG_PATH_1 = IMG_PATH + "ia_1200000644.jpg"; - private final static String IMG_PATH_2 = IMG_PATH + "ia_1700001489.jpg"; + private final static String IMG_PATH_1 = IMG_PATH + "1.jpg"; + private final static String IMG_PATH_2 = IMG_PATH + "2.jpg"; public static void main(String[] args) throws IOException { Date start = new Date(); @@ -84,7 +84,6 @@ public class FontTest { System.out.println("file capital :" + (file.length() / 1024 / 1024) + "M name :" + file.getName()); System.out.println("file cost time :" + (end.getTime() - start.getTime())); os.close(); - FileUtil.del(new File(IMG_PATH_1)); } diff --git a/src/test/java/com/ibiz/excel/picture/support/EasyUseExample1.java b/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample1.java similarity index 98% rename from src/test/java/com/ibiz/excel/picture/support/EasyUseExample1.java rename to src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample1.java index 549cc3e..e88dca1 100644 --- a/src/test/java/com/ibiz/excel/picture/support/EasyUseExample1.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample1.java @@ -1,4 +1,4 @@ -package com.ibiz.excel.picture.support; +package com.ibiz.excel.picture.support.example; import cn.hutool.core.io.FileUtil; import com.ibiz.excel.picture.support.constants.WorkbookConstant; diff --git a/src/test/java/com/ibiz/excel/picture/support/EasyUseExample2.java b/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample2.java similarity index 98% rename from src/test/java/com/ibiz/excel/picture/support/EasyUseExample2.java rename to src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample2.java index c88e9b9..2b8d978 100644 --- a/src/test/java/com/ibiz/excel/picture/support/EasyUseExample2.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample2.java @@ -1,4 +1,4 @@ -package com.ibiz.excel.picture.support; +package com.ibiz.excel.picture.support.example; import cn.hutool.core.io.FileUtil; import com.ibiz.excel.picture.support.constants.WorkbookConstant; diff --git a/src/test/java/com/ibiz/excel/picture/support/EasyUseExample3.java b/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample3.java similarity index 92% rename from src/test/java/com/ibiz/excel/picture/support/EasyUseExample3.java rename to src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample3.java index ffcbb1c..441444e 100644 --- a/src/test/java/com/ibiz/excel/picture/support/EasyUseExample3.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample3.java @@ -1,4 +1,4 @@ -package com.ibiz.excel.picture.support; +package com.ibiz.excel.picture.support.example; import cn.hutool.core.io.FileUtil; import com.ibiz.excel.picture.support.model.*; @@ -32,10 +32,10 @@ public class EasyUseExample3 { Sheet sheet = workBook.createSheet("测试"); // 需要在创建行前预设宽度 - sheet.addColumnHelper(new ColumnHelper(1, 10)) - .addColumnHelper(new ColumnHelper(3, 50)) - .addColumnHelper(new ColumnHelper(4, 50)) - .addColumnHelper(new ColumnHelper(5, 50)); + sheet.setColumnWidth(1, 10) + .setColumnWidth(3, 50) + .setColumnWidth(4, 50) + .setColumnWidth(5, 50); // 第一行表头 Row row = sheet.createRow(0) -- Gitee From 6c75f36f29d527e573ad2c1d5929a29b7422aa95 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Mon, 8 Feb 2021 15:45:46 +0800 Subject: [PATCH 034/161] =?UTF-8?q?update=20=E7=A4=BA=E4=BE=8B=E5=9C=B0?= =?UTF-8?q?=E5=9D=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c7bc7c3..f187def 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, 2. ### 示例 - - [excel含图片导出demo地址](https://gitee.com/mwk719/excel-batch-picture-support/tree/master/src/test/java/com/ibiz/excel/picture/support) + - [excel含图片导出demo地址](https://gitee.com/mwk719/excel-batch-picture-support/tree/dev/src/test/java/com/ibiz/excel/picture/support/example) - [微云-6767张图片共800mb资源.rar 可用于测试](https://minwk.top/big-size-img/) 3. ### 版本更迭 -- Gitee From 20bc84720eb8315f9f9b252bedd85ce09d323589 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Fri, 26 Feb 2021 17:56:06 +0800 Subject: [PATCH 035/161] =?UTF-8?q?fix=20flushSize=20=3D=20-1=20=E6=97=B6?= =?UTF-8?q?=E4=B8=8D=E5=88=B7=E6=96=B0=E6=B5=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../excel/picture/support/model/Sheet.java | 2 +- .../excel/picture/support/model/Workbook.java | 5 +- .../com/ibiz/excel/picture/support/Demo.java | 4 +- .../excel/picture/support/PicturesDemo.java | 16 ++-- .../excel/picture/support/UserPicture.java | 83 +------------------ 5 files changed, 15 insertions(+), 95 deletions(-) diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java index c3634e0..009881c 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java @@ -260,7 +260,7 @@ public class Sheet { } Row createRow(int rowNumber) { writeRow = rowNumber; - if(rows.size() > flushSize){ + if(rows.size() > flushSize && flushSize != -1){ flush(); } Row row = new Row(rowNumber); diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Workbook.java b/src/main/java/com/ibiz/excel/picture/support/model/Workbook.java index ddfcf4e..67366ea 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Workbook.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Workbook.java @@ -16,7 +16,10 @@ import java.util.*; */ public class Workbook { private Logger logger = LoggerFactory.getLogger(this.getClass()); - /**到达row行数就刷新流*/ + /** + * 到达row行数就刷新流 + * flushSize = -1 时不刷新流 + */ private int flushSize; /**工作表sheet */ private List sheets; diff --git a/src/test/java/com/ibiz/excel/picture/support/Demo.java b/src/test/java/com/ibiz/excel/picture/support/Demo.java index 9b18521..17cf8aa 100644 --- a/src/test/java/com/ibiz/excel/picture/support/Demo.java +++ b/src/test/java/com/ibiz/excel/picture/support/Demo.java @@ -13,7 +13,7 @@ import java.util.stream.IntStream; * @date 2020/7/817:29 */ public class Demo { - static final String CURRENT_PATH = Demo.class.getClassLoader().getResource(".").getPath(); + static final String CURRENT_PATH = "E:\\test\\"; static final String picture1 = CURRENT_PATH + "image/image1.png"; static final String picture2 = CURRENT_PATH + "image/image2.png"; static final String picture3 = CURRENT_PATH + "image/image3.png"; @@ -23,7 +23,7 @@ public class Demo { Date start = new Date(); Workbook workBook = Workbook.getInstance(200); Sheet sheet = workBook.createSheet("导出个表"); - IntStream.range(1, 5000).forEach(r -> { + IntStream.range(1, 10).forEach(r -> { String pre = "a"; if (r % 3 == 0) { pre = "b"; diff --git a/src/test/java/com/ibiz/excel/picture/support/PicturesDemo.java b/src/test/java/com/ibiz/excel/picture/support/PicturesDemo.java index 03290fc..1a38ce0 100644 --- a/src/test/java/com/ibiz/excel/picture/support/PicturesDemo.java +++ b/src/test/java/com/ibiz/excel/picture/support/PicturesDemo.java @@ -1,7 +1,9 @@ package com.ibiz.excel.picture.support; import cn.hutool.core.io.FileUtil; +import com.ibiz.excel.picture.support.model.RowStyle; import com.ibiz.excel.picture.support.model.Sheet; +import com.ibiz.excel.picture.support.model.StyleEnum; import com.ibiz.excel.picture.support.model.Workbook; import java.io.File; @@ -28,12 +30,12 @@ public class PicturesDemo { public static void main(String[] args) throws IOException { Date start = new Date(); - Workbook workBook = Workbook.getInstance(1); + Workbook workBook = Workbook.getInstance(-1); Sheet sheet = workBook.createSheet("测试"); File[] files = FileUtil.ls(IMG_PATH); SUM = files.length; UserPicture u1; - for (int r = 0; r < 10; r++) { + for (int r = 0; r < 2; r++) { if (N == 0) { _COUNT = 0; } @@ -41,20 +43,14 @@ public class PicturesDemo { u1.setAge(15); u1.setName("测试-" + r); u1.setPicture(files[getIndex(N, 0)].getAbsolutePath()); - u1.setPicture1(files[getIndex(N, 1)].getAbsolutePath()); - u1.setPicture2(files[getIndex(N, 2)].getAbsolutePath()); - u1.setPicture3(files[getIndex(N, 3)].getAbsolutePath()); - u1.setPicture4(files[getIndex(N, 4)].getAbsolutePath()); - u1.setPicture5(files[getIndex(N, 5)].getAbsolutePath()); - u1.setPicture6(files[getIndex(N, 6)].getAbsolutePath()); - u1.setPicture7(files[getIndex(N, 7)].getAbsolutePath()); - u1.setPicture8(files[getIndex(N, 8)].getAbsolutePath()); sheet.createRow(u1); _COUNT++; N = _COUNT * 9; } + sheet.getRows().get(0).setRowStyle(new RowStyle(StyleEnum.GREEN_B)); + File file = createFile(); OutputStream os = new FileOutputStream(file); workBook.write(os); diff --git a/src/test/java/com/ibiz/excel/picture/support/UserPicture.java b/src/test/java/com/ibiz/excel/picture/support/UserPicture.java index 889424f..df4f5fe 100644 --- a/src/test/java/com/ibiz/excel/picture/support/UserPicture.java +++ b/src/test/java/com/ibiz/excel/picture/support/UserPicture.java @@ -11,70 +11,14 @@ public class UserPicture { public UserPicture() { } - @ExportModel(title = "姓名", mergeMaster = true) + @ExportModel(title = "姓名") private String name; @ExportModel(sort = 1, title = "年龄") private Integer age; - @ExportModel(sort = 2, title = "部门", merge = true) + @ExportModel(sort = 2, title = "部门") private String department; @ExportModel(sort = 3, isPicture = true, title = "图片1") private String picture; - @ExportModel(sort = 4, isPicture = true, title = "图片2") - private String picture1; - @ExportModel(sort = 5, isPicture = true, title = "图片3") - private String picture2; - @ExportModel(sort = 6, isPicture = true, title = "图片4") - private String picture3; - @ExportModel(sort = 7, isPicture = true, title = "图片5") - private String picture4; - @ExportModel(sort = 8, isPicture = true, title = "图片6") - private String picture5; - @ExportModel(sort = 9, isPicture = true, title = "图片7") - private String picture6; - @ExportModel(sort = 10, isPicture = true, title = "图片8") - private String picture7; - @ExportModel(sort = 11, isPicture = true, title = "图片9") - private String picture8; - - public String getPicture4() { - return picture4; - } - - public void setPicture4(String picture4) { - this.picture4 = picture4; - } - - public String getPicture5() { - return picture5; - } - - public void setPicture5(String picture5) { - this.picture5 = picture5; - } - - public String getPicture6() { - return picture6; - } - - public void setPicture6(String picture6) { - this.picture6 = picture6; - } - - public String getPicture7() { - return picture7; - } - - public void setPicture7(String picture7) { - this.picture7 = picture7; - } - - public String getPicture8() { - return picture8; - } - - public void setPicture8(String picture8) { - this.picture8 = picture8; - } public UserPicture(String name, Integer age, String department, String picture) { this.name = name; @@ -115,27 +59,4 @@ public class UserPicture { this.picture = picture; } - public String getPicture1() { - return picture1; - } - - public void setPicture1(String picture1) { - this.picture1 = picture1; - } - - public String getPicture2() { - return picture2; - } - - public void setPicture2(String picture2) { - this.picture2 = picture2; - } - - public String getPicture3() { - return picture3; - } - - public void setPicture3(String picture3) { - this.picture3 = picture3; - } } -- Gitee From baa9cba691a583e3e850cc177d5cfd1184067a9c Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Fri, 26 Feb 2021 18:16:59 +0800 Subject: [PATCH 036/161] release 1.0.3 --- README.md | 8 +++++++- pom.xml | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f187def..f1beeb4 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, top.minwk excel-x - 1.0.2 + 1.0.3 ``` @@ -42,6 +42,12 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, 3. ### 版本更迭 + #### 1.0.3(2021.02.26) + + - 简化使用示例 + - 修复flushSize = -1 时不刷新流 + - 修复其他未知问题 + #### 1.0.2(2021.01.26) - 修复MD5时未关闭流 diff --git a/pom.xml b/pom.xml index d6fda96..7171d1f 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 top.minwk excel-x - 1.0.2 + 1.0.3 excel-x excel-x https://gitee.com/mwk719/excel-batch-picture-support -- Gitee From 12b6120ec5a53e0489a6e929d6eab5b994a83516 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Fri, 26 Feb 2021 18:23:15 +0800 Subject: [PATCH 037/161] =?UTF-8?q?update=20=E6=9C=89=E7=9A=84=E6=B2=A1?= =?UTF-8?q?=E7=9A=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 7171d1f..df8e9b0 100644 --- a/pom.xml +++ b/pom.xml @@ -29,8 +29,8 @@ minwk - 1294608448@qq.com - mwk + minweikai@gmail.com + 凯创未来科技 https://minwk.top/ -- Gitee From ed42fbee58eb7744b09dd08124d73cca474f1b9f Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Fri, 26 Mar 2021 17:00:15 +0800 Subject: [PATCH 038/161] =?UTF-8?q?add=20=E5=A4=9A=E8=A1=8C=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=86=99=E5=85=A5=E7=A4=BA=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../support/example/EasyUseExample4.java | 117 ++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample4.java diff --git a/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample4.java b/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample4.java new file mode 100644 index 0000000..fab1038 --- /dev/null +++ b/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample4.java @@ -0,0 +1,117 @@ +package com.ibiz.excel.picture.support.example; + +import cn.hutool.core.io.FileUtil; +import com.ibiz.excel.picture.support.model.*; + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.IOException; +import java.util.*; + +/** + * 简化设置EasyUseExample4 + * 1. 需要文本列表信息 + * 2. 需要单元格填充多张图片 + * 3. 需要表头 + * 4. 多行数据写入 + * + * @author MinWeikai + * @date 2021-02-07 16:47:17 + */ +public class EasyUseExample4 { + static final String CURRENT_PATH = "E:\\test\\"; + + private final static String IMG_PATH = CURRENT_PATH + "img\\"; + + private final static String IMG_PATH_1 = IMG_PATH + "1.jpg"; + private final static String IMG_PATH_2 = IMG_PATH + "2.jpg"; + + + public static void main(String[] args) throws IOException { + Date start = new Date(); + Workbook workBook = Workbook.getInstance(Integer.MAX_VALUE); + Sheet sheet = workBook.createSheet("测试"); + + // 需要在创建行前预设宽度 + //序号宽度 + sheet.addColumnHelper(new ColumnHelper(1, 10)); + + // 第一行表头 + Row row = sheet.createRow(0) + //字体20 + .setRowStyle(new RowStyle(StyleEnum.F20)); + row.autoRowCells(Collections.singletonList(new Cell(0).setValue("表头"))); + + // 第二行放标题 + String[] excelName = {"文本1", "文本2", "图片1", "图片2", "图片3"}; + //要进行合并的列 + sheet.getMergeCells().add(new MergeCell(0, 0, 0, excelName.length - 1)); + row = sheet.createRow(1) + //配置该行颜色,现在默认只有绿色 + .setRowStyle(new RowStyle(StyleEnum.GREEN_B)); + List cells = new ArrayList<>(); + for (int i = 0; i < excelName.length; i++) { + cells.add(new Cell(i).setValue(excelName[i])); + } + row.autoRowCells(cells); + + // 第三行放内容 + int num; + List pictures = sheet.getPictures(); + for (int j = 0; j < 5; j++) { + // 第三行放内容 + num = j + 2; + row = sheet.createRow(num); + + cells = new ArrayList<>(); + int index = 0; + for (int i = 0; i < excelName.length; i++) { + Object propertyValue = null; + switch (i) { + case 0: + propertyValue = num - 1; + break; + case 1: + propertyValue = "文本2"; + break; + case 2: + //在第二列添加多张图片 + pictures.add(new Picture(2, row.getRowNumber(), 1000000, IMG_PATH_1)); + row.setHeight(80); + break; + case 3: + propertyValue = "333"; + break; + case 4: + propertyValue = "144411"; + break; + default: + } + cells.add(new Cell(num, index++).setValue(propertyValue == null ? "" : propertyValue.toString())); + row.setCells(cells); + } + } + + + File file = createFile(); + BufferedOutputStream os = FileUtil.getOutputStream(file); + workBook.write(os); + workBook.close(); + Date end = new Date(); + System.out.println("file capital :" + (file.length() / 1024 / 1024) + "M name :" + file.getName()); + System.out.println("file cost time :" + (end.getTime() - start.getTime())); + os.close(); + } + + + private static File createFile() { + String dir = CURRENT_PATH + "excel/"; + File file = new File(dir); + if (!file.exists()) { + file.mkdir(); + } + String name = CURRENT_PATH + "excel/" + UUID.randomUUID() + ".xlsx"; + return new File(name); + } + +} -- Gitee From 1983c6b6ede79380119016b43c49ada439350eda Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Tue, 7 Dec 2021 17:26:32 +0800 Subject: [PATCH 039/161] =?UTF-8?q?fix=20bug=E5=9B=BE=E7=89=87=E9=81=AE?= =?UTF-8?q?=E6=8C=A1=E6=89=80=E5=9C=A8=E5=8D=95=E5=85=83=E6=A0=BC=E8=BE=B9?= =?UTF-8?q?=E6=A1=86=E7=BA=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../support/flush/Drawing1Handler.java | 39 ++++++++++++++++--- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/ibiz/excel/picture/support/flush/Drawing1Handler.java b/src/main/java/com/ibiz/excel/picture/support/flush/Drawing1Handler.java index 254ac2d..858b1e3 100644 --- a/src/main/java/com/ibiz/excel/picture/support/flush/Drawing1Handler.java +++ b/src/main/java/com/ibiz/excel/picture/support/flush/Drawing1Handler.java @@ -18,6 +18,11 @@ import java.util.stream.Collectors; public class Drawing1Handler implements InvocationHandler { private IRepository target; + /** + * 容器间距 默认10000,可能约等于1px吧 + */ + private static final int PADDING = 10000; + public Drawing1Handler(IRepository proxy) { this.target = proxy; } @@ -49,19 +54,43 @@ public class Drawing1Handler implements InvocationHandler { /** * 写 drawing1.xml * - * @param picture - * @param i + * @param picture 图片 + * @param i 第几张图片,从0开始 */ private void writerDrawingXML( Picture picture, int i) { + /* + 表示从xx开始 + 2 第几个单元格 + 9525 离左边框距离 + 2 第几行 + 9525 离上边框距离 + + 表示到xx位置 + 2 第几个单元格 + 1009525 + 3 第几行 + 12225 离上边框距离 + + 图片标签 + + */ String content = "" + "" + picture.getFromCol() + ""; + // 图片间距 int colOff = i * picture.getWidth(); + // 默认从离左边框1个像素,防止图片遮挡边框线 + if(colOff == 0){ + colOff = PADDING; + } content = content + colOff + "" + - "" + picture.getFromRow() + "0" + + "" + picture.getFromRow() + "" + + "" + PADDING + + "" + + "" + "\n" + - "" + picture.getToCol() + "" + (colOff + picture.getWidth()) + "" + - "" + picture.getToRow() + "1260000" + + "" + picture.getToCol() + "" + (colOff + picture.getWidth() - PADDING) + "" + + "" + (picture.getToRow()) + "1260000" + "" + "" + "" + -- Gitee From 6c8f7ac670001df1c538c9545c3322912de87c72 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Tue, 7 Dec 2021 17:33:57 +0800 Subject: [PATCH 040/161] =?UTF-8?q?add=20=E6=B7=BB=E5=8A=A0excel=E5=AF=BC?= =?UTF-8?q?=E5=87=BA=E6=89=80=E7=94=A8=E4=BE=9D=E8=B5=96=EF=BC=8C=E5=AF=BC?= =?UTF-8?q?=E5=87=BA=E6=96=B9=E6=B3=95=E7=B1=BB=EF=BC=8C=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E7=A4=BA=E4=BE=8B=EF=BC=8C=E6=B5=8B=E8=AF=95=E7=94=9F=E6=88=90?= =?UTF-8?q?=E6=96=B9=E6=B3=95=EF=BC=9B=E6=9C=89=E5=A4=9A=E4=BD=99=E7=9A=84?= =?UTF-8?q?=E4=BE=9D=E8=B5=96=E4=B8=8D=E5=A5=BD=EF=BC=8C=E5=8F=AF=E4=BB=A5?= =?UTF-8?q?=E5=9C=A8=E6=89=93=E5=8C=85=E6=97=B6=E4=B8=8D=E6=89=93=E5=8C=85?= =?UTF-8?q?=E8=AF=A5=E4=BE=9D=E8=B5=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 17 ++++- .../excel/picture/support/util/WebUtil.java | 67 +++++++++++++++++++ .../excel/picture/support/UserPicture.java | 4 +- .../support/example/EasyUseExample4.java | 34 +++------- .../example/EasyUseExample_Annotation.java | 41 ++++++++++++ 5 files changed, 133 insertions(+), 30 deletions(-) create mode 100644 src/main/java/com/ibiz/excel/picture/support/util/WebUtil.java create mode 100644 src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample_Annotation.java diff --git a/pom.xml b/pom.xml index df8e9b0..286e3d7 100644 --- a/pom.xml +++ b/pom.xml @@ -16,6 +16,7 @@ 1.8 + 5.2.8.RELEASE @@ -55,12 +56,24 @@ org.springframework spring-core - 5.2.8.RELEASE + ${version.spring} org.springframework spring-beans - 5.2.8.RELEASE + ${version.spring} + + + + javax.servlet + javax.servlet-api + 3.1.0 + provided + + + org.springframework + spring-web + ${version.spring} diff --git a/src/main/java/com/ibiz/excel/picture/support/util/WebUtil.java b/src/main/java/com/ibiz/excel/picture/support/util/WebUtil.java new file mode 100644 index 0000000..82453d7 --- /dev/null +++ b/src/main/java/com/ibiz/excel/picture/support/util/WebUtil.java @@ -0,0 +1,67 @@ +package com.ibiz.excel.picture.support.util; + +import cn.hutool.core.io.FileUtil; +import com.ibiz.excel.picture.support.model.Workbook; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.web.util.WebUtils; + +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletResponse; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.IOException; +import java.net.URLEncoder; + +/** + * web文件处理工具 + * + * @author MinWeikai + * @date 2021-12-06 17:49:09 + */ +public class WebUtil { + + private static final Logger log = LoggerFactory.getLogger(WebUtils.class); + + /** + * excel导出测试 + * + * @param wb 自定义的excel工作簿excel + * @param fileName 文件名 + * @param tempPath 生成文件存放临时路径 + */ + public static void writeExcelTest(Workbook wb, String fileName, String tempPath) { + File file = FileUtil.touch(tempPath.concat(fileName)); + try (BufferedOutputStream os = FileUtil.getOutputStream(file)) { + wb.write(os); + } catch (Exception e) { + log.error("测试导出excel异常", e); + } + log.debug("测试导出excel路径:{}", file.getAbsolutePath()); + } + + /** + * excel web端下载 + * + * @param wb 自定义的excel工作簿excel + * @param fileName 文件名 + * @param response 响应体 + * @throws IOException + */ + public static void writeExcel(Workbook wb, String fileName, HttpServletResponse response) throws IOException { + response.reset(); + response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + URLEncoder.encode(fileName, "UTF-8")); + response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); + try (ServletOutputStream os = response.getOutputStream()) { + wb.write(os); + } catch (Exception e) { + log.error("导出excel异常", e); + } finally { + wb.close(); + } + } + + +} diff --git a/src/test/java/com/ibiz/excel/picture/support/UserPicture.java b/src/test/java/com/ibiz/excel/picture/support/UserPicture.java index df4f5fe..2f7bdfc 100644 --- a/src/test/java/com/ibiz/excel/picture/support/UserPicture.java +++ b/src/test/java/com/ibiz/excel/picture/support/UserPicture.java @@ -15,9 +15,9 @@ public class UserPicture { private String name; @ExportModel(sort = 1, title = "年龄") private Integer age; - @ExportModel(sort = 2, title = "部门") + @ExportModel(sort = 3, title = "部门") private String department; - @ExportModel(sort = 3, isPicture = true, title = "图片1") + @ExportModel(sort = 2, isPicture = true, title = "图片1") private String picture; public UserPicture(String name, Integer age, String department, String picture) { diff --git a/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample4.java b/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample4.java index fab1038..0bee561 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample4.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample4.java @@ -1,10 +1,8 @@ package com.ibiz.excel.picture.support.example; -import cn.hutool.core.io.FileUtil; import com.ibiz.excel.picture.support.model.*; +import com.ibiz.excel.picture.support.util.WebUtil; -import java.io.BufferedOutputStream; -import java.io.File; import java.io.IOException; import java.util.*; @@ -19,7 +17,9 @@ import java.util.*; * @date 2021-02-07 16:47:17 */ public class EasyUseExample4 { - static final String CURRENT_PATH = "E:\\test\\"; + private static final String CURRENT_PATH = "E:\\test\\"; + + private static final String TEMP_PATH = CURRENT_PATH + "excel\\"; private final static String IMG_PATH = CURRENT_PATH + "img\\"; @@ -28,8 +28,7 @@ public class EasyUseExample4 { public static void main(String[] args) throws IOException { - Date start = new Date(); - Workbook workBook = Workbook.getInstance(Integer.MAX_VALUE); + Workbook workBook = Workbook.getInstance(100); Sheet sheet = workBook.createSheet("测试"); // 需要在创建行前预设宽度 @@ -58,7 +57,7 @@ public class EasyUseExample4 { // 第三行放内容 int num; List pictures = sheet.getPictures(); - for (int j = 0; j < 5; j++) { + for (int j = 0; j < 1; j++) { // 第三行放内容 num = j + 2; row = sheet.createRow(num); @@ -77,6 +76,7 @@ public class EasyUseExample4 { case 2: //在第二列添加多张图片 pictures.add(new Picture(2, row.getRowNumber(), 1000000, IMG_PATH_1)); + pictures.add(new Picture(2, row.getRowNumber(), 1000000, IMG_PATH_2)); row.setHeight(80); break; case 3: @@ -92,26 +92,8 @@ public class EasyUseExample4 { } } - - File file = createFile(); - BufferedOutputStream os = FileUtil.getOutputStream(file); - workBook.write(os); - workBook.close(); - Date end = new Date(); - System.out.println("file capital :" + (file.length() / 1024 / 1024) + "M name :" + file.getName()); - System.out.println("file cost time :" + (end.getTime() - start.getTime())); - os.close(); + WebUtil.writeExcelTest(workBook, "多数据图测试导出".concat(String.valueOf(UUID.randomUUID())).concat(".xlsx"), TEMP_PATH); } - private static File createFile() { - String dir = CURRENT_PATH + "excel/"; - File file = new File(dir); - if (!file.exists()) { - file.mkdir(); - } - String name = CURRENT_PATH + "excel/" + UUID.randomUUID() + ".xlsx"; - return new File(name); - } - } diff --git a/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample_Annotation.java b/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample_Annotation.java new file mode 100644 index 0000000..dbce446 --- /dev/null +++ b/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample_Annotation.java @@ -0,0 +1,41 @@ +package com.ibiz.excel.picture.support.example; + +import com.ibiz.excel.picture.support.UserPicture; +import com.ibiz.excel.picture.support.model.Sheet; +import com.ibiz.excel.picture.support.model.Workbook; +import com.ibiz.excel.picture.support.util.WebUtil; + +import java.io.IOException; +import java.util.UUID; + +/** + * 注解使用导出 + * todo 使用注解目前一个单元格只能放一张图片,存在bug图片所在下边框不是加粗实线,待解决 + * todo 建议使用{@link EasyUseExample4} 示例,不过写法有点麻烦,待优化 + * @author MinWeikai + * @date 2021-12-07 10:59:49 + */ +public class EasyUseExample_Annotation { + static final String CURRENT_PATH = "E:\\test\\"; + private static final String TEMP_PATH = CURRENT_PATH + "excel\\"; + private final static String IMG_PATH = "E:\\test\\img\\"; + + private final static String IMG_PATH_1 = IMG_PATH + "1.jpg"; + private final static String IMG_PATH_2 = IMG_PATH + "2.jpg"; + + + public static void main(String[] args) throws IOException { + Workbook workBook = Workbook.getInstance(); + Sheet sheet = workBook.createSheet("测试"); + UserPicture u1; + for (int r = 0; r < 2; r++) { + u1 = new UserPicture(); + u1.setAge(15); + u1.setName("测试-" + r); + u1.setPicture(IMG_PATH_1); + sheet.createRow(u1); + } + WebUtil.writeExcelTest(workBook, "使用注解导出".concat(String.valueOf(UUID.randomUUID())).concat(".xlsx"), TEMP_PATH); + } + +} -- Gitee From 838aab790a34d3af7f1a32d1aa529da54b73412f Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Wed, 8 Dec 2021 11:24:17 +0800 Subject: [PATCH 041/161] =?UTF-8?q?fix=20=E4=BD=BF=E7=94=A8=E6=B3=A8?= =?UTF-8?q?=E8=A7=A3=E5=AF=BC=E5=87=BAbug=E5=9B=BE=E7=89=87=E6=89=80?= =?UTF-8?q?=E5=9C=A8=E4=B8=8B=E8=BE=B9=E6=A1=86=E4=B8=8D=E6=98=AF=E5=8A=A0?= =?UTF-8?q?=E7=B2=97=E5=AE=9E=E7=BA=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/ibiz/excel/picture/support/model/Sheet.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java index 009881c..165b2df 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java @@ -220,34 +220,38 @@ public class Sheet { boolean merge = model.merge(); String title = model.title(); Cell cell = new Cell(row.getRowNumber(), sort); + // 合并 是标题 并且 是要合并的基准列,将元素放在基准列中 if (isHead && mergeMaster) { mergeCellNumber = sort; autoMergeCell = true; colCells.add(cell.getCol()); } + // 合并 是标题 并且 是要合并的列 if (isHead && merge) { colCells.add(cell.getCol()); } + String value = null; try { value = null == f.get(t) ? "" : "" + f.get(t); } catch (IllegalAccessException e) { e.printStackTrace(); } + // 是标题,则将title设置为单元格的值 if (isHead) { cell.setValue(title); } else { cell.setValue(value); } + // 不是标题 并且 是图片 并且 值不为空 if (!isHead && isPicture && StringUtils.isNotBlank(value)) { //有图片的行,行高设置为100 row.setHeight(WorkbookConstant.PICTURE_ROW_HEIGHT); //增加图片 pictures.add(new Picture(row.getRowNumber(), cell.getCellNumber(), value)); } - if (isHead || !isPicture) { - row.getCells().add(cell); - } + // 将组装好的元素项,放到该行的元素项集合中 + row.getCells().add(cell); }); hasWriteHead = writeRow > -1; return row; -- Gitee From 92034ea0c649816cc208353d5f433162acc751cc Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Wed, 8 Dec 2021 11:25:48 +0800 Subject: [PATCH 042/161] =?UTF-8?q?add=20=E6=B7=BB=E5=8A=A0=E6=B3=A8?= =?UTF-8?q?=E8=A7=A3=E5=AF=BC=E5=87=BA=E5=9B=BE=E7=89=87=E5=92=8C=E6=96=87?= =?UTF-8?q?=E6=9C=AC=E4=BD=BF=E7=94=A8=E7=A4=BA=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../excel/picture/support/UserPicture.java | 9 +++++ ...va => AnnotationPictureExportExample.java} | 12 +++--- .../example/AnnotationTextExportExample.java | 39 +++++++++++++++++++ 3 files changed, 54 insertions(+), 6 deletions(-) rename src/test/java/com/ibiz/excel/picture/support/example/{EasyUseExample_Annotation.java => AnnotationPictureExportExample.java} (74%) create mode 100644 src/test/java/com/ibiz/excel/picture/support/example/AnnotationTextExportExample.java diff --git a/src/test/java/com/ibiz/excel/picture/support/UserPicture.java b/src/test/java/com/ibiz/excel/picture/support/UserPicture.java index 2f7bdfc..5171913 100644 --- a/src/test/java/com/ibiz/excel/picture/support/UserPicture.java +++ b/src/test/java/com/ibiz/excel/picture/support/UserPicture.java @@ -19,6 +19,8 @@ public class UserPicture { private String department; @ExportModel(sort = 2, isPicture = true, title = "图片1") private String picture; + @ExportModel(sort = 4, isPicture = true, title = "图片2") + private String headerPicture; public UserPicture(String name, Integer age, String department, String picture) { this.name = name; @@ -59,4 +61,11 @@ public class UserPicture { this.picture = picture; } + public String getHeaderPicture() { + return headerPicture; + } + + public void setHeaderPicture(String headerPicture) { + this.headerPicture = headerPicture; + } } diff --git a/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample_Annotation.java b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPictureExportExample.java similarity index 74% rename from src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample_Annotation.java rename to src/test/java/com/ibiz/excel/picture/support/example/AnnotationPictureExportExample.java index dbce446..181792f 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample_Annotation.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPictureExportExample.java @@ -6,16 +6,15 @@ import com.ibiz.excel.picture.support.model.Workbook; import com.ibiz.excel.picture.support.util.WebUtil; import java.io.IOException; -import java.util.UUID; /** - * 注解使用导出 - * todo 使用注解目前一个单元格只能放一张图片,存在bug图片所在下边框不是加粗实线,待解决 + * 注解图片导出示例 * todo 建议使用{@link EasyUseExample4} 示例,不过写法有点麻烦,待优化 + * * @author MinWeikai * @date 2021-12-07 10:59:49 */ -public class EasyUseExample_Annotation { +public class AnnotationPictureExportExample { static final String CURRENT_PATH = "E:\\test\\"; private static final String TEMP_PATH = CURRENT_PATH + "excel\\"; private final static String IMG_PATH = "E:\\test\\img\\"; @@ -28,14 +27,15 @@ public class EasyUseExample_Annotation { Workbook workBook = Workbook.getInstance(); Sheet sheet = workBook.createSheet("测试"); UserPicture u1; - for (int r = 0; r < 2; r++) { + for (int r = 0; r < 5; r++) { u1 = new UserPicture(); u1.setAge(15); u1.setName("测试-" + r); u1.setPicture(IMG_PATH_1); + u1.setHeaderPicture(IMG_PATH_2); sheet.createRow(u1); } - WebUtil.writeExcelTest(workBook, "使用注解导出".concat(String.valueOf(UUID.randomUUID())).concat(".xlsx"), TEMP_PATH); + WebUtil.writeExcelTest(workBook, "注解导出图片示例".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), TEMP_PATH); } } diff --git a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationTextExportExample.java b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationTextExportExample.java new file mode 100644 index 0000000..825a0d3 --- /dev/null +++ b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationTextExportExample.java @@ -0,0 +1,39 @@ +package com.ibiz.excel.picture.support.example; + +import com.ibiz.excel.picture.support.UserPicture; +import com.ibiz.excel.picture.support.model.Sheet; +import com.ibiz.excel.picture.support.model.Workbook; +import com.ibiz.excel.picture.support.util.WebUtil; + +import java.io.IOException; + +/** + * 注解无图导出示例 + * + * @author MinWeikai + * @date 2021-12-08 11:18:49 + */ +public class AnnotationTextExportExample { + static final String CURRENT_PATH = "E:\\test\\"; + private static final String TEMP_PATH = CURRENT_PATH + "excel\\"; + private final static String IMG_PATH = "E:\\test\\img\\"; + + private final static String IMG_PATH_1 = IMG_PATH + "1.jpg"; + private final static String IMG_PATH_2 = IMG_PATH + "2.jpg"; + + + public static void main(String[] args) throws IOException { + Workbook workBook = Workbook.getInstance(); + Sheet sheet = workBook.createSheet("测试"); + UserPicture u1; + for (int r = 0; r < 5; r++) { + u1 = new UserPicture(); + u1.setAge(15); + u1.setName("测试-" + r); + u1.setDepartment("研发部"); + sheet.createRow(u1); + } + WebUtil.writeExcelTest(workBook, "注解导出文本示例".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), TEMP_PATH); + } + +} -- Gitee From f19e5039a400c9af4165043797b0e991c083b4ee Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Wed, 8 Dec 2021 11:39:45 +0800 Subject: [PATCH 043/161] release 1.0.4 --- README.md | 8 +++++++- pom.xml | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f1beeb4..5670eff 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, top.minwk excel-x - 1.0.3 + 1.0.4 ``` @@ -42,6 +42,12 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, 3. ### 版本更迭 + #### 1.0.4(2021.12.08) + + - 添加使用注解导出含图片或文本的使用示例 + - 修复图片遮挡所在单元格边框线 + - 修复f使用注解导出图片所在下边框不是加粗实线 + #### 1.0.3(2021.02.26) - 简化使用示例 diff --git a/pom.xml b/pom.xml index 286e3d7..d59b9e1 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 top.minwk excel-x - 1.0.3 + 1.0.4 excel-x excel-x https://gitee.com/mwk719/excel-batch-picture-support -- Gitee From fc964c764d59ccb54c1e47eface59556e3c234f2 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Thu, 9 Dec 2021 14:15:01 +0800 Subject: [PATCH 044/161] =?UTF-8?q?add=20=E9=A1=B9=E7=9B=AE=E4=B8=AD?= =?UTF-8?q?=E5=AF=BC=E5=87=BA=E4=B8=8B=E8=BD=BDexcel=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E7=A4=BA=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 5670eff..021b2b0 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,7 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, - [excel含图片导出demo地址](https://gitee.com/mwk719/excel-batch-picture-support/tree/dev/src/test/java/com/ibiz/excel/picture/support/example) - [微云-6767张图片共800mb资源.rar 可用于测试](https://minwk.top/big-size-img/) + - [项目中导出下载excel使用示例](https://gitee.com/mwk719/spring-learn/blob/master/src/main/java/com/mwk/external/controller/ExcelController.java) 3. ### 版本更迭 -- Gitee From 33b6a58ba1fe4c1eb6e1e1a4336cd8a7de18a1af Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Thu, 30 Dec 2021 18:04:33 +0800 Subject: [PATCH 045/161] release 2.0.0 --- README.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 021b2b0..f7e5346 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, top.minwk excel-x - 1.0.4 + 2.0.0 ``` @@ -43,6 +43,15 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, 3. ### 版本更迭 + #### 2.0.0(2021.12.30) + + - [添加用户可自定义背景色样式](https://gitee.com/mwk719/excel-batch-picture-support/blob/dev/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java) + - [添加使用注解可对图片集合进行导出](https://gitee.com/mwk719/excel-batch-picture-support/blob/dev/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java) + - 添加自定义图片的高度;图片高度和单元格高度自适应 + - 修复导出图片集合变多时单元格宽度不够 + - 修复导出数据行数大于100 excel打开异常 + - 修复导出多组图片excel中缺失部分图片问题 + #### 1.0.4(2021.12.08) - 添加使用注解导出含图片或文本的使用示例 -- Gitee From 7759d202dd6fbcd51b28e12edc4465821931b0b8 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Thu, 9 Dec 2021 14:27:11 +0800 Subject: [PATCH 046/161] =?UTF-8?q?add=20=E5=AF=B9=E9=9B=86=E5=90=88?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E8=BF=9B=E8=A1=8C=E5=88=9B=E5=BB=BA=E8=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../excel/picture/support/model/Sheet.java | 9 +++++++++ .../AnnotationPictureExportExample.java | 20 ++++++++++++------- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java index 165b2df..ff524ee 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java @@ -94,6 +94,15 @@ public class Sheet { return SHEET_HANDLER.createRow(t); } + /** + * 对集合列表进行创建行,单元格会根据t的属性自动填充 + * @param collection 列属性集合 只会读取com.ibiz.excelx.annotation.Model 注解的属性 + * @param + */ + public void createRow(Collection collection) { + collection.forEach(this::createRow); + } + public Row createRow(int rowNumber) { return SHEET_HANDLER.createRow(rowNumber); } diff --git a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPictureExportExample.java b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPictureExportExample.java index 181792f..0736fe5 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPictureExportExample.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPictureExportExample.java @@ -6,6 +6,8 @@ import com.ibiz.excel.picture.support.model.Workbook; import com.ibiz.excel.picture.support.util.WebUtil; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; /** * 注解图片导出示例 @@ -26,15 +28,19 @@ public class AnnotationPictureExportExample { public static void main(String[] args) throws IOException { Workbook workBook = Workbook.getInstance(); Sheet sheet = workBook.createSheet("测试"); - UserPicture u1; + List userPictures = new ArrayList<>(); + UserPicture userPicture; for (int r = 0; r < 5; r++) { - u1 = new UserPicture(); - u1.setAge(15); - u1.setName("测试-" + r); - u1.setPicture(IMG_PATH_1); - u1.setHeaderPicture(IMG_PATH_2); - sheet.createRow(u1); + userPicture = new UserPicture(); + userPicture.setAge(15); + userPicture.setName("测试-" + r); + userPicture.setPicture(IMG_PATH_1); + userPicture.setHeaderPicture(IMG_PATH_2); + userPictures.add(userPicture); } + + // 创建集合的行数据在excel中 + sheet.createRow(userPictures); WebUtil.writeExcelTest(workBook, "注解导出图片示例".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), TEMP_PATH); } -- Gitee From e7ea1446bf0b9a798c46ef28c4fd43df1f8c764d Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Fri, 10 Dec 2021 17:33:09 +0800 Subject: [PATCH 047/161] =?UTF-8?q?add=20=E8=87=AA=E5=AE=9A=E4=B9=89?= =?UTF-8?q?=E6=A0=B7=E5=BC=8F=E5=BE=85=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../support/factory/RepositoryFactory.java | 2 + .../picture/support/flush/StylesHandler.java | 37 +++++ .../picture/support/model/ColumnHelper.java | 45 +++-- .../excel/picture/support/model/FontEnum.java | 4 +- .../excel/picture/support/model/RowStyle.java | 18 +- .../picture/support/model/StyleEnum.java | 4 +- .../excel/picture/support/module/Styles.java | 155 ++++++++++-------- .../excel/picture/support/util/WebUtil.java | 1 + .../support/example/EasyUseExample4.java | 6 +- 9 files changed, 184 insertions(+), 88 deletions(-) create mode 100644 src/main/java/com/ibiz/excel/picture/support/flush/StylesHandler.java diff --git a/src/main/java/com/ibiz/excel/picture/support/factory/RepositoryFactory.java b/src/main/java/com/ibiz/excel/picture/support/factory/RepositoryFactory.java index f844e24..166e3fe 100644 --- a/src/main/java/com/ibiz/excel/picture/support/factory/RepositoryFactory.java +++ b/src/main/java/com/ibiz/excel/picture/support/factory/RepositoryFactory.java @@ -36,6 +36,8 @@ public class RepositoryFactory { repository = (IRepository)Proxy.newProxyInstance(RepositoryFactory.class.getClassLoader(), new Class[]{IRepository.class}, new SharedStringXmlHandler(instance)); } else if (StringUtils.equals(alisa, Alias.SHEET1)) { repository = (IRepository)Proxy.newProxyInstance(RepositoryFactory.class.getClassLoader(), new Class[]{IRepository.class}, new Sheet1Handler(instance)); + } else if (StringUtils.equals(alisa, Alias.STYLES)) { + repository = (IRepository)Proxy.newProxyInstance(RepositoryFactory.class.getClassLoader(), new Class[]{IRepository.class}, new StylesHandler(instance)); } return repository; } diff --git a/src/main/java/com/ibiz/excel/picture/support/flush/StylesHandler.java b/src/main/java/com/ibiz/excel/picture/support/flush/StylesHandler.java new file mode 100644 index 0000000..99a0636 --- /dev/null +++ b/src/main/java/com/ibiz/excel/picture/support/flush/StylesHandler.java @@ -0,0 +1,37 @@ +package com.ibiz.excel.picture.support.flush; + +import com.ibiz.excel.picture.support.model.Row; +import com.ibiz.excel.picture.support.model.Sheet; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.util.List; + +/** + * 设置样式 + * + * @author MinWeikai + * @date 2021/12/10 16:55 + */ +public class StylesHandler implements InvocationHandler { + private IRepository target; + + public StylesHandler(IRepository proxy) { + this.target = proxy; + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + if (method.getName().equals("write")) { + Sheet sheet = (Sheet) args[0]; + List rows = sheet.getRows(); + if (!rows.isEmpty()) { + // TODO 待办。。 + + } + + + } + return method.invoke(target, args); + } +} diff --git a/src/main/java/com/ibiz/excel/picture/support/model/ColumnHelper.java b/src/main/java/com/ibiz/excel/picture/support/model/ColumnHelper.java index 184baec..11f6791 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/ColumnHelper.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/ColumnHelper.java @@ -8,23 +8,40 @@ package com.ibiz.excel.picture.support.model; */ public class ColumnHelper { - private Integer columnIndex; + /** + * 单元格列号, 1表示A列 + */ + private int columnIndex; - private Integer width; + /** + * 单元格宽度, 默认10 + */ + private int width = 10; - public ColumnHelper() { - } + /** + * 设置第几列单元格宽度 + * + * @param columnIndex 第几列单元格 + * @param width 宽度 + */ + public ColumnHelper(int columnIndex, int width) { + this.columnIndex = columnIndex; + this.width = width; + } - public ColumnHelper(Integer columnIndex, Integer width) { - this.columnIndex = columnIndex; - this.width = width; - } + /** + * 设置第几列单元格宽度 + * @param columnIndex 第几列单元格,默认宽度{@code width} + */ + public ColumnHelper(int columnIndex) { + this.columnIndex = columnIndex; + } - public Integer getColumnIndex() { - return columnIndex; - } + public int getColumnIndex() { + return columnIndex; + } - public Integer getWidth() { - return width; - } + public int getWidth() { + return width; + } } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/FontEnum.java b/src/main/java/com/ibiz/excel/picture/support/model/FontEnum.java index 0534c8a..1b96d32 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/FontEnum.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/FontEnum.java @@ -1,5 +1,7 @@ package com.ibiz.excel.picture.support.model; +import com.ibiz.excel.picture.support.module.Styles; + /** * 读取内置字体 * @@ -16,7 +18,7 @@ public enum FontEnum { F10(3) ; /** - * 与对应{@link com.ibiz.excel.picture.support.module.Styles} + * 与对应{@link Styles} */ private Integer fillId; diff --git a/src/main/java/com/ibiz/excel/picture/support/model/RowStyle.java b/src/main/java/com/ibiz/excel/picture/support/model/RowStyle.java index ac4319f..dd555c1 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/RowStyle.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/RowStyle.java @@ -10,14 +10,19 @@ public class RowStyle { private int fillId; + /** + * fgColor rgb颜色 + */ + private String fgColorRgb; + /** * 样式 */ private StyleEnum styleEnum; - - public RowStyle() { - } + public RowStyle(String fgColorRgb) { + this.fgColorRgb = fgColorRgb; + } public RowStyle(StyleEnum styleEnum) { this.styleEnum = styleEnum; @@ -28,4 +33,11 @@ public class RowStyle { return fillId; } + public String getFgColorRgb() { + return fgColorRgb; + } + + public void setFgColorRgb(String fgColorRgb) { + this.fgColorRgb = fgColorRgb; + } } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/StyleEnum.java b/src/main/java/com/ibiz/excel/picture/support/model/StyleEnum.java index 1d4dd7f..db4c3da 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/StyleEnum.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/StyleEnum.java @@ -1,5 +1,7 @@ package com.ibiz.excel.picture.support.model; +import com.ibiz.excel.picture.support.module.Styles; + /** * 样式枚举类 * @@ -21,7 +23,7 @@ public enum StyleEnum { /** * 填充色id - * 与对应{@link com.ibiz.excel.picture.support.module.Styles} + * 与对应{@link Styles} */ private Integer fillId; diff --git a/src/main/java/com/ibiz/excel/picture/support/module/Styles.java b/src/main/java/com/ibiz/excel/picture/support/module/Styles.java index 2947e73..254f15c 100644 --- a/src/main/java/com/ibiz/excel/picture/support/module/Styles.java +++ b/src/main/java/com/ibiz/excel/picture/support/module/Styles.java @@ -8,75 +8,98 @@ import com.ibiz.excel.picture.support.constants.Alias; * 有时间可以优化 * 电子表格样式参考处 * http://officeopenxml.com/SSstyles.php + * * @author MinWeikai - * @date 2021-01-19 14:00:55 + * @date 2021-01-19 14:00:55 */ @AutoWrite(dir = "xl") public class Styles { @AutoFile(fileName = "styles.xml", alias = Alias.STYLES) - String content = "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - ""+ - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + // 绿色背景,后续可在此追加 - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + // 填充色值坐标 - "" + - "" + - "" + - "" + - ""; + String content() { + return "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + // 绿色背景,后续可在此追加 + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + // 填充色值坐标 + "" + + "" + + "" + + "" + + ""; + } } diff --git a/src/main/java/com/ibiz/excel/picture/support/util/WebUtil.java b/src/main/java/com/ibiz/excel/picture/support/util/WebUtil.java index 82453d7..c21d4f6 100644 --- a/src/main/java/com/ibiz/excel/picture/support/util/WebUtil.java +++ b/src/main/java/com/ibiz/excel/picture/support/util/WebUtil.java @@ -36,6 +36,7 @@ public class WebUtil { File file = FileUtil.touch(tempPath.concat(fileName)); try (BufferedOutputStream os = FileUtil.getOutputStream(file)) { wb.write(os); + wb.close(); } catch (Exception e) { log.error("测试导出excel异常", e); } diff --git a/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample4.java b/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample4.java index 0bee561..e84926f 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample4.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample4.java @@ -32,8 +32,8 @@ public class EasyUseExample4 { Sheet sheet = workBook.createSheet("测试"); // 需要在创建行前预设宽度 - //序号宽度 - sheet.addColumnHelper(new ColumnHelper(1, 10)); + // 序号宽度 有时需要单独设置序号宽度窄一点 + sheet.addColumnHelper(new ColumnHelper(1)); // 第一行表头 Row row = sheet.createRow(0) @@ -77,7 +77,7 @@ public class EasyUseExample4 { //在第二列添加多张图片 pictures.add(new Picture(2, row.getRowNumber(), 1000000, IMG_PATH_1)); pictures.add(new Picture(2, row.getRowNumber(), 1000000, IMG_PATH_2)); - row.setHeight(80); + row.setHeight(90); break; case 3: propertyValue = "333"; -- Gitee From d6b1cceb282bc755a92a461e700fa9285053304f Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Sun, 12 Dec 2021 14:10:14 +0800 Subject: [PATCH 048/161] =?UTF-8?q?add=20=E8=87=AA=E5=AE=9A=E4=B9=89?= =?UTF-8?q?=E8=A1=8C=E6=A0=B7=E5=BC=8F=EF=BC=9B=E4=BF=AE=E6=94=B9=E8=A1=8C?= =?UTF-8?q?=E6=A0=B7=E5=BC=8F=E7=B1=BB=E5=91=BD=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../picture/support/flush/Sheet1Handler.java | 4 +- .../picture/support/flush/StylesHandler.java | 74 +++++++++++++---- .../picture/support/model/CellStyle.java | 81 +++++++++++++++++++ .../ibiz/excel/picture/support/model/Row.java | 15 ++-- .../excel/picture/support/model/RowStyle.java | 43 ---------- .../excel/picture/support/model/Sheet.java | 27 +++++++ .../excel/picture/support/model/Workbook.java | 15 ++++ .../excel/picture/support/module/Styles.java | 27 +------ .../excel/picture/support/CellWidthTest.java | 2 +- .../ibiz/excel/picture/support/FontTest.java | 4 +- .../picture/support/PictureCellWidthTest.java | 2 +- .../excel/picture/support/PicturesDemo.java | 4 +- .../excel/picture/support/RowFgColorTest.java | 2 +- .../support/example/EasyUseExample1.java | 2 +- .../support/example/EasyUseExample2.java | 4 +- .../support/example/EasyUseExample3.java | 4 +- .../support/example/EasyUseExample4.java | 14 ++-- 17 files changed, 216 insertions(+), 108 deletions(-) create mode 100644 src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java delete mode 100644 src/main/java/com/ibiz/excel/picture/support/model/RowStyle.java diff --git a/src/main/java/com/ibiz/excel/picture/support/flush/Sheet1Handler.java b/src/main/java/com/ibiz/excel/picture/support/flush/Sheet1Handler.java index a69528e..aab1e97 100644 --- a/src/main/java/com/ibiz/excel/picture/support/flush/Sheet1Handler.java +++ b/src/main/java/com/ibiz/excel/picture/support/flush/Sheet1Handler.java @@ -156,8 +156,8 @@ public class Sheet1Handler implements InvocationHandler { row.getCells().forEach(c -> content.append("") .append("") .append(c.getColDataNumber()) diff --git a/src/main/java/com/ibiz/excel/picture/support/flush/StylesHandler.java b/src/main/java/com/ibiz/excel/picture/support/flush/StylesHandler.java index 99a0636..52460c3 100644 --- a/src/main/java/com/ibiz/excel/picture/support/flush/StylesHandler.java +++ b/src/main/java/com/ibiz/excel/picture/support/flush/StylesHandler.java @@ -1,6 +1,7 @@ package com.ibiz.excel.picture.support.flush; import com.ibiz.excel.picture.support.model.Row; +import com.ibiz.excel.picture.support.model.CellStyle; import com.ibiz.excel.picture.support.model.Sheet; import java.lang.reflect.InvocationHandler; @@ -14,24 +15,67 @@ import java.util.List; * @date 2021/12/10 16:55 */ public class StylesHandler implements InvocationHandler { - private IRepository target; + private IRepository target; - public StylesHandler(IRepository proxy) { - this.target = proxy; - } + public StylesHandler(IRepository proxy) { + this.target = proxy; + } - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - if (method.getName().equals("write")) { - Sheet sheet = (Sheet) args[0]; - List rows = sheet.getRows(); - if (!rows.isEmpty()) { - // TODO 待办。。 + private StringBuilder xfBefore = new StringBuilder("" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + // 填充色值坐标 + ""); - } + private StringBuilder xfAfter = new StringBuilder("" + + "" + + "" + + ""); + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + if (method.getName().equals("write")) { + Sheet sheet = (Sheet) args[0]; + List rows = sheet.getRows(); + if (!rows.isEmpty()) { + // TODO 待办。。 + rows.stream().forEach(row -> { + CellStyle cellStyle = row.getCellStyle(); + if (row.getCellStyle() != null) { + this.appendFill(cellStyle); + + this.appendXf(cellStyle); + } + }); + target.append(xfBefore.append(xfAfter).toString()); + } + } + return method.invoke(target, args); + } + + private void appendXf(CellStyle cellStyle) { + xfBefore.append(""); + } + + private void appendFill(CellStyle cellStyle) { + target.append(""); + } - } - return method.invoke(target, args); - } } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java b/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java new file mode 100644 index 0000000..8ffef86 --- /dev/null +++ b/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java @@ -0,0 +1,81 @@ +package com.ibiz.excel.picture.support.model; + +/** + * 控制该行样式 + * + * @author MinWeikai + * @date 2021/1/19 14:04 + */ +public class CellStyle { + + /** + * 默认已有fill样式 + * 与对应{@link com.ibiz.excel.picture.support.module.Styles} + */ + private int fillId = 33; + + /** + * 默认已有cellStyles样式 + */ + private int s = 4; + + /** + * fgColor rgb颜色 + */ + private String fgColorRgb; + + /** + * 样式 + */ + private StyleEnum styleEnum; + + public CellStyle() { + } + + /** + * 创建单元格前景色 + * @param fgColorRgb + */ + public CellStyle(String fgColorRgb) { + // fillId+1,生成下一个编号 + fillId = fillId + 1; + s = s + 1; + this.fgColorRgb = fgColorRgb; + } + + public CellStyle(StyleEnum styleEnum) { + this.styleEnum = styleEnum; + this.fillId = styleEnum.getFillId(); + } + + public CellStyle(CellStyle cellStyle) { + // 生成下标 + cellStyle = cellStyle.addIndex(); + this.fillId = cellStyle.fillId; + this.s = cellStyle.s; + this.fgColorRgb = cellStyle.fgColorRgb; + } + + public CellStyle addIndex() { + // fillId+1,生成下一个编号 + fillId = fillId + 1; + s = s + 1; + return this; + } + + public int getFillId() { + return fillId; + } + + public int getS() { + return s; + } + + public String getFgColorRgb() { + return fgColorRgb; + } + + public void setFgColorRgb(String fgColorRgb) { + this.fgColorRgb = fgColorRgb; + } +} diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Row.java b/src/main/java/com/ibiz/excel/picture/support/model/Row.java index 239ba27..9e0849d 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Row.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Row.java @@ -20,7 +20,7 @@ public class Row { /** * 该行样式 */ - private RowStyle rowStyle; + private CellStyle cellStyle; public Row(){ this(1); @@ -69,12 +69,17 @@ public class Row { this.cells.clear(); } - public RowStyle getRowStyle() { - return rowStyle; + public CellStyle getCellStyle() { + return cellStyle; } - public Row setRowStyle(RowStyle rowStyle) { - this.rowStyle = rowStyle; + /** + * 设置行样式 + * @param cellStyle + * @return + */ + public Row setCellStyle(CellStyle cellStyle) { + this.cellStyle = new CellStyle(cellStyle); return this; } } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/RowStyle.java b/src/main/java/com/ibiz/excel/picture/support/model/RowStyle.java deleted file mode 100644 index dd555c1..0000000 --- a/src/main/java/com/ibiz/excel/picture/support/model/RowStyle.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.ibiz.excel.picture.support.model; - -/** - * 控制该行样式 - * - * @author MinWeikai - * @date 2021/1/19 14:04 - */ -public class RowStyle { - - private int fillId; - - /** - * fgColor rgb颜色 - */ - private String fgColorRgb; - - /** - * 样式 - */ - private StyleEnum styleEnum; - - public RowStyle(String fgColorRgb) { - this.fgColorRgb = fgColorRgb; - } - - public RowStyle(StyleEnum styleEnum) { - this.styleEnum = styleEnum; - this.fillId = styleEnum.getFillId(); - } - - public int getFillId() { - return fillId; - } - - public String getFgColorRgb() { - return fgColorRgb; - } - - public void setFgColorRgb(String fgColorRgb) { - this.fgColorRgb = fgColorRgb; - } -} diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java index ff524ee..afe922b 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java @@ -68,6 +68,33 @@ public class Sheet { */ private List columnHelpers = new ArrayList<>(); + /** + * 默认已有fill样式 + * 与对应{@link com.ibiz.excel.picture.support.module.Styles} + */ + private int fillId = 33; + + /** + * 默认已有cellStyles样式 + */ + private int s = 4; + + public int getFillId() { + return fillId; + } + + public void setFillId(int fillId) { + this.fillId = fillId; + } + + public int getS() { + return s; + } + + public void setS(int s) { + this.s = s; + } + public List getPictures() { return pictures; } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Workbook.java b/src/main/java/com/ibiz/excel/picture/support/model/Workbook.java index 67366ea..55869cf 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Workbook.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Workbook.java @@ -43,6 +43,8 @@ public class Workbook { */ private Map imageCache = new HashMap<>(); + private CellStyle cellStyle; + public Map getImageCache() { return imageCache; } @@ -116,4 +118,17 @@ public class Workbook { } } + public CellStyle getCellStyle() { + return cellStyle; + } + + public void setCellStyle(CellStyle cellStyle) { + this.cellStyle = cellStyle; + } + + public CellStyle createCellStyle() { + CellStyle cellStyle = new CellStyle(); + this.setCellStyle(cellStyle); + return cellStyle; + } } diff --git a/src/main/java/com/ibiz/excel/picture/support/module/Styles.java b/src/main/java/com/ibiz/excel/picture/support/module/Styles.java index 254f15c..657a5d1 100644 --- a/src/main/java/com/ibiz/excel/picture/support/module/Styles.java +++ b/src/main/java/com/ibiz/excel/picture/support/module/Styles.java @@ -76,30 +76,7 @@ public class Styles { "" + "" + "" + - "" + // 绿色背景,后续可在此追加 - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + // 填充色值坐标 - "" + - "" + - "" + - "" + - ""; + ""; // 绿色背景,后续可在此追加 + } } diff --git a/src/test/java/com/ibiz/excel/picture/support/CellWidthTest.java b/src/test/java/com/ibiz/excel/picture/support/CellWidthTest.java index 0328afe..2769309 100644 --- a/src/test/java/com/ibiz/excel/picture/support/CellWidthTest.java +++ b/src/test/java/com/ibiz/excel/picture/support/CellWidthTest.java @@ -34,7 +34,7 @@ public class CellWidthTest { // 第二行放标题 row = sheet.createRow(1) //配置该行颜色,现在默认只有绿色 - .setRowStyle(new RowStyle(StyleEnum.GREEN_B)); + .setCellStyle(new CellStyle(StyleEnum.GREEN_B)); List cells = new ArrayList<>(); for (int i = 0; i < excelName.length; i++) { Cell cell = new Cell(1, i).setValue(excelName[i]); diff --git a/src/test/java/com/ibiz/excel/picture/support/FontTest.java b/src/test/java/com/ibiz/excel/picture/support/FontTest.java index 34063f8..6bf49a1 100644 --- a/src/test/java/com/ibiz/excel/picture/support/FontTest.java +++ b/src/test/java/com/ibiz/excel/picture/support/FontTest.java @@ -36,7 +36,7 @@ public class FontTest { // 第一行表头 Row row = sheet.createRow(0) //字体20 - .setRowStyle(new RowStyle(StyleEnum.F20)) + .setCellStyle(new CellStyle(StyleEnum.F20)) ; String[] excelName = {"序号", "文本2", "图片1", "图片2", "图片3"}; sheet.getMergeCells().add(new MergeCell(0, 0, 0, excelName.length - 1)); @@ -45,7 +45,7 @@ public class FontTest { // 第二行放标题 row = sheet.createRow(1) //配置该行颜色,现在默认只有绿色 - .setRowStyle(new RowStyle(StyleEnum.GREEN_B)); + .setCellStyle(new CellStyle(StyleEnum.GREEN_B)); List cells = new ArrayList<>(); for (int i = 0; i < excelName.length; i++) { Cell cell = new Cell(1, i).setValue(excelName[i]); diff --git a/src/test/java/com/ibiz/excel/picture/support/PictureCellWidthTest.java b/src/test/java/com/ibiz/excel/picture/support/PictureCellWidthTest.java index ee58f5d..5361051 100644 --- a/src/test/java/com/ibiz/excel/picture/support/PictureCellWidthTest.java +++ b/src/test/java/com/ibiz/excel/picture/support/PictureCellWidthTest.java @@ -41,7 +41,7 @@ public class PictureCellWidthTest { // 第二行放标题 row = sheet.createRow(1) //配置该行颜色,现在默认只有绿色 - .setRowStyle(new RowStyle(StyleEnum.GREEN_B)); + .setCellStyle(new CellStyle(StyleEnum.GREEN_B)); List cells = new ArrayList<>(); for (int i = 0; i < excelName.length; i++) { Cell cell = new Cell(1, i).setValue(excelName[i]); diff --git a/src/test/java/com/ibiz/excel/picture/support/PicturesDemo.java b/src/test/java/com/ibiz/excel/picture/support/PicturesDemo.java index 1a38ce0..21cf91b 100644 --- a/src/test/java/com/ibiz/excel/picture/support/PicturesDemo.java +++ b/src/test/java/com/ibiz/excel/picture/support/PicturesDemo.java @@ -1,7 +1,7 @@ package com.ibiz.excel.picture.support; import cn.hutool.core.io.FileUtil; -import com.ibiz.excel.picture.support.model.RowStyle; +import com.ibiz.excel.picture.support.model.CellStyle; import com.ibiz.excel.picture.support.model.Sheet; import com.ibiz.excel.picture.support.model.StyleEnum; import com.ibiz.excel.picture.support.model.Workbook; @@ -49,7 +49,7 @@ public class PicturesDemo { N = _COUNT * 9; } - sheet.getRows().get(0).setRowStyle(new RowStyle(StyleEnum.GREEN_B)); + sheet.getRows().get(0).setCellStyle(new CellStyle(StyleEnum.GREEN_B)); File file = createFile(); OutputStream os = new FileOutputStream(file); diff --git a/src/test/java/com/ibiz/excel/picture/support/RowFgColorTest.java b/src/test/java/com/ibiz/excel/picture/support/RowFgColorTest.java index 17dfcc0..2acb667 100644 --- a/src/test/java/com/ibiz/excel/picture/support/RowFgColorTest.java +++ b/src/test/java/com/ibiz/excel/picture/support/RowFgColorTest.java @@ -32,7 +32,7 @@ public class RowFgColorTest { // 第二行放标题 row = sheet.createRow(1) //配置该行颜色,现在默认只有绿色 - .setRowStyle(new RowStyle(StyleEnum.GREEN_B)); + .setCellStyle(new CellStyle(StyleEnum.GREEN_B)); List cells = new ArrayList<>(); for (int i = 0; i < excelName.length; i++) { Cell cell = new Cell(1, i).setValue(excelName[i]); diff --git a/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample1.java b/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample1.java index e88dca1..ce3d64f 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample1.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample1.java @@ -39,7 +39,7 @@ public class EasyUseExample1 { sheet.getMergeCells().add(new MergeCell(0, 0, 0, excelName.length - 1)); Row row = sheet.createRow(1) //配置该行颜色,现在默认只有绿色 - .setRowStyle(new RowStyle(StyleEnum.GREEN_B)); + .setCellStyle(new CellStyle(StyleEnum.GREEN_B)); List cells = new ArrayList<>(); for (int i = 0; i < excelName.length; i++) { cells.add(new Cell(i).setValue(excelName[i])); diff --git a/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample2.java b/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample2.java index 2b8d978..95c112d 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample2.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample2.java @@ -34,7 +34,7 @@ public class EasyUseExample2 { // 第一行表头 Row row = sheet.createRow(0) //字体20 - .setRowStyle(new RowStyle(StyleEnum.F20)); + .setCellStyle(new CellStyle(StyleEnum.F20)); row.autoRowCells(Collections.singletonList(new Cell(0).setValue("表头"))); // 第二行放标题 @@ -43,7 +43,7 @@ public class EasyUseExample2 { sheet.getMergeCells().add(new MergeCell(0, 0, 0, excelName.length - 1)); row = sheet.createRow(1) //配置该行颜色,现在默认只有绿色 - .setRowStyle(new RowStyle(StyleEnum.GREEN_B)); + .setCellStyle(new CellStyle(StyleEnum.GREEN_B)); List cells = new ArrayList<>(); for (int i = 0; i < excelName.length; i++) { cells.add(new Cell(i).setValue(excelName[i])); diff --git a/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample3.java b/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample3.java index 441444e..74696c0 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample3.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample3.java @@ -40,7 +40,7 @@ public class EasyUseExample3 { // 第一行表头 Row row = sheet.createRow(0) //字体20 - .setRowStyle(new RowStyle(StyleEnum.F20)); + .setCellStyle(new CellStyle(StyleEnum.F20)); row.autoRowCells(Collections.singletonList(new Cell(0).setValue("表头"))); // 第二行放标题 @@ -49,7 +49,7 @@ public class EasyUseExample3 { sheet.getMergeCells().add(new MergeCell(0, 0, 0, excelName.length - 1)); row = sheet.createRow(1) //配置该行颜色,现在默认只有绿色 - .setRowStyle(new RowStyle(StyleEnum.GREEN_B)); + .setCellStyle(new CellStyle(StyleEnum.GREEN_B)); List cells = new ArrayList<>(); for (int i = 0; i < excelName.length; i++) { cells.add(new Cell(i).setValue(excelName[i])); diff --git a/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample4.java b/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample4.java index e84926f..4a9688f 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample4.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample4.java @@ -31,23 +31,25 @@ public class EasyUseExample4 { Workbook workBook = Workbook.getInstance(100); Sheet sheet = workBook.createSheet("测试"); + CellStyle cellStyle = workBook.createCellStyle(); + + cellStyle.setFgColorRgb("cc3300"); + // 需要在创建行前预设宽度 // 序号宽度 有时需要单独设置序号宽度窄一点 sheet.addColumnHelper(new ColumnHelper(1)); // 第一行表头 - Row row = sheet.createRow(0) - //字体20 - .setRowStyle(new RowStyle(StyleEnum.F20)); + Row row = sheet.createRow(0).setCellStyle(cellStyle); row.autoRowCells(Collections.singletonList(new Cell(0).setValue("表头"))); // 第二行放标题 String[] excelName = {"文本1", "文本2", "图片1", "图片2", "图片3"}; //要进行合并的列 sheet.getMergeCells().add(new MergeCell(0, 0, 0, excelName.length - 1)); - row = sheet.createRow(1) - //配置该行颜色,现在默认只有绿色 - .setRowStyle(new RowStyle(StyleEnum.GREEN_B)); + + cellStyle.setFgColorRgb("996699"); + row = sheet.createRow(1).setCellStyle(cellStyle); List cells = new ArrayList<>(); for (int i = 0; i < excelName.length; i++) { cells.add(new Cell(i).setValue(excelName[i])); -- Gitee From 4c6124417b28b6a41cb09ad490a7a40d4e1b1fba Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Tue, 14 Dec 2021 13:41:49 +0800 Subject: [PATCH 049/161] =?UTF-8?q?add=20=E6=B3=A8=E8=A7=A3=E5=9B=BE?= =?UTF-8?q?=E7=89=87=E9=9B=86=E5=90=88=E5=AF=BC=E5=87=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../support/annotation/ExportModel.java | 15 +++ .../excel/picture/support/model/Picture.java | 7 +- .../excel/picture/support/model/Sheet.java | 123 ++++++++++++------ .../ibiz/excel/picture/support/FontTest.java | 4 +- .../picture/support/PictureCellWidthTest.java | 2 +- .../excel/picture/support/UserPicture.java | 14 +- .../AnnotationPicturesExportExample.java | 48 +++++++ .../support/example/EasyUseExample3.java | 6 +- .../support/example/EasyUseExample4.java | 4 +- 9 files changed, 172 insertions(+), 51 deletions(-) create mode 100644 src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java diff --git a/src/main/java/com/ibiz/excel/picture/support/annotation/ExportModel.java b/src/main/java/com/ibiz/excel/picture/support/annotation/ExportModel.java index f325619..76a5f17 100644 --- a/src/main/java/com/ibiz/excel/picture/support/annotation/ExportModel.java +++ b/src/main/java/com/ibiz/excel/picture/support/annotation/ExportModel.java @@ -1,5 +1,7 @@ package com.ibiz.excel.picture.support.annotation; +import com.ibiz.excel.picture.support.constants.WorkbookConstant; + import java.lang.annotation.*; /** @@ -21,4 +23,17 @@ public @interface ExportModel { boolean mergeMaster() default false; /**这一列是否要合并*/ boolean merge() default false; + + /** + * 图片所在单元格宽度,图片和单元格宽度一致 + * {@link com.ibiz.excel.picture.support.model.Picture} + * @return + */ + int width() default 25; + + /** + * 有图片的行高设置为100 + * @return {@code WorkbookConstant.PICTURE_ROW_HEIGHT} + */ + int height() default WorkbookConstant.PICTURE_ROW_HEIGHT; } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Picture.java b/src/main/java/com/ibiz/excel/picture/support/model/Picture.java index 4f5d34e..41b2364 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Picture.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Picture.java @@ -30,14 +30,14 @@ public class Picture { this.picturePath = picturePath; } - public Picture(int fromCol, int fromRow, int width, String picturePath) { + public Picture(int fromRow,int fromCol, int width, String picturePath) { super(); this.fromRow = fromRow; this.fromCol = fromCol; this.toRow = fromRow; this.toCol = fromCol; this.picturePath = picturePath; - this.width = width; + this.setWidth(width); } public String getPicturePath() { @@ -93,7 +93,8 @@ public class Picture { } public Picture setWidth(int width) { - this.width = width; + // 转换在excel中阈值 80000 + this.width = width * 80000; return this; } } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java index afe922b..5019484 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java @@ -1,30 +1,31 @@ package com.ibiz.excel.picture.support.model; -import com.ibiz.excel.picture.support.constants.WorkbookConstant; -import com.ibiz.excel.picture.support.event.CloseEvent; -import com.ibiz.excel.picture.support.event.InitEvent; -import com.ibiz.excel.picture.support.factory.EventFactory; -import com.ibiz.excel.picture.support.listener.CloseListener; -import com.ibiz.excel.picture.support.listener.FlushListener; import com.ibiz.excel.picture.support.SheetContext; import com.ibiz.excel.picture.support.annotation.ExportModel; import com.ibiz.excel.picture.support.constants.Alias; +import com.ibiz.excel.picture.support.event.CloseEvent; import com.ibiz.excel.picture.support.event.FlushEvent; +import com.ibiz.excel.picture.support.event.InitEvent; +import com.ibiz.excel.picture.support.factory.EventFactory; import com.ibiz.excel.picture.support.factory.ListenerFactory; +import com.ibiz.excel.picture.support.listener.CloseListener; import com.ibiz.excel.picture.support.listener.ContentListener; +import com.ibiz.excel.picture.support.listener.FlushListener; import com.ibiz.excel.picture.support.listener.InitListener; -import com.ibiz.excel.picture.support.util.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; + import java.util.*; /** * 工作表 + * * @auther 喻场 * @date 2020/7/217:36 */ public class Sheet { private Logger logger = LoggerFactory.getLogger(this.getClass()); + //sheet上下文 //包括组件文件流,文件模版, private void init() { @@ -35,13 +36,14 @@ public class Sheet { private int flushSize; private Workbook workbook; private String sheetName; //默认sheet1 - private int drawingSequence = 1; //图片id序号 对应drawing1.xml.rels Id后的数字 - private int sharedStringSequence = -1; //单元格值序号 sharedString.xml对应标签序号 - private boolean autoMergeCell = Boolean.TRUE; //是否自动合并单元格 + private int drawingSequence = 1; //图片id序号 对应drawing1.xml.rels Id后的数字 + private int sharedStringSequence = -1; //单元格值序号 sharedString.xml对应标签序号 + private boolean autoMergeCell = Boolean.TRUE; //是否自动合并单元格 private boolean hasFlush; //是否已经执行过flush private boolean hasWriteHead; //是否已经写标题 private final List closeAlias = Arrays.asList(Alias.APP, Alias.WORKBOOK_XML); private final SheetHandler SHEET_HANDLER = new SheetHandler(); + private Sheet(int flushSize, String sheetName, Workbook workbook) { this.flushSize = flushSize; this.sheetName = sheetName; @@ -50,17 +52,25 @@ public class Sheet { } private int writeRow = -1; - /**行*/ + /** + * 行 + */ private List rows = new ArrayList<>(); //图片 private List pictures = new ArrayList<>(); - /**需要合并单元格*/ + /** + * 需要合并单元格 + */ private LinkedList mergeCells = new LinkedList<>(); - /**已这列值为标准,对colCells进行合并 - * 0代表A0列 */ - private int mergeCellNumber = 0; //根据第几列值合并 - /**需要合并单元格的列 - * 对应excel column {"A"} A列行相同的值要合并*/ + /** + * 已这列值为标准,对colCells进行合并 + * 0代表A0列 + */ + private int mergeCellNumber = 0; //根据第几列值合并 + /** + * 需要合并单元格的列 + * 对应excel column {"A"} A列行相同的值要合并 + */ private Set colCells = new HashSet<>(); /** @@ -113,7 +123,8 @@ public class Sheet { /** * 创建行,单元格会根据t的属性自动填充 - * @param t 列属性 只会读取com.ibiz.excelx.annotation.Model 注解的属性 + * + * @param t 列属性 只会读取com.ibiz.excelx.annotation.Model 注解的属性 * @param * @return Row */ @@ -123,6 +134,7 @@ public class Sheet { /** * 对集合列表进行创建行,单元格会根据t的属性自动填充 + * * @param collection 列属性集合 只会读取com.ibiz.excelx.annotation.Model 注解的属性 * @param */ @@ -156,7 +168,7 @@ public class Sheet { } //保证rowList中有一行数据,用作下一行与上一行对比是否合并单元格 - public void clear(){ + public void clear() { SHEET_HANDLER.clear(); } @@ -171,6 +183,7 @@ public class Sheet { public static Sheet getInstance(int flushSize, String sheetName, Workbook workbook) { return new Sheet(flushSize, sheetName, workbook); } + public boolean isAutoMergeCell() { return autoMergeCell; } @@ -218,7 +231,10 @@ public class Sheet { public void setDrawingSequence(int drawingSequence) { this.drawingSequence = drawingSequence; } - /**总行数*/ + + /** + * 总行数 + */ public int getRowCount() { return writeRow + 1; } @@ -243,9 +259,10 @@ public class Sheet { //创建组件文件 sheetContext.getEvents().stream().filter(e -> e instanceof InitEvent).forEach(e -> e.onEvent(Sheet.this)); } + Row create(T t, final boolean isHead) { Row row = createRow(++writeRow); - logger.info("create the " + writeRow + " row"); + logger.info("create the " + writeRow + " row"); Arrays.stream(t.getClass().getDeclaredFields()).filter(f -> null != f.getAnnotation(ExportModel.class)) .sorted(Comparator.comparing(c -> c.getAnnotation(ExportModel.class).sort())).forEach(f -> { f.setAccessible(true); @@ -254,6 +271,9 @@ public class Sheet { boolean isPicture = model.isPicture(); boolean mergeMaster = model.mergeMaster(); boolean merge = model.merge(); + // 图片所在单元格宽度,图片和单元格宽度一致 + int width = model.width(); + int height = model.height(); String title = model.title(); Cell cell = new Cell(row.getRowNumber(), sort); // 合并 是标题 并且 是要合并的基准列,将元素放在基准列中 @@ -267,9 +287,9 @@ public class Sheet { colCells.add(cell.getCol()); } - String value = null; + Object value = null; try { - value = null == f.get(t) ? "" : "" + f.get(t); + value = f.get(t); } catch (IllegalAccessException e) { e.printStackTrace(); } @@ -277,40 +297,64 @@ public class Sheet { if (isHead) { cell.setValue(title); } else { - cell.setValue(value); - } - // 不是标题 并且 是图片 并且 值不为空 - if (!isHead && isPicture && StringUtils.isNotBlank(value)) { - //有图片的行,行高设置为100 - row.setHeight(WorkbookConstant.PICTURE_ROW_HEIGHT); - //增加图片 - pictures.add(new Picture(row.getRowNumber(), cell.getCellNumber(), value)); + // 不是标题 并且 是图片 并且 值不为空 + if (isPicture && value != null) { + // 添加图片 + this.addPictures(row, cell.getCellNumber(), width, height, value); + } else { + cell.setValue(value == null ? "" : String.valueOf(value)); + } } + // 将组装好的元素项,放到该行的元素项集合中 row.getCells().add(cell); }); hasWriteHead = writeRow > -1; return row; } + + /** + * 添加图片 + * @param row + * @param cellNumber + * @param width + * @param value + */ + private void addPictures(Row row, int cellNumber, int width,int height, Object value) { + List values = new ArrayList<>(); + row.setHeight(height); + if (value instanceof List) { + values = (List) value; + } else { + values.add(String.valueOf(value)); + } + // 设置单元格宽度,单元格宽度 = 图片宽*图片数量 + setColumnWidth(cellNumber + 1, width * values.size()); + //增加图片 + values.forEach(v -> pictures.add(new Picture(row.getRowNumber(), cellNumber, width, v))); + } + Row createRow(T t) { if (!hasWriteHead) { create(t, true); } return create(t, false); } + Row createRow(int rowNumber) { writeRow = rowNumber; - if(rows.size() > flushSize && flushSize != -1){ + if (rows.size() > flushSize && flushSize != -1) { flush(); } Row row = new Row(rowNumber); rows.add(row); return row; } - void clear(){ + + void clear() { Row row = null; - if(rows.size()>1){ - row = rows.get(rows.size()-1); + if (rows.size() > 1) { + row = rows.get(rows.size() - 1); } List list = new ArrayList<>(); list.add(row); @@ -322,19 +366,20 @@ public class Sheet { /** * 设置单元格宽度 + * * @param columnIndex 坐标 - * @param width 宽度 + * @param width 宽度 */ - public Sheet setColumnWidth(int columnIndex, int width){ + public Sheet setColumnWidth(int columnIndex, int width) { return this.addColumnHelper(new ColumnHelper(columnIndex, width)); } - public Sheet addColumnHelper(ColumnHelper columnHelper){ + public Sheet addColumnHelper(ColumnHelper columnHelper) { return this.addAllColumnHelper(Collections.singletonList(columnHelper)); } - public Sheet addAllColumnHelper(List columnHelpers){ + public Sheet addAllColumnHelper(List columnHelpers) { this.columnHelpers.addAll(columnHelpers); return this; } diff --git a/src/test/java/com/ibiz/excel/picture/support/FontTest.java b/src/test/java/com/ibiz/excel/picture/support/FontTest.java index 6bf49a1..e6a9266 100644 --- a/src/test/java/com/ibiz/excel/picture/support/FontTest.java +++ b/src/test/java/com/ibiz/excel/picture/support/FontTest.java @@ -69,8 +69,8 @@ public class FontTest { //每个单元格增加一个图片 //pictures.add(new Picture(i, row.getRowNumber(),1000000 , IMG_PATH_1)); //在第三列添加多张图片 - pictures.add(new Picture(3, row.getRowNumber(), 1000000, IMG_PATH_1)); - pictures.add(new Picture(2, row.getRowNumber(), 1000000, IMG_PATH_2)); + pictures.add(new Picture(row.getRowNumber(), 3, 1000000, IMG_PATH_1)); + pictures.add(new Picture(row.getRowNumber(),2, 1000000, IMG_PATH_2)); } } row.setCells(cells); diff --git a/src/test/java/com/ibiz/excel/picture/support/PictureCellWidthTest.java b/src/test/java/com/ibiz/excel/picture/support/PictureCellWidthTest.java index 5361051..640c892 100644 --- a/src/test/java/com/ibiz/excel/picture/support/PictureCellWidthTest.java +++ b/src/test/java/com/ibiz/excel/picture/support/PictureCellWidthTest.java @@ -65,7 +65,7 @@ public class PictureCellWidthTest { //每个单元格增加一个图片 //pictures.add(new Picture(i, row.getRowNumber(),1000000 , IMG_PATH_1)); //在第三列添加多张图片 - pictures.add(new Picture(3, row.getRowNumber(), 1000000, IMG_PATH_1)); + pictures.add(new Picture( row.getRowNumber(), 3,1000000, IMG_PATH_1)); } } row.setCells(cells); diff --git a/src/test/java/com/ibiz/excel/picture/support/UserPicture.java b/src/test/java/com/ibiz/excel/picture/support/UserPicture.java index 5171913..4810080 100644 --- a/src/test/java/com/ibiz/excel/picture/support/UserPicture.java +++ b/src/test/java/com/ibiz/excel/picture/support/UserPicture.java @@ -2,6 +2,8 @@ package com.ibiz.excel.picture.support; import com.ibiz.excel.picture.support.annotation.ExportModel; +import java.util.List; + /** * @auther 喻场 * @date 2020/7/813:41 @@ -17,10 +19,12 @@ public class UserPicture { private Integer age; @ExportModel(sort = 3, title = "部门") private String department; - @ExportModel(sort = 2, isPicture = true, title = "图片1") + @ExportModel(sort = 2, isPicture = true, title = "图片1", width = 20) private String picture; @ExportModel(sort = 4, isPicture = true, title = "图片2") private String headerPicture; + @ExportModel(sort = 5, isPicture = true, title = "多图片", height = 80) + private List pictures; public UserPicture(String name, Integer age, String department, String picture) { this.name = name; @@ -68,4 +72,12 @@ public class UserPicture { public void setHeaderPicture(String headerPicture) { this.headerPicture = headerPicture; } + + public List getPictures() { + return pictures; + } + + public void setPictures(List pictures) { + this.pictures = pictures; + } } diff --git a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java new file mode 100644 index 0000000..3276615 --- /dev/null +++ b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java @@ -0,0 +1,48 @@ +package com.ibiz.excel.picture.support.example; + +import com.ibiz.excel.picture.support.UserPicture; +import com.ibiz.excel.picture.support.model.Sheet; +import com.ibiz.excel.picture.support.model.Workbook; +import com.ibiz.excel.picture.support.util.WebUtil; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * 注解图片集合导出示例 + * + * @author MinWeikai + * @date 2021/12/14 10:36 + */ +public class AnnotationPicturesExportExample { + + static final String CURRENT_PATH = "E:\\test\\"; + private static final String TEMP_PATH = CURRENT_PATH + "excel\\"; + private final static String IMG_PATH = "E:\\test\\img\\"; + + private final static String IMG_PATH_1 = IMG_PATH + "1.jpg"; + private final static String IMG_PATH_2 = IMG_PATH + "2.jpg"; + private final static String IMG_PATH_3 = IMG_PATH + "3.jpg"; + + public static void main(String[] args) throws IOException { + Workbook workBook = Workbook.getInstance(); + Sheet sheet = workBook.createSheet("测试"); + List userPictures = new ArrayList<>(); + UserPicture userPicture; + for (int r = 0; r < 1; r++) { + userPicture = new UserPicture(); + userPicture.setAge(15); + userPicture.setName("测试-" + r); + userPicture.setPicture(IMG_PATH_1); + userPicture.setHeaderPicture(IMG_PATH_2); + userPicture.setPictures(Arrays.asList(IMG_PATH_1, IMG_PATH_2, IMG_PATH_3)); + userPictures.add(userPicture); + } + + // 创建集合的行数据在excel中 + sheet.createRow(userPictures); + WebUtil.writeExcelTest(workBook, "注解导出图片集合示例".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), TEMP_PATH); + } +} diff --git a/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample3.java b/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample3.java index 74696c0..a0a9667 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample3.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample3.java @@ -70,10 +70,10 @@ public class EasyUseExample3 { //pictures.add(new Picture(i, row.getRowNumber(),1000000 , IMG_PATH_1)); //在第二列添加多张图片 - pictures.add(new Picture(2, row.getRowNumber(), 1000000, IMG_PATH_1)); + pictures.add(new Picture(row.getRowNumber(),2, 1000000, IMG_PATH_1)); //在第三列添加多张图片 - pictures.add(new Picture(3, row.getRowNumber(), 1000000, IMG_PATH_2)); - pictures.add(new Picture(4, row.getRowNumber(), 1000000, IMG_PATH_1)); + pictures.add(new Picture(row.getRowNumber(), 3, 1000000, IMG_PATH_2)); + pictures.add(new Picture(row.getRowNumber(), 4, 1000000, IMG_PATH_1)); } } row.autoRowCells(cells); diff --git a/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample4.java b/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample4.java index 4a9688f..e683024 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample4.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample4.java @@ -77,8 +77,8 @@ public class EasyUseExample4 { break; case 2: //在第二列添加多张图片 - pictures.add(new Picture(2, row.getRowNumber(), 1000000, IMG_PATH_1)); - pictures.add(new Picture(2, row.getRowNumber(), 1000000, IMG_PATH_2)); + pictures.add(new Picture(row.getRowNumber(), 2, 1000000, IMG_PATH_1)); + pictures.add(new Picture(row.getRowNumber(), 2, 1000000, IMG_PATH_2)); row.setHeight(90); break; case 3: -- Gitee From 917b34544086b4366858bae3a26087b6b5209de1 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Tue, 14 Dec 2021 13:54:49 +0800 Subject: [PATCH 050/161] =?UTF-8?q?add=20=E6=B3=A8=E8=A7=A3=E5=9B=BE?= =?UTF-8?q?=E7=89=87=E9=9B=86=E5=90=88=E5=AF=BC=E5=87=BA=E6=97=B6=E7=BB=99?= =?UTF-8?q?=E6=A0=87=E9=A2=98=E8=A1=8C=E5=8A=A0=E4=B8=8A=E8=83=8C=E6=99=AF?= =?UTF-8?q?=E8=89=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/ibiz/excel/picture/support/model/CellStyle.java | 5 +++++ .../java/com/ibiz/excel/picture/support/model/Sheet.java | 9 +++++++++ .../support/example/AnnotationPicturesExportExample.java | 8 +++++++- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java b/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java index 8ffef86..4754749 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java @@ -21,6 +21,7 @@ public class CellStyle { /** * fgColor rgb颜色 + * RGB网页颜色在线取色器 https://link.fobshanghai.com/rgbcolor.htm */ private String fgColorRgb; @@ -75,6 +76,10 @@ public class CellStyle { return fgColorRgb; } + /** + * fgColor rgb颜色 + * RGB网页颜色在线取色器 https://link.fobshanghai.com/rgbcolor.htm + */ public void setFgColorRgb(String fgColorRgb) { this.fgColorRgb = fgColorRgb; } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java index 5019484..6aece90 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java @@ -224,6 +224,15 @@ public class Sheet { return rows; } + /** + * 根据行号,获取行对象,默认从0开始 + * @param num + * @return + */ + public Row getRows(int num) { + return this.getRows().get(num); + } + public int getDrawingSequence() { return drawingSequence; } diff --git a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java index 3276615..389d117 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java @@ -1,6 +1,7 @@ package com.ibiz.excel.picture.support.example; import com.ibiz.excel.picture.support.UserPicture; +import com.ibiz.excel.picture.support.model.CellStyle; import com.ibiz.excel.picture.support.model.Sheet; import com.ibiz.excel.picture.support.model.Workbook; import com.ibiz.excel.picture.support.util.WebUtil; @@ -40,9 +41,14 @@ public class AnnotationPicturesExportExample { userPicture.setPictures(Arrays.asList(IMG_PATH_1, IMG_PATH_2, IMG_PATH_3)); userPictures.add(userPicture); } - // 创建集合的行数据在excel中 sheet.createRow(userPictures); + + // 给标题行加上背景色,加颜色时,会对字体加粗 + CellStyle cellStyle = workBook.createCellStyle(); + cellStyle.setFgColorRgb("66cc66"); + sheet.getRows(0).setCellStyle(cellStyle); + WebUtil.writeExcelTest(workBook, "注解导出图片集合示例".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), TEMP_PATH); } } -- Gitee From e70e6b70e256e81f0bfc58fea8342333dd7b3048 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Fri, 17 Dec 2021 10:14:31 +0800 Subject: [PATCH 051/161] =?UTF-8?q?fix=20=E5=AF=BC=E5=87=BA=E5=9B=BE?= =?UTF-8?q?=E7=89=87=E9=9B=86=E5=90=88=E5=8F=98=E5=A4=9A=E6=97=B6=E5=8D=95?= =?UTF-8?q?=E5=85=83=E6=A0=BC=E5=AE=BD=E5=BA=A6=E4=B8=8D=E5=A4=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 2 +- .../support/annotation/ExportModel.java | 2 +- .../excel/picture/support/model/Picture.java | 4 +-- .../excel/picture/support/model/Sheet.java | 5 +-- .../excel/picture/support/UserPicture.java | 2 +- .../AnnotationPicturesExportExample.java | 33 ++++++++++++++++--- 6 files changed, 35 insertions(+), 13 deletions(-) diff --git a/pom.xml b/pom.xml index d59b9e1..26ab20f 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 top.minwk excel-x - 1.0.4 + 1.1.0 excel-x excel-x https://gitee.com/mwk719/excel-batch-picture-support diff --git a/src/main/java/com/ibiz/excel/picture/support/annotation/ExportModel.java b/src/main/java/com/ibiz/excel/picture/support/annotation/ExportModel.java index 76a5f17..f83767d 100644 --- a/src/main/java/com/ibiz/excel/picture/support/annotation/ExportModel.java +++ b/src/main/java/com/ibiz/excel/picture/support/annotation/ExportModel.java @@ -29,7 +29,7 @@ public @interface ExportModel { * {@link com.ibiz.excel.picture.support.model.Picture} * @return */ - int width() default 25; + int width() default 1000000; /** * 有图片的行高设置为100 diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Picture.java b/src/main/java/com/ibiz/excel/picture/support/model/Picture.java index 41b2364..cc9af60 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Picture.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Picture.java @@ -37,7 +37,7 @@ public class Picture { this.toRow = fromRow; this.toCol = fromCol; this.picturePath = picturePath; - this.setWidth(width); + this.width = width; } public String getPicturePath() { @@ -93,8 +93,6 @@ public class Picture { } public Picture setWidth(int width) { - // 转换在excel中阈值 80000 - this.width = width * 80000; return this; } } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java index 6aece90..9850134 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java @@ -229,7 +229,7 @@ public class Sheet { * @param num * @return */ - public Row getRows(int num) { + public Row getRow(int num) { return this.getRows().get(num); } @@ -338,7 +338,8 @@ public class Sheet { values.add(String.valueOf(value)); } // 设置单元格宽度,单元格宽度 = 图片宽*图片数量 - setColumnWidth(cellNumber + 1, width * values.size()); + int columnWidth = (width / 76923) * values.size() + values.size() / 7; + setColumnWidth(cellNumber + 1, columnWidth); //增加图片 values.forEach(v -> pictures.add(new Picture(row.getRowNumber(), cellNumber, width, v))); } diff --git a/src/test/java/com/ibiz/excel/picture/support/UserPicture.java b/src/test/java/com/ibiz/excel/picture/support/UserPicture.java index 4810080..eb8e468 100644 --- a/src/test/java/com/ibiz/excel/picture/support/UserPicture.java +++ b/src/test/java/com/ibiz/excel/picture/support/UserPicture.java @@ -19,7 +19,7 @@ public class UserPicture { private Integer age; @ExportModel(sort = 3, title = "部门") private String department; - @ExportModel(sort = 2, isPicture = true, title = "图片1", width = 20) + @ExportModel(sort = 2, isPicture = true, title = "图片1") private String picture; @ExportModel(sort = 4, isPicture = true, title = "图片2") private String headerPicture; diff --git a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java index 389d117..afe0809 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java @@ -1,15 +1,17 @@ package com.ibiz.excel.picture.support.example; +import cn.hutool.core.io.FileUtil; import com.ibiz.excel.picture.support.UserPicture; import com.ibiz.excel.picture.support.model.CellStyle; import com.ibiz.excel.picture.support.model.Sheet; import com.ibiz.excel.picture.support.model.Workbook; import com.ibiz.excel.picture.support.util.WebUtil; +import java.io.File; import java.io.IOException; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; +import java.util.Random; /** * 注解图片集合导出示例 @@ -27,18 +29,23 @@ public class AnnotationPicturesExportExample { private final static String IMG_PATH_2 = IMG_PATH + "2.jpg"; private final static String IMG_PATH_3 = IMG_PATH + "3.jpg"; + private final static String IMAGES_PATH = CURRENT_PATH + "images\\"; + public static void main(String[] args) throws IOException { Workbook workBook = Workbook.getInstance(); Sheet sheet = workBook.createSheet("测试"); + // 图片数组 + File[] files = FileUtil.ls(IMAGES_PATH); List userPictures = new ArrayList<>(); UserPicture userPicture; for (int r = 0; r < 1; r++) { userPicture = new UserPicture(); userPicture.setAge(15); userPicture.setName("测试-" + r); - userPicture.setPicture(IMG_PATH_1); - userPicture.setHeaderPicture(IMG_PATH_2); - userPicture.setPictures(Arrays.asList(IMG_PATH_1, IMG_PATH_2, IMG_PATH_3)); +// userPicture.setPicture(IMG_PATH_1); +// userPicture.setHeaderPicture(IMG_PATH_2); + // 根据图片数组和要获取图片的数量,随机从图片数组中取出若干 + userPicture.setPictures(getPictures(files, 5)); userPictures.add(userPicture); } // 创建集合的行数据在excel中 @@ -47,8 +54,24 @@ public class AnnotationPicturesExportExample { // 给标题行加上背景色,加颜色时,会对字体加粗 CellStyle cellStyle = workBook.createCellStyle(); cellStyle.setFgColorRgb("66cc66"); - sheet.getRows(0).setCellStyle(cellStyle); + sheet.getRow(0).setCellStyle(cellStyle); WebUtil.writeExcelTest(workBook, "注解导出图片集合示例".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), TEMP_PATH); } + + /** + * 根据图片数组和要获取图片的数量,随机从图片数组中取出若干 + * @param files 图片数组 + * @param getCount 获取图片的数量 + * @return + */ + private static List getPictures(File[] files, int getCount) { + List list = new ArrayList<>(getCount); + for (int i = 0; i < getCount; i++) { + int index = new Random().nextInt(files.length); + list.add(files[index].getAbsolutePath()); + } + return list; + } + } -- Gitee From 464260b69a4ce12debd1c1deec630eda482591d9 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Tue, 21 Dec 2021 16:28:40 +0800 Subject: [PATCH 052/161] =?UTF-8?q?fix=20=E5=AF=BC=E5=87=BA=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E8=A1=8C=E6=95=B0=E5=A4=A7=E4=BA=8E100=20excel?= =?UTF-8?q?=E6=89=93=E5=BC=80=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../picture/support/flush/StylesHandler.java | 135 ++++++++++-------- .../excel/picture/support/model/Sheet.java | 4 + .../excel/picture/support/util/WebUtil.java | 2 + .../AnnotationPicturesExportExample.java | 26 ++-- 4 files changed, 96 insertions(+), 71 deletions(-) diff --git a/src/main/java/com/ibiz/excel/picture/support/flush/StylesHandler.java b/src/main/java/com/ibiz/excel/picture/support/flush/StylesHandler.java index 52460c3..925e5e9 100644 --- a/src/main/java/com/ibiz/excel/picture/support/flush/StylesHandler.java +++ b/src/main/java/com/ibiz/excel/picture/support/flush/StylesHandler.java @@ -1,7 +1,7 @@ package com.ibiz.excel.picture.support.flush; -import com.ibiz.excel.picture.support.model.Row; import com.ibiz.excel.picture.support.model.CellStyle; +import com.ibiz.excel.picture.support.model.Row; import com.ibiz.excel.picture.support.model.Sheet; import java.lang.reflect.InvocationHandler; @@ -15,67 +15,88 @@ import java.util.List; * @date 2021/12/10 16:55 */ public class StylesHandler implements InvocationHandler { - private IRepository target; - - public StylesHandler(IRepository proxy) { - this.target = proxy; - } + private IRepository target; - private StringBuilder xfBefore = new StringBuilder("" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + // 填充色值坐标 - ""); + public StylesHandler(IRepository proxy) { + this.target = proxy; + } - private StringBuilder xfAfter = new StringBuilder("" + - "" + - "" + - ""); + private StringBuilder xfBefore = new StringBuilder("" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + // 填充色值坐标 + ""); - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - if (method.getName().equals("write")) { - Sheet sheet = (Sheet) args[0]; - List rows = sheet.getRows(); - if (!rows.isEmpty()) { - // TODO 待办。。 - rows.stream().forEach(row -> { - CellStyle cellStyle = row.getCellStyle(); - if (row.getCellStyle() != null) { - this.appendFill(cellStyle); + private StringBuilder xfAfter = new StringBuilder("" + + "" + + "" + + ""); - this.appendXf(cellStyle); - } - }); - target.append(xfBefore.append(xfAfter).toString()); - } - } - return method.invoke(target, args); - } + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + // 因会写入磁盘,刷新sheet.getRows(),所以需要计算是否最后一块数据 + boolean last = true; + if (method.getName().equals("write")) { + Sheet sheet = (Sheet) args[0]; + List rows = sheet.getRows(); + if (!rows.isEmpty()) { + // 判断是否最后 + if (sheet.getRowCount() % sheet.getFlushSize() - rows.size() % sheet.getFlushSize() == 1) { + last = false; + } + rows.stream().forEach(row -> { + CellStyle cellStyle = row.getCellStyle(); + if (row.getCellStyle() != null) { + // 追加背景色样式 + this.appendFill(cellStyle); + // 追加调用下标样式 + this.appendXf(cellStyle); + } + }); + } + // 不是最后一块数据或者没有行数据,则不写入样式 + if (!last || rows.isEmpty()) { + return ""; + } + // 在Styles对象中追加样式 + target.append(xfBefore.append(xfAfter).toString()); + } + return method.invoke(target, args); + } - private void appendXf(CellStyle cellStyle) { - xfBefore.append(""); - } + /** + * 追加调用下标样式 + * + * @param cellStyle + */ + private void appendXf(CellStyle cellStyle) { + xfBefore.append(""); + } - private void appendFill(CellStyle cellStyle) { - target.append(""); - } + /** + * 追加背景色样式 + * + * @param cellStyle + */ + private void appendFill(CellStyle cellStyle) { + target.append(""); + } } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java index 9850134..637de8e 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java @@ -248,6 +248,10 @@ public class Sheet { return writeRow + 1; } + public int getFlushSize() { + return flushSize; + } + class SheetHandler { void init() { sheetContext = SheetContext.getInstance(Sheet.this); diff --git a/src/main/java/com/ibiz/excel/picture/support/util/WebUtil.java b/src/main/java/com/ibiz/excel/picture/support/util/WebUtil.java index c21d4f6..87f36bb 100644 --- a/src/main/java/com/ibiz/excel/picture/support/util/WebUtil.java +++ b/src/main/java/com/ibiz/excel/picture/support/util/WebUtil.java @@ -38,6 +38,8 @@ public class WebUtil { wb.write(os); wb.close(); } catch (Exception e) { + // 报错时删除文件 + FileUtil.del(file); log.error("测试导出excel异常", e); } log.debug("测试导出excel路径:{}", file.getAbsolutePath()); diff --git a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java index afe0809..5b01544 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java @@ -32,30 +32,28 @@ public class AnnotationPicturesExportExample { private final static String IMAGES_PATH = CURRENT_PATH + "images\\"; public static void main(String[] args) throws IOException { - Workbook workBook = Workbook.getInstance(); + Workbook workBook = Workbook.getInstance(56); Sheet sheet = workBook.createSheet("测试"); + // 给标题行加上背景色,加颜色时,会对字体加粗 + CellStyle cellStyle = workBook.createCellStyle(); + cellStyle.setFgColorRgb("66cc66"); // 图片数组 File[] files = FileUtil.ls(IMAGES_PATH); - List userPictures = new ArrayList<>(); UserPicture userPicture; - for (int r = 0; r < 1; r++) { + for (int r = 0; r < 15; r++) { userPicture = new UserPicture(); userPicture.setAge(15); userPicture.setName("测试-" + r); -// userPicture.setPicture(IMG_PATH_1); -// userPicture.setHeaderPicture(IMG_PATH_2); + userPicture.setPicture(IMG_PATH_1); + userPicture.setHeaderPicture(IMG_PATH_2); // 根据图片数组和要获取图片的数量,随机从图片数组中取出若干 userPicture.setPictures(getPictures(files, 5)); - userPictures.add(userPicture); + sheet.createRow(userPicture); + // 对标题行添加上样式 + if(r == 0){ + sheet.getRow(0).setCellStyle(cellStyle); + } } - // 创建集合的行数据在excel中 - sheet.createRow(userPictures); - - // 给标题行加上背景色,加颜色时,会对字体加粗 - CellStyle cellStyle = workBook.createCellStyle(); - cellStyle.setFgColorRgb("66cc66"); - sheet.getRow(0).setCellStyle(cellStyle); - WebUtil.writeExcelTest(workBook, "注解导出图片集合示例".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), TEMP_PATH); } -- Gitee From add2745f8cf8f6be19327737721967a77dda7e5d Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Tue, 21 Dec 2021 17:12:06 +0800 Subject: [PATCH 053/161] =?UTF-8?q?remove=20=E5=AF=B9=E9=9B=86=E5=90=88?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E8=BF=9B=E8=A1=8C=E5=88=9B=E5=BB=BA=E8=A1=8C?= =?UTF-8?q?=E6=96=B9=E6=B3=95=EF=BC=8C=E8=AF=A5=E6=96=B9=E6=B3=95=E5=9C=A8?= =?UTF-8?q?=E8=A1=8C=E6=95=B0=E5=A4=A7=E4=BA=8E=E5=88=B7=E5=85=A5=E7=A3=81?= =?UTF-8?q?=E7=9B=98=E6=95=B0=E6=97=B6=EF=BC=8C=E6=A0=B7=E5=BC=8F=E9=97=AE?= =?UTF-8?q?=E9=A2=98=E4=BC=9A=E5=87=BA=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/ibiz/excel/picture/support/model/Sheet.java | 10 ---------- .../example/AnnotationPictureExportExample.java | 9 ++------- 2 files changed, 2 insertions(+), 17 deletions(-) diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java index 637de8e..ea20d7b 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java @@ -132,16 +132,6 @@ public class Sheet { return SHEET_HANDLER.createRow(t); } - /** - * 对集合列表进行创建行,单元格会根据t的属性自动填充 - * - * @param collection 列属性集合 只会读取com.ibiz.excelx.annotation.Model 注解的属性 - * @param - */ - public void createRow(Collection collection) { - collection.forEach(this::createRow); - } - public Row createRow(int rowNumber) { return SHEET_HANDLER.createRow(rowNumber); } diff --git a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPictureExportExample.java b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPictureExportExample.java index 0736fe5..7a9fca4 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPictureExportExample.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPictureExportExample.java @@ -6,8 +6,6 @@ import com.ibiz.excel.picture.support.model.Workbook; import com.ibiz.excel.picture.support.util.WebUtil; import java.io.IOException; -import java.util.ArrayList; -import java.util.List; /** * 注解图片导出示例 @@ -28,7 +26,6 @@ public class AnnotationPictureExportExample { public static void main(String[] args) throws IOException { Workbook workBook = Workbook.getInstance(); Sheet sheet = workBook.createSheet("测试"); - List userPictures = new ArrayList<>(); UserPicture userPicture; for (int r = 0; r < 5; r++) { userPicture = new UserPicture(); @@ -36,11 +33,9 @@ public class AnnotationPictureExportExample { userPicture.setName("测试-" + r); userPicture.setPicture(IMG_PATH_1); userPicture.setHeaderPicture(IMG_PATH_2); - userPictures.add(userPicture); + // 创建行数据在excel中 + sheet.createRow(userPicture); } - - // 创建集合的行数据在excel中 - sheet.createRow(userPictures); WebUtil.writeExcelTest(workBook, "注解导出图片示例".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), TEMP_PATH); } -- Gitee From eaf12bccd51341acc82c98b9ee771e4281a430e0 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Tue, 21 Dec 2021 18:29:57 +0800 Subject: [PATCH 054/161] =?UTF-8?q?update=20=E5=8D=95=E5=85=83=E6=A0=BC?= =?UTF-8?q?=E5=AE=BD=E5=BA=A6=E6=8E=A7=E5=88=B6=E9=80=BB=E8=BE=91=EF=BC=9B?= =?UTF-8?q?=E5=8D=95=E5=85=83=E6=A0=BC=E5=9B=BE=E7=89=87=E5=AE=BD=E5=BA=A6?= =?UTF-8?q?=E9=BB=98=E8=AE=A4=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../support/annotation/ExportModel.java | 4 +-- .../picture/support/flush/Sheet1Handler.java | 8 +++--- .../picture/support/model/ColumnHelper.java | 6 ++--- .../excel/picture/support/model/Sheet.java | 26 ++++++++----------- .../ibiz/excel/picture/support/FontTest.java | 6 ++--- .../picture/support/PictureCellWidthTest.java | 6 ++--- .../AnnotationPicturesExportExample.java | 8 ++++-- .../support/example/EasyUseExample4.java | 2 +- 8 files changed, 33 insertions(+), 33 deletions(-) diff --git a/src/main/java/com/ibiz/excel/picture/support/annotation/ExportModel.java b/src/main/java/com/ibiz/excel/picture/support/annotation/ExportModel.java index f83767d..34461fb 100644 --- a/src/main/java/com/ibiz/excel/picture/support/annotation/ExportModel.java +++ b/src/main/java/com/ibiz/excel/picture/support/annotation/ExportModel.java @@ -25,11 +25,11 @@ public @interface ExportModel { boolean merge() default false; /** - * 图片所在单元格宽度,图片和单元格宽度一致 + * 图片所在单元格宽度,图片和单元格宽度一致,建议使用默认 1500000作为宽度 * {@link com.ibiz.excel.picture.support.model.Picture} * @return */ - int width() default 1000000; + int width() default 1500000; /** * 有图片的行高设置为100 diff --git a/src/main/java/com/ibiz/excel/picture/support/flush/Sheet1Handler.java b/src/main/java/com/ibiz/excel/picture/support/flush/Sheet1Handler.java index aab1e97..b15ee3a 100644 --- a/src/main/java/com/ibiz/excel/picture/support/flush/Sheet1Handler.java +++ b/src/main/java/com/ibiz/excel/picture/support/flush/Sheet1Handler.java @@ -57,13 +57,13 @@ public class Sheet1Handler implements InvocationHandler { // 默认宽度 .append(""); // 自定义的宽度 - sheet.getColumnHelpers().stream().forEach(column -> + sheet.getColumnHelperMap().entrySet().forEach(column -> content.append("")); content.append(""); target.append(content.toString()); diff --git a/src/main/java/com/ibiz/excel/picture/support/model/ColumnHelper.java b/src/main/java/com/ibiz/excel/picture/support/model/ColumnHelper.java index 11f6791..3732a97 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/ColumnHelper.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/ColumnHelper.java @@ -16,7 +16,7 @@ public class ColumnHelper { /** * 单元格宽度, 默认10 */ - private int width = 10; + private double width = 10; /** * 设置第几列单元格宽度 @@ -24,7 +24,7 @@ public class ColumnHelper { * @param columnIndex 第几列单元格 * @param width 宽度 */ - public ColumnHelper(int columnIndex, int width) { + public ColumnHelper(int columnIndex, double width) { this.columnIndex = columnIndex; this.width = width; } @@ -41,7 +41,7 @@ public class ColumnHelper { return columnIndex; } - public int getWidth() { + public double getWidth() { return width; } } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java index ea20d7b..5b2d179 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java @@ -76,7 +76,7 @@ public class Sheet { /** * 单元格辅助类 */ - private List columnHelpers = new ArrayList<>(); + private Map columnHelperMap = new HashMap<>(); /** * 默认已有fill样式 @@ -331,8 +331,10 @@ public class Sheet { } else { values.add(String.valueOf(value)); } + // 实际宽 + int actualWidth = width / 76923; // 设置单元格宽度,单元格宽度 = 图片宽*图片数量 - int columnWidth = (width / 76923) * values.size() + values.size() / 7; + double columnWidth = actualWidth * values.size() + values.size() / 1.5; setColumnWidth(cellNumber + 1, columnWidth); //增加图片 values.forEach(v -> pictures.add(new Picture(row.getRowNumber(), cellNumber, width, v))); @@ -374,21 +376,15 @@ public class Sheet { * @param columnIndex 坐标 * @param width 宽度 */ - public Sheet setColumnWidth(int columnIndex, int width) { - return this.addColumnHelper(new ColumnHelper(columnIndex, width)); - } - - - public Sheet addColumnHelper(ColumnHelper columnHelper) { - return this.addAllColumnHelper(Collections.singletonList(columnHelper)); - } - - public Sheet addAllColumnHelper(List columnHelpers) { - this.columnHelpers.addAll(columnHelpers); + public Sheet setColumnWidth(int columnIndex, double width) { + // 判断 columnHelperMap 不包含 columnIndex + if(!this.columnHelperMap.containsKey(columnIndex)){ + this.columnHelperMap.put(columnIndex, new ColumnHelper(columnIndex, width)); + } return this; } - public List getColumnHelpers() { - return columnHelpers; + public Map getColumnHelperMap() { + return columnHelperMap; } } diff --git a/src/test/java/com/ibiz/excel/picture/support/FontTest.java b/src/test/java/com/ibiz/excel/picture/support/FontTest.java index e6a9266..5d9bde3 100644 --- a/src/test/java/com/ibiz/excel/picture/support/FontTest.java +++ b/src/test/java/com/ibiz/excel/picture/support/FontTest.java @@ -29,9 +29,9 @@ public class FontTest { Sheet sheet = workBook.createSheet("测试"); // 需要在创建行前预设宽度 - sheet.addColumnHelper(new ColumnHelper(1, 10)) - .addColumnHelper(new ColumnHelper(3, 50)) - .addColumnHelper(new ColumnHelper(4, 50)); + sheet.setColumnWidth(1, 10) + .setColumnWidth(3, 50) + .setColumnWidth(4, 50); // 第一行表头 Row row = sheet.createRow(0) diff --git a/src/test/java/com/ibiz/excel/picture/support/PictureCellWidthTest.java b/src/test/java/com/ibiz/excel/picture/support/PictureCellWidthTest.java index 640c892..74ddb8d 100644 --- a/src/test/java/com/ibiz/excel/picture/support/PictureCellWidthTest.java +++ b/src/test/java/com/ibiz/excel/picture/support/PictureCellWidthTest.java @@ -28,9 +28,9 @@ public class PictureCellWidthTest { Sheet sheet = workBook.createSheet("测试"); // 需要在创建行前预设宽度 - sheet.addColumnHelper(new ColumnHelper(1, 10)) - .addColumnHelper(new ColumnHelper(3, 50)) - .addColumnHelper(new ColumnHelper(4, 50)); + sheet.setColumnWidth(1, 10) + .setColumnWidth(3, 50) + .setColumnWidth(4, 50); // 第一行表头 Row row = sheet.createRow(0); diff --git a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java index 5b01544..b22d9a2 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java @@ -34,20 +34,24 @@ public class AnnotationPicturesExportExample { public static void main(String[] args) throws IOException { Workbook workBook = Workbook.getInstance(56); Sheet sheet = workBook.createSheet("测试"); + +// 需要在创建行前预设宽度 +// sheet.setColumnWidth(6, 100); + // 给标题行加上背景色,加颜色时,会对字体加粗 CellStyle cellStyle = workBook.createCellStyle(); cellStyle.setFgColorRgb("66cc66"); // 图片数组 File[] files = FileUtil.ls(IMAGES_PATH); UserPicture userPicture; - for (int r = 0; r < 15; r++) { + for (int r = 0; r < 1; r++) { userPicture = new UserPicture(); userPicture.setAge(15); userPicture.setName("测试-" + r); userPicture.setPicture(IMG_PATH_1); userPicture.setHeaderPicture(IMG_PATH_2); // 根据图片数组和要获取图片的数量,随机从图片数组中取出若干 - userPicture.setPictures(getPictures(files, 5)); + userPicture.setPictures(getPictures(files, 1)); sheet.createRow(userPicture); // 对标题行添加上样式 if(r == 0){ diff --git a/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample4.java b/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample4.java index e683024..6be2e0b 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample4.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample4.java @@ -37,7 +37,7 @@ public class EasyUseExample4 { // 需要在创建行前预设宽度 // 序号宽度 有时需要单独设置序号宽度窄一点 - sheet.addColumnHelper(new ColumnHelper(1)); + sheet.setColumnWidth(1, 10); // 第一行表头 Row row = sheet.createRow(0).setCellStyle(cellStyle); -- Gitee From ee92ed3844afab9c58bc49db6ca2f6fa468be9bc Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Wed, 22 Dec 2021 15:26:10 +0800 Subject: [PATCH 055/161] =?UTF-8?q?add=20=E8=87=AA=E5=AE=9A=E4=B9=89?= =?UTF-8?q?=E5=9B=BE=E7=89=87=E7=9A=84=E9=AB=98=E5=BA=A6=EF=BC=9B=E5=9B=BE?= =?UTF-8?q?=E7=89=87=E9=AB=98=E5=BA=A6=E5=92=8C=E5=8D=95=E5=85=83=E6=A0=BC?= =?UTF-8?q?=E9=AB=98=E5=BA=A6=E8=87=AA=E9=80=82=E5=BA=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../support/annotation/ExportModel.java | 37 ++++++++++++++----- .../support/constants/WorkbookConstant.java | 9 +++++ .../support/flush/Drawing1Handler.java | 4 +- .../excel/picture/support/model/Picture.java | 28 +++++++++++++- .../excel/picture/support/model/Sheet.java | 6 ++- .../excel/picture/support/UserPicture.java | 2 +- .../AnnotationPicturesExportExample.java | 4 +- .../support/example/EasyUseExample4.java | 9 +++-- 8 files changed, 80 insertions(+), 19 deletions(-) diff --git a/src/main/java/com/ibiz/excel/picture/support/annotation/ExportModel.java b/src/main/java/com/ibiz/excel/picture/support/annotation/ExportModel.java index 34461fb..dab006b 100644 --- a/src/main/java/com/ibiz/excel/picture/support/annotation/ExportModel.java +++ b/src/main/java/com/ibiz/excel/picture/support/annotation/ExportModel.java @@ -7,33 +7,52 @@ import java.lang.annotation.*; /** * 导出模型 * 使用该注解程序会根据相应属性对单元格做设置 + * + * @author MinWeikai + * @date 2021-12-22 14:43:43 */ @Target({ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented public @interface ExportModel { - /**排序*/ + /** + * 排序 + */ int sort() default 0; - /**是否是图片*/ + + /** + * 是否是图片 + */ boolean isPicture() default false; - /**表头*/ + + /** + * 表头 + */ String title() default ""; - /**已这列为准进行合并列*/ + + /** + * 已这列为准进行合并列 + */ boolean mergeMaster() default false; - /**这一列是否要合并*/ + + /** + * 这一列是否要合并 + */ boolean merge() default false; /** * 图片所在单元格宽度,图片和单元格宽度一致,建议使用默认 1500000作为宽度 * {@link com.ibiz.excel.picture.support.model.Picture} + * * @return */ - int width() default 1500000; + int width() default WorkbookConstant.PICTURE_WEIGHT; /** - * 有图片的行高设置为100 - * @return {@code WorkbookConstant.PICTURE_ROW_HEIGHT} + * 图片所在单元格行高度,单元格会自适应图片的高度 + * 如需要自定义图片高度,注意:在导出类中有多个图片字段,需要在每个图片字段上注解配置自定义的高度 + * @return */ - int height() default WorkbookConstant.PICTURE_ROW_HEIGHT; + int height() default WorkbookConstant.PICTURE_HEIGHT; } diff --git a/src/main/java/com/ibiz/excel/picture/support/constants/WorkbookConstant.java b/src/main/java/com/ibiz/excel/picture/support/constants/WorkbookConstant.java index 9bf98ce..802ac35 100644 --- a/src/main/java/com/ibiz/excel/picture/support/constants/WorkbookConstant.java +++ b/src/main/java/com/ibiz/excel/picture/support/constants/WorkbookConstant.java @@ -11,4 +11,13 @@ public class WorkbookConstant { public static final String MEDIA_IMAGE_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"; /**有图片的行高设置为100*/ public static final int PICTURE_ROW_HEIGHT = 100; + + /** + * 图片默认高度 + */ + public static final int PICTURE_HEIGHT = 1260000; + /** + * 图片默认宽度 + */ + public static final int PICTURE_WEIGHT = 1500000; } diff --git a/src/main/java/com/ibiz/excel/picture/support/flush/Drawing1Handler.java b/src/main/java/com/ibiz/excel/picture/support/flush/Drawing1Handler.java index 858b1e3..79126e3 100644 --- a/src/main/java/com/ibiz/excel/picture/support/flush/Drawing1Handler.java +++ b/src/main/java/com/ibiz/excel/picture/support/flush/Drawing1Handler.java @@ -90,7 +90,9 @@ public class Drawing1Handler implements InvocationHandler { "" + "\n" + "" + picture.getToCol() + "" + (colOff + picture.getWidth() - PADDING) + "" + - "" + (picture.getToRow()) + "1260000" + + "" + (picture.getToRow()) + + // 设置图片高度 + ""+ picture.getHeight() +"" + "" + "" + "" + diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Picture.java b/src/main/java/com/ibiz/excel/picture/support/model/Picture.java index cc9af60..7b6a93b 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Picture.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Picture.java @@ -1,5 +1,7 @@ package com.ibiz.excel.picture.support.model; +import com.ibiz.excel.picture.support.constants.WorkbookConstant; + /** * @auther 喻场 * @date 2020/7/217:35 @@ -16,7 +18,12 @@ public class Picture { /** * 图片宽度 */ - private int width; + private int width = WorkbookConstant.PICTURE_WEIGHT; + + /** + * 图片高度 + */ + private int height = WorkbookConstant.PICTURE_HEIGHT; public Picture(){ } @@ -40,6 +47,17 @@ public class Picture { this.width = width; } + public Picture(int fromRow,int fromCol, int width, int height,String picturePath) { + super(); + this.fromRow = fromRow; + this.fromCol = fromCol; + this.toRow = fromRow; + this.toCol = fromCol; + this.picturePath = picturePath; + this.width = width; + this.height = height; + } + public String getPicturePath() { return picturePath; } @@ -95,4 +113,12 @@ public class Picture { public Picture setWidth(int width) { return this; } + + public int getHeight() { + return height; + } + + public void setHeight(int height) { + this.height = height; + } } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java index 5b2d179..df6c6ff 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java @@ -276,6 +276,7 @@ public class Sheet { boolean merge = model.merge(); // 图片所在单元格宽度,图片和单元格宽度一致 int width = model.width(); + // 图片所在单元格行高度 int height = model.height(); String title = model.title(); Cell cell = new Cell(row.getRowNumber(), sort); @@ -325,7 +326,8 @@ public class Sheet { */ private void addPictures(Row row, int cellNumber, int width,int height, Object value) { List values = new ArrayList<>(); - row.setHeight(height); + // 设置行高自适应于图片的高度 + row.setHeight((height / 12600) - 1); if (value instanceof List) { values = (List) value; } else { @@ -337,7 +339,7 @@ public class Sheet { double columnWidth = actualWidth * values.size() + values.size() / 1.5; setColumnWidth(cellNumber + 1, columnWidth); //增加图片 - values.forEach(v -> pictures.add(new Picture(row.getRowNumber(), cellNumber, width, v))); + values.forEach(v -> pictures.add(new Picture(row.getRowNumber(), cellNumber, width, height, v))); } Row createRow(T t) { diff --git a/src/test/java/com/ibiz/excel/picture/support/UserPicture.java b/src/test/java/com/ibiz/excel/picture/support/UserPicture.java index eb8e468..b494ec1 100644 --- a/src/test/java/com/ibiz/excel/picture/support/UserPicture.java +++ b/src/test/java/com/ibiz/excel/picture/support/UserPicture.java @@ -23,7 +23,7 @@ public class UserPicture { private String picture; @ExportModel(sort = 4, isPicture = true, title = "图片2") private String headerPicture; - @ExportModel(sort = 5, isPicture = true, title = "多图片", height = 80) + @ExportModel(sort = 5, isPicture = true, title = "多图片") private List pictures; public UserPicture(String name, Integer age, String department, String picture) { diff --git a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java index b22d9a2..ca86426 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java @@ -51,11 +51,11 @@ public class AnnotationPicturesExportExample { userPicture.setPicture(IMG_PATH_1); userPicture.setHeaderPicture(IMG_PATH_2); // 根据图片数组和要获取图片的数量,随机从图片数组中取出若干 - userPicture.setPictures(getPictures(files, 1)); + userPicture.setPictures(getPictures(files, 9)); sheet.createRow(userPicture); // 对标题行添加上样式 if(r == 0){ - sheet.getRow(0).setCellStyle(cellStyle); + sheet.getRow(r).setCellStyle(cellStyle); } } WebUtil.writeExcelTest(workBook, "注解导出图片集合示例".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), TEMP_PATH); diff --git a/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample4.java b/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample4.java index 6be2e0b..306042e 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample4.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample4.java @@ -1,5 +1,6 @@ package com.ibiz.excel.picture.support.example; +import com.ibiz.excel.picture.support.constants.WorkbookConstant; import com.ibiz.excel.picture.support.model.*; import com.ibiz.excel.picture.support.util.WebUtil; @@ -37,7 +38,9 @@ public class EasyUseExample4 { // 需要在创建行前预设宽度 // 序号宽度 有时需要单独设置序号宽度窄一点 - sheet.setColumnWidth(1, 10); + sheet.setColumnWidth(1, 5) + // 设置第三列宽度 + .setColumnWidth(3, 50); // 第一行表头 Row row = sheet.createRow(0).setCellStyle(cellStyle); @@ -77,8 +80,8 @@ public class EasyUseExample4 { break; case 2: //在第二列添加多张图片 - pictures.add(new Picture(row.getRowNumber(), 2, 1000000, IMG_PATH_1)); - pictures.add(new Picture(row.getRowNumber(), 2, 1000000, IMG_PATH_2)); + pictures.add(new Picture(row.getRowNumber(), 2, WorkbookConstant.PICTURE_WEIGHT, IMG_PATH_1)); + pictures.add(new Picture(row.getRowNumber(), 2, WorkbookConstant.PICTURE_WEIGHT, IMG_PATH_2)); row.setHeight(90); break; case 3: -- Gitee From 005aa6174b86d47c24b58e1d082e15d5ecbec2fb Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Thu, 23 Dec 2021 09:07:25 +0800 Subject: [PATCH 056/161] =?UTF-8?q?add=20=E5=8D=95=E5=85=83=E6=A0=BC?= =?UTF-8?q?=E8=87=AA=E9=80=82=E5=BA=94=E5=9B=BE=E7=89=87=E9=9B=86=E5=90=88?= =?UTF-8?q?=E4=B8=AD=E6=9C=80=E5=A4=A7=E7=9A=84=E6=95=B0=E6=8D=AE=E9=9B=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../picture/support/model/ColumnHelper.java | 4 + .../ibiz/excel/picture/support/model/Row.java | 5 ++ .../excel/picture/support/model/Sheet.java | 13 ++- .../AnnotationPicturesExportExample.java | 9 +- .../SimulateRealBusinessExportExample.java | 82 +++++++++++++++++++ 5 files changed, 109 insertions(+), 4 deletions(-) create mode 100644 src/test/java/com/ibiz/excel/picture/support/simulation/SimulateRealBusinessExportExample.java diff --git a/src/main/java/com/ibiz/excel/picture/support/model/ColumnHelper.java b/src/main/java/com/ibiz/excel/picture/support/model/ColumnHelper.java index 3732a97..faec35d 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/ColumnHelper.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/ColumnHelper.java @@ -44,4 +44,8 @@ public class ColumnHelper { public double getWidth() { return width; } + + public void setWidth(double width) { + this.width = width; + } } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Row.java b/src/main/java/com/ibiz/excel/picture/support/model/Row.java index 9e0849d..413c69a 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Row.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Row.java @@ -31,6 +31,11 @@ public class Row { public int getHeight() { return height <= 0 ? autoHeight : height; } + + /** + * 设置行高 + * @param height + */ public void setHeight(int height) { this.height = height; } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java index df6c6ff..d9f6ce6 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java @@ -335,8 +335,12 @@ public class Sheet { } // 实际宽 int actualWidth = width / 76923; + // 图片数 + int valuesSize = values.size(); + // 数组为空时,给默认值1,否则单元格宽度会被计算成0 + valuesSize = valuesSize == 0 ? 1 : valuesSize; // 设置单元格宽度,单元格宽度 = 图片宽*图片数量 - double columnWidth = actualWidth * values.size() + values.size() / 1.5; + double columnWidth = actualWidth * valuesSize + valuesSize / 1.5; setColumnWidth(cellNumber + 1, columnWidth); //增加图片 values.forEach(v -> pictures.add(new Picture(row.getRowNumber(), cellNumber, width, height, v))); @@ -382,6 +386,13 @@ public class Sheet { // 判断 columnHelperMap 不包含 columnIndex if(!this.columnHelperMap.containsKey(columnIndex)){ this.columnHelperMap.put(columnIndex, new ColumnHelper(columnIndex, width)); + }else { + // 存在时,则取出来 + ColumnHelper columnHelper = this.columnHelperMap.get(columnIndex); + // 比较新的宽度和存在的宽度,将最大的宽度设置进去 + if(width > columnHelper.getWidth()){ + columnHelper.setWidth(width); + } } return this; } diff --git a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java index ca86426..8bbf9b4 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java @@ -44,18 +44,21 @@ public class AnnotationPicturesExportExample { // 图片数组 File[] files = FileUtil.ls(IMAGES_PATH); UserPicture userPicture; - for (int r = 0; r < 1; r++) { + for (int r = 0; r < 3; r++) { userPicture = new UserPicture(); userPicture.setAge(15); userPicture.setName("测试-" + r); userPicture.setPicture(IMG_PATH_1); userPicture.setHeaderPicture(IMG_PATH_2); // 根据图片数组和要获取图片的数量,随机从图片数组中取出若干 - userPicture.setPictures(getPictures(files, 9)); +// userPicture.setPictures(getPictures(files, 5)); +// userPicture.setPictures(getPictures(files, 1)); sheet.createRow(userPicture); + // 不设置时,自适应图片的高度 +// .setHeight(200); // 对标题行添加上样式 if(r == 0){ - sheet.getRow(r).setCellStyle(cellStyle); + sheet.getRow(0).setCellStyle(cellStyle); } } WebUtil.writeExcelTest(workBook, "注解导出图片集合示例".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), TEMP_PATH); diff --git a/src/test/java/com/ibiz/excel/picture/support/simulation/SimulateRealBusinessExportExample.java b/src/test/java/com/ibiz/excel/picture/support/simulation/SimulateRealBusinessExportExample.java new file mode 100644 index 0000000..93b6fe8 --- /dev/null +++ b/src/test/java/com/ibiz/excel/picture/support/simulation/SimulateRealBusinessExportExample.java @@ -0,0 +1,82 @@ +package com.ibiz.excel.picture.support.simulation; + +import cn.hutool.core.io.FileUtil; +import com.ibiz.excel.picture.support.UserPicture; +import com.ibiz.excel.picture.support.model.CellStyle; +import com.ibiz.excel.picture.support.model.Sheet; +import com.ibiz.excel.picture.support.model.Workbook; +import com.ibiz.excel.picture.support.util.WebUtil; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +/** + * 模拟真实业务场景导出 + * + * @author MinWeikai + * @date 2021-12-22 15:36:46 + */ +public class SimulateRealBusinessExportExample { + + static final String CURRENT_PATH = "E:\\test\\"; + private static final String TEMP_PATH = CURRENT_PATH + "excel\\"; + private final static String IMG_PATH = "E:\\test\\img\\"; + + private final static String IMG_PATH_1 = IMG_PATH + "1.jpg"; + private final static String IMG_PATH_2 = IMG_PATH + "2.jpg"; + private final static String IMG_PATH_3 = IMG_PATH + "3.jpg"; + + private final static String IMAGES_PATH = CURRENT_PATH + "images\\"; + + public static void main(String[] args) throws IOException { + Workbook workBook = Workbook.getInstance(50); + Sheet sheet = workBook.createSheet("测试"); + + // 给标题行加上背景色,加颜色时,会对字体加粗 + CellStyle cellStyle = workBook.createCellStyle(); + cellStyle.setFgColorRgb("66cc66"); + // 图片数组 + File[] files = FileUtil.ls(IMAGES_PATH); + UserPicture userPicture; + for (int r = 0; r < 101; r++) { + userPicture = new UserPicture(); + userPicture.setAge(15); + userPicture.setName("测试-" + r); + if(new Random().nextInt(10) > 5){ + // 模拟场景1. 在业务数据集合中,有些数据没有图片,有图片时请传图片绝对路径,没有图片时则不设置值 + userPicture.setPicture(IMG_PATH_1); + } + userPicture.setHeaderPicture(IMG_PATH_2); + if(new Random().nextInt(10) > 5){ + // 模拟场景2. 在业务数据集合中,有些数据没有图片对应的图片集合,没有则不设置值 + userPicture.setPictures(getPictures(files, new Random().nextInt(10))); + } + sheet.createRow(userPicture); + // 对标题行添加上样式 + if (r == 0) { + sheet.getRow(r).setCellStyle(cellStyle); + } + } + WebUtil.writeExcelTest(workBook, "模拟真实业务场景导出示例".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), TEMP_PATH); + } + + /** + * 根据图片数组和要获取图片的数量,随机从图片数组中取出若干 + * + * @param files 图片数组 + * @param getCount 获取图片的数量 + * @return + */ + private static List getPictures(File[] files, int getCount) { + List list = new ArrayList<>(getCount); + for (int i = 0; i < getCount; i++) { + int index = new Random().nextInt(files.length); + list.add(files[index].getAbsolutePath()); + } + return list; + } + +} -- Gitee From 79af37b30420543227bb24a9f0355599206595cf Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Fri, 24 Dec 2021 09:07:27 +0800 Subject: [PATCH 057/161] =?UTF-8?q?fix=20=E5=AF=BC=E5=87=BA=E5=A4=9A?= =?UTF-8?q?=E7=BB=84=E5=9B=BE=E7=89=87excel=E4=B8=AD=E7=BC=BA=E5=A4=B1?= =?UTF-8?q?=E9=83=A8=E5=88=86=E5=9B=BE=E7=89=87=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../support/constants/WorkbookConstant.java | 5 +++ .../support/flush/Drawing1Handler.java | 8 ++--- .../picture/support/flush/Sheet1Handler.java | 3 +- .../excel/picture/support/model/Workbook.java | 36 ++++++++++++------- .../AnnotationPicturesExportExample.java | 7 ++-- 5 files changed, 37 insertions(+), 22 deletions(-) diff --git a/src/main/java/com/ibiz/excel/picture/support/constants/WorkbookConstant.java b/src/main/java/com/ibiz/excel/picture/support/constants/WorkbookConstant.java index 802ac35..d7f8ec0 100644 --- a/src/main/java/com/ibiz/excel/picture/support/constants/WorkbookConstant.java +++ b/src/main/java/com/ibiz/excel/picture/support/constants/WorkbookConstant.java @@ -20,4 +20,9 @@ public class WorkbookConstant { * 图片默认宽度 */ public static final int PICTURE_WEIGHT = 1500000; + + /** + * 单元格宽度 + */ + public static final double CELL_WEIGHT = 23.5; } diff --git a/src/main/java/com/ibiz/excel/picture/support/flush/Drawing1Handler.java b/src/main/java/com/ibiz/excel/picture/support/flush/Drawing1Handler.java index 79126e3..26a672b 100644 --- a/src/main/java/com/ibiz/excel/picture/support/flush/Drawing1Handler.java +++ b/src/main/java/com/ibiz/excel/picture/support/flush/Drawing1Handler.java @@ -31,10 +31,10 @@ public class Drawing1Handler implements InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (method.getName().equals("write")) { Sheet sheet = (Sheet) args[0]; - Map> listMap = sheet.getPictures().stream() - .collect(Collectors.groupingBy(e -> e.getFromCol() + e.getFromRow())); - - for (Map.Entry> map : listMap.entrySet()) { + // 将同一单元格的图片分组在一个集合中 + Map> listMap = sheet.getPictures().stream() + .collect(Collectors.groupingBy(e -> e.getFromCol() + "_" + e.getFromRow())); + for (Map.Entry> map : listMap.entrySet()) { this.writerDrawing(map.getValue()); } } diff --git a/src/main/java/com/ibiz/excel/picture/support/flush/Sheet1Handler.java b/src/main/java/com/ibiz/excel/picture/support/flush/Sheet1Handler.java index b15ee3a..af7179a 100644 --- a/src/main/java/com/ibiz/excel/picture/support/flush/Sheet1Handler.java +++ b/src/main/java/com/ibiz/excel/picture/support/flush/Sheet1Handler.java @@ -1,5 +1,6 @@ package com.ibiz.excel.picture.support.flush; +import com.ibiz.excel.picture.support.constants.WorkbookConstant; import com.ibiz.excel.picture.support.model.*; import com.ibiz.excel.picture.support.util.StringUtils; import org.springframework.util.CollectionUtils; @@ -55,7 +56,7 @@ public class Sheet1Handler implements InvocationHandler { StringBuilder content = new StringBuilder(); content.append("") // 默认宽度 - .append(""); + .append(""); // 自定义的宽度 sheet.getColumnHelperMap().entrySet().forEach(column -> content.append(" sheets; public File getWorkbookFile() { @@ -29,12 +31,18 @@ public class Workbook { } private final File workbookFile; - /**excel临时目录名*/ + /** + * excel临时目录名 + */ private final String filePath; - /**生成的excel文件绝对路径*/ + /** + * 生成的excel文件绝对路径 + */ private final String destPath; /**执行了close方法后,才会有dest*/ - /**目的文件*/ + /** + * 目的文件 + */ private File destFile; private boolean close; /*** @@ -48,9 +56,11 @@ public class Workbook { public Map getImageCache() { return imageCache; } + private Workbook() { this(100); } + private Workbook(int flushSize) { this.flushSize = flushSize; filePath = WorkbookConstant.AUTO_DIR + WorkbookConstant.FILE_SEPARATOR + UUID.randomUUID().toString().replace("-", ""); @@ -61,14 +71,17 @@ public class Workbook { /** * 获取WorkBook实例,默认100行刷新 + * * @return */ public static Workbook getInstance() { return getInstance(100); } + public static Workbook getInstance(int flushSize) { return new Workbook(flushSize); } + public Sheet createSheet() { Sheet sheet = Sheet.getInstance(flushSize, this); sheets.add(sheet); @@ -118,17 +131,14 @@ public class Workbook { } } - public CellStyle getCellStyle() { - return cellStyle; - } - - public void setCellStyle(CellStyle cellStyle) { - this.cellStyle = cellStyle; - } - + /** + * 创建工作簿样式 + * + * @return + */ public CellStyle createCellStyle() { CellStyle cellStyle = new CellStyle(); - this.setCellStyle(cellStyle); + this.cellStyle = cellStyle; return cellStyle; } } diff --git a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java index 8bbf9b4..8594fd1 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java @@ -44,15 +44,14 @@ public class AnnotationPicturesExportExample { // 图片数组 File[] files = FileUtil.ls(IMAGES_PATH); UserPicture userPicture; - for (int r = 0; r < 3; r++) { + for (int r = 0; r < 101; r++) { userPicture = new UserPicture(); userPicture.setAge(15); userPicture.setName("测试-" + r); userPicture.setPicture(IMG_PATH_1); - userPicture.setHeaderPicture(IMG_PATH_2); +// userPicture.setHeaderPicture(IMG_PATH_2); // 根据图片数组和要获取图片的数量,随机从图片数组中取出若干 -// userPicture.setPictures(getPictures(files, 5)); -// userPicture.setPictures(getPictures(files, 1)); + userPicture.setPictures(getPictures(files, new Random().nextInt(5))); sheet.createRow(userPicture); // 不设置时,自适应图片的高度 // .setHeight(200); -- Gitee From 47b0d74c1ac5db4e62f99a64b28fbff654b27afe Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Thu, 30 Dec 2021 17:51:29 +0800 Subject: [PATCH 058/161] update version2.0.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 26ab20f..5858ad9 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 top.minwk excel-x - 1.1.0 + 2.0.0 excel-x excel-x https://gitee.com/mwk719/excel-batch-picture-support -- Gitee From 5937a3c684db3dbe8d2b3c8aa5dfd5f46e349fc0 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Wed, 5 Jan 2022 09:17:06 +0800 Subject: [PATCH 059/161] add travis.yml --- .travis.yml | 18 ++++++++ README.md | 2 + pom.xml | 119 ++++++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 130 insertions(+), 9 deletions(-) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..18a94fd --- /dev/null +++ b/.travis.yml @@ -0,0 +1,18 @@ +language: java + +jdk: + - openjdk8 + +notifications: + email: false + +before_install: + - chmod +x mvnw + +script: + - export TZ=Asia/Shanghai + - mvn install -DskipTests=true -Dmaven.javadoc.skip=true -B -V + - mvn cobertura:cobertura -Dcobertura.report.format=xml -Dmaven.javadoc.skip.true + +after_success: + - bash <(curl -s https://codecov.io/bash) \ No newline at end of file diff --git a/README.md b/README.md index f7e5346..2dd24b7 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,6 @@ # Excel支持大量图片导出 +[![Build Status](https://travis-ci.com/mwk719/excel-batch-picture-support.svg?branch=dev)](https://app.travis-ci.com/github/mwk719/excel-batch-picture-support) +[![codecov](https://codecov.io/gh/mwk719/excel-batch-picture-support/branch/dev/graph/badge.svg?token=pNgL09o7hN)](https://codecov.io/gh/mwk719/excel-batch-picture-support) ## 背景 diff --git a/pom.xml b/pom.xml index 5858ad9..a29600d 100644 --- a/pom.xml +++ b/pom.xml @@ -2,6 +2,9 @@ 4.0.0 + + pom + top.minwk excel-x 2.0.0 @@ -15,8 +18,13 @@ + utf-8 + utf-8 + + + 8 1.8 - 5.2.8.RELEASE + 5.3.14 @@ -46,12 +54,12 @@ cn.hutool hutool-core - 5.5.5 + 5.7.18 org.slf4j slf4j-api - 1.7.30 + 1.7.32 org.springframework @@ -67,7 +75,7 @@ javax.servlet javax.servlet-api - 3.1.0 + 4.0.0 provided @@ -81,16 +89,109 @@ org.apache.maven.plugins - maven-javadoc-plugin - 3.0.0-M1 + maven-deploy-plugin + 2.8.2 + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 - - -Xdoclint:none - + ${compile.version} + ${compile.version} + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.1.1 + + + package + + jar + + + + + + + + release + + + oss + https://oss.sonatype.org/content/repositories/snapshots/ + + + oss + https://oss.sonatype.org/service/local/staging/deploy/maven2/ + + + + + + + org.apache.maven.plugins + maven-source-plugin + 3.2.1 + + + oss + package + + jar-no-fork + + + + + + + org.codehaus.mojo + cobertura-maven-plugin + 2.7 + + + html + xml + + + + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.6 + + + oss + verify + + sign + + + + + + org.sonatype.plugins + nexus-staging-maven-plugin + 1.6.8 + true + + oss + https://oss.sonatype.org/ + true + + + + + + + -- Gitee From 0b94dc3b3d4c17eb79b301553fddcaafd2f2b376 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Wed, 5 Jan 2022 09:44:15 +0800 Subject: [PATCH 060/161] update travis.yml --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2dd24b7..e7d9aa7 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Excel支持大量图片导出 -[![Build Status](https://travis-ci.com/mwk719/excel-batch-picture-support.svg?branch=dev)](https://app.travis-ci.com/github/mwk719/excel-batch-picture-support) -[![codecov](https://codecov.io/gh/mwk719/excel-batch-picture-support/branch/dev/graph/badge.svg?token=pNgL09o7hN)](https://codecov.io/gh/mwk719/excel-batch-picture-support) +[![Build Status](https://travis-ci.com/mwk719/excel-batch-picture-support.svg?branch=master)](https://app.travis-ci.com/github/mwk719/excel-batch-picture-support) +[![codecov](https://codecov.io/gh/mwk719/excel-batch-picture-support/branch/master/graph/badge.svg?token=40375Bb4s5)](https://codecov.io/gh/mwk719/excel-batch-picture-support) ## 背景 -- Gitee From cb3e59825c6ea7e437ac3948621634c7d5b49b1c Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Wed, 5 Jan 2022 10:13:17 +0800 Subject: [PATCH 061/161] update huizhang --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index e7d9aa7..fb9d6b7 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,10 @@ # Excel支持大量图片导出 [![Build Status](https://travis-ci.com/mwk719/excel-batch-picture-support.svg?branch=master)](https://app.travis-ci.com/github/mwk719/excel-batch-picture-support) [![codecov](https://codecov.io/gh/mwk719/excel-batch-picture-support/branch/master/graph/badge.svg?token=40375Bb4s5)](https://codecov.io/gh/mwk719/excel-batch-picture-support) + + + + ## 背景 -- Gitee From eb0f4aff3f95a8068f3a2218e3c47bb344b8186e Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Wed, 5 Jan 2022 10:13:17 +0800 Subject: [PATCH 062/161] update huizhang --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index e7d9aa7..fb9d6b7 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,10 @@ # Excel支持大量图片导出 [![Build Status](https://travis-ci.com/mwk719/excel-batch-picture-support.svg?branch=master)](https://app.travis-ci.com/github/mwk719/excel-batch-picture-support) [![codecov](https://codecov.io/gh/mwk719/excel-batch-picture-support/branch/master/graph/badge.svg?token=40375Bb4s5)](https://codecov.io/gh/mwk719/excel-batch-picture-support) + + + + ## 背景 -- Gitee From 4e1d990a7b3e79c847363ed2086d5fe84b705843 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Wed, 5 Jan 2022 14:13:08 +0800 Subject: [PATCH 063/161] update travis.yml --- .travis.yml | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index 18a94fd..7bddeb7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,16 +3,7 @@ language: java jdk: - openjdk8 -notifications: - email: false - -before_install: - - chmod +x mvnw - -script: - - export TZ=Asia/Shanghai - - mvn install -DskipTests=true -Dmaven.javadoc.skip=true -B -V - - mvn cobertura:cobertura -Dcobertura.report.format=xml -Dmaven.javadoc.skip.true +script: "mvn cobertura:cobertura" after_success: - bash <(curl -s https://codecov.io/bash) \ No newline at end of file -- Gitee From 7f29d6c23625ab6f035e27539fc33150ef37f712 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Wed, 5 Jan 2022 14:16:12 +0800 Subject: [PATCH 064/161] Revert "update travis.yml" This reverts commit 4e1d990a --- .travis.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 7bddeb7..f6af071 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,16 @@ language: java jdk: - openjdk8 -script: "mvn cobertura:cobertura" +notifications: + email: false + +before_install: + - chmod +x mvnw + +script: + - export TZ=Asia/Shanghai + - mvn install -DskipTests=true -Dmaven.javadoc.skip=true -B -V + - mvn cobertura:cobertura after_success: - bash <(curl -s https://codecov.io/bash) \ No newline at end of file -- Gitee From 9f1c9c046d897a69dd633aebdb95eb0e5bfb3c3d Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Wed, 5 Jan 2022 14:23:38 +0800 Subject: [PATCH 065/161] add codecov.yml --- codecov.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 codecov.yml diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 0000000..f7b43f4 --- /dev/null +++ b/codecov.yml @@ -0,0 +1,12 @@ +codecov: + token: "71bb337b-fc77-4f70-a64e-57bea3251a57" + bot: "codecov-io" + ci: + - "travis.org" + strict_yaml_branch: "yaml-config" + max_report_age: 24 + disable_default_path_fixes: no + require_ci_to_pass: yes + notify: + after_n_builds: 2 + wait_for_ci: yes \ No newline at end of file -- Gitee From be9cb572ecd2e2fab37464912ab607860cd79c85 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Wed, 5 Jan 2022 14:39:49 +0800 Subject: [PATCH 066/161] update .travis.yml --- .travis.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 7bddeb7..18a94fd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,16 @@ language: java jdk: - openjdk8 -script: "mvn cobertura:cobertura" +notifications: + email: false + +before_install: + - chmod +x mvnw + +script: + - export TZ=Asia/Shanghai + - mvn install -DskipTests=true -Dmaven.javadoc.skip=true -B -V + - mvn cobertura:cobertura -Dcobertura.report.format=xml -Dmaven.javadoc.skip.true after_success: - bash <(curl -s https://codecov.io/bash) \ No newline at end of file -- Gitee From c62f3429a56858d01bde728caefc3608d62ef3ef Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Wed, 5 Jan 2022 14:41:06 +0800 Subject: [PATCH 067/161] remove codecov.yml --- codecov.yml | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 codecov.yml diff --git a/codecov.yml b/codecov.yml deleted file mode 100644 index f7b43f4..0000000 --- a/codecov.yml +++ /dev/null @@ -1,12 +0,0 @@ -codecov: - token: "71bb337b-fc77-4f70-a64e-57bea3251a57" - bot: "codecov-io" - ci: - - "travis.org" - strict_yaml_branch: "yaml-config" - max_report_age: 24 - disable_default_path_fixes: no - require_ci_to_pass: yes - notify: - after_n_builds: 2 - wait_for_ci: yes \ No newline at end of file -- Gitee From 5130238f0158a7607c4c3591a71416445b37bb3f Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Fri, 7 Jan 2022 18:25:22 +0800 Subject: [PATCH 068/161] =?UTF-8?q?add=20=E5=AF=B9=E7=BD=91=E7=BB=9C?= =?UTF-8?q?=E5=9B=BE=E7=89=87=E5=AF=BC=E5=87=BA=E5=9C=A8excel?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 20 +++++-- .../support/annotation/ExportModel.java | 10 ++++ .../constants/PictureSourceContent.java | 20 +++++++ .../support/constants/WorkbookConstant.java | 5 ++ .../support/flush/DrawingXmlRelsHandler.java | 43 ++++++++++----- .../excel/picture/support/model/Picture.java | 26 +++++++++ .../excel/picture/support/model/Sheet.java | 53 ++++++++++++++----- .../picture/support/util/MD5Digester.java | 9 ++++ .../excel/picture/support/UserPicture.java | 3 +- .../excel/picture/support/WebImgTest.java | 21 ++++++++ .../picture/support/common/BaseJunitTest.java | 53 +++++++++++++++++++ .../AnnotationPicturesExportExample.java | 39 +++----------- .../picture/support/util/MD5DigesterTest.java | 17 ++++++ 13 files changed, 258 insertions(+), 61 deletions(-) create mode 100644 src/main/java/com/ibiz/excel/picture/support/constants/PictureSourceContent.java create mode 100644 src/test/java/com/ibiz/excel/picture/support/WebImgTest.java create mode 100644 src/test/java/com/ibiz/excel/picture/support/common/BaseJunitTest.java create mode 100644 src/test/java/com/ibiz/excel/picture/support/util/MD5DigesterTest.java diff --git a/pom.xml b/pom.xml index a29600d..6850a8f 100644 --- a/pom.xml +++ b/pom.xml @@ -25,6 +25,8 @@ 8 1.8 5.3.14 + 5.7.18 + 4.13.2 @@ -51,10 +53,12 @@ + - cn.hutool - hutool-core - 5.7.18 + junit + junit + ${junit.version} + test org.slf4j @@ -83,6 +87,16 @@ spring-web ${version.spring} + + cn.hutool + hutool-core + ${hutool.version} + + + cn.hutool + hutool-http + ${hutool.version} + diff --git a/src/main/java/com/ibiz/excel/picture/support/annotation/ExportModel.java b/src/main/java/com/ibiz/excel/picture/support/annotation/ExportModel.java index dab006b..51bb89b 100644 --- a/src/main/java/com/ibiz/excel/picture/support/annotation/ExportModel.java +++ b/src/main/java/com/ibiz/excel/picture/support/annotation/ExportModel.java @@ -1,5 +1,6 @@ package com.ibiz.excel.picture.support.annotation; +import com.ibiz.excel.picture.support.constants.PictureSourceContent; import com.ibiz.excel.picture.support.constants.WorkbookConstant; import java.lang.annotation.*; @@ -52,7 +53,16 @@ public @interface ExportModel { /** * 图片所在单元格行高度,单元格会自适应图片的高度 * 如需要自定义图片高度,注意:在导出类中有多个图片字段,需要在每个图片字段上注解配置自定义的高度 + * * @return */ int height() default WorkbookConstant.PICTURE_HEIGHT; + + /** + * 图片来源 默认为图片的绝对路径 + * {@link PictureSourceContent} + * + * @return + */ + int pictureSource() default PictureSourceContent.ABSOLUTE_PATH; } diff --git a/src/main/java/com/ibiz/excel/picture/support/constants/PictureSourceContent.java b/src/main/java/com/ibiz/excel/picture/support/constants/PictureSourceContent.java new file mode 100644 index 0000000..5e7f4cc --- /dev/null +++ b/src/main/java/com/ibiz/excel/picture/support/constants/PictureSourceContent.java @@ -0,0 +1,20 @@ +package com.ibiz.excel.picture.support.constants; + +/** + * 图片来源 + * + * @author MinWeikai + * @date 2022/1/7 16:51 + */ +public class PictureSourceContent { + + /** + * 绝对路径 + */ + public static final int ABSOLUTE_PATH = 1; + + /** + * 网络链接 + */ + public static final int WEB_URL = 2; +} diff --git a/src/main/java/com/ibiz/excel/picture/support/constants/WorkbookConstant.java b/src/main/java/com/ibiz/excel/picture/support/constants/WorkbookConstant.java index d7f8ec0..3e4be6f 100644 --- a/src/main/java/com/ibiz/excel/picture/support/constants/WorkbookConstant.java +++ b/src/main/java/com/ibiz/excel/picture/support/constants/WorkbookConstant.java @@ -25,4 +25,9 @@ public class WorkbookConstant { * 单元格宽度 */ public static final double CELL_WEIGHT = 23.5; + + /** + * 下载网络图片超时时间 + */ + public static final int DOWNLOAD_PICTURE_TIME_OUT = 10 * 1000; } diff --git a/src/main/java/com/ibiz/excel/picture/support/flush/DrawingXmlRelsHandler.java b/src/main/java/com/ibiz/excel/picture/support/flush/DrawingXmlRelsHandler.java index f375d03..c6e0a2e 100644 --- a/src/main/java/com/ibiz/excel/picture/support/flush/DrawingXmlRelsHandler.java +++ b/src/main/java/com/ibiz/excel/picture/support/flush/DrawingXmlRelsHandler.java @@ -1,6 +1,8 @@ package com.ibiz.excel.picture.support.flush; +import cn.hutool.http.HttpUtil; import com.ibiz.excel.picture.support.constants.Alias; +import com.ibiz.excel.picture.support.constants.PictureSourceContent; import com.ibiz.excel.picture.support.constants.WorkbookConstant; import com.ibiz.excel.picture.support.model.Picture; import com.ibiz.excel.picture.support.model.Sheet; @@ -13,7 +15,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; -import java.io.IOException; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.util.List; @@ -37,11 +38,8 @@ public class DrawingXmlRelsHandler implements InvocationHandler { List pictures = sheet.getPictures(); pictures.stream().filter(Objects::nonNull).forEach(p -> { if (StringUtils.isNotBlank(p.getPicturePath())) { - File file = new File(p.getPicturePath()); - if(file.exists()) { - //写图片 - copyPictureAppendDrawingRelsXML(sheet, p); - } + //写图片 + copyPictureAppendDrawingRelsXML(sheet, p); } }); } @@ -55,8 +53,21 @@ public class DrawingXmlRelsHandler implements InvocationHandler { */ private void copyPictureAppendDrawingRelsXML(Sheet sheet, Picture picture) { try { - File srcPicture = new File(picture.getPicturePath()); - String md5 = MD5Digester.digestMD5(srcPicture); + String md5; + File srcPicture = null; + String picturePath = picture.getPicturePath(); + // 判断图片来源 + if(PictureSourceContent.WEB_URL == picture.getPictureSource() ){ + md5 = MD5Digester.encodeHexStr(picturePath); + }else { + // 绝对路径图片 + srcPicture = new File(picturePath); + // 绝对路径下图片不存在则不执行 + if(!srcPicture.exists()){ + return; + } + md5 = MD5Digester.digestMD5(srcPicture); + } Integer drawingSequence = sheet.getWorkbook().getImageCache().get(md5); // 已存在的图片 if (Objects.nonNull(drawingSequence)) { @@ -67,7 +78,17 @@ public class DrawingXmlRelsHandler implements InvocationHandler { File media = sheet.getSheetContext().getRepositoryHolder().get(Alias.MEDIA).getFile(); drawingSequence = sheet.getDrawingSequence(); File destPicture = new File(media, "image"+ drawingSequence + ".png"); - FileUtil.copyFile(srcPicture, destPicture); + if(PictureSourceContent.WEB_URL == picture.getPictureSource() ){ + // 下载网络图片到excel资源路径 + HttpUtil.downloadFile(picturePath, destPicture, WorkbookConstant.DOWNLOAD_PICTURE_TIME_OUT); + }else { + // 复制绝对图片到excel资源路径 + FileUtil.copyFile(srcPicture, destPicture); + } + // 输出的图片不存在则跳出 + if(!destPicture.exists()){ + return; + } picture.setRembed(drawingSequence); RelationShip relationShip = new RelationShip("rId" + drawingSequence, WorkbookConstant.MEDIA_IMAGE_TYPE, "../media/image" + drawingSequence +".png"); //先把drawingSequence放入缓存,因为从缓存中获取时设置drawingSequence再+1对应图片。实际图片的drawingSequence不变 @@ -75,9 +96,7 @@ public class DrawingXmlRelsHandler implements InvocationHandler { drawingSequence++; sheet.setDrawingSequence(drawingSequence); target.append(CovertUtil.covert(relationShip)); - } catch (IOException e) { - logger.error("图片copy到media目录下异常",e); - }catch (Exception e) { + } catch (Exception e) { logger.error("图片copy到media目录下异常",e); } } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Picture.java b/src/main/java/com/ibiz/excel/picture/support/model/Picture.java index 7b6a93b..cda4e7b 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Picture.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Picture.java @@ -15,6 +15,12 @@ public class Picture { /**当前系统中图片的绝对路径*/ private String picturePath; //图片路径 + /** + * 图片来源 + * {@link com.ibiz.excel.picture.support.constants.PictureSourceContent} + */ + private int pictureSource; + /** * 图片宽度 */ @@ -58,6 +64,18 @@ public class Picture { this.height = height; } + public Picture(int fromRow,int fromCol, int width, int height,String picturePath, int pictureSource) { + super(); + this.fromRow = fromRow; + this.fromCol = fromCol; + this.toRow = fromRow; + this.toCol = fromCol; + this.picturePath = picturePath; + this.width = width; + this.height = height; + this.pictureSource = pictureSource; + } + public String getPicturePath() { return picturePath; } @@ -121,4 +139,12 @@ public class Picture { public void setHeight(int height) { this.height = height; } + + public int getPictureSource() { + return pictureSource; + } + + public void setPictureSource(int pictureSource) { + this.pictureSource = pictureSource; + } } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java index d9f6ce6..8981710 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java @@ -274,10 +274,6 @@ public class Sheet { boolean isPicture = model.isPicture(); boolean mergeMaster = model.mergeMaster(); boolean merge = model.merge(); - // 图片所在单元格宽度,图片和单元格宽度一致 - int width = model.width(); - // 图片所在单元格行高度 - int height = model.height(); String title = model.title(); Cell cell = new Cell(row.getRowNumber(), sort); // 合并 是标题 并且 是要合并的基准列,将元素放在基准列中 @@ -304,7 +300,7 @@ public class Sheet { // 不是标题 并且 是图片 并且 值不为空 if (isPicture && value != null) { // 添加图片 - this.addPictures(row, cell.getCellNumber(), width, height, value); + this.addPictures(row, cell.getCellNumber(), value, model); } else { cell.setValue(value == null ? "" : String.valueOf(value)); } @@ -321,29 +317,60 @@ public class Sheet { * 添加图片 * @param row * @param cellNumber - * @param width * @param value + * @param model */ - private void addPictures(Row row, int cellNumber, int width,int height, Object value) { + private void addPictures(Row row, int cellNumber, Object value, ExportModel model) { + // 图片所在单元格宽度,图片和单元格宽度一致 + int width = model.width(); + // 图片所在单元格行高度 + int height = model.height(); + List values = getValues(value); + // 计算行高 + calculateRowHeight(row, height); + // 计算单元格宽度根据单元格中值的数量 + calculateColumnWidth(cellNumber, width, values.size()); + //增加图片 + values.forEach(v -> pictures.add(new Picture(row.getRowNumber(), cellNumber, width, height, v, model.pictureSource()))); + } + + private List getValues(Object value) { List values = new ArrayList<>(); - // 设置行高自适应于图片的高度 - row.setHeight((height / 12600) - 1); if (value instanceof List) { values = (List) value; } else { values.add(String.valueOf(value)); } + return values; + } + + /** + * 计算行高 + * + * @param row + * @param height + */ + private void calculateRowHeight(Row row, int height) { + // 设置行高自适应于图片的高度 + row.setHeight((height / 12600) - 1); + } + + /** + * 计算单元格宽度根据单元格中值的数量 + * + * @param cellNumber + * @param width + * @param valuesSize 图片数 + */ + private void calculateColumnWidth(int cellNumber, int width, int valuesSize) { // 实际宽 int actualWidth = width / 76923; - // 图片数 - int valuesSize = values.size(); + // // 数组为空时,给默认值1,否则单元格宽度会被计算成0 valuesSize = valuesSize == 0 ? 1 : valuesSize; // 设置单元格宽度,单元格宽度 = 图片宽*图片数量 double columnWidth = actualWidth * valuesSize + valuesSize / 1.5; setColumnWidth(cellNumber + 1, columnWidth); - //增加图片 - values.forEach(v -> pictures.add(new Picture(row.getRowNumber(), cellNumber, width, height, v))); } Row createRow(T t) { diff --git a/src/main/java/com/ibiz/excel/picture/support/util/MD5Digester.java b/src/main/java/com/ibiz/excel/picture/support/util/MD5Digester.java index 0aceba0..1449704 100644 --- a/src/main/java/com/ibiz/excel/picture/support/util/MD5Digester.java +++ b/src/main/java/com/ibiz/excel/picture/support/util/MD5Digester.java @@ -1,6 +1,7 @@ package com.ibiz.excel.picture.support.util; import java.io.*; +import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; @@ -60,4 +61,12 @@ public class MD5Digester { return new String(result); } + public static String encodeHexStr(String str) { + if (str == null) { + return null; + } + byte[] bytes = str.getBytes(StandardCharsets.UTF_8); + return encodeHexStr(bytes); + } + } diff --git a/src/test/java/com/ibiz/excel/picture/support/UserPicture.java b/src/test/java/com/ibiz/excel/picture/support/UserPicture.java index b494ec1..4ea2fd4 100644 --- a/src/test/java/com/ibiz/excel/picture/support/UserPicture.java +++ b/src/test/java/com/ibiz/excel/picture/support/UserPicture.java @@ -1,6 +1,7 @@ package com.ibiz.excel.picture.support; import com.ibiz.excel.picture.support.annotation.ExportModel; +import com.ibiz.excel.picture.support.constants.PictureSourceContent; import java.util.List; @@ -21,7 +22,7 @@ public class UserPicture { private String department; @ExportModel(sort = 2, isPicture = true, title = "图片1") private String picture; - @ExportModel(sort = 4, isPicture = true, title = "图片2") + @ExportModel(sort = 4, isPicture = true, title = "图片2", pictureSource = PictureSourceContent.WEB_URL) private String headerPicture; @ExportModel(sort = 5, isPicture = true, title = "多图片") private List pictures; diff --git a/src/test/java/com/ibiz/excel/picture/support/WebImgTest.java b/src/test/java/com/ibiz/excel/picture/support/WebImgTest.java new file mode 100644 index 0000000..85cc78f --- /dev/null +++ b/src/test/java/com/ibiz/excel/picture/support/WebImgTest.java @@ -0,0 +1,21 @@ +package com.ibiz.excel.picture.support; + +import cn.hutool.http.HttpUtil; + +import java.io.File; + +/** + * 网络图片测试 + * + * @author MinWeikai + * @date 2022/1/7 16:34 + */ +public class WebImgTest { + + public static void main(String[] args) { + String url = "https://portrait.gitee.com/uploads/avatars/user/552/1657608_mwk719_1641537497.png"; + File destFilePath = new File("E:\\test\\img\\1111.png"); + long destFile = HttpUtil.downloadFile(url, destFilePath, 5 * 1000); + System.out.println(destFile); + } +} diff --git a/src/test/java/com/ibiz/excel/picture/support/common/BaseJunitTest.java b/src/test/java/com/ibiz/excel/picture/support/common/BaseJunitTest.java new file mode 100644 index 0000000..bf5b2f1 --- /dev/null +++ b/src/test/java/com/ibiz/excel/picture/support/common/BaseJunitTest.java @@ -0,0 +1,53 @@ +package com.ibiz.excel.picture.support.common; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +/** + * @author MinWeikai + * @date 2022/1/7 18:09 + */ +public class BaseJunitTest { + + protected static final String CURRENT_PATH = "E:\\test\\"; + protected static final String TEMP_PATH = CURRENT_PATH + "excel\\"; + protected final static String IMG_PATH = "E:\\test\\img\\"; + + protected final static String IMG_PATH_1 = IMG_PATH + "1.jpg"; + protected final static String IMG_PATH_2 = IMG_PATH + "2.jpg"; + protected final static String IMG_PATH_3 = IMG_PATH + "3.jpg"; + + protected final static String IMAGES_PATH = CURRENT_PATH + "images\\"; + + protected final static List urls = new ArrayList<>(); + + static { + urls.add("https://portrait.gitee.com/uploads/avatars/user/552/1657608_mwk719_1641537497.png"); + urls.add("https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.jj20.com%2Fup%2Fallimg%2F1114%2F060421091316%2F210604091316-6-1200.jpg&refer=http%3A%2F%2Fimg.jj20.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1644142768&t=82062e20360f72b0fd8d5fd7e2fc9885"); + urls.add("https://img2.baidu.com/it/u=121102239,1207969661&fm=253&fmt=auto&app=120&f=JPEG?w=1195&h=500"); + urls.add("https://img2.baidu.com/it/u=2602880481,728201544&fm=26&fmt=auto"); + } + + + /** + * 根据图片数组和要获取图片的数量,随机从图片数组中取出若干 + * @param files 图片数组 + * @param getCount 获取图片的数量 + * @return + */ + protected static List getPictures(File[] files, int getCount) { + List list = new ArrayList<>(getCount); + for (int i = 0; i < getCount; i++) { + int index = new Random().nextInt(files.length); + list.add(files[index].getAbsolutePath()); + } + return list; + } + + protected static String getUrl() { + int index = new Random().nextInt(urls.size()); + return urls.get(index); + } +} diff --git a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java index 8594fd1..f6dda39 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java @@ -2,15 +2,14 @@ package com.ibiz.excel.picture.support.example; import cn.hutool.core.io.FileUtil; import com.ibiz.excel.picture.support.UserPicture; +import com.ibiz.excel.picture.support.common.BaseJunitTest; import com.ibiz.excel.picture.support.model.CellStyle; import com.ibiz.excel.picture.support.model.Sheet; import com.ibiz.excel.picture.support.model.Workbook; import com.ibiz.excel.picture.support.util.WebUtil; +import org.junit.Test; import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; import java.util.Random; /** @@ -19,19 +18,10 @@ import java.util.Random; * @author MinWeikai * @date 2021/12/14 10:36 */ -public class AnnotationPicturesExportExample { +public class AnnotationPicturesExportExample extends BaseJunitTest { - static final String CURRENT_PATH = "E:\\test\\"; - private static final String TEMP_PATH = CURRENT_PATH + "excel\\"; - private final static String IMG_PATH = "E:\\test\\img\\"; - - private final static String IMG_PATH_1 = IMG_PATH + "1.jpg"; - private final static String IMG_PATH_2 = IMG_PATH + "2.jpg"; - private final static String IMG_PATH_3 = IMG_PATH + "3.jpg"; - - private final static String IMAGES_PATH = CURRENT_PATH + "images\\"; - - public static void main(String[] args) throws IOException { + @Test + public void export() { Workbook workBook = Workbook.getInstance(56); Sheet sheet = workBook.createSheet("测试"); @@ -44,12 +34,12 @@ public class AnnotationPicturesExportExample { // 图片数组 File[] files = FileUtil.ls(IMAGES_PATH); UserPicture userPicture; - for (int r = 0; r < 101; r++) { + for (int r = 0; r < 10; r++) { userPicture = new UserPicture(); userPicture.setAge(15); userPicture.setName("测试-" + r); userPicture.setPicture(IMG_PATH_1); -// userPicture.setHeaderPicture(IMG_PATH_2); + userPicture.setHeaderPicture(getUrl()); // 根据图片数组和要获取图片的数量,随机从图片数组中取出若干 userPicture.setPictures(getPictures(files, new Random().nextInt(5))); sheet.createRow(userPicture); @@ -63,19 +53,4 @@ public class AnnotationPicturesExportExample { WebUtil.writeExcelTest(workBook, "注解导出图片集合示例".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), TEMP_PATH); } - /** - * 根据图片数组和要获取图片的数量,随机从图片数组中取出若干 - * @param files 图片数组 - * @param getCount 获取图片的数量 - * @return - */ - private static List getPictures(File[] files, int getCount) { - List list = new ArrayList<>(getCount); - for (int i = 0; i < getCount; i++) { - int index = new Random().nextInt(files.length); - list.add(files[index].getAbsolutePath()); - } - return list; - } - } diff --git a/src/test/java/com/ibiz/excel/picture/support/util/MD5DigesterTest.java b/src/test/java/com/ibiz/excel/picture/support/util/MD5DigesterTest.java new file mode 100644 index 0000000..6803d89 --- /dev/null +++ b/src/test/java/com/ibiz/excel/picture/support/util/MD5DigesterTest.java @@ -0,0 +1,17 @@ +package com.ibiz.excel.picture.support.util; + +import java.io.File; + +/** + * @author MinWeikai + * @date 2022/1/7 17:26 + */ +public class MD5DigesterTest { + + public static void main(String[] args) { + File destFilePath = new File("E:\\test\\img\\0.jpg"); + String md5 = null; + md5 = MD5Digester.encodeHexStr("destFilePath"); + System.out.println(md5); + } +} \ No newline at end of file -- Gitee From d204d0ced29e9bf9b7b982afdd7fe68502027fc7 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Mon, 10 Jan 2022 13:52:32 +0800 Subject: [PATCH 069/161] =?UTF-8?q?add=20=E8=87=AA=E5=8A=A8=E5=8C=B9?= =?UTF-8?q?=E9=85=8D=E5=9B=BE=E7=89=87=E6=9D=A5=E6=BA=90=E5=AF=BC=E5=87=BA?= =?UTF-8?q?=E5=9C=A8excel?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../support/annotation/ExportModel.java | 12 ++- .../support/flush/DrawingXmlRelsHandler.java | 94 +++++++++++++------ .../picture/support/model/CellStyle.java | 13 +++ .../excel/picture/support/model/Picture.java | 26 ++++- .../excel/picture/support/model/Sheet.java | 34 ++----- .../picture/support/util/MD5Digester.java | 38 ++++++-- .../com/ibiz/excel/picture/support/User.java | 2 +- .../excel/picture/support/UserPicture.java | 12 ++- .../picture/support/common/BaseJunitTest.java | 16 ++++ .../AnnotationPicturesExportExample.java | 8 +- .../example/UrlPicturesExportExample.java | 45 +++++++++ .../picture/support/util/MD5DigesterTest.java | 17 ---- 12 files changed, 223 insertions(+), 94 deletions(-) create mode 100644 src/test/java/com/ibiz/excel/picture/support/example/UrlPicturesExportExample.java delete mode 100644 src/test/java/com/ibiz/excel/picture/support/util/MD5DigesterTest.java diff --git a/src/main/java/com/ibiz/excel/picture/support/annotation/ExportModel.java b/src/main/java/com/ibiz/excel/picture/support/annotation/ExportModel.java index 51bb89b..0cff822 100644 --- a/src/main/java/com/ibiz/excel/picture/support/annotation/ExportModel.java +++ b/src/main/java/com/ibiz/excel/picture/support/annotation/ExportModel.java @@ -2,6 +2,7 @@ package com.ibiz.excel.picture.support.annotation; import com.ibiz.excel.picture.support.constants.PictureSourceContent; import com.ibiz.excel.picture.support.constants.WorkbookConstant; +import com.ibiz.excel.picture.support.model.Picture; import java.lang.annotation.*; @@ -18,9 +19,10 @@ import java.lang.annotation.*; @Documented public @interface ExportModel { /** - * 排序 + * 排序,必填,且不能重复 + * */ - int sort() default 0; + int sort() ; /** * 是否是图片 @@ -59,10 +61,12 @@ public @interface ExportModel { int height() default WorkbookConstant.PICTURE_HEIGHT; /** - * 图片来源 默认为图片的绝对路径 + * 图片来源 默认为0,自动判断图片来源 + * {@link Picture#autoPictureSourceByPath()} + * 不设置的话自动匹配,也可自己指定 * {@link PictureSourceContent} * * @return */ - int pictureSource() default PictureSourceContent.ABSOLUTE_PATH; + int pictureSource() default 0; } diff --git a/src/main/java/com/ibiz/excel/picture/support/flush/DrawingXmlRelsHandler.java b/src/main/java/com/ibiz/excel/picture/support/flush/DrawingXmlRelsHandler.java index c6e0a2e..efb4684 100644 --- a/src/main/java/com/ibiz/excel/picture/support/flush/DrawingXmlRelsHandler.java +++ b/src/main/java/com/ibiz/excel/picture/support/flush/DrawingXmlRelsHandler.java @@ -15,6 +15,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.util.List; @@ -22,19 +24,22 @@ import java.util.Objects; /** * 图片 + * * @auther 喻场 * @date 2020/7/618:33 */ public class DrawingXmlRelsHandler implements InvocationHandler { private Logger logger = LoggerFactory.getLogger(this.getClass()); private IRepository target; + public DrawingXmlRelsHandler(IRepository proxy) { this.target = proxy; } + @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (method.getName().equals("write")) { - Sheet sheet = (Sheet)args[0]; + Sheet sheet = (Sheet) args[0]; List pictures = sheet.getPictures(); pictures.stream().filter(Objects::nonNull).forEach(p -> { if (StringUtils.isNotBlank(p.getPicturePath())) { @@ -48,26 +53,23 @@ public class DrawingXmlRelsHandler implements InvocationHandler { /** * 把图片copy到media目录下 + * * @param sheet * @param picture */ private void copyPictureAppendDrawingRelsXML(Sheet sheet, Picture picture) { + String picturePath = picture.getPicturePath(); + // 根据图片来源获取文件md5值 + String md5; + try { + md5 = getMd5BySource(picture.getPictureSource(), picturePath); + } catch (FileNotFoundException e) { + logger.warn("获取不到路径为{}的图片", picturePath); + // 获取不到时跳出 + return; + } + try { - String md5; - File srcPicture = null; - String picturePath = picture.getPicturePath(); - // 判断图片来源 - if(PictureSourceContent.WEB_URL == picture.getPictureSource() ){ - md5 = MD5Digester.encodeHexStr(picturePath); - }else { - // 绝对路径图片 - srcPicture = new File(picturePath); - // 绝对路径下图片不存在则不执行 - if(!srcPicture.exists()){ - return; - } - md5 = MD5Digester.digestMD5(srcPicture); - } Integer drawingSequence = sheet.getWorkbook().getImageCache().get(md5); // 已存在的图片 if (Objects.nonNull(drawingSequence)) { @@ -77,27 +79,65 @@ public class DrawingXmlRelsHandler implements InvocationHandler { } File media = sheet.getSheetContext().getRepositoryHolder().get(Alias.MEDIA).getFile(); drawingSequence = sheet.getDrawingSequence(); - File destPicture = new File(media, "image"+ drawingSequence + ".png"); - if(PictureSourceContent.WEB_URL == picture.getPictureSource() ){ - // 下载网络图片到excel资源路径 - HttpUtil.downloadFile(picturePath, destPicture, WorkbookConstant.DOWNLOAD_PICTURE_TIME_OUT); - }else { - // 复制绝对图片到excel资源路径 - FileUtil.copyFile(srcPicture, destPicture); - } + // 获取excel资源图片 + File destPicture = getExcelDestPicture(picture, picturePath, drawingSequence, media); // 输出的图片不存在则跳出 - if(!destPicture.exists()){ + if (!destPicture.exists()) { return; } picture.setRembed(drawingSequence); - RelationShip relationShip = new RelationShip("rId" + drawingSequence, WorkbookConstant.MEDIA_IMAGE_TYPE, "../media/image" + drawingSequence +".png"); + RelationShip relationShip = new RelationShip("rId" + drawingSequence, WorkbookConstant.MEDIA_IMAGE_TYPE, "../media/image" + drawingSequence + ".png"); //先把drawingSequence放入缓存,因为从缓存中获取时设置drawingSequence再+1对应图片。实际图片的drawingSequence不变 sheet.getWorkbook().getImageCache().put(md5, drawingSequence); drawingSequence++; sheet.setDrawingSequence(drawingSequence); target.append(CovertUtil.covert(relationShip)); } catch (Exception e) { - logger.error("图片copy到media目录下异常",e); + logger.error("图片copy到media目录下异常", e); + } + } + + /** + * 获取excel资源图片 + * @param picture + * @param picturePath + * @param drawingSequence + * @param media + * @return + * @throws IOException + */ + private static File getExcelDestPicture(Picture picture, String picturePath, Integer drawingSequence, File media) throws IOException { + File destPicture = new File(media, "image" + drawingSequence + ".png"); + if (PictureSourceContent.WEB_URL == picture.getPictureSource()) { + // 下载网络图片到excel资源路径 + HttpUtil.downloadFile(picturePath, destPicture, WorkbookConstant.DOWNLOAD_PICTURE_TIME_OUT); + } else { + // 绝对路径图片 + File srcPicture = new File(picturePath); + // 复制绝对图片到excel资源路径 + FileUtil.copyFile(srcPicture, destPicture); + } + return destPicture; + } + + /** + * 根据图片来源获取文件md5值 + * + * @param pictureSource + * @param picturePath + * @return + * @throws FileNotFoundException + */ + private static String getMd5BySource(int pictureSource, String picturePath) throws FileNotFoundException { + String md5; + // 判断图片来源 + if (PictureSourceContent.WEB_URL == pictureSource) { + md5 = MD5Digester.digestMD5(picturePath); + } else { + // 绝对路径图片 + File srcPicture = new File(picturePath); + md5 = MD5Digester.digestMD5(srcPicture); } + return md5; } } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java b/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java index 4754749..9454d84 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java @@ -8,6 +8,11 @@ package com.ibiz.excel.picture.support.model; */ public class CellStyle { + /** + * 行号 + */ + private int rowNumber; + /** * 默认已有fill样式 * 与对应{@link com.ibiz.excel.picture.support.module.Styles} @@ -83,4 +88,12 @@ public class CellStyle { public void setFgColorRgb(String fgColorRgb) { this.fgColorRgb = fgColorRgb; } + + public int getRowNumber() { + return rowNumber; + } + + public void setRowNumber(int rowNumber) { + this.rowNumber = rowNumber; + } } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Picture.java b/src/main/java/com/ibiz/excel/picture/support/model/Picture.java index cda4e7b..3af76f6 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Picture.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Picture.java @@ -1,6 +1,10 @@ package com.ibiz.excel.picture.support.model; +import com.ibiz.excel.picture.support.constants.PictureSourceContent; import com.ibiz.excel.picture.support.constants.WorkbookConstant; +import com.ibiz.excel.picture.support.util.StringUtils; + +import java.util.Objects; /** * @auther 喻场 @@ -12,7 +16,7 @@ public class Picture { private int fromRow; //图片起始行 Row.rowNumber private int toCol; //图片结束列 Cell.cellNumber + 1 private int toRow; //图片结束行 Row.rowNumber - /**当前系统中图片的绝对路径*/ + /**当前系统中图片的绝对路径 或 url地址*/ private String picturePath; //图片路径 /** @@ -76,6 +80,26 @@ public class Picture { this.pictureSource = pictureSource; } + /** + * 自动设置图片来源 + * @return + */ + public Picture autoPictureSourceByPath(){ + // 来源为0,自动匹配 + try { + if(this.pictureSource == 0 + // 图片路径不为空 + && StringUtils.isNotBlank(this.picturePath) + // 是url + && Objects.equals(this.picturePath.substring(0, 4),"http")){ + this.pictureSource = PictureSourceContent.WEB_URL; + } + }catch (Exception e){ + throw new RuntimeException("错误的图片地址: " + this.picturePath, e); + } + return this; + } + public String getPicturePath() { return picturePath; } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java index 8981710..fae44db 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java @@ -78,33 +78,6 @@ public class Sheet { */ private Map columnHelperMap = new HashMap<>(); - /** - * 默认已有fill样式 - * 与对应{@link com.ibiz.excel.picture.support.module.Styles} - */ - private int fillId = 33; - - /** - * 默认已有cellStyles样式 - */ - private int s = 4; - - public int getFillId() { - return fillId; - } - - public void setFillId(int fillId) { - this.fillId = fillId; - } - - public int getS() { - return s; - } - - public void setS(int s) { - this.s = s; - } - public List getPictures() { return pictures; } @@ -331,7 +304,12 @@ public class Sheet { // 计算单元格宽度根据单元格中值的数量 calculateColumnWidth(cellNumber, width, values.size()); //增加图片 - values.forEach(v -> pictures.add(new Picture(row.getRowNumber(), cellNumber, width, height, v, model.pictureSource()))); + values.forEach(val -> + pictures.add( + new Picture(row.getRowNumber(), cellNumber, width, height, val, model.pictureSource()) + // 自动设置图片来源 + .autoPictureSourceByPath() + )); } private List getValues(Object value) { diff --git a/src/main/java/com/ibiz/excel/picture/support/util/MD5Digester.java b/src/main/java/com/ibiz/excel/picture/support/util/MD5Digester.java index 1449704..0b5ccd4 100644 --- a/src/main/java/com/ibiz/excel/picture/support/util/MD5Digester.java +++ b/src/main/java/com/ibiz/excel/picture/support/util/MD5Digester.java @@ -1,12 +1,12 @@ package com.ibiz.excel.picture.support.util; import java.io.*; -import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; /** * 文件流md5 + * * @author yc 创建时间:2018年1月24日 下午4:50:35 */ public class MD5Digester { @@ -14,22 +14,26 @@ public class MD5Digester { * digital */ public static final char[] DIGITAL = "0123456789ABCDEF".toCharArray(); + /** * MD5Digester */ - private MD5Digester() {} + private MD5Digester() { + } public static String digestMD5(File file) throws FileNotFoundException { FileInputStream fis = new FileInputStream(file); return digestMD5(fis); } + /** * 文件流md5 + * * @param inputStream InputStream - * @return md5 + * @return md5 */ public static String digestMD5(InputStream inputStream) { - try(InputStream is = inputStream) { + try (InputStream is = inputStream) { MessageDigest digest = MessageDigest.getInstance("MD5"); byte[] buffer = new byte[8192]; int len; @@ -46,6 +50,7 @@ public class MD5Digester { /** * encodeHexStr + * * @param bytes bytes * @return String */ @@ -61,12 +66,27 @@ public class MD5Digester { return new String(result); } - public static String encodeHexStr(String str) { - if (str == null) { - return null; + /** + * 获取字符串的摘要 md5值 + * + * @param data + * @return + */ + public static String digestMD5(String data) { + MessageDigest message; + try { + message = MessageDigest.getInstance("MD5"); + message.update(data.getBytes()); + byte[] b = message.digest(); + return encodeHexStr(b); + } catch (Exception e) { + e.printStackTrace(); + throw new RuntimeException(e); } - byte[] bytes = str.getBytes(StandardCharsets.UTF_8); - return encodeHexStr(bytes); + } + + public static void main(String[] args) { + System.out.println(digestMD5("12312erdhhjfdkti5745468587ry87r4tuy87rt4u8rt44u36346")); } } diff --git a/src/test/java/com/ibiz/excel/picture/support/User.java b/src/test/java/com/ibiz/excel/picture/support/User.java index 14f48cd..3956c77 100644 --- a/src/test/java/com/ibiz/excel/picture/support/User.java +++ b/src/test/java/com/ibiz/excel/picture/support/User.java @@ -10,7 +10,7 @@ import java.util.StringJoiner; */ public class User { - @ExportModel(title = "姓名", mergeMaster = true) + @ExportModel(sort = 0,title = "姓名", mergeMaster = true) private String name; @ExportModel(sort = 1, title = "年龄") private Integer age; diff --git a/src/test/java/com/ibiz/excel/picture/support/UserPicture.java b/src/test/java/com/ibiz/excel/picture/support/UserPicture.java index 4ea2fd4..23388e0 100644 --- a/src/test/java/com/ibiz/excel/picture/support/UserPicture.java +++ b/src/test/java/com/ibiz/excel/picture/support/UserPicture.java @@ -14,7 +14,7 @@ public class UserPicture { public UserPicture() { } - @ExportModel(title = "姓名") + @ExportModel(sort = 0, title = "姓名") private String name; @ExportModel(sort = 1, title = "年龄") private Integer age; @@ -26,6 +26,8 @@ public class UserPicture { private String headerPicture; @ExportModel(sort = 5, isPicture = true, title = "多图片") private List pictures; + @ExportModel(sort = 6, isPicture = true, title = "url图片") + private List urlPictures; public UserPicture(String name, Integer age, String department, String picture) { this.name = name; @@ -81,4 +83,12 @@ public class UserPicture { public void setPictures(List pictures) { this.pictures = pictures; } + + public List getUrlPictures() { + return urlPictures; + } + + public void setUrlPictures(List urlPictures) { + this.urlPictures = urlPictures; + } } diff --git a/src/test/java/com/ibiz/excel/picture/support/common/BaseJunitTest.java b/src/test/java/com/ibiz/excel/picture/support/common/BaseJunitTest.java index bf5b2f1..6b7e44a 100644 --- a/src/test/java/com/ibiz/excel/picture/support/common/BaseJunitTest.java +++ b/src/test/java/com/ibiz/excel/picture/support/common/BaseJunitTest.java @@ -1,5 +1,7 @@ package com.ibiz.excel.picture.support.common; +import cn.hutool.core.io.FileUtil; + import java.io.File; import java.util.ArrayList; import java.util.List; @@ -21,13 +23,19 @@ public class BaseJunitTest { protected final static String IMAGES_PATH = CURRENT_PATH + "images\\"; + // url图片测试集合 protected final static List urls = new ArrayList<>(); + // 本地测试图片数组 + protected final static File[] localTestFiles; + static { urls.add("https://portrait.gitee.com/uploads/avatars/user/552/1657608_mwk719_1641537497.png"); urls.add("https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.jj20.com%2Fup%2Fallimg%2F1114%2F060421091316%2F210604091316-6-1200.jpg&refer=http%3A%2F%2Fimg.jj20.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1644142768&t=82062e20360f72b0fd8d5fd7e2fc9885"); urls.add("https://img2.baidu.com/it/u=121102239,1207969661&fm=253&fmt=auto&app=120&f=JPEG?w=1195&h=500"); urls.add("https://img2.baidu.com/it/u=2602880481,728201544&fm=26&fmt=auto"); + + localTestFiles = FileUtil.ls(IMAGES_PATH); } @@ -50,4 +58,12 @@ public class BaseJunitTest { int index = new Random().nextInt(urls.size()); return urls.get(index); } + + protected static List getUrls(int getCount) { + List list = new ArrayList<>(getCount); + for (int i = 0; i < getCount; i++) { + list.add(getUrl()); + } + return list; + } } diff --git a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java index f6dda39..a6f5013 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java @@ -1,6 +1,5 @@ package com.ibiz.excel.picture.support.example; -import cn.hutool.core.io.FileUtil; import com.ibiz.excel.picture.support.UserPicture; import com.ibiz.excel.picture.support.common.BaseJunitTest; import com.ibiz.excel.picture.support.model.CellStyle; @@ -9,7 +8,6 @@ import com.ibiz.excel.picture.support.model.Workbook; import com.ibiz.excel.picture.support.util.WebUtil; import org.junit.Test; -import java.io.File; import java.util.Random; /** @@ -31,8 +29,6 @@ public class AnnotationPicturesExportExample extends BaseJunitTest { // 给标题行加上背景色,加颜色时,会对字体加粗 CellStyle cellStyle = workBook.createCellStyle(); cellStyle.setFgColorRgb("66cc66"); - // 图片数组 - File[] files = FileUtil.ls(IMAGES_PATH); UserPicture userPicture; for (int r = 0; r < 10; r++) { userPicture = new UserPicture(); @@ -40,8 +36,8 @@ public class AnnotationPicturesExportExample extends BaseJunitTest { userPicture.setName("测试-" + r); userPicture.setPicture(IMG_PATH_1); userPicture.setHeaderPicture(getUrl()); - // 根据图片数组和要获取图片的数量,随机从图片数组中取出若干 - userPicture.setPictures(getPictures(files, new Random().nextInt(5))); + // 根据图片数组和要获取图片的数量,随机从本地测试图片数组中取出若干 + userPicture.setPictures(getPictures(localTestFiles, new Random().nextInt(5))); sheet.createRow(userPicture); // 不设置时,自适应图片的高度 // .setHeight(200); diff --git a/src/test/java/com/ibiz/excel/picture/support/example/UrlPicturesExportExample.java b/src/test/java/com/ibiz/excel/picture/support/example/UrlPicturesExportExample.java new file mode 100644 index 0000000..08b671f --- /dev/null +++ b/src/test/java/com/ibiz/excel/picture/support/example/UrlPicturesExportExample.java @@ -0,0 +1,45 @@ +package com.ibiz.excel.picture.support.example; + +import com.ibiz.excel.picture.support.UserPicture; +import com.ibiz.excel.picture.support.common.BaseJunitTest; +import com.ibiz.excel.picture.support.model.CellStyle; +import com.ibiz.excel.picture.support.model.Sheet; +import com.ibiz.excel.picture.support.model.Workbook; +import com.ibiz.excel.picture.support.util.WebUtil; +import org.junit.Test; + +/** + * url图片导出excel示例 + * + * @author MinWeikai + * @date 2022-01-10 10:08:03 + */ +public class UrlPicturesExportExample extends BaseJunitTest { + + @Test + public void export() { + Workbook workBook = Workbook.getInstance(); + Sheet sheet = workBook.createSheet("测试"); + + // 给标题行加上背景色,加颜色时,会对字体加粗 + CellStyle cellStyle = workBook.createCellStyle(); + cellStyle.setFgColorRgb("66cc66"); + UserPicture userPicture; + for (int r = 0; r < 10; r++) { + userPicture = new UserPicture(); + userPicture.setAge(15); + userPicture.setName("测试-" + r); + userPicture.setPicture(IMG_PATH_1); + userPicture.setHeaderPicture(getUrl()); + // 根据图片数组和要获取图片的数量,随机从url图片测试集合中取出若干 + userPicture.setUrlPictures(getUrls(5)); + sheet.createRow(userPicture); + // 对标题行添加上样式 + if (r == 0) { + sheet.getRow(0).setCellStyle(cellStyle); + } + } + WebUtil.writeExcelTest(workBook, "url图片导出excel示例".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), TEMP_PATH); + } + +} diff --git a/src/test/java/com/ibiz/excel/picture/support/util/MD5DigesterTest.java b/src/test/java/com/ibiz/excel/picture/support/util/MD5DigesterTest.java deleted file mode 100644 index 6803d89..0000000 --- a/src/test/java/com/ibiz/excel/picture/support/util/MD5DigesterTest.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.ibiz.excel.picture.support.util; - -import java.io.File; - -/** - * @author MinWeikai - * @date 2022/1/7 17:26 - */ -public class MD5DigesterTest { - - public static void main(String[] args) { - File destFilePath = new File("E:\\test\\img\\0.jpg"); - String md5 = null; - md5 = MD5Digester.encodeHexStr("destFilePath"); - System.out.println(md5); - } -} \ No newline at end of file -- Gitee From 8fe27fc26af743dd9d1380c91201f07e0f1f510f Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Mon, 10 Jan 2022 16:04:02 +0800 Subject: [PATCH 070/161] =?UTF-8?q?update=20CellStyle=E6=A0=B7=E5=BC=8F?= =?UTF-8?q?=E7=9A=84=E4=BD=BF=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../picture/support/flush/Sheet1Handler.java | 9 +- .../picture/support/flush/StylesIndex.java | 42 ++++ .../picture/support/model/CellStyle.java | 182 +++++++++--------- .../ibiz/excel/picture/support/model/Row.java | 2 +- .../excel/picture/support/model/Sheet.java | 39 +++- .../excel/picture/support/model/Workbook.java | 13 -- .../AnnotationPictureExportExample.java | 1 - .../AnnotationPicturesExportExample.java | 8 +- .../support/example/EasyUseExample1.java | 86 --------- .../support/example/EasyUseExample2.java | 90 --------- .../support/example/EasyUseExample3.java | 102 ---------- .../support/example/EasyUseExample4.java | 9 +- .../example/UrlPicturesExportExample.java | 8 +- .../SimulateRealBusinessExportExample.java | 40 +--- 14 files changed, 194 insertions(+), 437 deletions(-) create mode 100644 src/main/java/com/ibiz/excel/picture/support/flush/StylesIndex.java delete mode 100644 src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample1.java delete mode 100644 src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample2.java delete mode 100644 src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample3.java diff --git a/src/main/java/com/ibiz/excel/picture/support/flush/Sheet1Handler.java b/src/main/java/com/ibiz/excel/picture/support/flush/Sheet1Handler.java index af7179a..b9abe1e 100644 --- a/src/main/java/com/ibiz/excel/picture/support/flush/Sheet1Handler.java +++ b/src/main/java/com/ibiz/excel/picture/support/flush/Sheet1Handler.java @@ -17,7 +17,7 @@ import java.util.Set; * @auther 喻场 * @date 2020/7/618:33 */ -public class Sheet1Handler implements InvocationHandler { +public class Sheet1Handler extends StylesIndex implements InvocationHandler { private IRepository target; public Sheet1Handler(IRepository proxy) { @@ -154,10 +154,15 @@ public class Sheet1Handler implements InvocationHandler { //customHeight=1 使用自定义高度 content.append(""); + CellStyle cellStyle = row.getCellStyle(); + if(cellStyle != null){ + // 设置cellStyle样式下标 + this.addCellStyle(cellStyle); + } row.getCells().forEach(c -> content.append("") .append("") diff --git a/src/main/java/com/ibiz/excel/picture/support/flush/StylesIndex.java b/src/main/java/com/ibiz/excel/picture/support/flush/StylesIndex.java new file mode 100644 index 0000000..fbcbcce --- /dev/null +++ b/src/main/java/com/ibiz/excel/picture/support/flush/StylesIndex.java @@ -0,0 +1,42 @@ +package com.ibiz.excel.picture.support.flush; + +import com.ibiz.excel.picture.support.model.CellStyle; + +/** + * 样式下标取值 + * + * @author MinWeikai + * @date 2022/1/10 15:31 + */ +public class StylesIndex { + + /** + * 默认已有fill样式 + * 与对应{@link com.ibiz.excel.picture.support.module.Styles} + */ + private int fillId = 33; + + /** + * 默认已有cellStyles样式 + */ + private int s = 4; + + /** + * 设置下标样式 + * + * @param cellStyle + */ + protected void addCellStyle(CellStyle cellStyle) { + this.addIndex(); + cellStyle.setFillId(fillId); + cellStyle.setS(s); + } + + protected void addIndex() { + // fillId+1,生成下一个编号 + fillId = fillId + 1; + s = s + 1; + } + + +} diff --git a/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java b/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java index 9454d84..00f2de0 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java @@ -8,92 +8,98 @@ package com.ibiz.excel.picture.support.model; */ public class CellStyle { - /** - * 行号 - */ - private int rowNumber; - - /** - * 默认已有fill样式 - * 与对应{@link com.ibiz.excel.picture.support.module.Styles} - */ - private int fillId = 33; - - /** - * 默认已有cellStyles样式 - */ - private int s = 4; - - /** - * fgColor rgb颜色 - * RGB网页颜色在线取色器 https://link.fobshanghai.com/rgbcolor.htm - */ - private String fgColorRgb; - - /** - * 样式 - */ - private StyleEnum styleEnum; - - public CellStyle() { - } - - /** - * 创建单元格前景色 - * @param fgColorRgb - */ - public CellStyle(String fgColorRgb) { - // fillId+1,生成下一个编号 - fillId = fillId + 1; - s = s + 1; - this.fgColorRgb = fgColorRgb; - } - - public CellStyle(StyleEnum styleEnum) { - this.styleEnum = styleEnum; - this.fillId = styleEnum.getFillId(); - } - - public CellStyle(CellStyle cellStyle) { - // 生成下标 - cellStyle = cellStyle.addIndex(); - this.fillId = cellStyle.fillId; - this.s = cellStyle.s; - this.fgColorRgb = cellStyle.fgColorRgb; - } - - public CellStyle addIndex() { - // fillId+1,生成下一个编号 - fillId = fillId + 1; - s = s + 1; - return this; - } - - public int getFillId() { - return fillId; - } - - public int getS() { - return s; - } - - public String getFgColorRgb() { - return fgColorRgb; - } - - /** - * fgColor rgb颜色 - * RGB网页颜色在线取色器 https://link.fobshanghai.com/rgbcolor.htm - */ - public void setFgColorRgb(String fgColorRgb) { - this.fgColorRgb = fgColorRgb; - } - - public int getRowNumber() { - return rowNumber; - } - - public void setRowNumber(int rowNumber) { - this.rowNumber = rowNumber; - } + /** + * 行号 + */ + private int rowNumber; + + /** + * 默认已有fill样式 + * 与对应{@link com.ibiz.excel.picture.support.module.Styles} + */ + private int fillId = 33; + + /** + * 默认已有cellStyles样式 + */ + private int s = 4; + + /** + * fgColor rgb颜色 + * RGB网页颜色在线取色器 https://link.fobshanghai.com/rgbcolor.htm + */ + private String fgColorRgb; + + /** + * 样式 + */ + private StyleEnum styleEnum; + + public CellStyle() { + } + + /** + * 创建单元格前景色 + * + * @param fgColorRgb + */ + public CellStyle(String fgColorRgb) { + this.fgColorRgb = fgColorRgb; + } + + /** + * 根据行号设置颜色 + * @param rowNumber + * @param fgColorRgb + */ + public CellStyle(int rowNumber, String fgColorRgb) { + this.rowNumber = rowNumber; + this.fgColorRgb = fgColorRgb; + } + + public CellStyle(StyleEnum styleEnum) { + this.styleEnum = styleEnum; + this.fillId = styleEnum.getFillId(); + } + + public CellStyle(CellStyle cellStyle) { + this.fgColorRgb = cellStyle.fgColorRgb; + } + + public int getFillId() { + return fillId; + } + + public int getS() { + return s; + } + + public String getFgColorRgb() { + return fgColorRgb; + } + + /** + * fgColor rgb颜色 + * RGB网页颜色在线取色器 https://link.fobshanghai.com/rgbcolor.htm + */ + public void setFgColorRgb(String fgColorRgb) { + this.fgColorRgb = fgColorRgb; + } + + public int getRowNumber() { + return rowNumber; + } + + public void setRowNumber(int rowNumber) { + this.rowNumber = rowNumber; + } + + + public void setFillId(int fillId) { + this.fillId = fillId; + } + + public void setS(int s) { + this.s = s; + } } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Row.java b/src/main/java/com/ibiz/excel/picture/support/model/Row.java index 413c69a..fbb9ef0 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Row.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Row.java @@ -84,7 +84,7 @@ public class Row { * @return */ public Row setCellStyle(CellStyle cellStyle) { - this.cellStyle = new CellStyle(cellStyle); + this.cellStyle = cellStyle; return this; } } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java index fae44db..7bdaa75 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java @@ -78,6 +78,11 @@ public class Sheet { */ private Map columnHelperMap = new HashMap<>(); + /** + * 预设样式 + */ + private final Map cellStyleMap = new HashMap<>(); + public List getPictures() { return pictures; } @@ -353,9 +358,20 @@ public class Sheet { Row createRow(T t) { if (!hasWriteHead) { - create(t, true); + createRowAndCellStyle(t, true); } - return create(t, false); + return createRowAndCellStyle(t, false); + } + + private Row createRowAndCellStyle(T t, final boolean isHead) { + // 创建行数据 + Row row = create(t, isHead); + // 获取样式 + CellStyle cellStyle = cellStyleMap.get(row.getRowNumber()); + if(cellStyle != null){ + row.setCellStyle(cellStyle); + } + return row; } Row createRow(int rowNumber) { @@ -405,4 +421,23 @@ public class Sheet { public Map getColumnHelperMap() { return columnHelperMap; } + + /** + * 批量添加样式 + * + * @param cellStyles + */ + public void addCellStyle(List cellStyles) { + cellStyles.forEach(cellStyle-> this.cellStyleMap.put(cellStyle.getRowNumber(), cellStyle)); + } + + /** + * 添加样式 + * @param cellStyle + * @return + */ + public Sheet addCellStyle(CellStyle cellStyle) { + this.cellStyleMap.put(cellStyle.getRowNumber(), cellStyle); + return this; + } } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Workbook.java b/src/main/java/com/ibiz/excel/picture/support/model/Workbook.java index 26020db..72dd4b7 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Workbook.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Workbook.java @@ -51,8 +51,6 @@ public class Workbook { */ private Map imageCache = new HashMap<>(); - private CellStyle cellStyle; - public Map getImageCache() { return imageCache; } @@ -130,15 +128,4 @@ public class Workbook { throw new RuntimeException("workbook is closed"); } } - - /** - * 创建工作簿样式 - * - * @return - */ - public CellStyle createCellStyle() { - CellStyle cellStyle = new CellStyle(); - this.cellStyle = cellStyle; - return cellStyle; - } } diff --git a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPictureExportExample.java b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPictureExportExample.java index 7a9fca4..16504a7 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPictureExportExample.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPictureExportExample.java @@ -32,7 +32,6 @@ public class AnnotationPictureExportExample { userPicture.setAge(15); userPicture.setName("测试-" + r); userPicture.setPicture(IMG_PATH_1); - userPicture.setHeaderPicture(IMG_PATH_2); // 创建行数据在excel中 sheet.createRow(userPicture); } diff --git a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java index a6f5013..1504081 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java @@ -25,10 +25,6 @@ public class AnnotationPicturesExportExample extends BaseJunitTest { // 需要在创建行前预设宽度 // sheet.setColumnWidth(6, 100); - - // 给标题行加上背景色,加颜色时,会对字体加粗 - CellStyle cellStyle = workBook.createCellStyle(); - cellStyle.setFgColorRgb("66cc66"); UserPicture userPicture; for (int r = 0; r < 10; r++) { userPicture = new UserPicture(); @@ -41,9 +37,9 @@ public class AnnotationPicturesExportExample extends BaseJunitTest { sheet.createRow(userPicture); // 不设置时,自适应图片的高度 // .setHeight(200); - // 对标题行添加上样式 + // 给标题行加上背景色,加颜色时,会对字体加粗 if(r == 0){ - sheet.getRow(0).setCellStyle(cellStyle); + sheet.getRow(0).setCellStyle(new CellStyle("66cc66")); } } WebUtil.writeExcelTest(workBook, "注解导出图片集合示例".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), TEMP_PATH); diff --git a/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample1.java b/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample1.java deleted file mode 100644 index ce3d64f..0000000 --- a/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample1.java +++ /dev/null @@ -1,86 +0,0 @@ -package com.ibiz.excel.picture.support.example; - -import cn.hutool.core.io.FileUtil; -import com.ibiz.excel.picture.support.constants.WorkbookConstant; -import com.ibiz.excel.picture.support.model.*; - -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.UUID; - -/** - * 简化设置EasyUseExample1 - * 1. 需要文本列表信息 - * 2. 需要单元格填充单个图片 - * - * @author MinWeikai - * @date 2021-02-07 16:47:17 - */ -public class EasyUseExample1 { - static final String CURRENT_PATH = "E:\\test\\"; - - private final static String IMG_PATH = CURRENT_PATH + "img\\"; - - private final static String IMG_PATH_1 = IMG_PATH + "1.jpg"; - - - public static void main(String[] args) throws IOException { - Date start = new Date(); - Workbook workBook = Workbook.getInstance(1); - Sheet sheet = workBook.createSheet("测试"); - - // 第一行放标题 - String[] excelName = {"文本1", "文本2", "图片1", "图片2", "图片3"}; - //要进行合并的列 - sheet.getMergeCells().add(new MergeCell(0, 0, 0, excelName.length - 1)); - Row row = sheet.createRow(1) - //配置该行颜色,现在默认只有绿色 - .setCellStyle(new CellStyle(StyleEnum.GREEN_B)); - List cells = new ArrayList<>(); - for (int i = 0; i < excelName.length; i++) { - cells.add(new Cell(i).setValue(excelName[i])); - } - row.autoRowCells(cells); - - // 第二行放内容 - row = sheet.createRow(2); - List pictures = sheet.getPictures(); - cells = new ArrayList<>(); - for (int i = 0; i < excelName.length; i++) { - if (i < 2) { - cells.add(new Cell(i).setValue("文本")); - } else { - //有图片的行,行高设置为100 - row.setHeight(WorkbookConstant.PICTURE_ROW_HEIGHT); - //增加图片 - pictures.add(new Picture(row.getRowNumber(), i, IMG_PATH_1)); - } - } - row.autoRowCells(cells); - - File file = createFile(); - BufferedOutputStream os = FileUtil.getOutputStream(file); - workBook.write(os); - workBook.close(); - Date end = new Date(); - System.out.println("file capital :" + (file.length() / 1024 / 1024) + "M name :" + file.getName()); - System.out.println("file cost time :" + (end.getTime() - start.getTime())); - os.close(); - } - - - private static File createFile() { - String dir = CURRENT_PATH + "excel/"; - File file = new File(dir); - if (!file.exists()) { - file.mkdir(); - } - String name = CURRENT_PATH + "excel/" + UUID.randomUUID() + ".xlsx"; - return new File(name); - } - -} diff --git a/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample2.java b/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample2.java deleted file mode 100644 index 95c112d..0000000 --- a/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample2.java +++ /dev/null @@ -1,90 +0,0 @@ -package com.ibiz.excel.picture.support.example; - -import cn.hutool.core.io.FileUtil; -import com.ibiz.excel.picture.support.constants.WorkbookConstant; -import com.ibiz.excel.picture.support.model.*; - -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.IOException; -import java.util.*; - -/** - * 简化设置EasyUseExample2 - * 1. 需要文本列表信息 - * 2. 需要单元格填充单个图片 - * 3. 需要表头 - * - * @author MinWeikai - * @date 2021-02-07 16:47:17 - */ -public class EasyUseExample2 { - static final String CURRENT_PATH = "E:\\test\\"; - - private final static String IMG_PATH = CURRENT_PATH + "img\\"; - - private final static String IMG_PATH_1 = IMG_PATH + "1.jpg"; - - - public static void main(String[] args) throws IOException { - Date start = new Date(); - Workbook workBook = Workbook.getInstance(1); - Sheet sheet = workBook.createSheet("测试"); - - // 第一行表头 - Row row = sheet.createRow(0) - //字体20 - .setCellStyle(new CellStyle(StyleEnum.F20)); - row.autoRowCells(Collections.singletonList(new Cell(0).setValue("表头"))); - - // 第二行放标题 - String[] excelName = {"文本1", "文本2", "图片1", "图片2", "图片3"}; - //要进行合并的列 - sheet.getMergeCells().add(new MergeCell(0, 0, 0, excelName.length - 1)); - row = sheet.createRow(1) - //配置该行颜色,现在默认只有绿色 - .setCellStyle(new CellStyle(StyleEnum.GREEN_B)); - List cells = new ArrayList<>(); - for (int i = 0; i < excelName.length; i++) { - cells.add(new Cell(i).setValue(excelName[i])); - } - row.autoRowCells(cells); - - // 第三行放内容 - row = sheet.createRow(2); - List pictures = sheet.getPictures(); - cells = new ArrayList<>(); - for (int i = 0; i < excelName.length; i++) { - if (i < 2) { - cells.add(new Cell(i).setValue("文本")); - } else { - //有图片的行,行高设置为100 - row.setHeight(WorkbookConstant.PICTURE_ROW_HEIGHT); - //增加图片 - pictures.add(new Picture(row.getRowNumber(), i, IMG_PATH_1)); - } - } - row.autoRowCells(cells); - - File file = createFile(); - BufferedOutputStream os = FileUtil.getOutputStream(file); - workBook.write(os); - workBook.close(); - Date end = new Date(); - System.out.println("file capital :" + (file.length() / 1024 / 1024) + "M name :" + file.getName()); - System.out.println("file cost time :" + (end.getTime() - start.getTime())); - os.close(); - } - - - private static File createFile() { - String dir = CURRENT_PATH + "excel/"; - File file = new File(dir); - if (!file.exists()) { - file.mkdir(); - } - String name = CURRENT_PATH + "excel/" + UUID.randomUUID() + ".xlsx"; - return new File(name); - } - -} diff --git a/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample3.java b/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample3.java deleted file mode 100644 index a0a9667..0000000 --- a/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample3.java +++ /dev/null @@ -1,102 +0,0 @@ -package com.ibiz.excel.picture.support.example; - -import cn.hutool.core.io.FileUtil; -import com.ibiz.excel.picture.support.model.*; - -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.IOException; -import java.util.*; - -/** - * 简化设置EasyUseExample3 - * 1. 需要文本列表信息 - * 2. 需要单元格填充多张图片 - * 3. 需要表头 - * - * @author MinWeikai - * @date 2021-02-07 16:47:17 - */ -public class EasyUseExample3 { - static final String CURRENT_PATH = "E:\\test\\"; - - private final static String IMG_PATH = CURRENT_PATH + "img\\"; - - private final static String IMG_PATH_1 = IMG_PATH + "1.jpg"; - private final static String IMG_PATH_2 = IMG_PATH + "2.jpg"; - - - public static void main(String[] args) throws IOException { - Date start = new Date(); - Workbook workBook = Workbook.getInstance(1); - Sheet sheet = workBook.createSheet("测试"); - - // 需要在创建行前预设宽度 - sheet.setColumnWidth(1, 10) - .setColumnWidth(3, 50) - .setColumnWidth(4, 50) - .setColumnWidth(5, 50); - - // 第一行表头 - Row row = sheet.createRow(0) - //字体20 - .setCellStyle(new CellStyle(StyleEnum.F20)); - row.autoRowCells(Collections.singletonList(new Cell(0).setValue("表头"))); - - // 第二行放标题 - String[] excelName = {"文本1", "文本2", "图片1", "图片2", "图片3"}; - //要进行合并的列 - sheet.getMergeCells().add(new MergeCell(0, 0, 0, excelName.length - 1)); - row = sheet.createRow(1) - //配置该行颜色,现在默认只有绿色 - .setCellStyle(new CellStyle(StyleEnum.GREEN_B)); - List cells = new ArrayList<>(); - for (int i = 0; i < excelName.length; i++) { - cells.add(new Cell(i).setValue(excelName[i])); - } - row.autoRowCells(cells); - - // 第三行放内容 - row = sheet.createRow(2); - List pictures = sheet.getPictures(); - cells = new ArrayList<>(); - for (int i = 0; i < excelName.length; i++) { - if (i < 2) { - cells.add(new Cell(i).setValue("文本")); - } else { - //有图片的行,行高设置为100 - row.setHeight(80); - //每个单元格增加一个图片 - //pictures.add(new Picture(i, row.getRowNumber(),1000000 , IMG_PATH_1)); - - //在第二列添加多张图片 - pictures.add(new Picture(row.getRowNumber(),2, 1000000, IMG_PATH_1)); - //在第三列添加多张图片 - pictures.add(new Picture(row.getRowNumber(), 3, 1000000, IMG_PATH_2)); - pictures.add(new Picture(row.getRowNumber(), 4, 1000000, IMG_PATH_1)); - } - } - row.autoRowCells(cells); - - File file = createFile(); - BufferedOutputStream os = FileUtil.getOutputStream(file); - workBook.write(os); - workBook.close(); - Date end = new Date(); - System.out.println("file capital :" + (file.length() / 1024 / 1024) + "M name :" + file.getName()); - System.out.println("file cost time :" + (end.getTime() - start.getTime())); - os.close(); - } - - - private static File createFile() { - String dir = CURRENT_PATH + "excel/"; - File file = new File(dir); - if (!file.exists()) { - file.mkdir(); - } - String name = CURRENT_PATH + "excel/" + UUID.randomUUID() + ".xlsx"; - return new File(name); - } - -} diff --git a/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample4.java b/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample4.java index 306042e..c8553e4 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample4.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample4.java @@ -32,10 +32,6 @@ public class EasyUseExample4 { Workbook workBook = Workbook.getInstance(100); Sheet sheet = workBook.createSheet("测试"); - CellStyle cellStyle = workBook.createCellStyle(); - - cellStyle.setFgColorRgb("cc3300"); - // 需要在创建行前预设宽度 // 序号宽度 有时需要单独设置序号宽度窄一点 sheet.setColumnWidth(1, 5) @@ -43,7 +39,7 @@ public class EasyUseExample4 { .setColumnWidth(3, 50); // 第一行表头 - Row row = sheet.createRow(0).setCellStyle(cellStyle); + Row row = sheet.createRow(0).setCellStyle(new CellStyle("cc3300")); row.autoRowCells(Collections.singletonList(new Cell(0).setValue("表头"))); // 第二行放标题 @@ -51,8 +47,7 @@ public class EasyUseExample4 { //要进行合并的列 sheet.getMergeCells().add(new MergeCell(0, 0, 0, excelName.length - 1)); - cellStyle.setFgColorRgb("996699"); - row = sheet.createRow(1).setCellStyle(cellStyle); + row = sheet.createRow(1).setCellStyle(new CellStyle("996699")); List cells = new ArrayList<>(); for (int i = 0; i < excelName.length; i++) { cells.add(new Cell(i).setValue(excelName[i])); diff --git a/src/test/java/com/ibiz/excel/picture/support/example/UrlPicturesExportExample.java b/src/test/java/com/ibiz/excel/picture/support/example/UrlPicturesExportExample.java index 08b671f..1398df4 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/UrlPicturesExportExample.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/UrlPicturesExportExample.java @@ -20,10 +20,8 @@ public class UrlPicturesExportExample extends BaseJunitTest { public void export() { Workbook workBook = Workbook.getInstance(); Sheet sheet = workBook.createSheet("测试"); - // 给标题行加上背景色,加颜色时,会对字体加粗 - CellStyle cellStyle = workBook.createCellStyle(); - cellStyle.setFgColorRgb("66cc66"); + sheet.addCellStyle(new CellStyle(0, "66cc66")); UserPicture userPicture; for (int r = 0; r < 10; r++) { userPicture = new UserPicture(); @@ -34,10 +32,6 @@ public class UrlPicturesExportExample extends BaseJunitTest { // 根据图片数组和要获取图片的数量,随机从url图片测试集合中取出若干 userPicture.setUrlPictures(getUrls(5)); sheet.createRow(userPicture); - // 对标题行添加上样式 - if (r == 0) { - sheet.getRow(0).setCellStyle(cellStyle); - } } WebUtil.writeExcelTest(workBook, "url图片导出excel示例".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), TEMP_PATH); } diff --git a/src/test/java/com/ibiz/excel/picture/support/simulation/SimulateRealBusinessExportExample.java b/src/test/java/com/ibiz/excel/picture/support/simulation/SimulateRealBusinessExportExample.java index 93b6fe8..374f737 100644 --- a/src/test/java/com/ibiz/excel/picture/support/simulation/SimulateRealBusinessExportExample.java +++ b/src/test/java/com/ibiz/excel/picture/support/simulation/SimulateRealBusinessExportExample.java @@ -1,16 +1,13 @@ package com.ibiz.excel.picture.support.simulation; -import cn.hutool.core.io.FileUtil; import com.ibiz.excel.picture.support.UserPicture; +import com.ibiz.excel.picture.support.common.BaseJunitTest; import com.ibiz.excel.picture.support.model.CellStyle; import com.ibiz.excel.picture.support.model.Sheet; import com.ibiz.excel.picture.support.model.Workbook; import com.ibiz.excel.picture.support.util.WebUtil; +import org.junit.Test; -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; import java.util.Random; /** @@ -19,7 +16,7 @@ import java.util.Random; * @author MinWeikai * @date 2021-12-22 15:36:46 */ -public class SimulateRealBusinessExportExample { +public class SimulateRealBusinessExportExample extends BaseJunitTest { static final String CURRENT_PATH = "E:\\test\\"; private static final String TEMP_PATH = CURRENT_PATH + "excel\\"; @@ -31,15 +28,10 @@ public class SimulateRealBusinessExportExample { private final static String IMAGES_PATH = CURRENT_PATH + "images\\"; - public static void main(String[] args) throws IOException { + @Test + public void export() { Workbook workBook = Workbook.getInstance(50); Sheet sheet = workBook.createSheet("测试"); - - // 给标题行加上背景色,加颜色时,会对字体加粗 - CellStyle cellStyle = workBook.createCellStyle(); - cellStyle.setFgColorRgb("66cc66"); - // 图片数组 - File[] files = FileUtil.ls(IMAGES_PATH); UserPicture userPicture; for (int r = 0; r < 101; r++) { userPicture = new UserPicture(); @@ -52,31 +44,15 @@ public class SimulateRealBusinessExportExample { userPicture.setHeaderPicture(IMG_PATH_2); if(new Random().nextInt(10) > 5){ // 模拟场景2. 在业务数据集合中,有些数据没有图片对应的图片集合,没有则不设置值 - userPicture.setPictures(getPictures(files, new Random().nextInt(10))); + userPicture.setPictures(getPictures(localTestFiles, new Random().nextInt(10))); } sheet.createRow(userPicture); - // 对标题行添加上样式 + // 给标题行加上背景色,加颜色时,会对字体加粗 if (r == 0) { - sheet.getRow(r).setCellStyle(cellStyle); + sheet.getRow(r).setCellStyle(new CellStyle("66cc66")); } } WebUtil.writeExcelTest(workBook, "模拟真实业务场景导出示例".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), TEMP_PATH); } - /** - * 根据图片数组和要获取图片的数量,随机从图片数组中取出若干 - * - * @param files 图片数组 - * @param getCount 获取图片的数量 - * @return - */ - private static List getPictures(File[] files, int getCount) { - List list = new ArrayList<>(getCount); - for (int i = 0; i < getCount; i++) { - int index = new Random().nextInt(files.length); - list.add(files[index].getAbsolutePath()); - } - return list; - } - } -- Gitee From 89f0cf311eb93f825f3bf7ebbff7db2c8a367d21 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Mon, 10 Jan 2022 16:21:35 +0800 Subject: [PATCH 071/161] =?UTF-8?q?update=20=E6=B5=8B=E8=AF=95=E6=96=B9?= =?UTF-8?q?=E6=B3=95=E5=91=BD=E5=90=8D=E5=92=8C=E7=89=88=E6=9C=AC=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 11 ++++++++--- .../ibiz/excel/picture/support/UserPicture.java | 4 ++-- .../example/AnnotationPictureExportExample.java | 1 - ...tExample.java => ExportExample_20220110.java} | 16 +++++++++++----- 4 files changed, 21 insertions(+), 11 deletions(-) rename src/test/java/com/ibiz/excel/picture/support/example/{UrlPicturesExportExample.java => ExportExample_20220110.java} (66%) diff --git a/README.md b/README.md index fb9d6b7..7a949e2 100644 --- a/README.md +++ b/README.md @@ -31,24 +31,29 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, 1. ### Maven导入 - 在项目的pom.xml的dependencies中加入以下内容: + 在项目的pom.xml的dependencies中加入以下内容: 点击查看[最新版本 ${excel-x.version}](https://search.maven.org/artifact/top.minwk/excel-x) ```xml top.minwk excel-x - 2.0.0 + ${excel-x.version} ``` 2. ### 示例 - - [excel含图片导出demo地址](https://gitee.com/mwk719/excel-batch-picture-support/tree/dev/src/test/java/com/ibiz/excel/picture/support/example) + - [excel含图片导出demo地址](https://gitee.com/mwk719/excel-batch-picture-support/tree/dev/src/test/java/com/ibiz/excel/picture/support/example),具体使用以后缀最新日期为准,其他示例仅供测试 - [微云-6767张图片共800mb资源.rar 可用于测试](https://minwk.top/big-size-img/) - [项目中导出下载excel使用示例](https://gitee.com/mwk719/spring-learn/blob/master/src/main/java/com/mwk/external/controller/ExcelController.java) 3. ### 版本更迭 + #### 2.1.0(2022.01.14) + + - 添加导出网络链接图片到excel中 + - 修改CellStyle样式的使用 + #### 2.0.0(2021.12.30) - [添加用户可自定义背景色样式](https://gitee.com/mwk719/excel-batch-picture-support/blob/dev/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java) diff --git a/src/test/java/com/ibiz/excel/picture/support/UserPicture.java b/src/test/java/com/ibiz/excel/picture/support/UserPicture.java index 23388e0..9ce134e 100644 --- a/src/test/java/com/ibiz/excel/picture/support/UserPicture.java +++ b/src/test/java/com/ibiz/excel/picture/support/UserPicture.java @@ -24,9 +24,9 @@ public class UserPicture { private String picture; @ExportModel(sort = 4, isPicture = true, title = "图片2", pictureSource = PictureSourceContent.WEB_URL) private String headerPicture; - @ExportModel(sort = 5, isPicture = true, title = "多图片") + @ExportModel(sort = 5, isPicture = true, title = "本地多图片") private List pictures; - @ExportModel(sort = 6, isPicture = true, title = "url图片") + @ExportModel(sort = 6, isPicture = true, title = "url多图片") private List urlPictures; public UserPicture(String name, Integer age, String department, String picture) { diff --git a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPictureExportExample.java b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPictureExportExample.java index 16504a7..6ac17ff 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPictureExportExample.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPictureExportExample.java @@ -9,7 +9,6 @@ import java.io.IOException; /** * 注解图片导出示例 - * todo 建议使用{@link EasyUseExample4} 示例,不过写法有点麻烦,待优化 * * @author MinWeikai * @date 2021-12-07 10:59:49 diff --git a/src/test/java/com/ibiz/excel/picture/support/example/UrlPicturesExportExample.java b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220110.java similarity index 66% rename from src/test/java/com/ibiz/excel/picture/support/example/UrlPicturesExportExample.java rename to src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220110.java index 1398df4..80f4c24 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/UrlPicturesExportExample.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220110.java @@ -8,13 +8,15 @@ import com.ibiz.excel.picture.support.model.Workbook; import com.ibiz.excel.picture.support.util.WebUtil; import org.junit.Test; +import java.util.Random; + /** - * url图片导出excel示例 + * 导出excel示例 * * @author MinWeikai * @date 2022-01-10 10:08:03 */ -public class UrlPicturesExportExample extends BaseJunitTest { +public class ExportExample_20220110 extends BaseJunitTest { @Test public void export() { @@ -23,17 +25,21 @@ public class UrlPicturesExportExample extends BaseJunitTest { // 给标题行加上背景色,加颜色时,会对字体加粗 sheet.addCellStyle(new CellStyle(0, "66cc66")); UserPicture userPicture; - for (int r = 0; r < 10; r++) { + for (int r = 0; r < 101; r++) { userPicture = new UserPicture(); userPicture.setAge(15); userPicture.setName("测试-" + r); + // 导出本地单张图片 userPicture.setPicture(IMG_PATH_1); + // 导出url单张图片 userPicture.setHeaderPicture(getUrl()); - // 根据图片数组和要获取图片的数量,随机从url图片测试集合中取出若干 + // 导出本地图片集合 + userPicture.setPictures(getPictures(localTestFiles, new Random().nextInt(5))); + // 导出url图片集合 userPicture.setUrlPictures(getUrls(5)); sheet.createRow(userPicture); } - WebUtil.writeExcelTest(workBook, "url图片导出excel示例".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), TEMP_PATH); + WebUtil.writeExcelTest(workBook, "ExportExample_20220110_导出excel示例".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), TEMP_PATH); } } -- Gitee From 44e26f8e782b8d76a2fffa2532418a215b56e35e Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Mon, 10 Jan 2022 17:36:08 +0800 Subject: [PATCH 072/161] =?UTF-8?q?remove=20=E4=B8=8D=E5=BF=85=E8=A6=81?= =?UTF-8?q?=E7=9A=84=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 2 +- .../picture/support/flush/StylesIndex.java | 14 +++ .../picture/support/model/CellStyle.java | 41 +------- .../excel/picture/support/model/FontEnum.java | 32 ------ .../picture/support/model/StyleEnum.java | 37 ------- .../excel/picture/support/CellWidthTest.java | 75 -------------- .../ibiz/excel/picture/support/FontTest.java | 99 ------------------- .../picture/support/PictureCellWidthTest.java | 94 ------------------ .../excel/picture/support/PicturesDemo.java | 84 ---------------- .../excel/picture/support/RowFgColorTest.java | 73 -------------- .../picture/support/common/BaseJunitTest.java | 32 +++--- .../AnnotationPicturesExportExample.java | 2 +- .../example/ExportExample_20220110.java | 2 +- .../SimulateRealBusinessExportExample.java | 2 +- 14 files changed, 39 insertions(+), 550 deletions(-) delete mode 100644 src/main/java/com/ibiz/excel/picture/support/model/FontEnum.java delete mode 100644 src/main/java/com/ibiz/excel/picture/support/model/StyleEnum.java delete mode 100644 src/test/java/com/ibiz/excel/picture/support/CellWidthTest.java delete mode 100644 src/test/java/com/ibiz/excel/picture/support/FontTest.java delete mode 100644 src/test/java/com/ibiz/excel/picture/support/PictureCellWidthTest.java delete mode 100644 src/test/java/com/ibiz/excel/picture/support/PicturesDemo.java delete mode 100644 src/test/java/com/ibiz/excel/picture/support/RowFgColorTest.java diff --git a/pom.xml b/pom.xml index 6850a8f..e3c449a 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ top.minwk excel-x - 2.0.0 + 2.1.0 excel-x excel-x https://gitee.com/mwk719/excel-batch-picture-support diff --git a/src/main/java/com/ibiz/excel/picture/support/flush/StylesIndex.java b/src/main/java/com/ibiz/excel/picture/support/flush/StylesIndex.java index fbcbcce..55a52d3 100644 --- a/src/main/java/com/ibiz/excel/picture/support/flush/StylesIndex.java +++ b/src/main/java/com/ibiz/excel/picture/support/flush/StylesIndex.java @@ -38,5 +38,19 @@ public class StylesIndex { s = s + 1; } + public int getFillId() { + return fillId; + } + + public void setFillId(int fillId) { + this.fillId = fillId; + } + public int getS() { + return s; + } + + public void setS(int s) { + this.s = s; + } } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java b/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java index 00f2de0..0f25627 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java @@ -1,40 +1,26 @@ package com.ibiz.excel.picture.support.model; +import com.ibiz.excel.picture.support.flush.StylesIndex; + /** * 控制该行样式 * * @author MinWeikai * @date 2021/1/19 14:04 */ -public class CellStyle { +public class CellStyle extends StylesIndex { /** * 行号 */ private int rowNumber; - /** - * 默认已有fill样式 - * 与对应{@link com.ibiz.excel.picture.support.module.Styles} - */ - private int fillId = 33; - - /** - * 默认已有cellStyles样式 - */ - private int s = 4; - /** * fgColor rgb颜色 * RGB网页颜色在线取色器 https://link.fobshanghai.com/rgbcolor.htm */ private String fgColorRgb; - /** - * 样式 - */ - private StyleEnum styleEnum; - public CellStyle() { } @@ -57,23 +43,10 @@ public class CellStyle { this.fgColorRgb = fgColorRgb; } - public CellStyle(StyleEnum styleEnum) { - this.styleEnum = styleEnum; - this.fillId = styleEnum.getFillId(); - } - public CellStyle(CellStyle cellStyle) { this.fgColorRgb = cellStyle.fgColorRgb; } - public int getFillId() { - return fillId; - } - - public int getS() { - return s; - } - public String getFgColorRgb() { return fgColorRgb; } @@ -94,12 +67,4 @@ public class CellStyle { this.rowNumber = rowNumber; } - - public void setFillId(int fillId) { - this.fillId = fillId; - } - - public void setS(int s) { - this.s = s; - } } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/FontEnum.java b/src/main/java/com/ibiz/excel/picture/support/model/FontEnum.java deleted file mode 100644 index 1b96d32..0000000 --- a/src/main/java/com/ibiz/excel/picture/support/model/FontEnum.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.ibiz.excel.picture.support.model; - -import com.ibiz.excel.picture.support.module.Styles; - -/** - * 读取内置字体 - * - * @author MinWeikai - * @date 2021/1/20 11:57 - */ -public enum FontEnum { - - /** - * font size 20 - */ - F20(22), - - F10(3) - ; - /** - * 与对应{@link Styles} - */ - private Integer fillId; - - FontEnum(Integer fillId) { - this.fillId = fillId; - } - - public Integer getFillId() { - return fillId; - } -} diff --git a/src/main/java/com/ibiz/excel/picture/support/model/StyleEnum.java b/src/main/java/com/ibiz/excel/picture/support/model/StyleEnum.java deleted file mode 100644 index db4c3da..0000000 --- a/src/main/java/com/ibiz/excel/picture/support/model/StyleEnum.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.ibiz.excel.picture.support.model; - -import com.ibiz.excel.picture.support.module.Styles; - -/** - * 样式枚举类 - * - * @author MinWeikai - * @date 2021/1/19 14:10 - */ -public enum StyleEnum { - - /** - * 绿色填充色,字体加粗 - */ - GREEN_B(3), - - /** - * 字体-20 - */ - F20(4); - - - /** - * 填充色id - * 与对应{@link Styles} - */ - private Integer fillId; - - StyleEnum(Integer fillId) { - this.fillId = fillId; - } - - public Integer getFillId() { - return fillId; - } -} diff --git a/src/test/java/com/ibiz/excel/picture/support/CellWidthTest.java b/src/test/java/com/ibiz/excel/picture/support/CellWidthTest.java deleted file mode 100644 index 2769309..0000000 --- a/src/test/java/com/ibiz/excel/picture/support/CellWidthTest.java +++ /dev/null @@ -1,75 +0,0 @@ -package com.ibiz.excel.picture.support; - -import cn.hutool.core.io.FileUtil; -import com.ibiz.excel.picture.support.model.*; - -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.IOException; -import java.util.*; - -/** - * 单元格自定义宽度 - * - * @author MinWeikai - * @date 2021-01-19 14:47:39 - */ -public class CellWidthTest { - - static final String CURRENT_PATH = "E:\\test\\"; - - public static void main(String[] args) throws IOException { - Date start = new Date(); - Workbook workBook = Workbook.getInstance(1); - Sheet sheet = workBook.createSheet("测试"); - // 设置宽度 - sheet.setColumnWidth(1, 50); - - // 第一行表头 - Row row = sheet.createRow(0); - String[] excelName = {"文本1", "文本2", "图片1", "图片2", "图片3"}; - sheet.getMergeCells().add(new MergeCell(0, 0, 0, excelName.length - 1)); - row.setCells(Collections.singletonList(new Cell(0, 0).setValue("表头"))); - - // 第二行放标题 - row = sheet.createRow(1) - //配置该行颜色,现在默认只有绿色 - .setCellStyle(new CellStyle(StyleEnum.GREEN_B)); - List cells = new ArrayList<>(); - for (int i = 0; i < excelName.length; i++) { - Cell cell = new Cell(1, i).setValue(excelName[i]); - cells.add(cell); - } - row.setCells(cells); - - // 第三行放内容 - row = sheet.createRow(2); - cells = new ArrayList<>(); - for (int i = 0; i < excelName.length; i++) { - Cell cell = new Cell(2, i).setValue("文本" + i); - cells.add(cell); - } - row.setCells(cells); - - - File file = createFile(); - BufferedOutputStream os = FileUtil.getOutputStream(file); - workBook.write(os); - workBook.close(); - Date end = new Date(); - System.out.println("file capital :" + (file.length() / 1024 / 1024) + "M name :" + file.getName()); - System.out.println("file cost time :" + (end.getTime() - start.getTime())); - os.close(); - } - - - private static File createFile() { - String dir = CURRENT_PATH + "excel/"; - File file = new File(dir); - if (!file.exists()) { - file.mkdir(); - } - String name = CURRENT_PATH + "excel/" + UUID.randomUUID() + ".xlsx"; - return new File(name); - } -} diff --git a/src/test/java/com/ibiz/excel/picture/support/FontTest.java b/src/test/java/com/ibiz/excel/picture/support/FontTest.java deleted file mode 100644 index 5d9bde3..0000000 --- a/src/test/java/com/ibiz/excel/picture/support/FontTest.java +++ /dev/null @@ -1,99 +0,0 @@ -package com.ibiz.excel.picture.support; - -import cn.hutool.core.io.FileUtil; -import com.ibiz.excel.picture.support.model.*; - -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.IOException; -import java.util.*; - -/** - * 字体控制 - * - * @author MinWeikai - * @date 2021/1/20 11:45 - */ -public class FontTest { - - private static final String CURRENT_PATH = "E:\\test\\"; - - private final static String IMG_PATH = CURRENT_PATH + "img\\"; - - private final static String IMG_PATH_1 = IMG_PATH + "1.jpg"; - private final static String IMG_PATH_2 = IMG_PATH + "2.jpg"; - - public static void main(String[] args) throws IOException { - Date start = new Date(); - Workbook workBook = Workbook.getInstance(1); - Sheet sheet = workBook.createSheet("测试"); - - // 需要在创建行前预设宽度 - sheet.setColumnWidth(1, 10) - .setColumnWidth(3, 50) - .setColumnWidth(4, 50); - - // 第一行表头 - Row row = sheet.createRow(0) - //字体20 - .setCellStyle(new CellStyle(StyleEnum.F20)) - ; - String[] excelName = {"序号", "文本2", "图片1", "图片2", "图片3"}; - sheet.getMergeCells().add(new MergeCell(0, 0, 0, excelName.length - 1)); - row.setCells(Collections.singletonList(new Cell(0, 0).setValue("表头"))); - - // 第二行放标题 - row = sheet.createRow(1) - //配置该行颜色,现在默认只有绿色 - .setCellStyle(new CellStyle(StyleEnum.GREEN_B)); - List cells = new ArrayList<>(); - for (int i = 0; i < excelName.length; i++) { - Cell cell = new Cell(1, i).setValue(excelName[i]); - cells.add(cell); - } - row.setCells(cells); - - // 第三行放内容和图片 - row = sheet.createRow(2); - - cells = new ArrayList<>(); - List pictures = sheet.getPictures(); - //序号 - cells.add(new Cell(2, 0).setValue("1")); - for (int i = 0; i < excelName.length; i++) { - if (i == 1) { - cells.add(new Cell(2, i).setValue("文本" + i)); - } else { - //有图片的行,行高设置为100 - row.setHeight(80); - //每个单元格增加一个图片 - //pictures.add(new Picture(i, row.getRowNumber(),1000000 , IMG_PATH_1)); - //在第三列添加多张图片 - pictures.add(new Picture(row.getRowNumber(), 3, 1000000, IMG_PATH_1)); - pictures.add(new Picture(row.getRowNumber(),2, 1000000, IMG_PATH_2)); - } - } - row.setCells(cells); - - - File file = createFile(); - BufferedOutputStream os = FileUtil.getOutputStream(file); - workBook.write(os); - workBook.close(); - Date end = new Date(); - System.out.println("file capital :" + (file.length() / 1024 / 1024) + "M name :" + file.getName()); - System.out.println("file cost time :" + (end.getTime() - start.getTime())); - os.close(); - } - - - private static File createFile() { - String dir = CURRENT_PATH + "excel/"; - File file = new File(dir); - if (!file.exists()) { - file.mkdir(); - } - String name = CURRENT_PATH + "excel/" + UUID.randomUUID() + ".xlsx"; - return new File(name); - } -} diff --git a/src/test/java/com/ibiz/excel/picture/support/PictureCellWidthTest.java b/src/test/java/com/ibiz/excel/picture/support/PictureCellWidthTest.java deleted file mode 100644 index 74ddb8d..0000000 --- a/src/test/java/com/ibiz/excel/picture/support/PictureCellWidthTest.java +++ /dev/null @@ -1,94 +0,0 @@ -package com.ibiz.excel.picture.support; - -import cn.hutool.core.io.FileUtil; -import com.ibiz.excel.picture.support.model.*; - -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.IOException; -import java.util.*; - -/** - * 图片放在一个单元格宽度 - * - * @author MinWeikai - * @date 2021-01-19 16:03:21 - */ -public class PictureCellWidthTest { - - private static final String CURRENT_PATH = "E:\\test\\"; - - private final static String IMG_PATH = CURRENT_PATH + "img\\"; - - private final static String IMG_PATH_1 = IMG_PATH + "ia_1900002528.jpeg"; - - public static void main(String[] args) throws IOException { - Date start = new Date(); - Workbook workBook = Workbook.getInstance(1); - Sheet sheet = workBook.createSheet("测试"); - - // 需要在创建行前预设宽度 - sheet.setColumnWidth(1, 10) - .setColumnWidth(3, 50) - .setColumnWidth(4, 50); - - // 第一行表头 - Row row = sheet.createRow(0); - String[] excelName = {"序号", "文本2", "图片1", "图片2", "图片3"}; - sheet.getMergeCells().add(new MergeCell(0, 0, 0, excelName.length - 1)); - row.setCells(Collections.singletonList(new Cell(0, 0).setValue("表头"))); - - // 第二行放标题 - row = sheet.createRow(1) - //配置该行颜色,现在默认只有绿色 - .setCellStyle(new CellStyle(StyleEnum.GREEN_B)); - List cells = new ArrayList<>(); - for (int i = 0; i < excelName.length; i++) { - Cell cell = new Cell(1, i).setValue(excelName[i]); - cells.add(cell); - } - row.setCells(cells); - - // 第三行放内容和图片 - row = sheet.createRow(2); - - cells = new ArrayList<>(); - List pictures = sheet.getPictures(); - //序号 - cells.add(new Cell(2, 0).setValue("1")); - for (int i = 0; i < excelName.length; i++) { - if (i < 2) { - cells.add(new Cell(2, i).setValue("文本" + i)); - } else { - //有图片的行,行高设置为100 - row.setHeight(80); - //每个单元格增加一个图片 - //pictures.add(new Picture(i, row.getRowNumber(),1000000 , IMG_PATH_1)); - //在第三列添加多张图片 - pictures.add(new Picture( row.getRowNumber(), 3,1000000, IMG_PATH_1)); - } - } - row.setCells(cells); - - - File file = createFile(); - BufferedOutputStream os = FileUtil.getOutputStream(file); - workBook.write(os); - workBook.close(); - Date end = new Date(); - System.out.println("file capital :" + (file.length() / 1024 / 1024) + "M name :" + file.getName()); - System.out.println("file cost time :" + (end.getTime() - start.getTime())); - os.close(); - } - - - private static File createFile() { - String dir = CURRENT_PATH + "excel/"; - File file = new File(dir); - if (!file.exists()) { - file.mkdir(); - } - String name = CURRENT_PATH + "excel/" + UUID.randomUUID() + ".xlsx"; - return new File(name); - } -} diff --git a/src/test/java/com/ibiz/excel/picture/support/PicturesDemo.java b/src/test/java/com/ibiz/excel/picture/support/PicturesDemo.java deleted file mode 100644 index 21cf91b..0000000 --- a/src/test/java/com/ibiz/excel/picture/support/PicturesDemo.java +++ /dev/null @@ -1,84 +0,0 @@ -package com.ibiz.excel.picture.support; - -import cn.hutool.core.io.FileUtil; -import com.ibiz.excel.picture.support.model.CellStyle; -import com.ibiz.excel.picture.support.model.Sheet; -import com.ibiz.excel.picture.support.model.StyleEnum; -import com.ibiz.excel.picture.support.model.Workbook; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.Date; -import java.util.UUID; - -/** - * 多图片导入测试 - * - * @author MinWeikai - * @date 2021-01-15 09:46:32 - */ -public class PicturesDemo { - static final String CURRENT_PATH = "E:\\test\\"; - - private final static String IMG_PATH = "E:\\test\\img\\"; - - private static Integer SUM = 0; - private static Integer N = 0; - private static Integer _COUNT = 0; - - public static void main(String[] args) throws IOException { - Date start = new Date(); - Workbook workBook = Workbook.getInstance(-1); - Sheet sheet = workBook.createSheet("测试"); - File[] files = FileUtil.ls(IMG_PATH); - SUM = files.length; - UserPicture u1; - for (int r = 0; r < 2; r++) { - if (N == 0) { - _COUNT = 0; - } - u1 = new UserPicture(); - u1.setAge(15); - u1.setName("测试-" + r); - u1.setPicture(files[getIndex(N, 0)].getAbsolutePath()); - sheet.createRow(u1); - - _COUNT++; - N = _COUNT * 9; - } - - sheet.getRows().get(0).setCellStyle(new CellStyle(StyleEnum.GREEN_B)); - - File file = createFile(); - OutputStream os = new FileOutputStream(file); - workBook.write(os); - workBook.close(); - Date end = new Date(); - System.out.println("file capital :" + (file.length() / 1024 / 1024) + "M name :" + file.getName()); - System.out.println("file cost time :" + (end.getTime() - start.getTime())); - os.close(); - } - - private static int getIndex(int i, int i1) { - int count = i + i1; - if (count >= SUM) { - N = 0; - count = 0; - _COUNT = 0; - } - return count; - } - - private static File createFile() { - String dir = CURRENT_PATH + "excel/"; - File file = new File(dir); - if (!file.exists()) { - file.mkdir(); - } - String name = CURRENT_PATH + "excel/" + UUID.randomUUID() + ".xlsx"; - return new File(name); - } - -} diff --git a/src/test/java/com/ibiz/excel/picture/support/RowFgColorTest.java b/src/test/java/com/ibiz/excel/picture/support/RowFgColorTest.java deleted file mode 100644 index 2acb667..0000000 --- a/src/test/java/com/ibiz/excel/picture/support/RowFgColorTest.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.ibiz.excel.picture.support; - -import cn.hutool.core.io.FileUtil; -import com.ibiz.excel.picture.support.model.*; - -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.IOException; -import java.util.*; - -/** - * 行填充色 - * - * @author MinWeikai - * @date 2021-01-19 13:58:14 - */ -public class RowFgColorTest { - - static final String CURRENT_PATH = "E:\\test\\"; - - public static void main(String[] args) throws IOException { - Date start = new Date(); - Workbook workBook = Workbook.getInstance(1); - Sheet sheet = workBook.createSheet("测试"); - - // 第一行表头 - Row row = sheet.createRow(0); - String[] excelName = {"文本1", "文本2", "图片1", "图片2", "图片3"}; - sheet.getMergeCells().add(new MergeCell(0, 0, 0, excelName.length - 1)); - row.setCells(Collections.singletonList(new Cell(0, 0).setValue("表头"))); - - // 第二行放标题 - row = sheet.createRow(1) - //配置该行颜色,现在默认只有绿色 - .setCellStyle(new CellStyle(StyleEnum.GREEN_B)); - List cells = new ArrayList<>(); - for (int i = 0; i < excelName.length; i++) { - Cell cell = new Cell(1, i).setValue(excelName[i]); - cells.add(cell); - } - row.setCells(cells); - - // 第三行放内容 - row = sheet.createRow(2); - cells = new ArrayList<>(); - for (int i = 0; i < excelName.length; i++) { - Cell cell = new Cell(2, i).setValue("文本" + i); - cells.add(cell); - } - row.setCells(cells); - - - File file = createFile(); - BufferedOutputStream os = FileUtil.getOutputStream(file); - workBook.write(os); - workBook.close(); - Date end = new Date(); - System.out.println("file capital :" + (file.length() / 1024 / 1024) + "M name :" + file.getName()); - System.out.println("file cost time :" + (end.getTime() - start.getTime())); - os.close(); - } - - - private static File createFile() { - String dir = CURRENT_PATH + "excel/"; - File file = new File(dir); - if (!file.exists()) { - file.mkdir(); - } - String name = CURRENT_PATH + "excel/" + UUID.randomUUID() + ".xlsx"; - return new File(name); - } -} diff --git a/src/test/java/com/ibiz/excel/picture/support/common/BaseJunitTest.java b/src/test/java/com/ibiz/excel/picture/support/common/BaseJunitTest.java index 6b7e44a..b2ca444 100644 --- a/src/test/java/com/ibiz/excel/picture/support/common/BaseJunitTest.java +++ b/src/test/java/com/ibiz/excel/picture/support/common/BaseJunitTest.java @@ -23,19 +23,23 @@ public class BaseJunitTest { protected final static String IMAGES_PATH = CURRENT_PATH + "images\\"; - // url图片测试集合 - protected final static List urls = new ArrayList<>(); + /** + * url图片测试集合 + */ + protected final static List URLS = new ArrayList<>(); - // 本地测试图片数组 - protected final static File[] localTestFiles; + /** + * 本地测试图片数组 + */ + protected final static File[] LOCAL_TEST_FILES; static { - urls.add("https://portrait.gitee.com/uploads/avatars/user/552/1657608_mwk719_1641537497.png"); - urls.add("https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.jj20.com%2Fup%2Fallimg%2F1114%2F060421091316%2F210604091316-6-1200.jpg&refer=http%3A%2F%2Fimg.jj20.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1644142768&t=82062e20360f72b0fd8d5fd7e2fc9885"); - urls.add("https://img2.baidu.com/it/u=121102239,1207969661&fm=253&fmt=auto&app=120&f=JPEG?w=1195&h=500"); - urls.add("https://img2.baidu.com/it/u=2602880481,728201544&fm=26&fmt=auto"); + URLS.add("https://portrait.gitee.com/uploads/avatars/user/552/1657608_mwk719_1641537497.png"); + URLS.add("https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.jj20.com%2Fup%2Fallimg%2F1114%2F060421091316%2F210604091316-6-1200.jpg&refer=http%3A%2F%2Fimg.jj20.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1644142768&t=82062e20360f72b0fd8d5fd7e2fc9885"); + URLS.add("https://img2.baidu.com/it/u=121102239,1207969661&fm=253&fmt=auto&app=120&f=JPEG?w=1195&h=500"); + URLS.add("https://img2.baidu.com/it/u=2602880481,728201544&fm=26&fmt=auto"); - localTestFiles = FileUtil.ls(IMAGES_PATH); + LOCAL_TEST_FILES = FileUtil.ls(IMAGES_PATH); } @@ -45,18 +49,18 @@ public class BaseJunitTest { * @param getCount 获取图片的数量 * @return */ - protected static List getPictures(File[] files, int getCount) { + protected static List getPictures(int getCount) { List list = new ArrayList<>(getCount); for (int i = 0; i < getCount; i++) { - int index = new Random().nextInt(files.length); - list.add(files[index].getAbsolutePath()); + int index = new Random().nextInt(LOCAL_TEST_FILES.length); + list.add(LOCAL_TEST_FILES[index].getAbsolutePath()); } return list; } protected static String getUrl() { - int index = new Random().nextInt(urls.size()); - return urls.get(index); + int index = new Random().nextInt(URLS.size()); + return URLS.get(index); } protected static List getUrls(int getCount) { diff --git a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java index 1504081..68aadd2 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java @@ -33,7 +33,7 @@ public class AnnotationPicturesExportExample extends BaseJunitTest { userPicture.setPicture(IMG_PATH_1); userPicture.setHeaderPicture(getUrl()); // 根据图片数组和要获取图片的数量,随机从本地测试图片数组中取出若干 - userPicture.setPictures(getPictures(localTestFiles, new Random().nextInt(5))); + userPicture.setPictures(getPictures(new Random().nextInt(5))); sheet.createRow(userPicture); // 不设置时,自适应图片的高度 // .setHeight(200); diff --git a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220110.java b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220110.java index 80f4c24..cb2143f 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220110.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220110.java @@ -34,7 +34,7 @@ public class ExportExample_20220110 extends BaseJunitTest { // 导出url单张图片 userPicture.setHeaderPicture(getUrl()); // 导出本地图片集合 - userPicture.setPictures(getPictures(localTestFiles, new Random().nextInt(5))); + userPicture.setPictures(getPictures(new Random().nextInt(5))); // 导出url图片集合 userPicture.setUrlPictures(getUrls(5)); sheet.createRow(userPicture); diff --git a/src/test/java/com/ibiz/excel/picture/support/simulation/SimulateRealBusinessExportExample.java b/src/test/java/com/ibiz/excel/picture/support/simulation/SimulateRealBusinessExportExample.java index 374f737..2030772 100644 --- a/src/test/java/com/ibiz/excel/picture/support/simulation/SimulateRealBusinessExportExample.java +++ b/src/test/java/com/ibiz/excel/picture/support/simulation/SimulateRealBusinessExportExample.java @@ -44,7 +44,7 @@ public class SimulateRealBusinessExportExample extends BaseJunitTest { userPicture.setHeaderPicture(IMG_PATH_2); if(new Random().nextInt(10) > 5){ // 模拟场景2. 在业务数据集合中,有些数据没有图片对应的图片集合,没有则不设置值 - userPicture.setPictures(getPictures(localTestFiles, new Random().nextInt(10))); + userPicture.setPictures(getPictures(new Random().nextInt(10))); } sheet.createRow(userPicture); // 给标题行加上背景色,加颜色时,会对字体加粗 -- Gitee From 2c30cf3552004cb813dea51c184a611e0ec91579 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Tue, 11 Jan 2022 15:54:00 +0800 Subject: [PATCH 073/161] =?UTF-8?q?fix=20flushSize=3D1=E6=97=B6=E5=AF=BC?= =?UTF-8?q?=E5=87=BA=E6=A0=BC=E5=BC=8F=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 39 ++++++++++++ pom.xml | 4 +- .../picture/support/flush/StylesHandler.java | 63 ++++++++++--------- .../excel/picture/support/model/Workbook.java | 18 +++++- .../example/ExportExample_20220110.java | 4 +- 5 files changed, 92 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index 7a949e2..fb31e3e 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,45 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, 2. ### 示例 + - 最新使用示例代码 + + ```java + @GetMapping("/export/lastversion/{row}") + public void exportLastVersion(HttpServletResponse response, @PathVariable int row) throws IOException { + /* + 操作窗口 + 当写入excel数据行数大于flushSize时{@link Sheet.SheetHandler#createRow(int)}, + 会刷新数据到流,调用该方法 + {@link com.ibiz.excel.picture.support.flush.DrawingXmlRelsHandler#copyPictureAppendDrawingRelsXML(Sheet, Picture)} + 将图片刷新在磁盘中 + 不会占用内存空间 + flushSize = -1 时不刷新流 + */ + Workbook workBook = Workbook.getInstance(1); + Sheet sheet = workBook.createSheet("测试"); + // 给标题行加上背景色,加颜色时,会对字体加粗 + sheet.addCellStyle(new CellStyle(0, "66cc66")); + UserPicture userPicture; + for (int r = 0; r < row; r++) { + userPicture = new UserPicture(); + userPicture.setAge(15); + userPicture.setName("测试-" + r); + // 导出本地单张图片 + userPicture.setPicture("E:\\test\\img\\1.jpg"); + // 导出url单张图片 + userPicture.setHeaderPicture("https://portrait.gitee.com/uploads/avatars/user/552/1657608_mwk719_1641537497.png"); + // 导出本地图片集合 + userPicture.setPictures(Arrays.asList("E:\\test\\img\\1.jpg","E:\\test\\img\\2.jpg")); + // 导出url图片集合 + userPicture.setUrlPictures(Arrays.asList("https://portrait.gitee.com/uploads/avatars/user/552/1657608_mwk719_1641537497.png", + "https://img2.baidu.com/it/u=2602880481,728201544&fm=26&fmt=auto")); + sheet.createRow(userPicture); + } + WebUtil.writeExcel(workBook, "最新使用示例代码导出".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), response); + } + ``` + + - [excel含图片导出demo地址](https://gitee.com/mwk719/excel-batch-picture-support/tree/dev/src/test/java/com/ibiz/excel/picture/support/example),具体使用以后缀最新日期为准,其他示例仅供测试 - [微云-6767张图片共800mb资源.rar 可用于测试](https://minwk.top/big-size-img/) - [项目中导出下载excel使用示例](https://gitee.com/mwk719/spring-learn/blob/master/src/main/java/com/mwk/external/controller/ExcelController.java) diff --git a/pom.xml b/pom.xml index e3c449a..967fa10 100644 --- a/pom.xml +++ b/pom.xml @@ -2,9 +2,7 @@ 4.0.0 - - pom - + jar top.minwk excel-x 2.1.0 diff --git a/src/main/java/com/ibiz/excel/picture/support/flush/StylesHandler.java b/src/main/java/com/ibiz/excel/picture/support/flush/StylesHandler.java index 925e5e9..9d50573 100644 --- a/src/main/java/com/ibiz/excel/picture/support/flush/StylesHandler.java +++ b/src/main/java/com/ibiz/excel/picture/support/flush/StylesHandler.java @@ -21,31 +21,31 @@ public class StylesHandler implements InvocationHandler { this.target = proxy; } - private StringBuilder xfBefore = new StringBuilder("" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + // 填充色值坐标 - ""); + private final StringBuilder xfBefore = new StringBuilder("".concat( + "").concat( + "").concat( + "").concat( + "").concat( + "").concat( + "").concat( + "").concat( + "").concat( + "").concat( + "").concat( + "").concat( + "").concat( + "").concat( + "").concat( + "").concat( + "").concat( + "").concat( + "").concat( // 填充色值坐标 + "")); - private StringBuilder xfAfter = new StringBuilder("" + - "" + - "" + - ""); + private final StringBuilder xfAfter = new StringBuilder("".concat( + "").concat( + "").concat( + "")); @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { @@ -55,10 +55,6 @@ public class StylesHandler implements InvocationHandler { Sheet sheet = (Sheet) args[0]; List rows = sheet.getRows(); if (!rows.isEmpty()) { - // 判断是否最后 - if (sheet.getRowCount() % sheet.getFlushSize() - rows.size() % sheet.getFlushSize() == 1) { - last = false; - } rows.stream().forEach(row -> { CellStyle cellStyle = row.getCellStyle(); if (row.getCellStyle() != null) { @@ -69,8 +65,15 @@ public class StylesHandler implements InvocationHandler { } }); } + + int x = sheet.getRowCount() % sheet.getFlushSize(); + int y = rows.size() % sheet.getFlushSize(); + // 判断是否最后 + last = x - y != 1; + // 只写入一条数据需要特殊判断 + boolean one = y == 0 && sheet.hasFlush(); // 不是最后一块数据或者没有行数据,则不写入样式 - if (!last || rows.isEmpty()) { + if (!last || rows.isEmpty() || one) { return ""; } // 在Styles对象中追加样式 @@ -96,7 +99,7 @@ public class StylesHandler implements InvocationHandler { * @param cellStyle */ private void appendFill(CellStyle cellStyle) { - target.append(""); + target.append("")); } } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Workbook.java b/src/main/java/com/ibiz/excel/picture/support/model/Workbook.java index 72dd4b7..7329a16 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Workbook.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Workbook.java @@ -17,7 +17,12 @@ import java.util.*; public class Workbook { private Logger logger = LoggerFactory.getLogger(this.getClass()); /** - * 到达row行数就刷新流 + * 操作窗口 + * 当写入excel数据行数大于flushSize时{@link Sheet.SheetHandler#createRow(int)}, + * 会刷新数据到流,调用该方法 + * {@link com.ibiz.excel.picture.support.flush.DrawingXmlRelsHandler#copyPictureAppendDrawingRelsXML(Sheet, Picture)} + * 将图片刷新在磁盘中 + * 不会占用内存空间 * flushSize = -1 时不刷新流 */ private int flushSize; @@ -76,6 +81,17 @@ public class Workbook { return getInstance(100); } + /** + * 操作窗口 + * 当写入excel数据行数大于flushSize时{@link Sheet.SheetHandler#createRow(int)}, + * 会刷新数据到流,调用该方法 + * {@link com.ibiz.excel.picture.support.flush.DrawingXmlRelsHandler#copyPictureAppendDrawingRelsXML(Sheet, Picture)} + * 将图片刷新在磁盘中 + * 不会占用内存空间 + * flushSize = -1 时不刷新流 + * @param flushSize + * @return + */ public static Workbook getInstance(int flushSize) { return new Workbook(flushSize); } diff --git a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220110.java b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220110.java index cb2143f..812c24e 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220110.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220110.java @@ -20,12 +20,12 @@ public class ExportExample_20220110 extends BaseJunitTest { @Test public void export() { - Workbook workBook = Workbook.getInstance(); + Workbook workBook = Workbook.getInstance(3); Sheet sheet = workBook.createSheet("测试"); // 给标题行加上背景色,加颜色时,会对字体加粗 sheet.addCellStyle(new CellStyle(0, "66cc66")); UserPicture userPicture; - for (int r = 0; r < 101; r++) { + for (int r = 0; r < 16; r++) { userPicture = new UserPicture(); userPicture.setAge(15); userPicture.setName("测试-" + r); -- Gitee From e4c98b1883adcfb598af432cc7cbd7f4d007ed99 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Wed, 12 Jan 2022 09:35:45 +0800 Subject: [PATCH 074/161] =?UTF-8?q?fix=20=E5=9C=A8close=E6=97=B6=E5=86=99?= =?UTF-8?q?=E5=85=A5styles?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 172 ++++++++++++++---- .../picture/support/flush/StylesHandler.java | 16 +- .../example/ExportExample_20220110.java | 6 +- 3 files changed, 144 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index fb31e3e..6d93734 100644 --- a/README.md +++ b/README.md @@ -43,49 +43,155 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, 2. ### 示例 - - 最新使用示例代码 + - 最新使用示例代码 ```java @GetMapping("/export/lastversion/{row}") - public void exportLastVersion(HttpServletResponse response, @PathVariable int row) throws IOException { - /* - 操作窗口 - 当写入excel数据行数大于flushSize时{@link Sheet.SheetHandler#createRow(int)}, - 会刷新数据到流,调用该方法 - {@link com.ibiz.excel.picture.support.flush.DrawingXmlRelsHandler#copyPictureAppendDrawingRelsXML(Sheet, Picture)} - 将图片刷新在磁盘中 - 不会占用内存空间 - flushSize = -1 时不刷新流 - */ - Workbook workBook = Workbook.getInstance(1); - Sheet sheet = workBook.createSheet("测试"); - // 给标题行加上背景色,加颜色时,会对字体加粗 - sheet.addCellStyle(new CellStyle(0, "66cc66")); - UserPicture userPicture; - for (int r = 0; r < row; r++) { - userPicture = new UserPicture(); - userPicture.setAge(15); - userPicture.setName("测试-" + r); - // 导出本地单张图片 - userPicture.setPicture("E:\\test\\img\\1.jpg"); - // 导出url单张图片 - userPicture.setHeaderPicture("https://portrait.gitee.com/uploads/avatars/user/552/1657608_mwk719_1641537497.png"); - // 导出本地图片集合 - userPicture.setPictures(Arrays.asList("E:\\test\\img\\1.jpg","E:\\test\\img\\2.jpg")); - // 导出url图片集合 - userPicture.setUrlPictures(Arrays.asList("https://portrait.gitee.com/uploads/avatars/user/552/1657608_mwk719_1641537497.png", - "https://img2.baidu.com/it/u=2602880481,728201544&fm=26&fmt=auto")); - sheet.createRow(userPicture); - } - WebUtil.writeExcel(workBook, "最新使用示例代码导出".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), response); - } + public void exportLastVersion(HttpServletResponse response, @PathVariable int row) throws IOException { + /* + 操作窗口 + 当写入excel数据行数大于flushSize时{@link Sheet.SheetHandler#createRow(int)}, + 会刷新数据到流,调用该方法 + {@link com.ibiz.excel.picture.support.flush.DrawingXmlRelsHandler#copyPictureAppendDrawingRelsXML(Sheet, Picture)} + 将图片刷新在磁盘中 + 不会占用内存空间 + flushSize = -1 时不刷新流 + */ + Workbook workBook = Workbook.getInstance(1); + Sheet sheet = workBook.createSheet("测试"); + // 给标题行加上背景色,加颜色时,会对字体加粗 + sheet.addCellStyle(new CellStyle(0, "66cc66")); + UserPicture userPicture; + for (int r = 0; r < row; r++) { + userPicture = new UserPicture(); + userPicture.setAge(15); + userPicture.setName("测试-" + r); + // 导出本地单张图片 + userPicture.setPicture("E:\\test\\img\\1.jpg"); + // 导出url单张图片 + userPicture.setHeaderPicture("https://portrait.gitee.com/uploads/avatars/user/552/1657608_mwk719_1641537497.png"); + // 导出本地图片集合 + userPicture.setPictures(Arrays.asList("E:\\test\\img\\1.jpg","E:\\test\\img\\2.jpg")); + // 导出url图片集合 + userPicture.setUrlPictures(Arrays.asList("https://portrait.gitee.com/uploads/avatars/user/552/1657608_mwk719_1641537497.png", + "https://img2.baidu.com/it/u=2602880481,728201544&fm=26&fmt=auto")); + sheet.createRow(userPicture); + } + WebUtil.writeExcel(workBook, "最新使用示例代码导出".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), response); + } ``` + ```java + /** + * @auther 喻场 + * @date 2020/7/813:41 + */ + public class UserPicture { + + public UserPicture() { + } + + @ExportModel( sort = 0, title = "姓名") + private String name; + @ExportModel(sort = 1, title = "年龄") + private Integer age; + @ExportModel(sort = 3, title = "部门") + private String department; + @ExportModel(sort = 2, isPicture = true, title = "图片1") + private String picture; + @ExportModel(sort = 4, isPicture = true, title = "图片2") + private String headerPicture; + @ExportModel(sort = 5, isPicture = true, title = "多图片") + private List pictures; + @ExportModel(sort = 6, isPicture = true, title = "url多图片") + private List urlPictures; + + public UserPicture(String name, Integer age, String department, String picture) { + this.name = name; + this.age = age; + this.department = department; + this.picture = picture; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getAge() { + return age; + } + + public void setAge(Integer age) { + this.age = age; + } + + public String getDepartment() { + return department; + } + + public void setDepartment(String department) { + this.department = department; + } + + public String getPicture() { + return picture; + } + + public void setPicture(String picture) { + this.picture = picture; + } + + public String getHeaderPicture() { + return headerPicture; + } + + public void setHeaderPicture(String headerPicture) { + this.headerPicture = headerPicture; + } + + public List getPictures() { + return pictures; + } + + public void setPictures(List pictures) { + this.pictures = pictures; + } + + public List getUrlPictures() { + return urlPictures; + } + + public void setUrlPictures(List urlPictures) { + this.urlPictures = urlPictures; + } + } + + ``` - [excel含图片导出demo地址](https://gitee.com/mwk719/excel-batch-picture-support/tree/dev/src/test/java/com/ibiz/excel/picture/support/example),具体使用以后缀最新日期为准,其他示例仅供测试 + - [微云-6767张图片共800mb资源.rar 可用于测试](https://minwk.top/big-size-img/) + - [项目中导出下载excel使用示例](https://gitee.com/mwk719/spring-learn/blob/master/src/main/java/com/mwk/external/controller/ExcelController.java) + #### 项目中测试使用 + + 1. 设置项目jvm堆栈大小都是20m + + ```bash + -Xms20m -Xmx20m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:\log\springlearn.hprof + ``` + + 2. 复制上方 【最新使用示例代码】到项目中 + + 3. 找一堆图片随机添加到UserPicture中 + + 4. 导出一个5000条的记录,在最大堆栈占用为20m的情况下,导出excel大小为700m,未发生内存溢出情况 + 3. ### 版本更迭 #### 2.1.0(2022.01.14) diff --git a/src/main/java/com/ibiz/excel/picture/support/flush/StylesHandler.java b/src/main/java/com/ibiz/excel/picture/support/flush/StylesHandler.java index 9d50573..713ea91 100644 --- a/src/main/java/com/ibiz/excel/picture/support/flush/StylesHandler.java +++ b/src/main/java/com/ibiz/excel/picture/support/flush/StylesHandler.java @@ -49,8 +49,6 @@ public class StylesHandler implements InvocationHandler { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - // 因会写入磁盘,刷新sheet.getRows(),所以需要计算是否最后一块数据 - boolean last = true; if (method.getName().equals("write")) { Sheet sheet = (Sheet) args[0]; List rows = sheet.getRows(); @@ -65,18 +63,8 @@ public class StylesHandler implements InvocationHandler { } }); } - - int x = sheet.getRowCount() % sheet.getFlushSize(); - int y = rows.size() % sheet.getFlushSize(); - // 判断是否最后 - last = x - y != 1; - // 只写入一条数据需要特殊判断 - boolean one = y == 0 && sheet.hasFlush(); - // 不是最后一块数据或者没有行数据,则不写入样式 - if (!last || rows.isEmpty() || one) { - return ""; - } - // 在Styles对象中追加样式 + }else if (method.getName().equals("close")) { + // 关闭时将所有的样式追加在Styles对象中 target.append(xfBefore.append(xfAfter).toString()); } return method.invoke(target, args); diff --git a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220110.java b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220110.java index 812c24e..afb37a9 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220110.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220110.java @@ -20,12 +20,12 @@ public class ExportExample_20220110 extends BaseJunitTest { @Test public void export() { - Workbook workBook = Workbook.getInstance(3); + Workbook workBook = Workbook.getInstance(); Sheet sheet = workBook.createSheet("测试"); // 给标题行加上背景色,加颜色时,会对字体加粗 sheet.addCellStyle(new CellStyle(0, "66cc66")); UserPicture userPicture; - for (int r = 0; r < 16; r++) { + for (int r = 0; r < 101; r++) { userPicture = new UserPicture(); userPicture.setAge(15); userPicture.setName("测试-" + r); @@ -39,7 +39,7 @@ public class ExportExample_20220110 extends BaseJunitTest { userPicture.setUrlPictures(getUrls(5)); sheet.createRow(userPicture); } - WebUtil.writeExcelTest(workBook, "ExportExample_20220110_导出excel示例".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), TEMP_PATH); + WebUtil.writeExcelTest(workBook, "ExportExample_20220110_".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), TEMP_PATH); } } -- Gitee From e1e7c925f308df9937a584b90b088a72dc736276 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Wed, 12 Jan 2022 14:21:37 +0800 Subject: [PATCH 075/161] =?UTF-8?q?add=20createRow=E9=9B=86=E5=90=88?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E7=94=9F=E6=88=90excel=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 5 ++- .../excel/picture/support/model/Sheet.java | 45 ++++++++++++++++++- .../excel/picture/support/UserPicture.java | 10 +++++ .../example/ExportExample_20220110.java | 28 ++++++++++++ 4 files changed, 86 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6d93734..88740ff 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,7 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, Sheet sheet = workBook.createSheet("测试"); // 给标题行加上背景色,加颜色时,会对字体加粗 sheet.addCellStyle(new CellStyle(0, "66cc66")); + List list = new ArrayList<>(); UserPicture userPicture; for (int r = 0; r < row; r++) { userPicture = new UserPicture(); @@ -75,8 +76,9 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, // 导出url图片集合 userPicture.setUrlPictures(Arrays.asList("https://portrait.gitee.com/uploads/avatars/user/552/1657608_mwk719_1641537497.png", "https://img2.baidu.com/it/u=2602880481,728201544&fm=26&fmt=auto")); - sheet.createRow(userPicture); + list.add(userPicture); } + sheet.write(UserPicture.class).createRow(list); WebUtil.writeExcel(workBook, "最新使用示例代码导出".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), response); } ``` @@ -197,6 +199,7 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, #### 2.1.0(2022.01.14) - 添加导出网络链接图片到excel中 + - 添加createRow集合列表生成excel方法 - 修改CellStyle样式的使用 #### 2.0.0(2021.12.30) diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java index 7bdaa75..43cea92 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java @@ -14,6 +14,7 @@ import com.ibiz.excel.picture.support.listener.FlushListener; import com.ibiz.excel.picture.support.listener.InitListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.util.CollectionUtils; import java.util.*; @@ -102,7 +103,7 @@ public class Sheet { /** * 创建行,单元格会根据t的属性自动填充 * - * @param t 列属性 只会读取com.ibiz.excelx.annotation.Model 注解的属性 + * @param t 列属性 只会读取{@link ExportModel} 注解的属性 * @param * @return Row */ @@ -110,10 +111,37 @@ public class Sheet { return SHEET_HANDLER.createRow(t); } + /** + * 创建集合行数据,单元格会根据t的属性自动填充 + * 需要调用{@link Sheet#write(Class)}写入excel信息 + * 否则 collections为空时,excel中没u有标题 + * 写法如: sheet.write(UserPicture.class).createRow(list); + * @param collections 集合列属性 只会读取{@link ExportModel} 注解的属性 + * @return + */ + public Sheet createRow(Collection collections) { + if(!CollectionUtils.isEmpty(collections)){ + collections.forEach(this::createRow); + } + return this; + } + public Row createRow(int rowNumber) { return SHEET_HANDLER.createRow(rowNumber); } + /** + * 构建并写入excel信息 + * + * @param + * @param head 标题 + * @return + */ + public Sheet write(Class head) { + SHEET_HANDLER.write(head); + return this; + } + /** * 刷新数据到流 */ @@ -395,6 +423,21 @@ public class Sheet { rows.addAll(list); pictures.clear(); } + + /** + * 构建并写入excel信息 + * + * @param head 标题类 + * @param + */ + public void write(Class head) { + try { + createRowAndCellStyle(head.newInstance() , true); + } catch (InstantiationException | IllegalAccessException e) { + throw new RuntimeException("写入标题异常", e); + } + } + } /** diff --git a/src/test/java/com/ibiz/excel/picture/support/UserPicture.java b/src/test/java/com/ibiz/excel/picture/support/UserPicture.java index 9ce134e..4febea8 100644 --- a/src/test/java/com/ibiz/excel/picture/support/UserPicture.java +++ b/src/test/java/com/ibiz/excel/picture/support/UserPicture.java @@ -29,6 +29,8 @@ public class UserPicture { @ExportModel(sort = 6, isPicture = true, title = "url多图片") private List urlPictures; + private String address; + public UserPicture(String name, Integer age, String department, String picture) { this.name = name; this.age = age; @@ -91,4 +93,12 @@ public class UserPicture { public void setUrlPictures(List urlPictures) { this.urlPictures = urlPictures; } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } } diff --git a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220110.java b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220110.java index afb37a9..8b69da3 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220110.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220110.java @@ -8,6 +8,8 @@ import com.ibiz.excel.picture.support.model.Workbook; import com.ibiz.excel.picture.support.util.WebUtil; import org.junit.Test; +import java.util.ArrayList; +import java.util.List; import java.util.Random; /** @@ -42,4 +44,30 @@ public class ExportExample_20220110 extends BaseJunitTest { WebUtil.writeExcelTest(workBook, "ExportExample_20220110_".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), TEMP_PATH); } + @Test + public void export1() { + Workbook workBook = Workbook.getInstance(); + Sheet sheet = workBook.createSheet("测试"); + // 给标题行加上背景色,加颜色时,会对字体加粗 + sheet.addCellStyle(new CellStyle(0, "66cc66")); + List list = new ArrayList<>(); + UserPicture userPicture; + for (int r = 0; r < 101; r++) { + userPicture = new UserPicture(); + userPicture.setAge(15); + userPicture.setName("测试-" + r); + // 导出本地单张图片 + userPicture.setPicture(IMG_PATH_1); + // 导出url单张图片 + userPicture.setHeaderPicture(getUrl()); + // 导出本地图片集合 + userPicture.setPictures(getPictures(new Random().nextInt(5))); + // 导出url图片集合 + userPicture.setUrlPictures(getUrls(5)); + list.add(userPicture); + } + sheet.write(UserPicture.class).createRow(list); + WebUtil.writeExcelTest(workBook, "ExportExample_20220110_".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), TEMP_PATH); + } + } -- Gitee From 1aa75e38cb1819d5370e9aed3272480182118d73 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Fri, 14 Jan 2022 09:26:54 +0800 Subject: [PATCH 076/161] =?UTF-8?q?add=20=E5=8F=91=E5=B8=83=E8=B7=B3?= =?UTF-8?q?=E8=BF=87=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .mvn/wrapper/MavenWrapperDownloader.java | 118 ------------------ .mvn/wrapper/maven-wrapper.jar | Bin 50710 -> 0 bytes .mvn/wrapper/maven-wrapper.properties | 2 - pom.xml | 18 +-- .../excel/picture/support/util/WebUtil.java | 3 +- .../AnnotationPicturesExportExample.java | 2 + .../example/ExportExample_20220110.java | 2 + .../SimulateRealBusinessExportExample.java | 12 +- 8 files changed, 17 insertions(+), 140 deletions(-) delete mode 100644 .mvn/wrapper/MavenWrapperDownloader.java delete mode 100644 .mvn/wrapper/maven-wrapper.jar delete mode 100644 .mvn/wrapper/maven-wrapper.properties diff --git a/.mvn/wrapper/MavenWrapperDownloader.java b/.mvn/wrapper/MavenWrapperDownloader.java deleted file mode 100644 index a45eb6b..0000000 --- a/.mvn/wrapper/MavenWrapperDownloader.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 2007-present the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import java.net.*; -import java.io.*; -import java.nio.channels.*; -import java.util.Properties; - -public class MavenWrapperDownloader { - - private static final String WRAPPER_VERSION = "0.5.6"; - /** - * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. - */ - private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" - + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; - - /** - * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to - * use instead of the default one. - */ - private static final String MAVEN_WRAPPER_PROPERTIES_PATH = - ".mvn/wrapper/maven-wrapper.properties"; - - /** - * Path where the maven-wrapper.jar will be saved to. - */ - private static final String MAVEN_WRAPPER_JAR_PATH = - ".mvn/wrapper/maven-wrapper.jar"; - - /** - * Name of the property which should be used to override the default download url for the wrapper. - */ - private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; - - public static void main(String args[]) { - System.out.println("- Downloader started"); - File baseDirectory = new File(args[0]); - System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); - - // If the maven-wrapper.properties exists, read it and check if it contains a custom - // wrapperUrl parameter. - File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); - String url = DEFAULT_DOWNLOAD_URL; - if (mavenWrapperPropertyFile.exists()) { - FileInputStream mavenWrapperPropertyFileInputStream = null; - try { - mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); - Properties mavenWrapperProperties = new Properties(); - mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); - url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); - } catch (IOException e) { - System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); - } finally { - try { - if (mavenWrapperPropertyFileInputStream != null) { - mavenWrapperPropertyFileInputStream.close(); - } - } catch (IOException e) { - // Ignore ... - } - } - } - System.out.println("- Downloading from: " + url); - - File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); - if (!outputFile.getParentFile().exists()) { - if (!outputFile.getParentFile().mkdirs()) { - System.out.println( - "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); - } - } - System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); - try { - downloadFileFromURL(url, outputFile); - System.out.println("Done"); - System.exit(0); - } catch (Throwable e) { - System.out.println("- Error downloading"); - e.printStackTrace(); - System.exit(1); - } - } - - private static void downloadFileFromURL(String urlString, File destination) throws Exception { - if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { - String username = System.getenv("MVNW_USERNAME"); - char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); - Authenticator.setDefault(new Authenticator() { - @Override - protected PasswordAuthentication getPasswordAuthentication() { - return new PasswordAuthentication(username, password); - } - }); - } - URL website = new URL(urlString); - ReadableByteChannel rbc; - rbc = Channels.newChannel(website.openStream()); - FileOutputStream fos = new FileOutputStream(destination); - fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); - fos.close(); - rbc.close(); - } - -} diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar deleted file mode 100644 index 2cc7d4a55c0cd0092912bf49ae38b3a9e3fd0054..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 50710 zcmbTd1CVCTmM+|7+wQV$+qP}n>auOywyU~q+qUhh+uxis_~*a##hm*_WW?9E7Pb7N%LRFiwbEGCJ0XP=%-6oeT$XZcYgtzC2~q zk(K08IQL8oTl}>>+hE5YRgXTB@fZ4TH9>7=79e`%%tw*SQUa9~$xKD5rS!;ZG@ocK zQdcH}JX?W|0_Afv?y`-NgLum62B&WSD$-w;O6G0Sm;SMX65z)l%m1e-g8Q$QTI;(Q z+x$xth4KFvH@Bs6(zn!iF#nenk^Y^ce;XIItAoCsow38eq?Y-Auh!1in#Rt-_D>H^ z=EjbclGGGa6VnaMGmMLj`x3NcwA43Jb(0gzl;RUIRAUDcR1~99l2SAPkVhoRMMtN} zXvC<tOmX83grD8GSo_Lo?%lNfhD#EBgPo z*nf@ppMC#B!T)Ae0RG$mlJWmGl7CkuU~B8-==5i;rS;8i6rJ=PoQxf446XDX9g|c> zU64ePyMlsI^V5Jq5A+BPe#e73+kpc_r1tv#B)~EZ;7^67F0*QiYfrk0uVW;Qb=NsG zN>gsuCwvb?s-KQIppEaeXtEMdc9dy6Dfduz-tMTms+i01{eD9JE&h?Kht*$eOl#&L zJdM_-vXs(V#$Ed;5wyNWJdPNh+Z$+;$|%qR(t`4W@kDhd*{(7-33BOS6L$UPDeE_53j${QfKN-0v-HG z(QfyvFNbwPK%^!eIo4ac1;b>c0vyf9}Xby@YY!lkz-UvNp zwj#Gg|4B~?n?G^{;(W;|{SNoJbHTMpQJ*Wq5b{l9c8(%?Kd^1?H1om1de0Da9M;Q=n zUfn{f87iVb^>Exl*nZ0hs(Yt>&V9$Pg`zX`AI%`+0SWQ4Zc(8lUDcTluS z5a_KerZWe}a-MF9#Cd^fi!y3%@RFmg&~YnYZ6<=L`UJ0v={zr)>$A;x#MCHZy1st7 ztT+N07NR+vOwSV2pvWuN1%lO!K#Pj0Fr>Q~R40{bwdL%u9i`DSM4RdtEH#cW)6}+I-eE< z&tZs+(Ogu(H_;$a$!7w`MH0r%h&@KM+<>gJL@O~2K2?VrSYUBbhCn#yy?P)uF3qWU z0o09mIik+kvzV6w>vEZy@&Mr)SgxPzUiDA&%07m17udz9usD82afQEps3$pe!7fUf z0eiidkJ)m3qhOjVHC_M(RYCBO%CZKZXFb8}s0-+}@CIn&EF(rRWUX2g^yZCvl0bI} zbP;1S)iXnRC&}5-Tl(hASKqdSnO?ASGJ*MIhOXIblmEudj(M|W!+I3eDc}7t`^mtg z)PKlaXe(OH+q-)qcQ8a@!llRrpGI8DsjhoKvw9T;TEH&?s=LH0w$EzI>%u;oD@x83 zJL7+ncjI9nn!TlS_KYu5vn%f*@qa5F;| zEFxY&B?g=IVlaF3XNm_03PA)=3|{n-UCgJoTr;|;1AU9|kPE_if8!Zvb}0q$5okF$ zHaJdmO&gg!9oN|M{!qGE=tb|3pVQ8PbL$}e;NgXz<6ZEggI}wO@aBP**2Wo=yN#ZC z4G$m^yaM9g=|&!^ft8jOLuzc3Psca*;7`;gnHm}tS0%f4{|VGEwu45KptfNmwxlE~ z^=r30gi@?cOm8kAz!EylA4G~7kbEiRlRIzwrb~{_2(x^$-?|#e6Bi_**(vyr_~9Of z!n>Gqf+Qwiu!xhi9f53=PM3`3tNF}pCOiPU|H4;pzjcsqbwg*{{kyrTxk<;mx~(;; z1NMrpaQ`57yn34>Jo3b|HROE(UNcQash!0p2-!Cz;{IRv#Vp5!3o$P8!%SgV~k&Hnqhp`5eLjTcy93cK!3Hm-$`@yGnaE=?;*2uSpiZTs_dDd51U%i z{|Zd9ou-;laGS_x=O}a+ zB||za<795A?_~Q=r=coQ+ZK@@ zId~hWQL<%)fI_WDIX#=(WNl!Dm$a&ROfLTd&B$vatq!M-2Jcs;N2vps$b6P1(N}=oI3<3luMTmC|0*{ zm1w8bt7vgX($!0@V0A}XIK)w!AzUn7vH=pZEp0RU0p?}ch2XC-7r#LK&vyc2=-#Q2 z^L%8)JbbcZ%g0Du;|8=q8B>X=mIQirpE=&Ox{TiuNDnOPd-FLI^KfEF729!!0x#Es z@>3ursjFSpu%C-8WL^Zw!7a0O-#cnf`HjI+AjVCFitK}GXO`ME&on|^=~Zc}^LBp9 zj=-vlN;Uc;IDjtK38l7}5xxQF&sRtfn4^TNtnzXv4M{r&ek*(eNbIu!u$>Ed%` z5x7+&)2P&4>0J`N&ZP8$vcR+@FS0126s6+Jx_{{`3ZrIMwaJo6jdrRwE$>IU_JTZ} z(||hyyQ)4Z1@wSlT94(-QKqkAatMmkT7pCycEB1U8KQbFX&?%|4$yyxCtm3=W`$4fiG0WU3yI@c zx{wfmkZAYE_5M%4{J-ygbpH|(|GD$2f$3o_Vti#&zfSGZMQ5_f3xt6~+{RX=$H8at z?GFG1Tmp}}lmm-R->ve*Iv+XJ@58p|1_jRvfEgz$XozU8#iJS})UM6VNI!3RUU!{5 zXB(+Eqd-E;cHQ>)`h0(HO_zLmzR3Tu-UGp;08YntWwMY-9i^w_u#wR?JxR2bky5j9 z3Sl-dQQU$xrO0xa&>vsiK`QN<$Yd%YXXM7*WOhnRdSFt5$aJux8QceC?lA0_if|s> ze{ad*opH_kb%M&~(~&UcX0nFGq^MqjxW?HJIP462v9XG>j(5Gat_)#SiNfahq2Mz2 zU`4uV8m$S~o9(W>mu*=h%Gs(Wz+%>h;R9Sg)jZ$q8vT1HxX3iQnh6&2rJ1u|j>^Qf`A76K%_ubL`Zu?h4`b=IyL>1!=*%!_K)=XC z6d}4R5L+sI50Q4P3upXQ3Z!~1ZXLlh!^UNcK6#QpYt-YC=^H=EPg3)z*wXo*024Q4b2sBCG4I# zlTFFY=kQ>xvR+LsuDUAk)q%5pEcqr(O_|^spjhtpb1#aC& zghXzGkGDC_XDa%t(X`E+kvKQ4zrQ*uuQoj>7@@ykWvF332)RO?%AA&Fsn&MNzmFa$ zWk&&^=NNjxLjrli_8ESU)}U|N{%j&TQmvY~lk!~Jh}*=^INA~&QB9em!in_X%Rl1&Kd~Z(u z9mra#<@vZQlOY+JYUwCrgoea4C8^(xv4ceCXcejq84TQ#sF~IU2V}LKc~Xlr_P=ry zl&Hh0exdCbVd^NPCqNNlxM3vA13EI8XvZ1H9#bT7y*U8Y{H8nwGpOR!e!!}*g;mJ#}T{ekSb}5zIPmye*If(}}_=PcuAW#yidAa^9-`<8Gr0 z)Fz=NiZ{)HAvw{Pl5uu)?)&i&Us$Cx4gE}cIJ}B4Xz~-q7)R_%owbP!z_V2=Aq%Rj z{V;7#kV1dNT9-6R+H}}(ED*_!F=~uz>&nR3gb^Ce%+0s#u|vWl<~JD3MvS0T9thdF zioIG3c#Sdsv;LdtRv3ml7%o$6LTVL>(H`^@TNg`2KPIk*8-IB}X!MT0`hN9Ddf7yN z?J=GxPL!uJ7lqwowsl?iRrh@#5C$%E&h~Z>XQcvFC*5%0RN-Opq|=IwX(dq(*sjs+ zqy99+v~m|6T#zR*e1AVxZ8djd5>eIeCi(b8sUk)OGjAsKSOg^-ugwl2WSL@d#?mdl zib0v*{u-?cq}dDGyZ%$XRY=UkQwt2oGu`zQneZh$=^! zj;!pCBWQNtvAcwcWIBM2y9!*W|8LmQy$H~5BEx)78J`4Z0(FJO2P^!YyQU{*Al+fs z){!4JvT1iLrJ8aU3k0t|P}{RN)_^v%$$r;+p0DY7N8CXzmS*HB*=?qaaF9D@#_$SN zSz{moAK<*RH->%r7xX~9gVW$l7?b|_SYI)gcjf0VAUJ%FcQP(TpBs; zg$25D!Ry_`8xpS_OJdeo$qh#7U+cepZ??TII7_%AXsT$B z=e)Bx#v%J0j``00Zk5hsvv6%T^*xGNx%KN-=pocSoqE5_R)OK%-Pbu^1MNzfds)mL zxz^F4lDKV9D&lEY;I+A)ui{TznB*CE$=9(wgE{m}`^<--OzV-5V4X2w9j(_!+jpTr zJvD*y6;39&T+==$F&tsRKM_lqa1HC}aGL0o`%c9mO=fts?36@8MGm7Vi{Y z^<7m$(EtdSr#22<(rm_(l_(`j!*Pu~Y>>xc>I9M#DJYDJNHO&4=HM%YLIp?;iR&$m z#_$ZWYLfGLt5FJZhr3jpYb`*%9S!zCG6ivNHYzNHcI%khtgHBliM^Ou}ZVD7ehU9 zS+W@AV=?Ro!=%AJ>Kcy9aU3%VX3|XM_K0A+ZaknKDyIS3S-Hw1C7&BSW5)sqj5Ye_ z4OSW7Yu-;bCyYKHFUk}<*<(@TH?YZPHr~~Iy%9@GR2Yd}J2!N9K&CN7Eq{Ka!jdu; zQNB*Y;i(7)OxZK%IHGt#Rt?z`I|A{q_BmoF!f^G}XVeTbe1Wnzh%1g>j}>DqFf;Rp zz7>xIs12@Ke0gr+4-!pmFP84vCIaTjqFNg{V`5}Rdt~xE^I;Bxp4)|cs8=f)1YwHz zqI`G~s2~qqDV+h02b`PQpUE#^^Aq8l%y2|ByQeXSADg5*qMprEAE3WFg0Q39`O+i1 z!J@iV!`Y~C$wJ!5Z+j5$i<1`+@)tBG$JL=!*uk=2k;T<@{|s1$YL079FvK%mPhyHV zP8^KGZnp`(hVMZ;s=n~3r2y;LTwcJwoBW-(ndU-$03{RD zh+Qn$ja_Z^OuMf3Ub|JTY74s&Am*(n{J3~@#OJNYuEVVJd9*H%)oFoRBkySGm`hx! zT3tG|+aAkXcx-2Apy)h^BkOyFTWQVeZ%e2@;*0DtlG9I3Et=PKaPt&K zw?WI7S;P)TWED7aSH$3hL@Qde?H#tzo^<(o_sv_2ci<7M?F$|oCFWc?7@KBj-;N$P zB;q!8@bW-WJY9do&y|6~mEruZAVe$!?{)N9rZZxD-|oltkhW9~nR8bLBGXw<632!l z*TYQn^NnUy%Ds}$f^=yQ+BM-a5X4^GHF=%PDrRfm_uqC zh{sKwIu|O0&jWb27;wzg4w5uA@TO_j(1X?8E>5Zfma|Ly7Bklq|s z9)H`zoAGY3n-+&JPrT!>u^qg9Evx4y@GI4$n-Uk_5wttU1_t?6><>}cZ-U+&+~JE) zPlDbO_j;MoxdLzMd~Ew|1o^a5q_1R*JZ=#XXMzg?6Zy!^hop}qoLQlJ{(%!KYt`MK z8umEN@Z4w!2=q_oe=;QttPCQy3Nm4F@x>@v4sz_jo{4m*0r%J(w1cSo;D_hQtJs7W z><$QrmG^+<$4{d2bgGo&3-FV}avg9zI|Rr(k{wTyl3!M1q+a zD9W{pCd%il*j&Ft z5H$nENf>>k$;SONGW`qo6`&qKs*T z2^RS)pXk9b@(_Fw1bkb)-oqK|v}r$L!W&aXA>IpcdNZ_vWE#XO8X`#Yp1+?RshVcd zknG%rPd*4ECEI0wD#@d+3NbHKxl}n^Sgkx==Iu%}HvNliOqVBqG?P2va zQ;kRJ$J6j;+wP9cS za#m;#GUT!qAV%+rdWolk+)6kkz4@Yh5LXP+LSvo9_T+MmiaP-eq6_k;)i6_@WSJ zlT@wK$zqHu<83U2V*yJ|XJU4farT#pAA&@qu)(PO^8PxEmPD4;Txpio+2)#!9 z>&=i7*#tc0`?!==vk>s7V+PL#S1;PwSY?NIXN2=Gu89x(cToFm))7L;< z+bhAbVD*bD=}iU`+PU+SBobTQ%S!=VL!>q$rfWsaaV}Smz>lO9JXT#`CcH_mRCSf4%YQAw`$^yY z3Y*^Nzk_g$xn7a_NO(2Eb*I=^;4f!Ra#Oo~LLjlcjke*k*o$~U#0ZXOQ5@HQ&T46l z7504MUgZkz2gNP1QFN8Y?nSEnEai^Rgyvl}xZfMUV6QrJcXp;jKGqB=D*tj{8(_pV zqyB*DK$2lgYGejmJUW)*s_Cv65sFf&pb(Yz8oWgDtQ0~k^0-wdF|tj}MOXaN@ydF8 zNr={U?=;&Z?wr^VC+`)S2xl}QFagy;$mG=TUs7Vi2wws5zEke4hTa2)>O0U?$WYsZ z<8bN2bB_N4AWd%+kncgknZ&}bM~eDtj#C5uRkp21hWW5gxWvc6b*4+dn<{c?w9Rmf zIVZKsPl{W2vQAlYO3yh}-{Os=YBnL8?uN5(RqfQ=-1cOiUnJu>KcLA*tQK3FU`_bM zM^T28w;nAj5EdAXFi&Kk1Nnl2)D!M{@+D-}bIEe+Lc4{s;YJc-{F#``iS2uk;2!Zp zF9#myUmO!wCeJIoi^A+T^e~20c+c2C}XltaR!|U-HfDA=^xF97ev}$l6#oY z&-&T{egB)&aV$3_aVA51XGiU07$s9vubh_kQG?F$FycvS6|IO!6q zq^>9|3U^*!X_C~SxX&pqUkUjz%!j=VlXDo$!2VLH!rKj@61mDpSr~7B2yy{>X~_nc zRI+7g2V&k zd**H++P9dg!-AOs3;GM`(g<+GRV$+&DdMVpUxY9I1@uK28$az=6oaa+PutlO9?6#? zf-OsgT>^@8KK>ggkUQRPPgC7zjKFR5spqQb3ojCHzj^(UH~v+!y*`Smv)VpVoPwa6 zWG18WJaPKMi*F6Zdk*kU^`i~NNTfn3BkJniC`yN98L-Awd)Z&mY? zprBW$!qL-OL7h@O#kvYnLsfff@kDIegt~?{-*5A7JrA;#TmTe?jICJqhub-G@e??D zqiV#g{)M!kW1-4SDel7TO{;@*h2=_76g3NUD@|c*WO#>MfYq6_YVUP+&8e4|%4T`w zXzhmVNziAHazWO2qXcaOu@R1MrPP{t)`N)}-1&~mq=ZH=w=;-E$IOk=y$dOls{6sRR`I5>|X zpq~XYW4sd;J^6OwOf**J>a7u$S>WTFPRkjY;BfVgQst)u4aMLR1|6%)CB^18XCz+r ztkYQ}G43j~Q&1em(_EkMv0|WEiKu;z2zhb(L%$F&xWwzOmk;VLBYAZ8lOCziNoPw1 zv2BOyXA`A8z^WH!nXhKXM`t0;6D*-uGds3TYGrm8SPnJJOQ^fJU#}@aIy@MYWz**H zvkp?7I5PE{$$|~{-ZaFxr6ZolP^nL##mHOErB^AqJqn^hFA=)HWj!m3WDaHW$C)i^ z9@6G$SzB=>jbe>4kqr#sF7#K}W*Cg-5y6kun3u&0L7BpXF9=#7IN8FOjWrWwUBZiU zT_se3ih-GBKx+Uw0N|CwP3D@-C=5(9T#BH@M`F2!Goiqx+Js5xC92|Sy0%WWWp={$(am!#l~f^W_oz78HX<0X#7 zp)p1u~M*o9W@O8P{0Qkg@Wa# z2{Heb&oX^CQSZWSFBXKOfE|tsAm#^U-WkDnU;IowZ`Ok4!mwHwH=s|AqZ^YD4!5!@ zPxJj+Bd-q6w_YG`z_+r;S86zwXb+EO&qogOq8h-Ect5(M2+>(O7n7)^dP*ws_3U6v zVsh)sk^@*c>)3EML|0<-YROho{lz@Nd4;R9gL{9|64xVL`n!m$-Jjrx?-Bacp!=^5 z1^T^eB{_)Y<9)y{-4Rz@9_>;_7h;5D+@QcbF4Wv7hu)s0&==&6u)33 zHRj+&Woq-vDvjwJCYES@$C4{$?f$Ibi4G()UeN11rgjF+^;YE^5nYprYoJNoudNj= zm1pXSeG64dcWHObUetodRn1Fw|1nI$D9z}dVEYT0lQnsf_E1x2vBLql7NrHH!n&Sq z6lc*mvU=WS6=v9Lrl}&zRiu_6u;6g%_DU{9b+R z#YHqX7`m9eydf?KlKu6Sb%j$%_jmydig`B*TN`cZL-g!R)iE?+Q5oOqBFKhx z%MW>BC^(F_JuG(ayE(MT{S3eI{cKiwOtPwLc0XO*{*|(JOx;uQOfq@lp_^cZo=FZj z4#}@e@dJ>Bn%2`2_WPeSN7si^{U#H=7N4o%Dq3NdGybrZgEU$oSm$hC)uNDC_M9xc zGzwh5Sg?mpBIE8lT2XsqTt3j3?We8}3bzLBTQd639vyg^$0#1epq8snlDJP2(BF)K zSx30RM+{f+b$g{9usIL8H!hCO117Xgv}ttPJm9wVRjPk;ePH@zxv%j9k5`TzdXLeT zFgFX`V7cYIcBls5WN0Pf6SMBN+;CrQ(|EsFd*xtwr#$R{Z9FP`OWtyNsq#mCgZ7+P z^Yn$haBJ)r96{ZJd8vlMl?IBxrgh=fdq_NF!1{jARCVz>jNdC)H^wfy?R94#MPdUjcYX>#wEx+LB#P-#4S-%YH>t-j+w zOFTI8gX$ard6fAh&g=u&56%3^-6E2tpk*wx3HSCQ+t7+*iOs zPk5ysqE}i*cQocFvA68xHfL|iX(C4h*67@3|5Qwle(8wT&!&{8*{f%0(5gH+m>$tq zp;AqrP7?XTEooYG1Dzfxc>W%*CyL16q|fQ0_jp%%Bk^k!i#Nbi(N9&T>#M{gez_Ws zYK=l}adalV(nH}I_!hNeb;tQFk3BHX7N}}R8%pek^E`X}%ou=cx8InPU1EE0|Hen- zyw8MoJqB5=)Z%JXlrdTXAE)eqLAdVE-=>wGHrkRet}>3Yu^lt$Kzu%$3#(ioY}@Gu zjk3BZuQH&~7H+C*uX^4}F*|P89JX;Hg2U!pt>rDi(n(Qe-c}tzb0#6_ItoR0->LSt zR~UT<-|@TO%O`M+_e_J4wx7^)5_%%u+J=yF_S#2Xd?C;Ss3N7KY^#-vx+|;bJX&8r zD?|MetfhdC;^2WG`7MCgs>TKKN=^=!x&Q~BzmQio_^l~LboTNT=I zC5pme^P@ER``p$2md9>4!K#vV-Fc1an7pl>_|&>aqP}+zqR?+~Z;f2^`a+-!Te%V? z;H2SbF>jP^GE(R1@%C==XQ@J=G9lKX+Z<@5}PO(EYkJh=GCv#)Nj{DkWJM2}F&oAZ6xu8&g7pn1ps2U5srwQ7CAK zN&*~@t{`31lUf`O;2w^)M3B@o)_mbRu{-`PrfNpF!R^q>yTR&ETS7^-b2*{-tZAZz zw@q5x9B5V8Qd7dZ!Ai$9hk%Q!wqbE1F1c96&zwBBaRW}(^axoPpN^4Aw}&a5dMe+*Gomky_l^54*rzXro$ z>LL)U5Ry>~FJi=*{JDc)_**c)-&faPz`6v`YU3HQa}pLtb5K)u%K+BOqXP0)rj5Au$zB zW1?vr?mDv7Fsxtsr+S6ucp2l#(4dnr9sD*v+@*>g#M4b|U?~s93>Pg{{a5|rm2xfI z`>E}?9S@|IoUX{Q1zjm5YJT|3S>&09D}|2~BiMo=z4YEjXlWh)V&qs;*C{`UMxp$9 zX)QB?G$fPD6z5_pNs>Jeh{^&U^)Wbr?2D6-q?)`*1k@!UvwQgl8eG$r+)NnFoT)L6 zg7lEh+E6J17krfYJCSjWzm67hEth24pomhz71|Qodn#oAILN)*Vwu2qpJirG)4Wnv}9GWOFrQg%Je+gNrPl8mw7ykE8{ z=|B4+uwC&bpp%eFcRU6{mxRV32VeH8XxX>v$du<$(DfinaaWxP<+Y97Z#n#U~V zVEu-GoPD=9$}P;xv+S~Ob#mmi$JQmE;Iz4(){y*9pFyW-jjgdk#oG$fl4o9E8bo|L zWjo4l%n51@Kz-n%zeSCD`uB?T%FVk+KBI}=ve zvlcS#wt`U6wrJo}6I6Rwb=1GzZfwE=I&Ne@p7*pH84XShXYJRgvK)UjQL%R9Zbm(m zxzTQsLTON$WO7vM)*vl%Pc0JH7WhP;$z@j=y#avW4X8iqy6mEYr@-}PW?H)xfP6fQ z&tI$F{NNct4rRMSHhaelo<5kTYq+(?pY)Ieh8*sa83EQfMrFupMM@nfEV@EmdHUv9 z35uzIrIuo4#WnF^_jcpC@uNNaYTQ~uZWOE6P@LFT^1@$o&q+9Qr8YR+ObBkpP9=F+$s5+B!mX2~T zAuQ6RenX?O{IlLMl1%)OK{S7oL}X%;!XUxU~xJN8xk z`xywS*naF(J#?vOpB(K=o~lE;m$zhgPWDB@=p#dQIW>xe_p1OLoWInJRKbEuoncf; zmS1!u-ycc1qWnDg5Nk2D)BY%jmOwCLC+Ny>`f&UxFowIsHnOXfR^S;&F(KXd{ODlm z$6#1ccqt-HIH9)|@fHnrKudu!6B$_R{fbCIkSIb#aUN|3RM>zuO>dpMbROZ`^hvS@ z$FU-;e4W}!ubzKrU@R*dW*($tFZ>}dd*4_mv)#O>X{U@zSzQt*83l9mI zI$8O<5AIDx`wo0}f2fsPC_l>ONx_`E7kdXu{YIZbp1$(^oBAH({T~&oQ&1{X951QW zmhHUxd)t%GQ9#ak5fTjk-cahWC;>^Rg7(`TVlvy0W@Y!Jc%QL3Ozu# zDPIqBCy&T2PWBj+d-JA-pxZlM=9ja2ce|3B(^VCF+a*MMp`(rH>Rt6W1$;r{n1(VK zLs>UtkT43LR2G$AOYHVailiqk7naz2yZGLo*xQs!T9VN5Q>eE(w zw$4&)&6xIV$IO^>1N-jrEUg>O8G4^@y+-hQv6@OmF@gy^nL_n1P1-Rtyy$Bl;|VcV zF=p*&41-qI5gG9UhKmmnjs932!6hceXa#-qfK;3d*a{)BrwNFeKU|ge?N!;zk+kB! zMD_uHJR#%b54c2tr~uGPLTRLg$`fupo}cRJeTwK;~}A>(Acy4k-Xk&Aa1&eWYS1ULWUj@fhBiWY$pdfy+F z@G{OG{*v*mYtH3OdUjwEr6%_ZPZ3P{@rfbNPQG!BZ7lRyC^xlMpWH`@YRar`tr}d> z#wz87t?#2FsH-jM6m{U=gp6WPrZ%*w0bFm(T#7m#v^;f%Z!kCeB5oiF`W33W5Srdt zdU?YeOdPG@98H7NpI{(uN{FJdu14r(URPH^F6tOpXuhU7T9a{3G3_#Ldfx_nT(Hec zo<1dyhsVsTw;ZkVcJ_0-h-T3G1W@q)_Q30LNv)W?FbMH+XJ* zy=$@39Op|kZv`Rt>X`zg&at(?PO^I=X8d9&myFEx#S`dYTg1W+iE?vt#b47QwoHI9 zNP+|3WjtXo{u}VG(lLUaW0&@yD|O?4TS4dfJI`HC-^q;M(b3r2;7|FONXphw-%7~* z&;2!X17|05+kZOpQ3~3!Nb>O94b&ZSs%p)TK)n3m=4eiblVtSx@KNFgBY_xV6ts;NF;GcGxMP8OKV^h6LmSb2E#Qnw ze!6Mnz7>lE9u{AgQ~8u2zM8CYD5US8dMDX-5iMlgpE9m*s+Lh~A#P1er*rF}GHV3h z=`STo?kIXw8I<`W0^*@mB1$}pj60R{aJ7>C2m=oghKyxMbFNq#EVLgP0cH3q7H z%0?L93-z6|+jiN|@v>ix?tRBU(v-4RV`}cQH*fp|)vd3)8i9hJ3hkuh^8dz{F5-~_ zUUr1T3cP%cCaTooM8dj|4*M=e6flH0&8ve32Q)0dyisl))XkZ7Wg~N}6y`+Qi2l+e zUd#F!nJp{#KIjbQdI`%oZ`?h=5G^kZ_uN`<(`3;a!~EMsWV|j-o>c?x#;zR2ktiB! z);5rrHl?GPtr6-o!tYd|uK;Vbsp4P{v_4??=^a>>U4_aUXPWQ$FPLE4PK$T^3Gkf$ zHo&9$U&G`d(Os6xt1r?sg14n)G8HNyWa^q8#nf0lbr4A-Fi;q6t-`pAx1T*$eKM*$ z|CX|gDrk#&1}>5H+`EjV$9Bm)Njw&7-ZR{1!CJTaXuP!$Pcg69`{w5BRHysB$(tWUes@@6aM69kb|Lx$%BRY^-o6bjH#0!7b;5~{6J+jKxU!Kmi# zndh@+?}WKSRY2gZ?Q`{(Uj|kb1%VWmRryOH0T)f3cKtG4oIF=F7RaRnH0Rc_&372={_3lRNsr95%ZO{IX{p@YJ^EI%+gvvKes5cY+PE@unghjdY5#9A!G z70u6}?zmd?v+{`vCu-53_v5@z)X{oPC@P)iA3jK$`r zSA2a7&!^zmUiZ82R2=1cumBQwOJUPz5Ay`RLfY(EiwKkrx%@YN^^XuET;tE zmr-6~I7j!R!KrHu5CWGSChO6deaLWa*9LLJbcAJsFd%Dy>a!>J`N)Z&oiU4OEP-!Ti^_!p}O?7`}i7Lsf$-gBkuY*`Zb z7=!nTT;5z$_5$=J=Ko+Cp|Q0J=%oFr>hBgnL3!tvFoLNhf#D0O=X^h+x08iB;@8pXdRHxX}6R4k@i6%vmsQwu^5z zk1ip`#^N)^#Lg#HOW3sPI33xqFB4#bOPVnY%d6prwxf;Y-w9{ky4{O6&94Ra8VN@K zb-lY;&`HtxW@sF!doT5T$2&lIvJpbKGMuDAFM#!QPXW87>}=Q4J3JeXlwHys?!1^#37q_k?N@+u&Ns20pEoBeZC*np;i;M{2C0Z4_br2gsh6eL z#8`#sn41+$iD?^GL%5?cbRcaa-Nx0vE(D=*WY%rXy3B%gNz0l?#noGJGP728RMY#q z=2&aJf@DcR?QbMmN)ItUe+VM_U!ryqA@1VVt$^*xYt~-qvW!J4Tp<-3>jT=7Zow5M z8mSKp0v4b%a8bxFr>3MwZHSWD73D@+$5?nZAqGM#>H@`)mIeC#->B)P8T$zh-Pxnc z8)~Zx?TWF4(YfKuF3WN_ckpCe5;x4V4AA3(i$pm|78{%!q?|~*eH0f=?j6i)n~Hso zmTo>vqEtB)`%hP55INf7HM@taH)v`Fw40Ayc*R!T?O{ziUpYmP)AH`euTK!zg9*6Z z!>M=$3pd0!&TzU=hc_@@^Yd3eUQpX4-33}b{?~5t5lgW=ldJ@dUAH%`l5US1y_`40 zs(X`Qk}vvMDYYq+@Rm+~IyCX;iD~pMgq^KY)T*aBz@DYEB={PxA>)mI6tM*sx-DmGQHEaHwRrAmNjO!ZLHO4b;;5mf@zzlPhkP($JeZGE7 z?^XN}Gf_feGoG~BjUgVa*)O`>lX=$BSR2)uD<9 z>o^|nb1^oVDhQbfW>>!;8-7<}nL6L^V*4pB=>wwW+RXAeRvKED(n1;R`A6v$6gy0I(;Vf?!4;&sgn7F%LpM}6PQ?0%2Z@b{It<(G1CZ|>913E0nR2r^Pa*Bp z@tFGi*CQ~@Yc-?{cwu1 zsilf=k^+Qs>&WZG(3WDixisHpR>`+ihiRwkL(3T|=xsoNP*@XX3BU8hr57l3k;pni zI``=3Nl4xh4oDj<%>Q1zYXHr%Xg_xrK3Nq?vKX3|^Hb(Bj+lONTz>4yhU-UdXt2>j z<>S4NB&!iE+ao{0Tx^N*^|EZU;0kJkx@zh}S^P{ieQjGl468CbC`SWnwLRYYiStXm zOxt~Rb3D{dz=nHMcY)#r^kF8|q8KZHVb9FCX2m^X*(|L9FZg!5a7((!J8%MjT$#Fs)M1Pb zq6hBGp%O1A+&%2>l0mpaIzbo&jc^!oN^3zxap3V2dNj3x<=TwZ&0eKX5PIso9j1;e zwUg+C&}FJ`k(M|%%}p=6RPUq4sT3-Y;k-<68ciZ~_j|bt>&9ZLHNVrp#+pk}XvM{8 z`?k}o-!if>hVlCP9j%&WI2V`5SW)BCeR5>MQhF)po=p~AYN%cNa_BbV6EEh_kk^@a zD>4&>uCGCUmyA-c)%DIcF4R6!>?6T~Mj_m{Hpq`*(wj>foHL;;%;?(((YOxGt)Bhx zuS+K{{CUsaC++%}S6~CJ=|vr(iIs-je)e9uJEU8ZJAz)w166q)R^2XI?@E2vUQ!R% zn@dxS!JcOimXkWJBz8Y?2JKQr>`~SmE2F2SL38$SyR1^yqj8_mkBp)o$@+3BQ~Mid z9U$XVqxX3P=XCKj0*W>}L0~Em`(vG<>srF8+*kPrw z20{z(=^w+ybdGe~Oo_i|hYJ@kZl*(9sHw#Chi&OIc?w`nBODp?ia$uF%Hs(X>xm?j zqZQ`Ybf@g#wli`!-al~3GWiE$K+LCe=Ndi!#CVjzUZ z!sD2O*;d28zkl))m)YN7HDi^z5IuNo3^w(zy8 zszJG#mp#Cj)Q@E@r-=NP2FVxxEAeOI2e=|KshybNB6HgE^(r>HD{*}S}mO>LuRGJT{*tfTzw_#+er-0${}%YPe@CMJ1Ng#j#)i)SnY@ss3gL;g zg2D~#Kpdfu#G;q1qz_TwSz1VJT(b3zby$Vk&;Y#1(A)|xj`_?i5YQ;TR%jice5E;0 zYHg;`zS5{S*9xI6o^j>rE8Ua*XhIw{_-*&@(R|C(am8__>+Ws&Q^ymy*X4~hR2b5r zm^p3sw}yv=tdyncy_Ui7{BQS732et~Z_@{-IhHDXAV`(Wlay<#hb>%H%WDi+K$862nA@BDtM#UCKMu+kM`!JHyWSi?&)A7_ z3{cyNG%a~nnH_!+;g&JxEMAmh-Z}rC!o7>OVzW&PoMyTA_g{hqXG)SLraA^OP**<7 zjWbr7z!o2n3hnx7A=2O=WL;`@9N{vQIM@&|G-ljrPvIuJHYtss0Er0fT5cMXNUf1B z7FAwBDixt0X7C3S)mPe5g`YtME23wAnbU)+AtV}z+e8G;0BP=bI;?(#|Ep!vVfDbK zvx+|CKF>yt0hWQ3drchU#XBU+HiuG*V^snFAPUp-5<#R&BUAzoB!aZ+e*KIxa26V}s6?nBK(U-7REa573wg-jqCg>H8~>O{ z*C0JL-?X-k_y%hpUFL?I>0WV{oV`Nb)nZbJG01R~AG>flIJf)3O*oB2i8~;!P?Wo_ z0|QEB*fifiL6E6%>tlAYHm2cjTFE@*<);#>689Z6S#BySQ@VTMhf9vYQyLeDg1*F} zjq>i1*x>5|CGKN{l9br3kB0EHY|k4{%^t7-uhjd#NVipUZa=EUuE5kS1_~qYX?>hJ z$}!jc9$O$>J&wnu0SgfYods^z?J4X;X7c77Me0kS-dO_VUQ39T(Kv(Y#s}Qqz-0AH z^?WRL(4RzpkD+T5FG_0NyPq-a-B7A5LHOCqwObRJi&oRi(<;OuIN7SV5PeHU$<@Zh zPozEV`dYmu0Z&Tqd>t>8JVde9#Pt+l95iHe$4Xwfy1AhI zDM4XJ;bBTTvRFtW>E+GzkN)9k!hA5z;xUOL2 zq4}zn-DP{qc^i|Y%rvi|^5k-*8;JZ~9a;>-+q_EOX+p1Wz;>i7c}M6Nv`^NY&{J-> z`(mzDJDM}QPu5i44**2Qbo(XzZ-ZDu%6vm8w@DUarqXj41VqP~ zs&4Y8F^Waik3y1fQo`bVUH;b=!^QrWb)3Gl=QVKr+6sxc=ygauUG|cm?|X=;Q)kQ8 zM(xrICifa2p``I7>g2R~?a{hmw@{!NS5`VhH8+;cV(F>B94M*S;5#O`YzZH1Z%yD? zZ61w(M`#aS-*~Fj;x|J!KM|^o;MI#Xkh0ULJcA?o4u~f%Z^16ViA27FxU5GM*rKq( z7cS~MrZ=f>_OWx8j#-Q3%!aEU2hVuTu(7`TQk-Bi6*!<}0WQi;_FpO;fhpL4`DcWp zGOw9vx0N~6#}lz(r+dxIGZM3ah-8qrqMmeRh%{z@dbUD2w15*_4P?I~UZr^anP}DB zU9CCrNiy9I3~d#&!$DX9e?A});BjBtQ7oGAyoI$8YQrkLBIH@2;lt4E^)|d6Jwj}z z&2_E}Y;H#6I4<10d_&P0{4|EUacwFHauvrjAnAm6yeR#}f}Rk27CN)vhgRqEyPMMS7zvunj2?`f;%?alsJ+-K+IzjJx>h8 zu~m_y$!J5RWAh|C<6+uiCNsOKu)E72M3xKK(a9Okw3e_*O&}7llNV!=P87VM2DkAk zci!YXS2&=P0}Hx|wwSc9JP%m8dMJA*q&VFB0yMI@5vWoAGraygwn){R+Cj6B1a2Px z5)u(K5{+;z2n*_XD!+Auv#LJEM)(~Hx{$Yb^ldQmcYF2zNH1V30*)CN_|1$v2|`LnFUT$%-tO0Eg|c5$BB~yDfzS zcOXJ$wpzVK0MfTjBJ0b$r#_OvAJ3WRt+YOLlJPYMx~qp>^$$$h#bc|`g0pF-Ao43? z>*A+8lx>}L{p(Tni2Vvk)dtzg$hUKjSjXRagj)$h#8=KV>5s)J4vGtRn5kP|AXIz! zPgbbVxW{2o4s-UM;c#We8P&mPN|DW7_uLF!a|^0S=wr6Esx9Z$2|c1?GaupU6$tb| zY_KU`(_29O_%k(;>^|6*pZURH3`@%EuKS;Ns z1lujmf;r{qAN&Q0&m{wJSZ8MeE7RM5+Sq;ul_ z`+ADrd_Um+G37js6tKsArNB}n{p*zTUxQr>3@wA;{EUbjNjlNd6$Mx zg0|MyU)v`sa~tEY5$en7^PkC=S<2@!nEdG6L=h(vT__0F=S8Y&eM=hal#7eM(o^Lu z2?^;05&|CNliYrq6gUv;|i!(W{0N)LWd*@{2q*u)}u*> z7MQgk6t9OqqXMln?zoMAJcc zMKaof_Up})q#DzdF?w^%tTI7STI^@8=Wk#enR*)&%8yje>+tKvUYbW8UAPg55xb70 zEn5&Ba~NmOJlgI#iS8W3-@N%>V!#z-ZRwfPO1)dQdQkaHsiqG|~we2ALqG7Ruup(DqSOft2RFg_X%3w?6VqvV1uzX_@F(diNVp z4{I|}35=11u$;?|JFBEE*gb;T`dy+8gWJ9~pNsecrO`t#V9jW-6mnfO@ff9od}b(3s4>p0i30gbGIv~1@a^F2kl7YO;DxmF3? zWi-RoXhzRJV0&XE@ACc?+@6?)LQ2XNm4KfalMtsc%4!Fn0rl zpHTrHwR>t>7W?t!Yc{*-^xN%9P0cs0kr=`?bQ5T*oOo&VRRu+1chM!qj%2I!@+1XF z4GWJ=7ix9;Wa@xoZ0RP`NCWw0*8247Y4jIZ>GEW7zuoCFXl6xIvz$ezsWgKdVMBH> z{o!A7f;R-@eK9Vj7R40xx)T<2$?F2E<>Jy3F;;=Yt}WE59J!1WN367 zA^6pu_zLoZIf*x031CcwotS{L8bJE(<_F%j_KJ2P_IusaZXwN$&^t716W{M6X2r_~ zaiMwdISX7Y&Qi&Uh0upS3TyEIXNDICQlT5fHXC`aji-c{U(J@qh-mWl-uMN|T&435 z5)a1dvB|oe%b2mefc=Vpm0C%IUYYh7HI*;3UdgNIz}R##(#{(_>82|zB0L*1i4B5j-xi9O4x10rs_J6*gdRBX=@VJ+==sWb&_Qc6tSOowM{BX@(zawtjl zdU!F4OYw2@Tk1L^%~JCwb|e#3CC>srRHQ*(N%!7$Mu_sKh@|*XtR>)BmWw!;8-mq7 zBBnbjwx8Kyv|hd*`5}84flTHR1Y@@uqjG`UG+jN_YK&RYTt7DVwfEDXDW4U+iO{>K zw1hr{_XE*S*K9TzzUlJH2rh^hUm2v7_XjwTuYap|>zeEDY$HOq3X4Tz^X}E9z)x4F zs+T?Ed+Hj<#jY-`Va~fT2C$=qFT-5q$@p9~0{G&eeL~tiIAHXA!f6C(rAlS^)&k<- zXU|ZVs}XQ>s5iONo~t!XXZgtaP$Iau;JT%h)>}v54yut~pykaNye4axEK#5@?TSsQ zE;Jvf9I$GVb|S`7$pG)4vgo9NXsKr?u=F!GnA%VS2z$@Z(!MR9?EPcAqi5ft)Iz6sNl`%kj+_H-X`R<>BFrBW=fSlD|{`D%@Rcbu2?%>t7i34k?Ujb)2@J-`j#4 zLK<69qcUuniIan-$A1+fR=?@+thwDIXtF1Tks@Br-xY zfB+zblrR(ke`U;6U~-;p1Kg8Lh6v~LjW@9l2P6s+?$2!ZRPX`(ZkRGe7~q(4&gEi<$ch`5kQ?*1=GSqkeV z{SA1EaW_A!t{@^UY2D^YO0(H@+kFVzZaAh0_`A`f(}G~EP~?B|%gtxu&g%^x{EYSz zk+T;_c@d;+n@$<>V%P=nk36?L!}?*=vK4>nJSm+1%a}9UlmTJTrfX4{Lb7smNQn@T zw9p2%(Zjl^bWGo1;DuMHN(djsEm)P8mEC2sL@KyPjwD@d%QnZ$ zMJ3cnn!_!iP{MzWk%PI&D?m?C(y2d|2VChluN^yHya(b`h>~GkI1y;}O_E57zOs!{ zt2C@M$^PR2U#(dZmA-sNreB@z-yb0Bf7j*yONhZG=onhx>t4)RB`r6&TP$n zgmN*)eCqvgriBO-abHQ8ECN0bw?z5Bxpx z=jF@?zFdVn?@gD5egM4o$m`}lV(CWrOKKq(sv*`mNcHcvw&Xryfw<{ch{O&qc#WCTXX6=#{MV@q#iHYba!OUY+MGeNTjP%Fj!WgM&`&RlI^=AWTOqy-o zHo9YFt!gQ*p7{Fl86>#-JLZo(b^O`LdFK~OsZBRR@6P?ad^Ujbqm_j^XycM4ZHFyg ziUbIFW#2tj`65~#2V!4z7DM8Z;fG0|APaQ{a2VNYpNotB7eZ5kp+tPDz&Lqs0j%Y4tA*URpcfi z_M(FD=fRGdqf430j}1z`O0I=;tLu81bwJXdYiN7_&a-?ly|-j*+=--XGvCq#32Gh(=|qj5F?kmihk{%M&$}udW5)DHK zF_>}5R8&&API}o0osZJRL3n~>76nUZ&L&iy^s>PMnNcYZ|9*1$v-bzbT3rpWsJ+y{ zPrg>5Zlery96Um?lc6L|)}&{992{_$J&=4%nRp9BAC6!IB=A&=tF>r8S*O-=!G(_( zwXbX_rGZgeiK*&n5E;f=k{ktyA1(;x_kiMEt0*gpp_4&(twlS2e5C?NoD{n>X2AT# zY@Zp?#!b1zNq96MQqeO*M1MMBin5v#RH52&Xd~DO6-BZLnA6xO1$sou(YJ1Dlc{WF zVa%2DyYm`V#81jP@70IJ;DX@y*iUt$MLm)ByAD$eUuji|5{ptFYq(q)mE(5bOpxjM z^Q`AHWq44SG3`_LxC9fwR)XRVIp=B%<(-lOC3jI#bb@dK(*vjom!=t|#<@dZql%>O z15y^{4tQoeW9Lu%G&V$90x6F)xN6y_oIn;!Q zs)8jT$;&;u%Y>=T3hg34A-+Y*na=|glcStr5D;&5*t5*DmD~x;zQAV5{}Ya`?RRGa zT*t9@$a~!co;pD^!J5bo?lDOWFx%)Y=-fJ+PDGc0>;=q=s?P4aHForSB+)v0WY2JH z?*`O;RHum6j%#LG)Vu#ciO#+jRC3!>T(9fr+XE7T2B7Z|0nR5jw@WG)kDDzTJ=o4~ zUpeyt7}_nd`t}j9BKqryOha{34erm)RmST)_9Aw)@ zHbiyg5n&E{_CQR@h<}34d7WM{s{%5wdty1l+KX8*?+-YkNK2Be*6&jc>@{Fd;Ps|| z26LqdI3#9le?;}risDq$K5G3yoqK}C^@-8z^wj%tdgw-6@F#Ju{Sg7+y)L?)U$ez> zoOaP$UFZ?y5BiFycir*pnaAaY+|%1%8&|(@VB)zweR%?IidwJyK5J!STzw&2RFx zZV@qeaCB01Hu#U9|1#=Msc8Pgz5P*4Lrp!Q+~(G!OiNR{qa7|r^H?FC6gVhkk3y7=uW#Sh;&>78bZ}aK*C#NH$9rX@M3f{nckYI+5QG?Aj1DM)@~z_ zw!UAD@gedTlePB*%4+55naJ8ak_;))#S;4ji!LOqY5VRI){GMwHR~}6t4g>5C_#U# ztYC!tjKjrKvRy=GAsJVK++~$|+s!w9z3H4G^mACv=EErXNSmH7qN}%PKcN|8%9=i)qS5+$L zu&ya~HW%RMVJi4T^pv?>mw*Gf<)-7gf#Qj|e#w2|v4#t!%Jk{&xlf;$_?jW*n!Pyx zkG$<18kiLOAUPuFfyu-EfWX%4jYnjBYc~~*9JEz6oa)_R|8wjZA|RNrAp%}14L7fW zi7A5Wym*K+V8pkqqO-X#3ft{0qs?KVt^)?kS>AicmeO&q+~J~ zp0YJ_P~_a8j= zsAs~G=8F=M{4GZL{|B__UorX@MRNQLn?*_gym4aW(~+i13knnk1P=khoC-ViMZk+x zLW(l}oAg1H`dU+Fv**;qw|ANDSRs>cGqL!Yw^`; zv;{E&8CNJcc)GHzTYM}f&NPw<6j{C3gaeelU#y!M)w-utYEHOCCJo|Vgp7K6C_$14 zqIrLUB0bsgz^D%V%fbo2f9#yb#CntTX?55Xy|Kps&Xek*4_r=KDZ z+`TQuv|$l}MWLzA5Ay6Cvsa^7xvwXpy?`w(6vx4XJ zWuf1bVSb#U8{xlY4+wlZ$9jjPk)X_;NFMqdgq>m&W=!KtP+6NL57`AMljW+es zzqjUjgz;V*kktJI?!NOg^s_)ph45>4UDA!Vo0hn>KZ+h-3=?Y3*R=#!fOX zP$Y~+14$f66ix?UWB_6r#fMcC^~X4R-<&OD1CSDNuX~y^YwJ>sW0j`T<2+3F9>cLo z#!j57$ll2K9(%$4>eA7(>FJX5e)pR5&EZK!IMQzOfik#FU*o*LGz~7u(8}XzIQRy- z!U7AlMTIe|DgQFmc%cHy_9^{o`eD%ja_L>ckU6$O4*U**o5uR7`FzqkU8k4gxtI=o z^P^oGFPm5jwZMI{;nH}$?p@uV8FT4r=|#GziKXK07bHJLtK}X%I0TON$uj(iJ`SY^ zc$b2CoxCQ>7LH@nxcdW&_C#fMYBtTxcg46dL{vf%EFCZ~eErMvZq&Z%Lhumnkn^4A zsx$ay(FnN7kYah}tZ@0?-0Niroa~13`?hVi6`ndno`G+E8;$<6^gsE-K3)TxyoJ4M zb6pj5=I8^FD5H@`^V#Qb2^0cx7wUz&cruA5g>6>qR5)O^t1(-qqP&1g=qvY#s&{bx zq8Hc%LsbK1*%n|Y=FfojpE;w~)G0-X4i*K3{o|J7`krhIOd*c*$y{WIKz2n2*EXEH zT{oml3Th5k*vkswuFXdGDlcLj15Nec5pFfZ*0?XHaF_lVuiB%Pv&p7z)%38}%$Gup zVTa~C8=cw%6BKn_|4E?bPNW4PT7}jZQLhDJhvf4z;~L)506IE0 zX!tWXX(QOQPRj-p80QG79t8T2^az4Zp2hOHziQlvT!|H)jv{Ixodabzv6lBj)6WRB z{)Kg@$~~(7$-az?lw$4@L%I&DI0Lo)PEJJziWP33a3azb?jyXt1v0N>2kxwA6b%l> zZqRpAo)Npi&loWbjFWtEV)783BbeIAhqyuc+~>i7aQ8shIXt)bjCWT6$~ro^>99G} z2XfmT0(|l!)XJb^E!#3z4oEGIsL(xd; zYX1`1I(cG|u#4R4T&C|m*9KB1`UzKvho5R@1eYtUL9B72{i(ir&ls8g!pD ztR|25xGaF!4z5M+U@@lQf(12?xGy`!|3E}7pI$k`jOIFjiDr{tqf0va&3pOn6Pu)% z@xtG2zjYuJXrV)DUrIF*y<1O1<$#54kZ#2;=X51J^F#0nZ0(;S$OZDt_U2bx{RZ=Q zMMdd$fH|!s{ zXq#l;{`xfV`gp&C>A`WrQU?d{!Ey5(1u*VLJt>i27aZ-^&2IIk=zP5p+{$q(K?2(b z8?9h)kvj9SF!Dr zoyF}?V|9;6abHxWk2cEvGs$-}Pg}D+ZzgkaN&$Snp%;5m%zh1E#?Wac-}x?BYlGN#U#Mek*}kek#I9XaHt?mz3*fDrRTQ#&#~xyeqJk1QJ~E$7qsw6 z?sV;|?*=-{M<1+hXoj?@-$y+(^BJ1H~wQ9G8C0#^aEAyhDduNX@haoa=PuPp zYsGv8UBfQaRHgBgLjmP^eh>fLMeh{8ic)?xz?#3kX-D#Z{;W#cd_`9OMFIaJg-=t`_3*!YDgtNQ2+QUEAJB9M{~AvT$H`E)IKmCR21H532+ata8_i_MR@ z2Xj<3w<`isF~Ah$W{|9;51ub*f4#9ziKrOR&jM{x7I_7()O@`F*5o$KtZ?fxU~g`t zUovNEVKYn$U~VX8eR)qb`7;D8pn*Pp$(otYTqL)5KH$lUS-jf}PGBjy$weoceAcPp z&5ZYB$r&P$MN{0H0AxCe4Qmd3T%M*5d4i%#!nmBCN-WU-4m4Tjxn-%j3HagwTxCZ9 z)j5vO-C7%s%D!&UfO>bi2oXiCw<-w{vVTK^rVbv#W=WjdADJy8$khnU!`ZWCIU`># zyjc^1W~pcu>@lDZ{zr6gv%)2X4n27~Ve+cQqcND%0?IFSP4sH#yIaXXYAq^z3|cg` z`I3$m%jra>e2W-=DiD@84T!cb%||k)nPmEE09NC%@PS_OLhkrX*U!cgD*;;&gIaA(DyVT4QD+q_xu z>r`tg{hiGY&DvD-)B*h+YEd+Zn)WylQl}<4>(_NlsKXCRV;a)Rcw!wtelM2_rWX`j zTh5A|i6=2BA(iMCnj_fob@*eA;V?oa4Z1kRBGaU07O70fb6-qmA$Hg$ps@^ka1=RO zTbE_2#)1bndC3VuK@e!Sftxq4=Uux}fDxXE#Q5_x=E1h>T5`DPHz zbH<_OjWx$wy7=%0!mo*qH*7N4tySm+R0~(rbus`7;+wGh;C0O%x~fEMkt!eV>U$`i z5>Q(o z=t$gPjgGh0&I7KY#k50V7DJRX<%^X z>6+ebc9efB3@eE2Tr){;?_w`vhgF>`-GDY(YkR{9RH(MiCnyRtd!LxXJ75z+?2 zGi@m^+2hKJ5sB1@Xi@s_@p_Kwbc<*LQ_`mr^Y%j}(sV_$`J(?_FWP)4NW*BIL~sR>t6 zM;qTJZ~GoY36&{h-Pf}L#y2UtR}>ZaI%A6VkU>vG4~}9^i$5WP2Tj?Cc}5oQxe2=q z8BeLa$hwCg_psjZyC2+?yX4*hJ58Wu^w9}}7X*+i5Rjqu5^@GzXiw#SUir1G1`jY% zOL=GE_ENYxhcyUrEt9XlMNP6kx6h&%6^u3@zB8KUCAa18T(R2J`%JjWZ z!{7cXaEW+Qu*iJPu+m>QqW}Lo$4Z+!I)0JNzZ&_M%=|B1yejFRM04bGAvu{=lNPd+ zJRI^DRQ(?FcVUD+bgEcAi@o(msqys9RTCG#)TjI!9~3-dc`>gW;HSJuQvH~d`MQs86R$|SKXHh zqS9Qy)u;T`>>a!$LuaE2keJV%;8g)tr&Nnc;EkvA-RanHXsy)D@XN0a>h}z2j81R; zsUNJf&g&rKpuD0WD@=dDrPHdBoK42WoBU|nMo17o(5^;M|dB4?|FsAGVrSyWcI`+FVw^vTVC`y}f(BwJl zrw3Sp151^9=}B})6@H*i4-dIN_o^br+BkcLa^H56|^2XsT0dESw2 zMX>(KqNl=x2K5=zIKg}2JpGAZu{I_IO}0$EQ5P{4zol**PCt3F4`GX}2@vr8#Y)~J zKb)gJeHcFnR@4SSh%b;c%J`l=W*40UPjF#q{<}ywv-=vHRFmDjv)NtmC zQx9qm)d%0zH&qG7AFa3VAU1S^(n8VFTC~Hb+HjYMjX8r#&_0MzlNR*mnLH5hi}`@{ zK$8qiDDvS_(L9_2vHgzEQ${DYSE;DqB!g*jhJghE&=LTnbgl&Xepo<*uRtV{2wDHN z)l;Kg$TA>Y|K8Lc&LjWGj<+bp4Hiye_@BfU(y#nF{fpR&|Ltbye?e^j0}8JC4#xi% zv29ZR%8%hk=3ZDvO-@1u8KmQ@6p%E|dlHuy#H1&MiC<*$YdLkHmR#F3ae;bKd;@*i z2_VfELG=B}JMLCO-6UQy^>RDE%K4b>c%9ki`f~Z2Qu8hO7C#t%Aeg8E%+}6P7Twtg z-)dj(w}_zFK&86KR@q9MHicUAucLVshUdmz_2@32(V`y3`&Kf8Q2I)+!n0mR=rrDU zXvv^$ho;yh*kNqJ#r1}b0|i|xRUF6;lhx$M*uG3SNLUTC@|htC z-=fsw^F%$qqz4%QdjBrS+ov}Qv!z00E+JWas>p?z@=t!WWU3K*?Z(0meTuTOC7OTx zU|kFLE0bLZ+WGcL$u4E}5dB0g`h|uwv3=H6f+{5z9oLv-=Q45+n~V4WwgO=CabjM% zBAN+RjM65(-}>Q2V#i1Na@a0`08g&y;W#@sBiX6Tpy8r}*+{RnyGUT`?XeHSqo#|J z^ww~c;ou|iyzpErDtlVU=`8N7JSu>4M z_pr9=tX0edVn9B}YFO2y(88j#S{w%E8vVOpAboK*27a7e4Ekjt0)hIX99*1oE;vex z7#%jhY=bPijA=Ce@9rRO(Vl_vnd00!^TAc<+wVvRM9{;hP*rqEL_(RzfK$er_^SN; z)1a8vo8~Dr5?;0X0J62Cusw$A*c^Sx1)dom`-)Pl7hsW4i(r*^Mw`z5K>!2ixB_mu z*Ddqjh}zceRFdmuX1akM1$3>G=#~|y?eYv(e-`Qy?bRHIq=fMaN~fB zUa6I8Rt=)jnplP>yuS+P&PxeWpJ#1$F`iqRl|jF$WL_aZFZl@kLo&d$VJtu&w?Q0O zzuXK>6gmygq(yXJy0C1SL}T8AplK|AGNUOhzlGeK_oo|haD@)5PxF}rV+5`-w{Aag zus45t=FU*{LguJ11Sr-28EZkq;!mJO7AQGih1L4rEyUmp>B!%X0YemsrV3QFvlgt* z5kwlPzaiJ+kZ^PMd-RRbl(Y?F*m`4*UIhIuf#8q>H_M=fM*L_Op-<_r zBZagV=4B|EW+KTja?srADTZXCd3Yv%^Chfpi)cg{ED${SI>InNpRj5!euKv?=Xn92 zsS&FH(*w`qLIy$doc>RE&A5R?u zzkl1sxX|{*fLpXvIW>9d<$ePROttn3oc6R!sN{&Y+>Jr@yeQN$sFR z;w6A<2-0%UA?c8Qf;sX7>>uKRBv3Ni)E9pI{uVzX|6Bb0U)`lhLE3hK58ivfRs1}d zNjlGK0hdq0qjV@q1qI%ZFMLgcpWSY~mB^LK)4GZ^h_@H+3?dAe_a~k*;9P_d7%NEFP6+ zgV(oGr*?W(ql?6SQ~`lUsjLb%MbfC4V$)1E0Y_b|OIYxz4?O|!kRb?BGrgiH5+(>s zoqM}v*;OBfg-D1l`M6T6{K`LG+0dJ1)!??G5g(2*vlNkm%Q(MPABT$r13q?|+kL4- zf)Mi5r$sn;u41aK(K#!m+goyd$c!KPl~-&-({j#D4^7hQkV3W|&>l_b!}!z?4($OA z5IrkfuT#F&S1(`?modY&I40%gtroig{YMvF{K{>5u^I51k8RriGd${z)=5k2tG zM|&Bp5kDTfb#vfuTTd?)a=>bX=lokw^y9+2LS?kwHQIWI~pYgy7 zb?A-RKVm_vM5!9?C%qYdfRAw& zAU7`up~%g=p@}pg#b7E)BFYx3g%(J36Nw(Dij!b>cMl@CSNbrW!DBDbTD4OXk!G4x zi}JBKc8HBYx$J~31PXH+4^x|UxK~(<@I;^3pWN$E=sYma@JP|8YL`L(zI6Y#c%Q{6 z*APf`DU$S4pr#_!60BH$FGViP14iJmbrzSrOkR;f3YZa{#E7Wpd@^4E-zH8EgPc-# zKWFPvh%WbqU_%ZEt`=Q?odKHc7@SUmY{GK`?40VuL~o)bS|is$Hn=<=KGHOsEC5tB zFb|q}gGlL97NUf$G$>^1b^3E18PZ~Pm9kX%*ftnolljiEt@2#F2R5ah$zbXd%V_Ev zyDd{1o_uuoBga$fB@Fw!V5F3jIr=a-ykqrK?WWZ#a(bglI_-8pq74RK*KfQ z0~Dzus7_l;pMJYf>Bk`)`S8gF!To-BdMnVw5M-pyu+aCiC5dwNH|6fgRsIKZcF&)g zr}1|?VOp}I3)IR@m1&HX1~#wsS!4iYqES zK}4J{Ei>;e3>LB#Oly>EZkW14^@YmpbgxCDi#0RgdM${&wxR+LiX}B+iRioOB0(pDKpVEI;ND?wNx>%e|m{RsqR_{(nmQ z3ZS}@t!p4a(BKx_-CYwrcyJ5u1TO9bcXti$8sy>xcLKqKCc#~UOZYD{llKTSFEjJ~ zyNWt>tLU}*>^`TvPxtP%F`ZJQw@W0^>x;!^@?k_)9#bF$j0)S3;mH-IR5y82l|%=F z2lR8zhP?XNP-ucZZ6A+o$xOyF!w;RaLHGh57GZ|TCXhJqY~GCh)aXEV$1O&$c}La1 zjuJxkY9SM4av^Hb;i7efiYaMwI%jGy`3NdY)+mcJhF(3XEiSlU3c|jMBi|;m-c?~T z+x0_@;SxcoY=(6xNgO$bBt~Pj8`-<1S|;Bsjrzw3@zSjt^JC3X3*$HI79i~!$RmTz zsblZsLYs7L$|=1CB$8qS!tXrWs!F@BVuh?kN(PvE5Av-*r^iYu+L^j^m9JG^#=m>@ z=1soa)H*w6KzoR$B8mBCXoU;f5^bVuwQ3~2LKg!yxomG1#XPmn(?YH@E~_ED+W6mxs%x{%Z<$pW`~ON1~2XjP5v(0{C{+6Dm$00tsd3w=f=ZENy zOgb-=f}|Hb*LQ$YdWg<(u7x3`PKF)B7ZfZ6;1FrNM63 z?O6tE%EiU@6%rVuwIQjvGtOofZBGZT1Sh(xLIYt9c4VI8`!=UJd2BfLjdRI#SbVAX ziT(f*RI^T!IL5Ac>ql7uduF#nuCRJ1)2bdvAyMxp-5^Ww5p#X{rb5)(X|fEhDHHW{ zw(Lfc$g;+Q`B0AiPGtmK%*aWfQQ$d!*U<|-@n2HZvCWSiw^I>#vh+LyC;aaVWGbmkENr z&kl*8o^_FW$T?rDYLO1Pyi%>@&kJKQoH2E0F`HjcN}Zlnx1ddoDA>G4Xu_jyp6vuT zPvC}pT&Owx+qB`zUeR|4G;OH(<<^_bzkjln0k40t`PQxc$7h(T8Ya~X+9gDc8Z9{Z z&y0RAU}#_kQGrM;__MK9vwIwK^aoqFhk~dK!ARf1zJqHMxF2?7-8|~yoO@_~Ed;_wvT%Vs{9RK$6uUQ|&@#6vyBsFK9eZW1Ft#D2)VpQRwpR(;x^ zdoTgMqfF9iBl%{`QDv7B0~8{8`8k`C4@cbZAXBu00v#kYl!#_Wug{)2PwD5cNp?K^ z9+|d-4z|gZ!L{57>!Ogfbzchm>J1)Y%?NThxIS8frAw@z>Zb9v%3_3~F@<=LG%r*U zaTov}{{^z~SeX!qgSYow`_5)ij*QtGp4lvF`aIGQ>@3ZTkDmsl#@^5*NGjOuu82}o zzLF~Q9SW+mP=>88%eSA1W4_W7-Q>rdq^?t=m6}^tDPaBRGFLg%ak93W!kOp#EO{6& zP%}Iff5HZQ9VW$~+9r=|Quj#z*=YwcnssS~9|ub2>v|u1JXP47vZ1&L1O%Z1DsOrDfSIMHU{VT>&>H=9}G3i@2rP+rx@eU@uE8rJNec zij~#FmuEBj03F1~ct@C@$>y)zB+tVyjV3*n`mtAhIM0$58vM9jOQC}JJOem|EpwqeMuYPxu3sv}oMS?S#o6GGK@8PN59)m&K4Dc&X% z(;XL_kKeYkafzS3Wn5DD>Yiw{LACy_#jY4op(>9q>>-*9@C0M+=b#bknAWZ37^(Ij zq>H%<@>o4a#6NydoF{_M4i4zB_KG)#PSye9bk0Ou8h%1Dtl7Q_y#7*n%g)?m>xF~( zjqvOwC;*qvN_3(*a+w2|ao0D?@okOvg8JskUw(l7n`0fncglavwKd?~l_ryKJ^Ky! zKCHkIC-o7%fFvPa$)YNh022lakMar^dgL=t#@XLyNHHw!b?%WlM)R@^!)I!smZL@k zBi=6wE5)2v&!UNV(&)oOYW(6Qa!nUjDKKBf-~Da=#^HE4(@mWk)LPvhyN3i4goB$3K8iV7uh zsv+a?#c4&NWeK(3AH;ETrMOIFgu{_@%XRwCZ;L=^8Ts)hix4Pf3yJRQ<8xb^CkdmC z?c_gB)XmRsk`9ch#tx4*hO=#qS7={~Vb4*tTf<5P%*-XMfUUYkI9T1cEF;ObfxxI-yNuA=I$dCtz3ey znVkctYD*`fUuZ(57+^B*R=Q}~{1z#2!ca?)+YsRQb+lt^LmEvZt_`=j^wqig+wz@n@ z`LIMQJT3bxMzuKg8EGBU+Q-6cs5(@5W?N>JpZL{$9VF)veF`L5%DSYTNQEypW%6$u zm_~}T{HeHj1bAlKl8ii92l9~$dm=UM21kLemA&b$;^!wB7#IKWGnF$TVq!!lBlG4 z{?Rjz?P(uvid+|i$VH?`-C&Gcb3{(~Vpg`w+O);Wk1|Mrjxrht0GfRUnZqz2MhrXa zqgVC9nemD5)H$to=~hp)c=l9?#~Z_7i~=U-`FZxb-|TR9@YCxx;Zjo-WpMNOn2)z) zFPGGVl%3N$f`gp$gPnWC+f4(rmts%fidpo^BJx72zAd7|*Xi{2VXmbOm)1`w^tm9% znM=0Fg4bDxH5PxPEm{P3#A(mxqlM7SIARP?|2&+c7qmU8kP&iApzL|F>Dz)Ixp_`O zP%xrP1M6@oYhgo$ZWwrAsYLa4 z|I;DAvJxno9HkQrhLPQk-8}=De{9U3U%)dJ$955?_AOms!9gia%)0E$Mp}$+0er@< zq7J&_SzvShM?e%V?_zUu{niL@gt5UFOjFJUJ}L?$f%eU%jUSoujr{^O=?=^{19`ON zlRIy8Uo_nqcPa6@yyz`CM?pMJ^^SN^Fqtt`GQ8Q#W4kE7`V9^LT}j#pMChl!j#g#J zr-=CCaV%xyFeQ9SK+mG(cTwW*)xa(eK;_Z(jy)woZp~> zA(4}-&VH+TEeLzPTqw&FOoK(ZjD~m{KW05fiGLe@E3Z2`rLukIDahE*`u!ubU)9`o zn^-lyht#E#-dt~S>}4y$-mSbR8{T@}22cn^refuQ08NjLOv?JiEWjyOnzk<^R5%gO zhUH_B{oz~u#IYwVnUg8?3P*#DqD8#X;%q%HY**=I>>-S|!X*-!x1{^l#OnR56O>iD zc;i;KS+t$koh)E3)w0OjWJl_aW2;xF=9D9Kr>)(5}4FqUbk# zI#$N8o0w;IChL49m9CJTzoC!|u{Ljd%ECgBOf$}&jA^$(V#P#~)`&g`H8E{uv52pp zwto`xUL-L&WTAVREEm$0g_gYPL(^vHq(*t1WCH_6alhkeW&GCZ3hL)|{O-jiFOBrF z!EW=Jej|dqQitT6!B-7&io2K)WIm~Q)v@yq%U|VpV+I?{y0@Yd%n8~-NuuM*pM~KA z85YB};IS~M(c<}4Hxx>qRK0cdl&e?t253N%vefkgds>Ubn8X}j6Vpgs>a#nFq$osY z1ZRwLqFv=+BTb=i%D2Wv>_yE0z}+niZ4?rE|*a3d7^kndWGwnFqt+iZ(7+aln<}jzbAQ(#Z2SS}3S$%Bd}^ zc9ghB%O)Z_mTZMRC&H#)I#fiLuIkGa^`4e~9oM5zKPx?zjkC&Xy0~r{;S?FS%c7w< zWbMpzc(xSw?9tGxG~_l}Acq}zjt5ClaB7-!vzqnlrX;}$#+PyQ9oU)_DfePh2E1<7 ztok6g6K^k^DuHR*iJ?jw?bs_whk|bx`dxu^nC6#e{1*m~z1eq7m}Cf$*^Eua(oi_I zAL+3opNhJteu&mWQ@kQWPucmiP)4|nFG`b2tpC;h{-PI@`+h?9v=9mn|0R-n8#t=+Z*FD(c5 zjj79Jxkgck*DV=wpFgRZuwr%}KTm+dx?RT@aUHJdaX-ODh~gByS?WGx&czAkvkg;x zrf92l8$Or_zOwJVwh>5rB`Q5_5}ef6DjS*$x30nZbuO3dijS*wvNEqTY5p1_A0gWr znH<(Qvb!os14|R)n2Ost>jS2;d1zyLHu`Svm|&dZD+PpP{Bh>U&`Md;gRl64q;>{8MJJM$?UNUd`aC>BiLe>*{ zJY15->yW+<3rLgYeTruFDtk1ovU<$(_y7#HgUq>)r0{^}Xbth}V#6?%5jeFYt;SG^ z3qF)=uWRU;Jj)Q}cpY8-H+l_n$2$6{ZR?&*IGr{>ek!69ZH0ZoJ*Ji+ezzlJ^%qL3 zO5a`6gwFw(moEzqxh=yJ9M1FTn!eo&qD#y5AZXErHs%22?A+JmS&GIolml!)rZTnUDM3YgzYfT#;OXn)`PWv3Ta z!-i|-Wojv*k&bC}_JJDjiAK(Ba|YZgUI{f}TdEOFT2+}nPmttytw7j%@bQZDV1vvj z^rp{gRkCDmYJHGrE1~e~AE!-&6B6`7UxVQuvRrfdFkGX8H~SNP_X4EodVd;lXd^>eV1jN+Tt4}Rsn)R0LxBz0c=NXU|pUe!MQQFkGBWbR3&(jLm z%RSLc#p}5_dO{GD=DEFr=Fc% z85CBF>*t!6ugI?soX(*JNxBp+-DdZ4X0LldiK}+WWGvXV(C(Ht|!3$psR=&c*HIM=BmX;pRIpz@Ale{9dhGe(U2|Giv;# zOc|;?p67J=Q(kamB*aus=|XP|m{jN^6@V*Bpm?ye56Njh#vyJqE=DweC;?Rv7faX~ zde03n^I~0B2vUmr;w^X37tVxUK?4}ifsSH5_kpKZIzpYu0;Kv}SBGfI2AKNp+VN#z`nI{UNDRbo-wqa4NEls zICRJpu)??cj^*WcZ^MAv+;bDbh~gpN$1Cor<{Y2oyIDws^JsfW^5AL$azE(T0p&pP z1Mv~6Q44R&RHoH95&OuGx2srIr<@zYJTOMKiVs;Bx3py89I87LOb@%mr`0)#;7_~Z zzcZj8?w=)>%5@HoCHE_&hnu(n_yQ-L(~VjpjjkbT7e)Dk5??fApg(d>vwLRJ-x{um z*Nt?DqTSxh_MIyogY!vf1mU1`Gld-&L)*43f6dilz`Q@HEz;+>MDDYv9u!s;WXeao zUq=TaL$P*IFgJzrGc>j1dDOd zed+=ZBo?w4mr$2)Ya}?vedDopomhW1`#P<%YOJ_j=WwClX0xJH-f@s?^tmzs_j7t!k zK@j^zS0Q|mM4tVP5Ram$VbS6|YDY&y?Q1r1joe9dj08#CM{RSMTU}(RCh`hp_Rkl- zGd|Cv~G@F{DLhCizAm9AN!^{rNs8hu!G@8RpnGx7e`-+K$ffN<0qjR zGq^$dj_Tv!n*?zOSyk5skI7JVKJ)3jysnjIu-@VSzQiP8r6MzudCU=~?v-U8yzo^7 zGf~SUTvEp+S*!X9uX!sq=o}lH;r{pzk~M*VA(uyQ`3C8!{C;)&6)95fv(cK!%Cuz$ z_Zal57H6kPN>25KNiI6z6F)jzEkh#%OqU#-__Xzy)KyH};81#N6OfX$$IXWzOn`Q& z4f$Z1t>)8&8PcYfEwY5UadU1yg+U*(1m2ZlHoC-!2?gB!!fLhmTl))D@dhvkx#+Yj z1O=LV{(T%{^IeCuFK>%QR!VZ4GnO5tK8a+thWE zg4VytZrwcS?7^ zuZfhYnB8dwd%VLO?DK7pV5Wi<(`~DYqOXn8#jUIL^)12*Dbhk4GmL_E2`WX&iT16o zk(t|hok(Y|v-wzn?4x34T)|+SfZP>fiq!><*%vnxGN~ypST-FtC+@TPv*vYv@iU!_ z@2gf|PrgQ?Ktf*9^CnJ(x*CtZVB8!OBfg0%!wL;Z8(tYYre0vcnPGlyCc$V(Ipl*P z_(J!a=o@vp^%Efme!K74(Ke7A>Y}|sxV+JL^aYa{~m%5#$$+R1? zGaQhZTTX!#s#=Xtpegqero$RNt&`4xn3g$)=y*;=N=Qai)}~`xtxI_N*#MMCIq#HFifT zz(-*m;pVH&+4bixL&Bbg)W5FN^bH87pAHp)zPkWNMfTFqS=l~AC$3FX3kQUSh_C?-ZftyClgM)o_D7cX$RGlEYblux0jv5 zTr|i-I3@ZPCGheCl~BGhImF)K4!9@?pC(gi3ozX=a!|r1)LFxy_8c&wY0<^{2cm|P zv6Y`QktY*;I)IUd5y3ne1CqpVanlY45z8hf4&$EUBnucDj16pDa4&GI&TArYhf*xh zdj>*%APH8(h~c>o@l#%T>R$e>rwVx_WUB|~V`p^JHsg*y12lzj&zF}w6W09HwB2yb z%Q~`es&(;7#*DUC_w-Dmt7|$*?TA_m;zB+-u{2;Bg{O}nV7G_@7~<)Bv8fH^G$XG8$(&{A zwXJK5LRK%M34(t$&NI~MHT{UQ9qN-V_yn|%PqC81EIiSzmMM=2zb`mIwiP_b)x+2M z7Gd`83h79j#SItpQ}luuf2uOU`my_rY5T{6P#BNlb%h%<#MZb=m@y5aW;#o1^2Z)SWo+b`y0gV^iRcZtz5!-05vF z7wNo=hc6h4hc&s@uL^jqRvD6thVYtbErDK9k!;+a0xoE0WL7zLixjn5;$fXvT=O3I zT6jI&^A7k6R{&5#lVjz#8%_RiAa2{di{`kx79K+j72$H(!ass|B%@l%KeeKchYLe_ z>!(JC2fxsv>XVen+Y42GeYPxMWqm`6F$(E<6^s|g(slNk!lL*6v^W2>f6hh^mE$s= z3D$)}{V5(Qm&A6bp%2Q}*GZ5Qrf}n7*Hr51?bJOyA-?B4vg6y_EX<*-e20h{=0Mxs zbuQGZ$fLyO5v$nQ&^kuH+mNq9O#MWSfThtH|0q1i!NrWj^S}_P;Q1OkYLW6U^?_7G zx2wg?CULj7))QU(n{$0JE%1t2dWrMi2g-Os{v|8^wK{@qlj%+1b^?NI z$}l2tjp0g>K3O+p%yK<9!XqmQ?E9>z&(|^Pi~aSRwI5x$jaA62GFz9%fmO3t3a>cq zK8Xbv=5Ps~4mKN5+Eqw12(!PEyedFXv~VLxMB~HwT1Vfo51pQ#D8e$e4pFZ{&RC2P z5gTIzl{3!&(tor^BwZfR8j4k{7Rq#`riKXP2O-Bh66#WWK2w=z;iD9GLl+3 zpHIaI4#lQ&S-xBK8PiQ%dwOh?%BO~DCo06pN7<^dnZCN@NzY{_Z1>rrB0U|nC&+!2 z2y!oBcTd2;@lzyk(B=TkyZ)zy0deK05*Q0zk+o$@nun`VI1Er7pjq>8V zNmlW{p7S^Btgb(TA}jL(uR>`0w8gHP^T~Sh5Tkip^spk4SBAhC{TZU}_Z)UJw-}zm zPq{KBm!k)?P{`-(9?LFt&YN4s%SIZ-9lJ!Ws~B%exHOeVFk3~}HewnnH(d)qkLQ_d z6h>O)pEE{vbOVw}E+jdYC^wM+AAhaI(YAibUc@B#_mDss0Ji&BK{WG`4 zOk>vSNq(Bq2IB@s>>Rxm6Wv?h;ZXkpb1l8u|+_qXWdC*jjcPCixq;!%BVPSp#hP zqo`%cNf&YoQXHC$D=D45RiT|5ngPlh?0T~?lUf*O)){K@*Kbh?3RW1j9-T?%lDk@y z4+~?wKI%Y!-=O|_IuKz|=)F;V7ps=5@g)RrE;;tvM$gUhG>jHcw2Hr@fS+k^Zr~>G z^JvPrZc}_&d_kEsqAEMTMJw!!CBw)u&ZVzmq+ZworuaE&TT>$pYsd9|g9O^0orAe8 z221?Va!l1|Y5X1Y?{G7rt1sX#qFA^?RLG^VjoxPf63;AS=_mVDfGJKg73L zsGdnTUD40y(>S##2l|W2Cy!H(@@5KBa(#gs`vlz}Y~$ot5VsqPQ{{YtjYFvIumZzt zA{CcxZLJR|4#{j7k~Tu*jkwz8QA|5G1$Cl895R`Zyp;irp1{KN){kB30O8P1W5;@bG znvX74roeMmQlUi=v9Y%(wl$ZC#9tKNFpvi3!C}f1m6Ct|l2g%psc{TJp)@yu)*e2> z((p0Fg*8gJ!|3WZke9;Z{8}&NRkv7iP=#_y-F}x^y?2m%-D_aj^)f04%mneyjo_;) z6qc_Zu$q37d~X``*eP~Q>I2gg%rrV8v=kDfpp$=%Vj}hF)^dsSWygoN(A$g*E=Do6FX?&(@F#7pbiJ`;c0c@Ul zDqW_90Wm#5f2L<(Lf3)3TeXtI7nhYwRm(F;*r_G6K@OPW4H(Y3O5SjUzBC}u3d|eQ8*8d@?;zUPE+i#QNMn=r(ap?2SH@vo*m z3HJ%XuG_S6;QbWy-l%qU;8x;>z>4pMW7>R}J%QLf%@1BY(4f_1iixd-6GlO7Vp*yU zp{VU^3?s?90i=!#>H`lxT!q8rk>W_$2~kbpz7eV{3wR|8E=8**5?qn8#n`*(bt1xRQrdGxyx2y%B$qmw#>ZV$c7%cO#%JM1lY$Y0q?Yuo> ze9KdJoiM)RH*SB%^;TAdX-zEjA7@%y=!0=Zg%iWK7jVI9b&Dk}0$Af&08KHo+ zOwDhFvA(E|ER%a^cdh@^wLUlmIv6?_3=BvX8jKk92L=Y}7Jf5OGMfh` zBdR1wFCi-i5@`9km{isRb0O%TX+f~)KNaEz{rXQa89`YIF;EN&gN)cigu6mNh>?Cm zAO&Im2flv6D{jwm+y<%WsPe4!89n~KN|7}Cb{Z;XweER73r}Qp2 zz}WP4j}U0&(uD&9yGy6`!+_v-S(yG*iytsTR#x_Rc>=6u^vnRDnf1gP{#2>`ffrAC% zTZ5WQ@hAK;P;>kX{D)mIXe4%a5p=LO1xXH@8T?mz7Q@d)$3pL{{B!2{-v70L*o1AO+|n5beiw~ zk@(>m?T3{2k2c;NWc^`4@P&Z?BjxXJ@;x1qhn)9Mn*IFdt_J-dIqx5#d`NfyfX~m( zIS~5)MfZ2Uy?_4W`47i}u0ZgPh<{D|w_d#;D}Q&U$Q-G}xM1A@1f{#%A$jh6Qp&0hQ<0bPOM z-{1Wm&p%%#eb_?x7i;bol EfAhh=DF6Tf diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties deleted file mode 100644 index 642d572..0000000 --- a/.mvn/wrapper/maven-wrapper.properties +++ /dev/null @@ -1,2 +0,0 @@ -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip -wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar diff --git a/pom.xml b/pom.xml index 967fa10..a12a6aa 100644 --- a/pom.xml +++ b/pom.xml @@ -2,23 +2,18 @@ 4.0.0 - jar top.minwk excel-x 2.1.0 excel-x - excel-x + 支持excel中批量导出图片 https://gitee.com/mwk719/excel-batch-picture-support - - org.sonatype.oss - oss-parent - 9 - utf-8 utf-8 - + + true 8 1.8 @@ -126,6 +121,11 @@ + + + none + + @@ -171,7 +171,7 @@ html xml - + diff --git a/src/main/java/com/ibiz/excel/picture/support/util/WebUtil.java b/src/main/java/com/ibiz/excel/picture/support/util/WebUtil.java index 87f36bb..aefa9bb 100644 --- a/src/main/java/com/ibiz/excel/picture/support/util/WebUtil.java +++ b/src/main/java/com/ibiz/excel/picture/support/util/WebUtil.java @@ -36,11 +36,12 @@ public class WebUtil { File file = FileUtil.touch(tempPath.concat(fileName)); try (BufferedOutputStream os = FileUtil.getOutputStream(file)) { wb.write(os); - wb.close(); } catch (Exception e) { // 报错时删除文件 FileUtil.del(file); log.error("测试导出excel异常", e); + }finally { + wb.close(); } log.debug("测试导出excel路径:{}", file.getAbsolutePath()); } diff --git a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java index 68aadd2..75c9cae 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java @@ -6,6 +6,7 @@ import com.ibiz.excel.picture.support.model.CellStyle; import com.ibiz.excel.picture.support.model.Sheet; import com.ibiz.excel.picture.support.model.Workbook; import com.ibiz.excel.picture.support.util.WebUtil; +import org.junit.Ignore; import org.junit.Test; import java.util.Random; @@ -16,6 +17,7 @@ import java.util.Random; * @author MinWeikai * @date 2021/12/14 10:36 */ +@Ignore public class AnnotationPicturesExportExample extends BaseJunitTest { @Test diff --git a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220110.java b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220110.java index 8b69da3..88d6d36 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220110.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220110.java @@ -6,6 +6,7 @@ import com.ibiz.excel.picture.support.model.CellStyle; import com.ibiz.excel.picture.support.model.Sheet; import com.ibiz.excel.picture.support.model.Workbook; import com.ibiz.excel.picture.support.util.WebUtil; +import org.junit.Ignore; import org.junit.Test; import java.util.ArrayList; @@ -18,6 +19,7 @@ import java.util.Random; * @author MinWeikai * @date 2022-01-10 10:08:03 */ +@Ignore public class ExportExample_20220110 extends BaseJunitTest { @Test diff --git a/src/test/java/com/ibiz/excel/picture/support/simulation/SimulateRealBusinessExportExample.java b/src/test/java/com/ibiz/excel/picture/support/simulation/SimulateRealBusinessExportExample.java index 2030772..a610f09 100644 --- a/src/test/java/com/ibiz/excel/picture/support/simulation/SimulateRealBusinessExportExample.java +++ b/src/test/java/com/ibiz/excel/picture/support/simulation/SimulateRealBusinessExportExample.java @@ -6,6 +6,7 @@ import com.ibiz.excel.picture.support.model.CellStyle; import com.ibiz.excel.picture.support.model.Sheet; import com.ibiz.excel.picture.support.model.Workbook; import com.ibiz.excel.picture.support.util.WebUtil; +import org.junit.Ignore; import org.junit.Test; import java.util.Random; @@ -16,18 +17,9 @@ import java.util.Random; * @author MinWeikai * @date 2021-12-22 15:36:46 */ +@Ignore public class SimulateRealBusinessExportExample extends BaseJunitTest { - static final String CURRENT_PATH = "E:\\test\\"; - private static final String TEMP_PATH = CURRENT_PATH + "excel\\"; - private final static String IMG_PATH = "E:\\test\\img\\"; - - private final static String IMG_PATH_1 = IMG_PATH + "1.jpg"; - private final static String IMG_PATH_2 = IMG_PATH + "2.jpg"; - private final static String IMG_PATH_3 = IMG_PATH + "3.jpg"; - - private final static String IMAGES_PATH = CURRENT_PATH + "images\\"; - @Test public void export() { Workbook workBook = Workbook.getInstance(50); -- Gitee From 6142b3b4652b43d971a99418e8469ae223976a50 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Fri, 7 Jan 2022 18:25:22 +0800 Subject: [PATCH 077/161] =?UTF-8?q?add=20=E5=AF=B9=E7=BD=91=E7=BB=9C?= =?UTF-8?q?=E5=9B=BE=E7=89=87=E5=AF=BC=E5=87=BA=E5=9C=A8excel?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 20 +++++-- .../support/annotation/ExportModel.java | 10 ++++ .../constants/PictureSourceContent.java | 20 +++++++ .../support/constants/WorkbookConstant.java | 5 ++ .../support/flush/DrawingXmlRelsHandler.java | 43 ++++++++++----- .../excel/picture/support/model/Picture.java | 26 +++++++++ .../excel/picture/support/model/Sheet.java | 53 ++++++++++++++----- .../picture/support/util/MD5Digester.java | 9 ++++ .../excel/picture/support/UserPicture.java | 3 +- .../excel/picture/support/WebImgTest.java | 21 ++++++++ .../picture/support/common/BaseJunitTest.java | 53 +++++++++++++++++++ .../AnnotationPicturesExportExample.java | 39 +++----------- .../picture/support/util/MD5DigesterTest.java | 17 ++++++ 13 files changed, 258 insertions(+), 61 deletions(-) create mode 100644 src/main/java/com/ibiz/excel/picture/support/constants/PictureSourceContent.java create mode 100644 src/test/java/com/ibiz/excel/picture/support/WebImgTest.java create mode 100644 src/test/java/com/ibiz/excel/picture/support/common/BaseJunitTest.java create mode 100644 src/test/java/com/ibiz/excel/picture/support/util/MD5DigesterTest.java diff --git a/pom.xml b/pom.xml index a29600d..6850a8f 100644 --- a/pom.xml +++ b/pom.xml @@ -25,6 +25,8 @@ 8 1.8 5.3.14 + 5.7.18 + 4.13.2 @@ -51,10 +53,12 @@ + - cn.hutool - hutool-core - 5.7.18 + junit + junit + ${junit.version} + test org.slf4j @@ -83,6 +87,16 @@ spring-web ${version.spring} + + cn.hutool + hutool-core + ${hutool.version} + + + cn.hutool + hutool-http + ${hutool.version} + diff --git a/src/main/java/com/ibiz/excel/picture/support/annotation/ExportModel.java b/src/main/java/com/ibiz/excel/picture/support/annotation/ExportModel.java index dab006b..51bb89b 100644 --- a/src/main/java/com/ibiz/excel/picture/support/annotation/ExportModel.java +++ b/src/main/java/com/ibiz/excel/picture/support/annotation/ExportModel.java @@ -1,5 +1,6 @@ package com.ibiz.excel.picture.support.annotation; +import com.ibiz.excel.picture.support.constants.PictureSourceContent; import com.ibiz.excel.picture.support.constants.WorkbookConstant; import java.lang.annotation.*; @@ -52,7 +53,16 @@ public @interface ExportModel { /** * 图片所在单元格行高度,单元格会自适应图片的高度 * 如需要自定义图片高度,注意:在导出类中有多个图片字段,需要在每个图片字段上注解配置自定义的高度 + * * @return */ int height() default WorkbookConstant.PICTURE_HEIGHT; + + /** + * 图片来源 默认为图片的绝对路径 + * {@link PictureSourceContent} + * + * @return + */ + int pictureSource() default PictureSourceContent.ABSOLUTE_PATH; } diff --git a/src/main/java/com/ibiz/excel/picture/support/constants/PictureSourceContent.java b/src/main/java/com/ibiz/excel/picture/support/constants/PictureSourceContent.java new file mode 100644 index 0000000..5e7f4cc --- /dev/null +++ b/src/main/java/com/ibiz/excel/picture/support/constants/PictureSourceContent.java @@ -0,0 +1,20 @@ +package com.ibiz.excel.picture.support.constants; + +/** + * 图片来源 + * + * @author MinWeikai + * @date 2022/1/7 16:51 + */ +public class PictureSourceContent { + + /** + * 绝对路径 + */ + public static final int ABSOLUTE_PATH = 1; + + /** + * 网络链接 + */ + public static final int WEB_URL = 2; +} diff --git a/src/main/java/com/ibiz/excel/picture/support/constants/WorkbookConstant.java b/src/main/java/com/ibiz/excel/picture/support/constants/WorkbookConstant.java index d7f8ec0..3e4be6f 100644 --- a/src/main/java/com/ibiz/excel/picture/support/constants/WorkbookConstant.java +++ b/src/main/java/com/ibiz/excel/picture/support/constants/WorkbookConstant.java @@ -25,4 +25,9 @@ public class WorkbookConstant { * 单元格宽度 */ public static final double CELL_WEIGHT = 23.5; + + /** + * 下载网络图片超时时间 + */ + public static final int DOWNLOAD_PICTURE_TIME_OUT = 10 * 1000; } diff --git a/src/main/java/com/ibiz/excel/picture/support/flush/DrawingXmlRelsHandler.java b/src/main/java/com/ibiz/excel/picture/support/flush/DrawingXmlRelsHandler.java index f375d03..c6e0a2e 100644 --- a/src/main/java/com/ibiz/excel/picture/support/flush/DrawingXmlRelsHandler.java +++ b/src/main/java/com/ibiz/excel/picture/support/flush/DrawingXmlRelsHandler.java @@ -1,6 +1,8 @@ package com.ibiz.excel.picture.support.flush; +import cn.hutool.http.HttpUtil; import com.ibiz.excel.picture.support.constants.Alias; +import com.ibiz.excel.picture.support.constants.PictureSourceContent; import com.ibiz.excel.picture.support.constants.WorkbookConstant; import com.ibiz.excel.picture.support.model.Picture; import com.ibiz.excel.picture.support.model.Sheet; @@ -13,7 +15,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; -import java.io.IOException; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.util.List; @@ -37,11 +38,8 @@ public class DrawingXmlRelsHandler implements InvocationHandler { List pictures = sheet.getPictures(); pictures.stream().filter(Objects::nonNull).forEach(p -> { if (StringUtils.isNotBlank(p.getPicturePath())) { - File file = new File(p.getPicturePath()); - if(file.exists()) { - //写图片 - copyPictureAppendDrawingRelsXML(sheet, p); - } + //写图片 + copyPictureAppendDrawingRelsXML(sheet, p); } }); } @@ -55,8 +53,21 @@ public class DrawingXmlRelsHandler implements InvocationHandler { */ private void copyPictureAppendDrawingRelsXML(Sheet sheet, Picture picture) { try { - File srcPicture = new File(picture.getPicturePath()); - String md5 = MD5Digester.digestMD5(srcPicture); + String md5; + File srcPicture = null; + String picturePath = picture.getPicturePath(); + // 判断图片来源 + if(PictureSourceContent.WEB_URL == picture.getPictureSource() ){ + md5 = MD5Digester.encodeHexStr(picturePath); + }else { + // 绝对路径图片 + srcPicture = new File(picturePath); + // 绝对路径下图片不存在则不执行 + if(!srcPicture.exists()){ + return; + } + md5 = MD5Digester.digestMD5(srcPicture); + } Integer drawingSequence = sheet.getWorkbook().getImageCache().get(md5); // 已存在的图片 if (Objects.nonNull(drawingSequence)) { @@ -67,7 +78,17 @@ public class DrawingXmlRelsHandler implements InvocationHandler { File media = sheet.getSheetContext().getRepositoryHolder().get(Alias.MEDIA).getFile(); drawingSequence = sheet.getDrawingSequence(); File destPicture = new File(media, "image"+ drawingSequence + ".png"); - FileUtil.copyFile(srcPicture, destPicture); + if(PictureSourceContent.WEB_URL == picture.getPictureSource() ){ + // 下载网络图片到excel资源路径 + HttpUtil.downloadFile(picturePath, destPicture, WorkbookConstant.DOWNLOAD_PICTURE_TIME_OUT); + }else { + // 复制绝对图片到excel资源路径 + FileUtil.copyFile(srcPicture, destPicture); + } + // 输出的图片不存在则跳出 + if(!destPicture.exists()){ + return; + } picture.setRembed(drawingSequence); RelationShip relationShip = new RelationShip("rId" + drawingSequence, WorkbookConstant.MEDIA_IMAGE_TYPE, "../media/image" + drawingSequence +".png"); //先把drawingSequence放入缓存,因为从缓存中获取时设置drawingSequence再+1对应图片。实际图片的drawingSequence不变 @@ -75,9 +96,7 @@ public class DrawingXmlRelsHandler implements InvocationHandler { drawingSequence++; sheet.setDrawingSequence(drawingSequence); target.append(CovertUtil.covert(relationShip)); - } catch (IOException e) { - logger.error("图片copy到media目录下异常",e); - }catch (Exception e) { + } catch (Exception e) { logger.error("图片copy到media目录下异常",e); } } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Picture.java b/src/main/java/com/ibiz/excel/picture/support/model/Picture.java index 7b6a93b..cda4e7b 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Picture.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Picture.java @@ -15,6 +15,12 @@ public class Picture { /**当前系统中图片的绝对路径*/ private String picturePath; //图片路径 + /** + * 图片来源 + * {@link com.ibiz.excel.picture.support.constants.PictureSourceContent} + */ + private int pictureSource; + /** * 图片宽度 */ @@ -58,6 +64,18 @@ public class Picture { this.height = height; } + public Picture(int fromRow,int fromCol, int width, int height,String picturePath, int pictureSource) { + super(); + this.fromRow = fromRow; + this.fromCol = fromCol; + this.toRow = fromRow; + this.toCol = fromCol; + this.picturePath = picturePath; + this.width = width; + this.height = height; + this.pictureSource = pictureSource; + } + public String getPicturePath() { return picturePath; } @@ -121,4 +139,12 @@ public class Picture { public void setHeight(int height) { this.height = height; } + + public int getPictureSource() { + return pictureSource; + } + + public void setPictureSource(int pictureSource) { + this.pictureSource = pictureSource; + } } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java index d9f6ce6..8981710 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java @@ -274,10 +274,6 @@ public class Sheet { boolean isPicture = model.isPicture(); boolean mergeMaster = model.mergeMaster(); boolean merge = model.merge(); - // 图片所在单元格宽度,图片和单元格宽度一致 - int width = model.width(); - // 图片所在单元格行高度 - int height = model.height(); String title = model.title(); Cell cell = new Cell(row.getRowNumber(), sort); // 合并 是标题 并且 是要合并的基准列,将元素放在基准列中 @@ -304,7 +300,7 @@ public class Sheet { // 不是标题 并且 是图片 并且 值不为空 if (isPicture && value != null) { // 添加图片 - this.addPictures(row, cell.getCellNumber(), width, height, value); + this.addPictures(row, cell.getCellNumber(), value, model); } else { cell.setValue(value == null ? "" : String.valueOf(value)); } @@ -321,29 +317,60 @@ public class Sheet { * 添加图片 * @param row * @param cellNumber - * @param width * @param value + * @param model */ - private void addPictures(Row row, int cellNumber, int width,int height, Object value) { + private void addPictures(Row row, int cellNumber, Object value, ExportModel model) { + // 图片所在单元格宽度,图片和单元格宽度一致 + int width = model.width(); + // 图片所在单元格行高度 + int height = model.height(); + List values = getValues(value); + // 计算行高 + calculateRowHeight(row, height); + // 计算单元格宽度根据单元格中值的数量 + calculateColumnWidth(cellNumber, width, values.size()); + //增加图片 + values.forEach(v -> pictures.add(new Picture(row.getRowNumber(), cellNumber, width, height, v, model.pictureSource()))); + } + + private List getValues(Object value) { List values = new ArrayList<>(); - // 设置行高自适应于图片的高度 - row.setHeight((height / 12600) - 1); if (value instanceof List) { values = (List) value; } else { values.add(String.valueOf(value)); } + return values; + } + + /** + * 计算行高 + * + * @param row + * @param height + */ + private void calculateRowHeight(Row row, int height) { + // 设置行高自适应于图片的高度 + row.setHeight((height / 12600) - 1); + } + + /** + * 计算单元格宽度根据单元格中值的数量 + * + * @param cellNumber + * @param width + * @param valuesSize 图片数 + */ + private void calculateColumnWidth(int cellNumber, int width, int valuesSize) { // 实际宽 int actualWidth = width / 76923; - // 图片数 - int valuesSize = values.size(); + // // 数组为空时,给默认值1,否则单元格宽度会被计算成0 valuesSize = valuesSize == 0 ? 1 : valuesSize; // 设置单元格宽度,单元格宽度 = 图片宽*图片数量 double columnWidth = actualWidth * valuesSize + valuesSize / 1.5; setColumnWidth(cellNumber + 1, columnWidth); - //增加图片 - values.forEach(v -> pictures.add(new Picture(row.getRowNumber(), cellNumber, width, height, v))); } Row createRow(T t) { diff --git a/src/main/java/com/ibiz/excel/picture/support/util/MD5Digester.java b/src/main/java/com/ibiz/excel/picture/support/util/MD5Digester.java index 0aceba0..1449704 100644 --- a/src/main/java/com/ibiz/excel/picture/support/util/MD5Digester.java +++ b/src/main/java/com/ibiz/excel/picture/support/util/MD5Digester.java @@ -1,6 +1,7 @@ package com.ibiz.excel.picture.support.util; import java.io.*; +import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; @@ -60,4 +61,12 @@ public class MD5Digester { return new String(result); } + public static String encodeHexStr(String str) { + if (str == null) { + return null; + } + byte[] bytes = str.getBytes(StandardCharsets.UTF_8); + return encodeHexStr(bytes); + } + } diff --git a/src/test/java/com/ibiz/excel/picture/support/UserPicture.java b/src/test/java/com/ibiz/excel/picture/support/UserPicture.java index b494ec1..4ea2fd4 100644 --- a/src/test/java/com/ibiz/excel/picture/support/UserPicture.java +++ b/src/test/java/com/ibiz/excel/picture/support/UserPicture.java @@ -1,6 +1,7 @@ package com.ibiz.excel.picture.support; import com.ibiz.excel.picture.support.annotation.ExportModel; +import com.ibiz.excel.picture.support.constants.PictureSourceContent; import java.util.List; @@ -21,7 +22,7 @@ public class UserPicture { private String department; @ExportModel(sort = 2, isPicture = true, title = "图片1") private String picture; - @ExportModel(sort = 4, isPicture = true, title = "图片2") + @ExportModel(sort = 4, isPicture = true, title = "图片2", pictureSource = PictureSourceContent.WEB_URL) private String headerPicture; @ExportModel(sort = 5, isPicture = true, title = "多图片") private List pictures; diff --git a/src/test/java/com/ibiz/excel/picture/support/WebImgTest.java b/src/test/java/com/ibiz/excel/picture/support/WebImgTest.java new file mode 100644 index 0000000..85cc78f --- /dev/null +++ b/src/test/java/com/ibiz/excel/picture/support/WebImgTest.java @@ -0,0 +1,21 @@ +package com.ibiz.excel.picture.support; + +import cn.hutool.http.HttpUtil; + +import java.io.File; + +/** + * 网络图片测试 + * + * @author MinWeikai + * @date 2022/1/7 16:34 + */ +public class WebImgTest { + + public static void main(String[] args) { + String url = "https://portrait.gitee.com/uploads/avatars/user/552/1657608_mwk719_1641537497.png"; + File destFilePath = new File("E:\\test\\img\\1111.png"); + long destFile = HttpUtil.downloadFile(url, destFilePath, 5 * 1000); + System.out.println(destFile); + } +} diff --git a/src/test/java/com/ibiz/excel/picture/support/common/BaseJunitTest.java b/src/test/java/com/ibiz/excel/picture/support/common/BaseJunitTest.java new file mode 100644 index 0000000..bf5b2f1 --- /dev/null +++ b/src/test/java/com/ibiz/excel/picture/support/common/BaseJunitTest.java @@ -0,0 +1,53 @@ +package com.ibiz.excel.picture.support.common; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +/** + * @author MinWeikai + * @date 2022/1/7 18:09 + */ +public class BaseJunitTest { + + protected static final String CURRENT_PATH = "E:\\test\\"; + protected static final String TEMP_PATH = CURRENT_PATH + "excel\\"; + protected final static String IMG_PATH = "E:\\test\\img\\"; + + protected final static String IMG_PATH_1 = IMG_PATH + "1.jpg"; + protected final static String IMG_PATH_2 = IMG_PATH + "2.jpg"; + protected final static String IMG_PATH_3 = IMG_PATH + "3.jpg"; + + protected final static String IMAGES_PATH = CURRENT_PATH + "images\\"; + + protected final static List urls = new ArrayList<>(); + + static { + urls.add("https://portrait.gitee.com/uploads/avatars/user/552/1657608_mwk719_1641537497.png"); + urls.add("https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.jj20.com%2Fup%2Fallimg%2F1114%2F060421091316%2F210604091316-6-1200.jpg&refer=http%3A%2F%2Fimg.jj20.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1644142768&t=82062e20360f72b0fd8d5fd7e2fc9885"); + urls.add("https://img2.baidu.com/it/u=121102239,1207969661&fm=253&fmt=auto&app=120&f=JPEG?w=1195&h=500"); + urls.add("https://img2.baidu.com/it/u=2602880481,728201544&fm=26&fmt=auto"); + } + + + /** + * 根据图片数组和要获取图片的数量,随机从图片数组中取出若干 + * @param files 图片数组 + * @param getCount 获取图片的数量 + * @return + */ + protected static List getPictures(File[] files, int getCount) { + List list = new ArrayList<>(getCount); + for (int i = 0; i < getCount; i++) { + int index = new Random().nextInt(files.length); + list.add(files[index].getAbsolutePath()); + } + return list; + } + + protected static String getUrl() { + int index = new Random().nextInt(urls.size()); + return urls.get(index); + } +} diff --git a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java index 8594fd1..f6dda39 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java @@ -2,15 +2,14 @@ package com.ibiz.excel.picture.support.example; import cn.hutool.core.io.FileUtil; import com.ibiz.excel.picture.support.UserPicture; +import com.ibiz.excel.picture.support.common.BaseJunitTest; import com.ibiz.excel.picture.support.model.CellStyle; import com.ibiz.excel.picture.support.model.Sheet; import com.ibiz.excel.picture.support.model.Workbook; import com.ibiz.excel.picture.support.util.WebUtil; +import org.junit.Test; import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; import java.util.Random; /** @@ -19,19 +18,10 @@ import java.util.Random; * @author MinWeikai * @date 2021/12/14 10:36 */ -public class AnnotationPicturesExportExample { +public class AnnotationPicturesExportExample extends BaseJunitTest { - static final String CURRENT_PATH = "E:\\test\\"; - private static final String TEMP_PATH = CURRENT_PATH + "excel\\"; - private final static String IMG_PATH = "E:\\test\\img\\"; - - private final static String IMG_PATH_1 = IMG_PATH + "1.jpg"; - private final static String IMG_PATH_2 = IMG_PATH + "2.jpg"; - private final static String IMG_PATH_3 = IMG_PATH + "3.jpg"; - - private final static String IMAGES_PATH = CURRENT_PATH + "images\\"; - - public static void main(String[] args) throws IOException { + @Test + public void export() { Workbook workBook = Workbook.getInstance(56); Sheet sheet = workBook.createSheet("测试"); @@ -44,12 +34,12 @@ public class AnnotationPicturesExportExample { // 图片数组 File[] files = FileUtil.ls(IMAGES_PATH); UserPicture userPicture; - for (int r = 0; r < 101; r++) { + for (int r = 0; r < 10; r++) { userPicture = new UserPicture(); userPicture.setAge(15); userPicture.setName("测试-" + r); userPicture.setPicture(IMG_PATH_1); -// userPicture.setHeaderPicture(IMG_PATH_2); + userPicture.setHeaderPicture(getUrl()); // 根据图片数组和要获取图片的数量,随机从图片数组中取出若干 userPicture.setPictures(getPictures(files, new Random().nextInt(5))); sheet.createRow(userPicture); @@ -63,19 +53,4 @@ public class AnnotationPicturesExportExample { WebUtil.writeExcelTest(workBook, "注解导出图片集合示例".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), TEMP_PATH); } - /** - * 根据图片数组和要获取图片的数量,随机从图片数组中取出若干 - * @param files 图片数组 - * @param getCount 获取图片的数量 - * @return - */ - private static List getPictures(File[] files, int getCount) { - List list = new ArrayList<>(getCount); - for (int i = 0; i < getCount; i++) { - int index = new Random().nextInt(files.length); - list.add(files[index].getAbsolutePath()); - } - return list; - } - } diff --git a/src/test/java/com/ibiz/excel/picture/support/util/MD5DigesterTest.java b/src/test/java/com/ibiz/excel/picture/support/util/MD5DigesterTest.java new file mode 100644 index 0000000..6803d89 --- /dev/null +++ b/src/test/java/com/ibiz/excel/picture/support/util/MD5DigesterTest.java @@ -0,0 +1,17 @@ +package com.ibiz.excel.picture.support.util; + +import java.io.File; + +/** + * @author MinWeikai + * @date 2022/1/7 17:26 + */ +public class MD5DigesterTest { + + public static void main(String[] args) { + File destFilePath = new File("E:\\test\\img\\0.jpg"); + String md5 = null; + md5 = MD5Digester.encodeHexStr("destFilePath"); + System.out.println(md5); + } +} \ No newline at end of file -- Gitee From 638b5cdf4cf93ee5168ad3c6c8803e5de684f605 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Mon, 10 Jan 2022 13:52:32 +0800 Subject: [PATCH 078/161] =?UTF-8?q?add=20=E8=87=AA=E5=8A=A8=E5=8C=B9?= =?UTF-8?q?=E9=85=8D=E5=9B=BE=E7=89=87=E6=9D=A5=E6=BA=90=E5=AF=BC=E5=87=BA?= =?UTF-8?q?=E5=9C=A8excel?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../support/annotation/ExportModel.java | 12 ++- .../support/flush/DrawingXmlRelsHandler.java | 94 +++++++++++++------ .../picture/support/model/CellStyle.java | 13 +++ .../excel/picture/support/model/Picture.java | 26 ++++- .../excel/picture/support/model/Sheet.java | 34 ++----- .../picture/support/util/MD5Digester.java | 38 ++++++-- .../com/ibiz/excel/picture/support/User.java | 2 +- .../excel/picture/support/UserPicture.java | 12 ++- .../picture/support/common/BaseJunitTest.java | 16 ++++ .../AnnotationPicturesExportExample.java | 8 +- .../example/UrlPicturesExportExample.java | 45 +++++++++ .../picture/support/util/MD5DigesterTest.java | 17 ---- 12 files changed, 223 insertions(+), 94 deletions(-) create mode 100644 src/test/java/com/ibiz/excel/picture/support/example/UrlPicturesExportExample.java delete mode 100644 src/test/java/com/ibiz/excel/picture/support/util/MD5DigesterTest.java diff --git a/src/main/java/com/ibiz/excel/picture/support/annotation/ExportModel.java b/src/main/java/com/ibiz/excel/picture/support/annotation/ExportModel.java index 51bb89b..0cff822 100644 --- a/src/main/java/com/ibiz/excel/picture/support/annotation/ExportModel.java +++ b/src/main/java/com/ibiz/excel/picture/support/annotation/ExportModel.java @@ -2,6 +2,7 @@ package com.ibiz.excel.picture.support.annotation; import com.ibiz.excel.picture.support.constants.PictureSourceContent; import com.ibiz.excel.picture.support.constants.WorkbookConstant; +import com.ibiz.excel.picture.support.model.Picture; import java.lang.annotation.*; @@ -18,9 +19,10 @@ import java.lang.annotation.*; @Documented public @interface ExportModel { /** - * 排序 + * 排序,必填,且不能重复 + * */ - int sort() default 0; + int sort() ; /** * 是否是图片 @@ -59,10 +61,12 @@ public @interface ExportModel { int height() default WorkbookConstant.PICTURE_HEIGHT; /** - * 图片来源 默认为图片的绝对路径 + * 图片来源 默认为0,自动判断图片来源 + * {@link Picture#autoPictureSourceByPath()} + * 不设置的话自动匹配,也可自己指定 * {@link PictureSourceContent} * * @return */ - int pictureSource() default PictureSourceContent.ABSOLUTE_PATH; + int pictureSource() default 0; } diff --git a/src/main/java/com/ibiz/excel/picture/support/flush/DrawingXmlRelsHandler.java b/src/main/java/com/ibiz/excel/picture/support/flush/DrawingXmlRelsHandler.java index c6e0a2e..efb4684 100644 --- a/src/main/java/com/ibiz/excel/picture/support/flush/DrawingXmlRelsHandler.java +++ b/src/main/java/com/ibiz/excel/picture/support/flush/DrawingXmlRelsHandler.java @@ -15,6 +15,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.util.List; @@ -22,19 +24,22 @@ import java.util.Objects; /** * 图片 + * * @auther 喻场 * @date 2020/7/618:33 */ public class DrawingXmlRelsHandler implements InvocationHandler { private Logger logger = LoggerFactory.getLogger(this.getClass()); private IRepository target; + public DrawingXmlRelsHandler(IRepository proxy) { this.target = proxy; } + @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (method.getName().equals("write")) { - Sheet sheet = (Sheet)args[0]; + Sheet sheet = (Sheet) args[0]; List pictures = sheet.getPictures(); pictures.stream().filter(Objects::nonNull).forEach(p -> { if (StringUtils.isNotBlank(p.getPicturePath())) { @@ -48,26 +53,23 @@ public class DrawingXmlRelsHandler implements InvocationHandler { /** * 把图片copy到media目录下 + * * @param sheet * @param picture */ private void copyPictureAppendDrawingRelsXML(Sheet sheet, Picture picture) { + String picturePath = picture.getPicturePath(); + // 根据图片来源获取文件md5值 + String md5; + try { + md5 = getMd5BySource(picture.getPictureSource(), picturePath); + } catch (FileNotFoundException e) { + logger.warn("获取不到路径为{}的图片", picturePath); + // 获取不到时跳出 + return; + } + try { - String md5; - File srcPicture = null; - String picturePath = picture.getPicturePath(); - // 判断图片来源 - if(PictureSourceContent.WEB_URL == picture.getPictureSource() ){ - md5 = MD5Digester.encodeHexStr(picturePath); - }else { - // 绝对路径图片 - srcPicture = new File(picturePath); - // 绝对路径下图片不存在则不执行 - if(!srcPicture.exists()){ - return; - } - md5 = MD5Digester.digestMD5(srcPicture); - } Integer drawingSequence = sheet.getWorkbook().getImageCache().get(md5); // 已存在的图片 if (Objects.nonNull(drawingSequence)) { @@ -77,27 +79,65 @@ public class DrawingXmlRelsHandler implements InvocationHandler { } File media = sheet.getSheetContext().getRepositoryHolder().get(Alias.MEDIA).getFile(); drawingSequence = sheet.getDrawingSequence(); - File destPicture = new File(media, "image"+ drawingSequence + ".png"); - if(PictureSourceContent.WEB_URL == picture.getPictureSource() ){ - // 下载网络图片到excel资源路径 - HttpUtil.downloadFile(picturePath, destPicture, WorkbookConstant.DOWNLOAD_PICTURE_TIME_OUT); - }else { - // 复制绝对图片到excel资源路径 - FileUtil.copyFile(srcPicture, destPicture); - } + // 获取excel资源图片 + File destPicture = getExcelDestPicture(picture, picturePath, drawingSequence, media); // 输出的图片不存在则跳出 - if(!destPicture.exists()){ + if (!destPicture.exists()) { return; } picture.setRembed(drawingSequence); - RelationShip relationShip = new RelationShip("rId" + drawingSequence, WorkbookConstant.MEDIA_IMAGE_TYPE, "../media/image" + drawingSequence +".png"); + RelationShip relationShip = new RelationShip("rId" + drawingSequence, WorkbookConstant.MEDIA_IMAGE_TYPE, "../media/image" + drawingSequence + ".png"); //先把drawingSequence放入缓存,因为从缓存中获取时设置drawingSequence再+1对应图片。实际图片的drawingSequence不变 sheet.getWorkbook().getImageCache().put(md5, drawingSequence); drawingSequence++; sheet.setDrawingSequence(drawingSequence); target.append(CovertUtil.covert(relationShip)); } catch (Exception e) { - logger.error("图片copy到media目录下异常",e); + logger.error("图片copy到media目录下异常", e); + } + } + + /** + * 获取excel资源图片 + * @param picture + * @param picturePath + * @param drawingSequence + * @param media + * @return + * @throws IOException + */ + private static File getExcelDestPicture(Picture picture, String picturePath, Integer drawingSequence, File media) throws IOException { + File destPicture = new File(media, "image" + drawingSequence + ".png"); + if (PictureSourceContent.WEB_URL == picture.getPictureSource()) { + // 下载网络图片到excel资源路径 + HttpUtil.downloadFile(picturePath, destPicture, WorkbookConstant.DOWNLOAD_PICTURE_TIME_OUT); + } else { + // 绝对路径图片 + File srcPicture = new File(picturePath); + // 复制绝对图片到excel资源路径 + FileUtil.copyFile(srcPicture, destPicture); + } + return destPicture; + } + + /** + * 根据图片来源获取文件md5值 + * + * @param pictureSource + * @param picturePath + * @return + * @throws FileNotFoundException + */ + private static String getMd5BySource(int pictureSource, String picturePath) throws FileNotFoundException { + String md5; + // 判断图片来源 + if (PictureSourceContent.WEB_URL == pictureSource) { + md5 = MD5Digester.digestMD5(picturePath); + } else { + // 绝对路径图片 + File srcPicture = new File(picturePath); + md5 = MD5Digester.digestMD5(srcPicture); } + return md5; } } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java b/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java index 4754749..9454d84 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java @@ -8,6 +8,11 @@ package com.ibiz.excel.picture.support.model; */ public class CellStyle { + /** + * 行号 + */ + private int rowNumber; + /** * 默认已有fill样式 * 与对应{@link com.ibiz.excel.picture.support.module.Styles} @@ -83,4 +88,12 @@ public class CellStyle { public void setFgColorRgb(String fgColorRgb) { this.fgColorRgb = fgColorRgb; } + + public int getRowNumber() { + return rowNumber; + } + + public void setRowNumber(int rowNumber) { + this.rowNumber = rowNumber; + } } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Picture.java b/src/main/java/com/ibiz/excel/picture/support/model/Picture.java index cda4e7b..3af76f6 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Picture.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Picture.java @@ -1,6 +1,10 @@ package com.ibiz.excel.picture.support.model; +import com.ibiz.excel.picture.support.constants.PictureSourceContent; import com.ibiz.excel.picture.support.constants.WorkbookConstant; +import com.ibiz.excel.picture.support.util.StringUtils; + +import java.util.Objects; /** * @auther 喻场 @@ -12,7 +16,7 @@ public class Picture { private int fromRow; //图片起始行 Row.rowNumber private int toCol; //图片结束列 Cell.cellNumber + 1 private int toRow; //图片结束行 Row.rowNumber - /**当前系统中图片的绝对路径*/ + /**当前系统中图片的绝对路径 或 url地址*/ private String picturePath; //图片路径 /** @@ -76,6 +80,26 @@ public class Picture { this.pictureSource = pictureSource; } + /** + * 自动设置图片来源 + * @return + */ + public Picture autoPictureSourceByPath(){ + // 来源为0,自动匹配 + try { + if(this.pictureSource == 0 + // 图片路径不为空 + && StringUtils.isNotBlank(this.picturePath) + // 是url + && Objects.equals(this.picturePath.substring(0, 4),"http")){ + this.pictureSource = PictureSourceContent.WEB_URL; + } + }catch (Exception e){ + throw new RuntimeException("错误的图片地址: " + this.picturePath, e); + } + return this; + } + public String getPicturePath() { return picturePath; } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java index 8981710..fae44db 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java @@ -78,33 +78,6 @@ public class Sheet { */ private Map columnHelperMap = new HashMap<>(); - /** - * 默认已有fill样式 - * 与对应{@link com.ibiz.excel.picture.support.module.Styles} - */ - private int fillId = 33; - - /** - * 默认已有cellStyles样式 - */ - private int s = 4; - - public int getFillId() { - return fillId; - } - - public void setFillId(int fillId) { - this.fillId = fillId; - } - - public int getS() { - return s; - } - - public void setS(int s) { - this.s = s; - } - public List getPictures() { return pictures; } @@ -331,7 +304,12 @@ public class Sheet { // 计算单元格宽度根据单元格中值的数量 calculateColumnWidth(cellNumber, width, values.size()); //增加图片 - values.forEach(v -> pictures.add(new Picture(row.getRowNumber(), cellNumber, width, height, v, model.pictureSource()))); + values.forEach(val -> + pictures.add( + new Picture(row.getRowNumber(), cellNumber, width, height, val, model.pictureSource()) + // 自动设置图片来源 + .autoPictureSourceByPath() + )); } private List getValues(Object value) { diff --git a/src/main/java/com/ibiz/excel/picture/support/util/MD5Digester.java b/src/main/java/com/ibiz/excel/picture/support/util/MD5Digester.java index 1449704..0b5ccd4 100644 --- a/src/main/java/com/ibiz/excel/picture/support/util/MD5Digester.java +++ b/src/main/java/com/ibiz/excel/picture/support/util/MD5Digester.java @@ -1,12 +1,12 @@ package com.ibiz.excel.picture.support.util; import java.io.*; -import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; /** * 文件流md5 + * * @author yc 创建时间:2018年1月24日 下午4:50:35 */ public class MD5Digester { @@ -14,22 +14,26 @@ public class MD5Digester { * digital */ public static final char[] DIGITAL = "0123456789ABCDEF".toCharArray(); + /** * MD5Digester */ - private MD5Digester() {} + private MD5Digester() { + } public static String digestMD5(File file) throws FileNotFoundException { FileInputStream fis = new FileInputStream(file); return digestMD5(fis); } + /** * 文件流md5 + * * @param inputStream InputStream - * @return md5 + * @return md5 */ public static String digestMD5(InputStream inputStream) { - try(InputStream is = inputStream) { + try (InputStream is = inputStream) { MessageDigest digest = MessageDigest.getInstance("MD5"); byte[] buffer = new byte[8192]; int len; @@ -46,6 +50,7 @@ public class MD5Digester { /** * encodeHexStr + * * @param bytes bytes * @return String */ @@ -61,12 +66,27 @@ public class MD5Digester { return new String(result); } - public static String encodeHexStr(String str) { - if (str == null) { - return null; + /** + * 获取字符串的摘要 md5值 + * + * @param data + * @return + */ + public static String digestMD5(String data) { + MessageDigest message; + try { + message = MessageDigest.getInstance("MD5"); + message.update(data.getBytes()); + byte[] b = message.digest(); + return encodeHexStr(b); + } catch (Exception e) { + e.printStackTrace(); + throw new RuntimeException(e); } - byte[] bytes = str.getBytes(StandardCharsets.UTF_8); - return encodeHexStr(bytes); + } + + public static void main(String[] args) { + System.out.println(digestMD5("12312erdhhjfdkti5745468587ry87r4tuy87rt4u8rt44u36346")); } } diff --git a/src/test/java/com/ibiz/excel/picture/support/User.java b/src/test/java/com/ibiz/excel/picture/support/User.java index 14f48cd..3956c77 100644 --- a/src/test/java/com/ibiz/excel/picture/support/User.java +++ b/src/test/java/com/ibiz/excel/picture/support/User.java @@ -10,7 +10,7 @@ import java.util.StringJoiner; */ public class User { - @ExportModel(title = "姓名", mergeMaster = true) + @ExportModel(sort = 0,title = "姓名", mergeMaster = true) private String name; @ExportModel(sort = 1, title = "年龄") private Integer age; diff --git a/src/test/java/com/ibiz/excel/picture/support/UserPicture.java b/src/test/java/com/ibiz/excel/picture/support/UserPicture.java index 4ea2fd4..23388e0 100644 --- a/src/test/java/com/ibiz/excel/picture/support/UserPicture.java +++ b/src/test/java/com/ibiz/excel/picture/support/UserPicture.java @@ -14,7 +14,7 @@ public class UserPicture { public UserPicture() { } - @ExportModel(title = "姓名") + @ExportModel(sort = 0, title = "姓名") private String name; @ExportModel(sort = 1, title = "年龄") private Integer age; @@ -26,6 +26,8 @@ public class UserPicture { private String headerPicture; @ExportModel(sort = 5, isPicture = true, title = "多图片") private List pictures; + @ExportModel(sort = 6, isPicture = true, title = "url图片") + private List urlPictures; public UserPicture(String name, Integer age, String department, String picture) { this.name = name; @@ -81,4 +83,12 @@ public class UserPicture { public void setPictures(List pictures) { this.pictures = pictures; } + + public List getUrlPictures() { + return urlPictures; + } + + public void setUrlPictures(List urlPictures) { + this.urlPictures = urlPictures; + } } diff --git a/src/test/java/com/ibiz/excel/picture/support/common/BaseJunitTest.java b/src/test/java/com/ibiz/excel/picture/support/common/BaseJunitTest.java index bf5b2f1..6b7e44a 100644 --- a/src/test/java/com/ibiz/excel/picture/support/common/BaseJunitTest.java +++ b/src/test/java/com/ibiz/excel/picture/support/common/BaseJunitTest.java @@ -1,5 +1,7 @@ package com.ibiz.excel.picture.support.common; +import cn.hutool.core.io.FileUtil; + import java.io.File; import java.util.ArrayList; import java.util.List; @@ -21,13 +23,19 @@ public class BaseJunitTest { protected final static String IMAGES_PATH = CURRENT_PATH + "images\\"; + // url图片测试集合 protected final static List urls = new ArrayList<>(); + // 本地测试图片数组 + protected final static File[] localTestFiles; + static { urls.add("https://portrait.gitee.com/uploads/avatars/user/552/1657608_mwk719_1641537497.png"); urls.add("https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.jj20.com%2Fup%2Fallimg%2F1114%2F060421091316%2F210604091316-6-1200.jpg&refer=http%3A%2F%2Fimg.jj20.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1644142768&t=82062e20360f72b0fd8d5fd7e2fc9885"); urls.add("https://img2.baidu.com/it/u=121102239,1207969661&fm=253&fmt=auto&app=120&f=JPEG?w=1195&h=500"); urls.add("https://img2.baidu.com/it/u=2602880481,728201544&fm=26&fmt=auto"); + + localTestFiles = FileUtil.ls(IMAGES_PATH); } @@ -50,4 +58,12 @@ public class BaseJunitTest { int index = new Random().nextInt(urls.size()); return urls.get(index); } + + protected static List getUrls(int getCount) { + List list = new ArrayList<>(getCount); + for (int i = 0; i < getCount; i++) { + list.add(getUrl()); + } + return list; + } } diff --git a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java index f6dda39..a6f5013 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java @@ -1,6 +1,5 @@ package com.ibiz.excel.picture.support.example; -import cn.hutool.core.io.FileUtil; import com.ibiz.excel.picture.support.UserPicture; import com.ibiz.excel.picture.support.common.BaseJunitTest; import com.ibiz.excel.picture.support.model.CellStyle; @@ -9,7 +8,6 @@ import com.ibiz.excel.picture.support.model.Workbook; import com.ibiz.excel.picture.support.util.WebUtil; import org.junit.Test; -import java.io.File; import java.util.Random; /** @@ -31,8 +29,6 @@ public class AnnotationPicturesExportExample extends BaseJunitTest { // 给标题行加上背景色,加颜色时,会对字体加粗 CellStyle cellStyle = workBook.createCellStyle(); cellStyle.setFgColorRgb("66cc66"); - // 图片数组 - File[] files = FileUtil.ls(IMAGES_PATH); UserPicture userPicture; for (int r = 0; r < 10; r++) { userPicture = new UserPicture(); @@ -40,8 +36,8 @@ public class AnnotationPicturesExportExample extends BaseJunitTest { userPicture.setName("测试-" + r); userPicture.setPicture(IMG_PATH_1); userPicture.setHeaderPicture(getUrl()); - // 根据图片数组和要获取图片的数量,随机从图片数组中取出若干 - userPicture.setPictures(getPictures(files, new Random().nextInt(5))); + // 根据图片数组和要获取图片的数量,随机从本地测试图片数组中取出若干 + userPicture.setPictures(getPictures(localTestFiles, new Random().nextInt(5))); sheet.createRow(userPicture); // 不设置时,自适应图片的高度 // .setHeight(200); diff --git a/src/test/java/com/ibiz/excel/picture/support/example/UrlPicturesExportExample.java b/src/test/java/com/ibiz/excel/picture/support/example/UrlPicturesExportExample.java new file mode 100644 index 0000000..08b671f --- /dev/null +++ b/src/test/java/com/ibiz/excel/picture/support/example/UrlPicturesExportExample.java @@ -0,0 +1,45 @@ +package com.ibiz.excel.picture.support.example; + +import com.ibiz.excel.picture.support.UserPicture; +import com.ibiz.excel.picture.support.common.BaseJunitTest; +import com.ibiz.excel.picture.support.model.CellStyle; +import com.ibiz.excel.picture.support.model.Sheet; +import com.ibiz.excel.picture.support.model.Workbook; +import com.ibiz.excel.picture.support.util.WebUtil; +import org.junit.Test; + +/** + * url图片导出excel示例 + * + * @author MinWeikai + * @date 2022-01-10 10:08:03 + */ +public class UrlPicturesExportExample extends BaseJunitTest { + + @Test + public void export() { + Workbook workBook = Workbook.getInstance(); + Sheet sheet = workBook.createSheet("测试"); + + // 给标题行加上背景色,加颜色时,会对字体加粗 + CellStyle cellStyle = workBook.createCellStyle(); + cellStyle.setFgColorRgb("66cc66"); + UserPicture userPicture; + for (int r = 0; r < 10; r++) { + userPicture = new UserPicture(); + userPicture.setAge(15); + userPicture.setName("测试-" + r); + userPicture.setPicture(IMG_PATH_1); + userPicture.setHeaderPicture(getUrl()); + // 根据图片数组和要获取图片的数量,随机从url图片测试集合中取出若干 + userPicture.setUrlPictures(getUrls(5)); + sheet.createRow(userPicture); + // 对标题行添加上样式 + if (r == 0) { + sheet.getRow(0).setCellStyle(cellStyle); + } + } + WebUtil.writeExcelTest(workBook, "url图片导出excel示例".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), TEMP_PATH); + } + +} diff --git a/src/test/java/com/ibiz/excel/picture/support/util/MD5DigesterTest.java b/src/test/java/com/ibiz/excel/picture/support/util/MD5DigesterTest.java deleted file mode 100644 index 6803d89..0000000 --- a/src/test/java/com/ibiz/excel/picture/support/util/MD5DigesterTest.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.ibiz.excel.picture.support.util; - -import java.io.File; - -/** - * @author MinWeikai - * @date 2022/1/7 17:26 - */ -public class MD5DigesterTest { - - public static void main(String[] args) { - File destFilePath = new File("E:\\test\\img\\0.jpg"); - String md5 = null; - md5 = MD5Digester.encodeHexStr("destFilePath"); - System.out.println(md5); - } -} \ No newline at end of file -- Gitee From e32aa0c6ecddc76287f73c0637fa0293433912fa Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Mon, 10 Jan 2022 16:04:02 +0800 Subject: [PATCH 079/161] =?UTF-8?q?update=20CellStyle=E6=A0=B7=E5=BC=8F?= =?UTF-8?q?=E7=9A=84=E4=BD=BF=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../picture/support/flush/Sheet1Handler.java | 9 +- .../picture/support/flush/StylesIndex.java | 42 ++++ .../picture/support/model/CellStyle.java | 182 +++++++++--------- .../ibiz/excel/picture/support/model/Row.java | 2 +- .../excel/picture/support/model/Sheet.java | 39 +++- .../excel/picture/support/model/Workbook.java | 13 -- .../AnnotationPictureExportExample.java | 1 - .../AnnotationPicturesExportExample.java | 8 +- .../support/example/EasyUseExample1.java | 86 --------- .../support/example/EasyUseExample2.java | 90 --------- .../support/example/EasyUseExample3.java | 102 ---------- .../support/example/EasyUseExample4.java | 9 +- .../example/UrlPicturesExportExample.java | 8 +- .../SimulateRealBusinessExportExample.java | 40 +--- 14 files changed, 194 insertions(+), 437 deletions(-) create mode 100644 src/main/java/com/ibiz/excel/picture/support/flush/StylesIndex.java delete mode 100644 src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample1.java delete mode 100644 src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample2.java delete mode 100644 src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample3.java diff --git a/src/main/java/com/ibiz/excel/picture/support/flush/Sheet1Handler.java b/src/main/java/com/ibiz/excel/picture/support/flush/Sheet1Handler.java index af7179a..b9abe1e 100644 --- a/src/main/java/com/ibiz/excel/picture/support/flush/Sheet1Handler.java +++ b/src/main/java/com/ibiz/excel/picture/support/flush/Sheet1Handler.java @@ -17,7 +17,7 @@ import java.util.Set; * @auther 喻场 * @date 2020/7/618:33 */ -public class Sheet1Handler implements InvocationHandler { +public class Sheet1Handler extends StylesIndex implements InvocationHandler { private IRepository target; public Sheet1Handler(IRepository proxy) { @@ -154,10 +154,15 @@ public class Sheet1Handler implements InvocationHandler { //customHeight=1 使用自定义高度 content.append(""); + CellStyle cellStyle = row.getCellStyle(); + if(cellStyle != null){ + // 设置cellStyle样式下标 + this.addCellStyle(cellStyle); + } row.getCells().forEach(c -> content.append("") .append("") diff --git a/src/main/java/com/ibiz/excel/picture/support/flush/StylesIndex.java b/src/main/java/com/ibiz/excel/picture/support/flush/StylesIndex.java new file mode 100644 index 0000000..fbcbcce --- /dev/null +++ b/src/main/java/com/ibiz/excel/picture/support/flush/StylesIndex.java @@ -0,0 +1,42 @@ +package com.ibiz.excel.picture.support.flush; + +import com.ibiz.excel.picture.support.model.CellStyle; + +/** + * 样式下标取值 + * + * @author MinWeikai + * @date 2022/1/10 15:31 + */ +public class StylesIndex { + + /** + * 默认已有fill样式 + * 与对应{@link com.ibiz.excel.picture.support.module.Styles} + */ + private int fillId = 33; + + /** + * 默认已有cellStyles样式 + */ + private int s = 4; + + /** + * 设置下标样式 + * + * @param cellStyle + */ + protected void addCellStyle(CellStyle cellStyle) { + this.addIndex(); + cellStyle.setFillId(fillId); + cellStyle.setS(s); + } + + protected void addIndex() { + // fillId+1,生成下一个编号 + fillId = fillId + 1; + s = s + 1; + } + + +} diff --git a/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java b/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java index 9454d84..00f2de0 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java @@ -8,92 +8,98 @@ package com.ibiz.excel.picture.support.model; */ public class CellStyle { - /** - * 行号 - */ - private int rowNumber; - - /** - * 默认已有fill样式 - * 与对应{@link com.ibiz.excel.picture.support.module.Styles} - */ - private int fillId = 33; - - /** - * 默认已有cellStyles样式 - */ - private int s = 4; - - /** - * fgColor rgb颜色 - * RGB网页颜色在线取色器 https://link.fobshanghai.com/rgbcolor.htm - */ - private String fgColorRgb; - - /** - * 样式 - */ - private StyleEnum styleEnum; - - public CellStyle() { - } - - /** - * 创建单元格前景色 - * @param fgColorRgb - */ - public CellStyle(String fgColorRgb) { - // fillId+1,生成下一个编号 - fillId = fillId + 1; - s = s + 1; - this.fgColorRgb = fgColorRgb; - } - - public CellStyle(StyleEnum styleEnum) { - this.styleEnum = styleEnum; - this.fillId = styleEnum.getFillId(); - } - - public CellStyle(CellStyle cellStyle) { - // 生成下标 - cellStyle = cellStyle.addIndex(); - this.fillId = cellStyle.fillId; - this.s = cellStyle.s; - this.fgColorRgb = cellStyle.fgColorRgb; - } - - public CellStyle addIndex() { - // fillId+1,生成下一个编号 - fillId = fillId + 1; - s = s + 1; - return this; - } - - public int getFillId() { - return fillId; - } - - public int getS() { - return s; - } - - public String getFgColorRgb() { - return fgColorRgb; - } - - /** - * fgColor rgb颜色 - * RGB网页颜色在线取色器 https://link.fobshanghai.com/rgbcolor.htm - */ - public void setFgColorRgb(String fgColorRgb) { - this.fgColorRgb = fgColorRgb; - } - - public int getRowNumber() { - return rowNumber; - } - - public void setRowNumber(int rowNumber) { - this.rowNumber = rowNumber; - } + /** + * 行号 + */ + private int rowNumber; + + /** + * 默认已有fill样式 + * 与对应{@link com.ibiz.excel.picture.support.module.Styles} + */ + private int fillId = 33; + + /** + * 默认已有cellStyles样式 + */ + private int s = 4; + + /** + * fgColor rgb颜色 + * RGB网页颜色在线取色器 https://link.fobshanghai.com/rgbcolor.htm + */ + private String fgColorRgb; + + /** + * 样式 + */ + private StyleEnum styleEnum; + + public CellStyle() { + } + + /** + * 创建单元格前景色 + * + * @param fgColorRgb + */ + public CellStyle(String fgColorRgb) { + this.fgColorRgb = fgColorRgb; + } + + /** + * 根据行号设置颜色 + * @param rowNumber + * @param fgColorRgb + */ + public CellStyle(int rowNumber, String fgColorRgb) { + this.rowNumber = rowNumber; + this.fgColorRgb = fgColorRgb; + } + + public CellStyle(StyleEnum styleEnum) { + this.styleEnum = styleEnum; + this.fillId = styleEnum.getFillId(); + } + + public CellStyle(CellStyle cellStyle) { + this.fgColorRgb = cellStyle.fgColorRgb; + } + + public int getFillId() { + return fillId; + } + + public int getS() { + return s; + } + + public String getFgColorRgb() { + return fgColorRgb; + } + + /** + * fgColor rgb颜色 + * RGB网页颜色在线取色器 https://link.fobshanghai.com/rgbcolor.htm + */ + public void setFgColorRgb(String fgColorRgb) { + this.fgColorRgb = fgColorRgb; + } + + public int getRowNumber() { + return rowNumber; + } + + public void setRowNumber(int rowNumber) { + this.rowNumber = rowNumber; + } + + + public void setFillId(int fillId) { + this.fillId = fillId; + } + + public void setS(int s) { + this.s = s; + } } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Row.java b/src/main/java/com/ibiz/excel/picture/support/model/Row.java index 413c69a..fbb9ef0 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Row.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Row.java @@ -84,7 +84,7 @@ public class Row { * @return */ public Row setCellStyle(CellStyle cellStyle) { - this.cellStyle = new CellStyle(cellStyle); + this.cellStyle = cellStyle; return this; } } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java index fae44db..7bdaa75 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java @@ -78,6 +78,11 @@ public class Sheet { */ private Map columnHelperMap = new HashMap<>(); + /** + * 预设样式 + */ + private final Map cellStyleMap = new HashMap<>(); + public List getPictures() { return pictures; } @@ -353,9 +358,20 @@ public class Sheet { Row createRow(T t) { if (!hasWriteHead) { - create(t, true); + createRowAndCellStyle(t, true); } - return create(t, false); + return createRowAndCellStyle(t, false); + } + + private Row createRowAndCellStyle(T t, final boolean isHead) { + // 创建行数据 + Row row = create(t, isHead); + // 获取样式 + CellStyle cellStyle = cellStyleMap.get(row.getRowNumber()); + if(cellStyle != null){ + row.setCellStyle(cellStyle); + } + return row; } Row createRow(int rowNumber) { @@ -405,4 +421,23 @@ public class Sheet { public Map getColumnHelperMap() { return columnHelperMap; } + + /** + * 批量添加样式 + * + * @param cellStyles + */ + public void addCellStyle(List cellStyles) { + cellStyles.forEach(cellStyle-> this.cellStyleMap.put(cellStyle.getRowNumber(), cellStyle)); + } + + /** + * 添加样式 + * @param cellStyle + * @return + */ + public Sheet addCellStyle(CellStyle cellStyle) { + this.cellStyleMap.put(cellStyle.getRowNumber(), cellStyle); + return this; + } } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Workbook.java b/src/main/java/com/ibiz/excel/picture/support/model/Workbook.java index 26020db..72dd4b7 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Workbook.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Workbook.java @@ -51,8 +51,6 @@ public class Workbook { */ private Map imageCache = new HashMap<>(); - private CellStyle cellStyle; - public Map getImageCache() { return imageCache; } @@ -130,15 +128,4 @@ public class Workbook { throw new RuntimeException("workbook is closed"); } } - - /** - * 创建工作簿样式 - * - * @return - */ - public CellStyle createCellStyle() { - CellStyle cellStyle = new CellStyle(); - this.cellStyle = cellStyle; - return cellStyle; - } } diff --git a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPictureExportExample.java b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPictureExportExample.java index 7a9fca4..16504a7 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPictureExportExample.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPictureExportExample.java @@ -32,7 +32,6 @@ public class AnnotationPictureExportExample { userPicture.setAge(15); userPicture.setName("测试-" + r); userPicture.setPicture(IMG_PATH_1); - userPicture.setHeaderPicture(IMG_PATH_2); // 创建行数据在excel中 sheet.createRow(userPicture); } diff --git a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java index a6f5013..1504081 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java @@ -25,10 +25,6 @@ public class AnnotationPicturesExportExample extends BaseJunitTest { // 需要在创建行前预设宽度 // sheet.setColumnWidth(6, 100); - - // 给标题行加上背景色,加颜色时,会对字体加粗 - CellStyle cellStyle = workBook.createCellStyle(); - cellStyle.setFgColorRgb("66cc66"); UserPicture userPicture; for (int r = 0; r < 10; r++) { userPicture = new UserPicture(); @@ -41,9 +37,9 @@ public class AnnotationPicturesExportExample extends BaseJunitTest { sheet.createRow(userPicture); // 不设置时,自适应图片的高度 // .setHeight(200); - // 对标题行添加上样式 + // 给标题行加上背景色,加颜色时,会对字体加粗 if(r == 0){ - sheet.getRow(0).setCellStyle(cellStyle); + sheet.getRow(0).setCellStyle(new CellStyle("66cc66")); } } WebUtil.writeExcelTest(workBook, "注解导出图片集合示例".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), TEMP_PATH); diff --git a/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample1.java b/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample1.java deleted file mode 100644 index ce3d64f..0000000 --- a/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample1.java +++ /dev/null @@ -1,86 +0,0 @@ -package com.ibiz.excel.picture.support.example; - -import cn.hutool.core.io.FileUtil; -import com.ibiz.excel.picture.support.constants.WorkbookConstant; -import com.ibiz.excel.picture.support.model.*; - -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.UUID; - -/** - * 简化设置EasyUseExample1 - * 1. 需要文本列表信息 - * 2. 需要单元格填充单个图片 - * - * @author MinWeikai - * @date 2021-02-07 16:47:17 - */ -public class EasyUseExample1 { - static final String CURRENT_PATH = "E:\\test\\"; - - private final static String IMG_PATH = CURRENT_PATH + "img\\"; - - private final static String IMG_PATH_1 = IMG_PATH + "1.jpg"; - - - public static void main(String[] args) throws IOException { - Date start = new Date(); - Workbook workBook = Workbook.getInstance(1); - Sheet sheet = workBook.createSheet("测试"); - - // 第一行放标题 - String[] excelName = {"文本1", "文本2", "图片1", "图片2", "图片3"}; - //要进行合并的列 - sheet.getMergeCells().add(new MergeCell(0, 0, 0, excelName.length - 1)); - Row row = sheet.createRow(1) - //配置该行颜色,现在默认只有绿色 - .setCellStyle(new CellStyle(StyleEnum.GREEN_B)); - List cells = new ArrayList<>(); - for (int i = 0; i < excelName.length; i++) { - cells.add(new Cell(i).setValue(excelName[i])); - } - row.autoRowCells(cells); - - // 第二行放内容 - row = sheet.createRow(2); - List pictures = sheet.getPictures(); - cells = new ArrayList<>(); - for (int i = 0; i < excelName.length; i++) { - if (i < 2) { - cells.add(new Cell(i).setValue("文本")); - } else { - //有图片的行,行高设置为100 - row.setHeight(WorkbookConstant.PICTURE_ROW_HEIGHT); - //增加图片 - pictures.add(new Picture(row.getRowNumber(), i, IMG_PATH_1)); - } - } - row.autoRowCells(cells); - - File file = createFile(); - BufferedOutputStream os = FileUtil.getOutputStream(file); - workBook.write(os); - workBook.close(); - Date end = new Date(); - System.out.println("file capital :" + (file.length() / 1024 / 1024) + "M name :" + file.getName()); - System.out.println("file cost time :" + (end.getTime() - start.getTime())); - os.close(); - } - - - private static File createFile() { - String dir = CURRENT_PATH + "excel/"; - File file = new File(dir); - if (!file.exists()) { - file.mkdir(); - } - String name = CURRENT_PATH + "excel/" + UUID.randomUUID() + ".xlsx"; - return new File(name); - } - -} diff --git a/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample2.java b/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample2.java deleted file mode 100644 index 95c112d..0000000 --- a/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample2.java +++ /dev/null @@ -1,90 +0,0 @@ -package com.ibiz.excel.picture.support.example; - -import cn.hutool.core.io.FileUtil; -import com.ibiz.excel.picture.support.constants.WorkbookConstant; -import com.ibiz.excel.picture.support.model.*; - -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.IOException; -import java.util.*; - -/** - * 简化设置EasyUseExample2 - * 1. 需要文本列表信息 - * 2. 需要单元格填充单个图片 - * 3. 需要表头 - * - * @author MinWeikai - * @date 2021-02-07 16:47:17 - */ -public class EasyUseExample2 { - static final String CURRENT_PATH = "E:\\test\\"; - - private final static String IMG_PATH = CURRENT_PATH + "img\\"; - - private final static String IMG_PATH_1 = IMG_PATH + "1.jpg"; - - - public static void main(String[] args) throws IOException { - Date start = new Date(); - Workbook workBook = Workbook.getInstance(1); - Sheet sheet = workBook.createSheet("测试"); - - // 第一行表头 - Row row = sheet.createRow(0) - //字体20 - .setCellStyle(new CellStyle(StyleEnum.F20)); - row.autoRowCells(Collections.singletonList(new Cell(0).setValue("表头"))); - - // 第二行放标题 - String[] excelName = {"文本1", "文本2", "图片1", "图片2", "图片3"}; - //要进行合并的列 - sheet.getMergeCells().add(new MergeCell(0, 0, 0, excelName.length - 1)); - row = sheet.createRow(1) - //配置该行颜色,现在默认只有绿色 - .setCellStyle(new CellStyle(StyleEnum.GREEN_B)); - List cells = new ArrayList<>(); - for (int i = 0; i < excelName.length; i++) { - cells.add(new Cell(i).setValue(excelName[i])); - } - row.autoRowCells(cells); - - // 第三行放内容 - row = sheet.createRow(2); - List pictures = sheet.getPictures(); - cells = new ArrayList<>(); - for (int i = 0; i < excelName.length; i++) { - if (i < 2) { - cells.add(new Cell(i).setValue("文本")); - } else { - //有图片的行,行高设置为100 - row.setHeight(WorkbookConstant.PICTURE_ROW_HEIGHT); - //增加图片 - pictures.add(new Picture(row.getRowNumber(), i, IMG_PATH_1)); - } - } - row.autoRowCells(cells); - - File file = createFile(); - BufferedOutputStream os = FileUtil.getOutputStream(file); - workBook.write(os); - workBook.close(); - Date end = new Date(); - System.out.println("file capital :" + (file.length() / 1024 / 1024) + "M name :" + file.getName()); - System.out.println("file cost time :" + (end.getTime() - start.getTime())); - os.close(); - } - - - private static File createFile() { - String dir = CURRENT_PATH + "excel/"; - File file = new File(dir); - if (!file.exists()) { - file.mkdir(); - } - String name = CURRENT_PATH + "excel/" + UUID.randomUUID() + ".xlsx"; - return new File(name); - } - -} diff --git a/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample3.java b/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample3.java deleted file mode 100644 index a0a9667..0000000 --- a/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample3.java +++ /dev/null @@ -1,102 +0,0 @@ -package com.ibiz.excel.picture.support.example; - -import cn.hutool.core.io.FileUtil; -import com.ibiz.excel.picture.support.model.*; - -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.IOException; -import java.util.*; - -/** - * 简化设置EasyUseExample3 - * 1. 需要文本列表信息 - * 2. 需要单元格填充多张图片 - * 3. 需要表头 - * - * @author MinWeikai - * @date 2021-02-07 16:47:17 - */ -public class EasyUseExample3 { - static final String CURRENT_PATH = "E:\\test\\"; - - private final static String IMG_PATH = CURRENT_PATH + "img\\"; - - private final static String IMG_PATH_1 = IMG_PATH + "1.jpg"; - private final static String IMG_PATH_2 = IMG_PATH + "2.jpg"; - - - public static void main(String[] args) throws IOException { - Date start = new Date(); - Workbook workBook = Workbook.getInstance(1); - Sheet sheet = workBook.createSheet("测试"); - - // 需要在创建行前预设宽度 - sheet.setColumnWidth(1, 10) - .setColumnWidth(3, 50) - .setColumnWidth(4, 50) - .setColumnWidth(5, 50); - - // 第一行表头 - Row row = sheet.createRow(0) - //字体20 - .setCellStyle(new CellStyle(StyleEnum.F20)); - row.autoRowCells(Collections.singletonList(new Cell(0).setValue("表头"))); - - // 第二行放标题 - String[] excelName = {"文本1", "文本2", "图片1", "图片2", "图片3"}; - //要进行合并的列 - sheet.getMergeCells().add(new MergeCell(0, 0, 0, excelName.length - 1)); - row = sheet.createRow(1) - //配置该行颜色,现在默认只有绿色 - .setCellStyle(new CellStyle(StyleEnum.GREEN_B)); - List cells = new ArrayList<>(); - for (int i = 0; i < excelName.length; i++) { - cells.add(new Cell(i).setValue(excelName[i])); - } - row.autoRowCells(cells); - - // 第三行放内容 - row = sheet.createRow(2); - List pictures = sheet.getPictures(); - cells = new ArrayList<>(); - for (int i = 0; i < excelName.length; i++) { - if (i < 2) { - cells.add(new Cell(i).setValue("文本")); - } else { - //有图片的行,行高设置为100 - row.setHeight(80); - //每个单元格增加一个图片 - //pictures.add(new Picture(i, row.getRowNumber(),1000000 , IMG_PATH_1)); - - //在第二列添加多张图片 - pictures.add(new Picture(row.getRowNumber(),2, 1000000, IMG_PATH_1)); - //在第三列添加多张图片 - pictures.add(new Picture(row.getRowNumber(), 3, 1000000, IMG_PATH_2)); - pictures.add(new Picture(row.getRowNumber(), 4, 1000000, IMG_PATH_1)); - } - } - row.autoRowCells(cells); - - File file = createFile(); - BufferedOutputStream os = FileUtil.getOutputStream(file); - workBook.write(os); - workBook.close(); - Date end = new Date(); - System.out.println("file capital :" + (file.length() / 1024 / 1024) + "M name :" + file.getName()); - System.out.println("file cost time :" + (end.getTime() - start.getTime())); - os.close(); - } - - - private static File createFile() { - String dir = CURRENT_PATH + "excel/"; - File file = new File(dir); - if (!file.exists()) { - file.mkdir(); - } - String name = CURRENT_PATH + "excel/" + UUID.randomUUID() + ".xlsx"; - return new File(name); - } - -} diff --git a/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample4.java b/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample4.java index 306042e..c8553e4 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample4.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample4.java @@ -32,10 +32,6 @@ public class EasyUseExample4 { Workbook workBook = Workbook.getInstance(100); Sheet sheet = workBook.createSheet("测试"); - CellStyle cellStyle = workBook.createCellStyle(); - - cellStyle.setFgColorRgb("cc3300"); - // 需要在创建行前预设宽度 // 序号宽度 有时需要单独设置序号宽度窄一点 sheet.setColumnWidth(1, 5) @@ -43,7 +39,7 @@ public class EasyUseExample4 { .setColumnWidth(3, 50); // 第一行表头 - Row row = sheet.createRow(0).setCellStyle(cellStyle); + Row row = sheet.createRow(0).setCellStyle(new CellStyle("cc3300")); row.autoRowCells(Collections.singletonList(new Cell(0).setValue("表头"))); // 第二行放标题 @@ -51,8 +47,7 @@ public class EasyUseExample4 { //要进行合并的列 sheet.getMergeCells().add(new MergeCell(0, 0, 0, excelName.length - 1)); - cellStyle.setFgColorRgb("996699"); - row = sheet.createRow(1).setCellStyle(cellStyle); + row = sheet.createRow(1).setCellStyle(new CellStyle("996699")); List cells = new ArrayList<>(); for (int i = 0; i < excelName.length; i++) { cells.add(new Cell(i).setValue(excelName[i])); diff --git a/src/test/java/com/ibiz/excel/picture/support/example/UrlPicturesExportExample.java b/src/test/java/com/ibiz/excel/picture/support/example/UrlPicturesExportExample.java index 08b671f..1398df4 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/UrlPicturesExportExample.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/UrlPicturesExportExample.java @@ -20,10 +20,8 @@ public class UrlPicturesExportExample extends BaseJunitTest { public void export() { Workbook workBook = Workbook.getInstance(); Sheet sheet = workBook.createSheet("测试"); - // 给标题行加上背景色,加颜色时,会对字体加粗 - CellStyle cellStyle = workBook.createCellStyle(); - cellStyle.setFgColorRgb("66cc66"); + sheet.addCellStyle(new CellStyle(0, "66cc66")); UserPicture userPicture; for (int r = 0; r < 10; r++) { userPicture = new UserPicture(); @@ -34,10 +32,6 @@ public class UrlPicturesExportExample extends BaseJunitTest { // 根据图片数组和要获取图片的数量,随机从url图片测试集合中取出若干 userPicture.setUrlPictures(getUrls(5)); sheet.createRow(userPicture); - // 对标题行添加上样式 - if (r == 0) { - sheet.getRow(0).setCellStyle(cellStyle); - } } WebUtil.writeExcelTest(workBook, "url图片导出excel示例".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), TEMP_PATH); } diff --git a/src/test/java/com/ibiz/excel/picture/support/simulation/SimulateRealBusinessExportExample.java b/src/test/java/com/ibiz/excel/picture/support/simulation/SimulateRealBusinessExportExample.java index 93b6fe8..374f737 100644 --- a/src/test/java/com/ibiz/excel/picture/support/simulation/SimulateRealBusinessExportExample.java +++ b/src/test/java/com/ibiz/excel/picture/support/simulation/SimulateRealBusinessExportExample.java @@ -1,16 +1,13 @@ package com.ibiz.excel.picture.support.simulation; -import cn.hutool.core.io.FileUtil; import com.ibiz.excel.picture.support.UserPicture; +import com.ibiz.excel.picture.support.common.BaseJunitTest; import com.ibiz.excel.picture.support.model.CellStyle; import com.ibiz.excel.picture.support.model.Sheet; import com.ibiz.excel.picture.support.model.Workbook; import com.ibiz.excel.picture.support.util.WebUtil; +import org.junit.Test; -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; import java.util.Random; /** @@ -19,7 +16,7 @@ import java.util.Random; * @author MinWeikai * @date 2021-12-22 15:36:46 */ -public class SimulateRealBusinessExportExample { +public class SimulateRealBusinessExportExample extends BaseJunitTest { static final String CURRENT_PATH = "E:\\test\\"; private static final String TEMP_PATH = CURRENT_PATH + "excel\\"; @@ -31,15 +28,10 @@ public class SimulateRealBusinessExportExample { private final static String IMAGES_PATH = CURRENT_PATH + "images\\"; - public static void main(String[] args) throws IOException { + @Test + public void export() { Workbook workBook = Workbook.getInstance(50); Sheet sheet = workBook.createSheet("测试"); - - // 给标题行加上背景色,加颜色时,会对字体加粗 - CellStyle cellStyle = workBook.createCellStyle(); - cellStyle.setFgColorRgb("66cc66"); - // 图片数组 - File[] files = FileUtil.ls(IMAGES_PATH); UserPicture userPicture; for (int r = 0; r < 101; r++) { userPicture = new UserPicture(); @@ -52,31 +44,15 @@ public class SimulateRealBusinessExportExample { userPicture.setHeaderPicture(IMG_PATH_2); if(new Random().nextInt(10) > 5){ // 模拟场景2. 在业务数据集合中,有些数据没有图片对应的图片集合,没有则不设置值 - userPicture.setPictures(getPictures(files, new Random().nextInt(10))); + userPicture.setPictures(getPictures(localTestFiles, new Random().nextInt(10))); } sheet.createRow(userPicture); - // 对标题行添加上样式 + // 给标题行加上背景色,加颜色时,会对字体加粗 if (r == 0) { - sheet.getRow(r).setCellStyle(cellStyle); + sheet.getRow(r).setCellStyle(new CellStyle("66cc66")); } } WebUtil.writeExcelTest(workBook, "模拟真实业务场景导出示例".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), TEMP_PATH); } - /** - * 根据图片数组和要获取图片的数量,随机从图片数组中取出若干 - * - * @param files 图片数组 - * @param getCount 获取图片的数量 - * @return - */ - private static List getPictures(File[] files, int getCount) { - List list = new ArrayList<>(getCount); - for (int i = 0; i < getCount; i++) { - int index = new Random().nextInt(files.length); - list.add(files[index].getAbsolutePath()); - } - return list; - } - } -- Gitee From 7915b17886b7042eff16083a62e100055b2a64a5 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Mon, 10 Jan 2022 16:21:35 +0800 Subject: [PATCH 080/161] =?UTF-8?q?update=20=E6=B5=8B=E8=AF=95=E6=96=B9?= =?UTF-8?q?=E6=B3=95=E5=91=BD=E5=90=8D=E5=92=8C=E7=89=88=E6=9C=AC=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 11 ++++++++--- .../ibiz/excel/picture/support/UserPicture.java | 4 ++-- .../example/AnnotationPictureExportExample.java | 1 - ...tExample.java => ExportExample_20220110.java} | 16 +++++++++++----- 4 files changed, 21 insertions(+), 11 deletions(-) rename src/test/java/com/ibiz/excel/picture/support/example/{UrlPicturesExportExample.java => ExportExample_20220110.java} (66%) diff --git a/README.md b/README.md index fb9d6b7..7a949e2 100644 --- a/README.md +++ b/README.md @@ -31,24 +31,29 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, 1. ### Maven导入 - 在项目的pom.xml的dependencies中加入以下内容: + 在项目的pom.xml的dependencies中加入以下内容: 点击查看[最新版本 ${excel-x.version}](https://search.maven.org/artifact/top.minwk/excel-x) ```xml top.minwk excel-x - 2.0.0 + ${excel-x.version} ``` 2. ### 示例 - - [excel含图片导出demo地址](https://gitee.com/mwk719/excel-batch-picture-support/tree/dev/src/test/java/com/ibiz/excel/picture/support/example) + - [excel含图片导出demo地址](https://gitee.com/mwk719/excel-batch-picture-support/tree/dev/src/test/java/com/ibiz/excel/picture/support/example),具体使用以后缀最新日期为准,其他示例仅供测试 - [微云-6767张图片共800mb资源.rar 可用于测试](https://minwk.top/big-size-img/) - [项目中导出下载excel使用示例](https://gitee.com/mwk719/spring-learn/blob/master/src/main/java/com/mwk/external/controller/ExcelController.java) 3. ### 版本更迭 + #### 2.1.0(2022.01.14) + + - 添加导出网络链接图片到excel中 + - 修改CellStyle样式的使用 + #### 2.0.0(2021.12.30) - [添加用户可自定义背景色样式](https://gitee.com/mwk719/excel-batch-picture-support/blob/dev/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java) diff --git a/src/test/java/com/ibiz/excel/picture/support/UserPicture.java b/src/test/java/com/ibiz/excel/picture/support/UserPicture.java index 23388e0..9ce134e 100644 --- a/src/test/java/com/ibiz/excel/picture/support/UserPicture.java +++ b/src/test/java/com/ibiz/excel/picture/support/UserPicture.java @@ -24,9 +24,9 @@ public class UserPicture { private String picture; @ExportModel(sort = 4, isPicture = true, title = "图片2", pictureSource = PictureSourceContent.WEB_URL) private String headerPicture; - @ExportModel(sort = 5, isPicture = true, title = "多图片") + @ExportModel(sort = 5, isPicture = true, title = "本地多图片") private List pictures; - @ExportModel(sort = 6, isPicture = true, title = "url图片") + @ExportModel(sort = 6, isPicture = true, title = "url多图片") private List urlPictures; public UserPicture(String name, Integer age, String department, String picture) { diff --git a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPictureExportExample.java b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPictureExportExample.java index 16504a7..6ac17ff 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPictureExportExample.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPictureExportExample.java @@ -9,7 +9,6 @@ import java.io.IOException; /** * 注解图片导出示例 - * todo 建议使用{@link EasyUseExample4} 示例,不过写法有点麻烦,待优化 * * @author MinWeikai * @date 2021-12-07 10:59:49 diff --git a/src/test/java/com/ibiz/excel/picture/support/example/UrlPicturesExportExample.java b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220110.java similarity index 66% rename from src/test/java/com/ibiz/excel/picture/support/example/UrlPicturesExportExample.java rename to src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220110.java index 1398df4..80f4c24 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/UrlPicturesExportExample.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220110.java @@ -8,13 +8,15 @@ import com.ibiz.excel.picture.support.model.Workbook; import com.ibiz.excel.picture.support.util.WebUtil; import org.junit.Test; +import java.util.Random; + /** - * url图片导出excel示例 + * 导出excel示例 * * @author MinWeikai * @date 2022-01-10 10:08:03 */ -public class UrlPicturesExportExample extends BaseJunitTest { +public class ExportExample_20220110 extends BaseJunitTest { @Test public void export() { @@ -23,17 +25,21 @@ public class UrlPicturesExportExample extends BaseJunitTest { // 给标题行加上背景色,加颜色时,会对字体加粗 sheet.addCellStyle(new CellStyle(0, "66cc66")); UserPicture userPicture; - for (int r = 0; r < 10; r++) { + for (int r = 0; r < 101; r++) { userPicture = new UserPicture(); userPicture.setAge(15); userPicture.setName("测试-" + r); + // 导出本地单张图片 userPicture.setPicture(IMG_PATH_1); + // 导出url单张图片 userPicture.setHeaderPicture(getUrl()); - // 根据图片数组和要获取图片的数量,随机从url图片测试集合中取出若干 + // 导出本地图片集合 + userPicture.setPictures(getPictures(localTestFiles, new Random().nextInt(5))); + // 导出url图片集合 userPicture.setUrlPictures(getUrls(5)); sheet.createRow(userPicture); } - WebUtil.writeExcelTest(workBook, "url图片导出excel示例".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), TEMP_PATH); + WebUtil.writeExcelTest(workBook, "ExportExample_20220110_导出excel示例".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), TEMP_PATH); } } -- Gitee From 7d5029f8d8acbad47b6ace7d76b34573713eaaf8 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Mon, 10 Jan 2022 17:36:08 +0800 Subject: [PATCH 081/161] =?UTF-8?q?remove=20=E4=B8=8D=E5=BF=85=E8=A6=81?= =?UTF-8?q?=E7=9A=84=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 2 +- .../picture/support/flush/StylesIndex.java | 14 +++ .../picture/support/model/CellStyle.java | 41 +------- .../excel/picture/support/model/FontEnum.java | 32 ------ .../picture/support/model/StyleEnum.java | 37 ------- .../excel/picture/support/CellWidthTest.java | 75 -------------- .../ibiz/excel/picture/support/FontTest.java | 99 ------------------- .../picture/support/PictureCellWidthTest.java | 94 ------------------ .../excel/picture/support/PicturesDemo.java | 84 ---------------- .../excel/picture/support/RowFgColorTest.java | 73 -------------- .../picture/support/common/BaseJunitTest.java | 32 +++--- .../AnnotationPicturesExportExample.java | 2 +- .../example/ExportExample_20220110.java | 2 +- .../SimulateRealBusinessExportExample.java | 2 +- 14 files changed, 39 insertions(+), 550 deletions(-) delete mode 100644 src/main/java/com/ibiz/excel/picture/support/model/FontEnum.java delete mode 100644 src/main/java/com/ibiz/excel/picture/support/model/StyleEnum.java delete mode 100644 src/test/java/com/ibiz/excel/picture/support/CellWidthTest.java delete mode 100644 src/test/java/com/ibiz/excel/picture/support/FontTest.java delete mode 100644 src/test/java/com/ibiz/excel/picture/support/PictureCellWidthTest.java delete mode 100644 src/test/java/com/ibiz/excel/picture/support/PicturesDemo.java delete mode 100644 src/test/java/com/ibiz/excel/picture/support/RowFgColorTest.java diff --git a/pom.xml b/pom.xml index 6850a8f..e3c449a 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ top.minwk excel-x - 2.0.0 + 2.1.0 excel-x excel-x https://gitee.com/mwk719/excel-batch-picture-support diff --git a/src/main/java/com/ibiz/excel/picture/support/flush/StylesIndex.java b/src/main/java/com/ibiz/excel/picture/support/flush/StylesIndex.java index fbcbcce..55a52d3 100644 --- a/src/main/java/com/ibiz/excel/picture/support/flush/StylesIndex.java +++ b/src/main/java/com/ibiz/excel/picture/support/flush/StylesIndex.java @@ -38,5 +38,19 @@ public class StylesIndex { s = s + 1; } + public int getFillId() { + return fillId; + } + + public void setFillId(int fillId) { + this.fillId = fillId; + } + public int getS() { + return s; + } + + public void setS(int s) { + this.s = s; + } } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java b/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java index 00f2de0..0f25627 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java @@ -1,40 +1,26 @@ package com.ibiz.excel.picture.support.model; +import com.ibiz.excel.picture.support.flush.StylesIndex; + /** * 控制该行样式 * * @author MinWeikai * @date 2021/1/19 14:04 */ -public class CellStyle { +public class CellStyle extends StylesIndex { /** * 行号 */ private int rowNumber; - /** - * 默认已有fill样式 - * 与对应{@link com.ibiz.excel.picture.support.module.Styles} - */ - private int fillId = 33; - - /** - * 默认已有cellStyles样式 - */ - private int s = 4; - /** * fgColor rgb颜色 * RGB网页颜色在线取色器 https://link.fobshanghai.com/rgbcolor.htm */ private String fgColorRgb; - /** - * 样式 - */ - private StyleEnum styleEnum; - public CellStyle() { } @@ -57,23 +43,10 @@ public class CellStyle { this.fgColorRgb = fgColorRgb; } - public CellStyle(StyleEnum styleEnum) { - this.styleEnum = styleEnum; - this.fillId = styleEnum.getFillId(); - } - public CellStyle(CellStyle cellStyle) { this.fgColorRgb = cellStyle.fgColorRgb; } - public int getFillId() { - return fillId; - } - - public int getS() { - return s; - } - public String getFgColorRgb() { return fgColorRgb; } @@ -94,12 +67,4 @@ public class CellStyle { this.rowNumber = rowNumber; } - - public void setFillId(int fillId) { - this.fillId = fillId; - } - - public void setS(int s) { - this.s = s; - } } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/FontEnum.java b/src/main/java/com/ibiz/excel/picture/support/model/FontEnum.java deleted file mode 100644 index 1b96d32..0000000 --- a/src/main/java/com/ibiz/excel/picture/support/model/FontEnum.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.ibiz.excel.picture.support.model; - -import com.ibiz.excel.picture.support.module.Styles; - -/** - * 读取内置字体 - * - * @author MinWeikai - * @date 2021/1/20 11:57 - */ -public enum FontEnum { - - /** - * font size 20 - */ - F20(22), - - F10(3) - ; - /** - * 与对应{@link Styles} - */ - private Integer fillId; - - FontEnum(Integer fillId) { - this.fillId = fillId; - } - - public Integer getFillId() { - return fillId; - } -} diff --git a/src/main/java/com/ibiz/excel/picture/support/model/StyleEnum.java b/src/main/java/com/ibiz/excel/picture/support/model/StyleEnum.java deleted file mode 100644 index db4c3da..0000000 --- a/src/main/java/com/ibiz/excel/picture/support/model/StyleEnum.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.ibiz.excel.picture.support.model; - -import com.ibiz.excel.picture.support.module.Styles; - -/** - * 样式枚举类 - * - * @author MinWeikai - * @date 2021/1/19 14:10 - */ -public enum StyleEnum { - - /** - * 绿色填充色,字体加粗 - */ - GREEN_B(3), - - /** - * 字体-20 - */ - F20(4); - - - /** - * 填充色id - * 与对应{@link Styles} - */ - private Integer fillId; - - StyleEnum(Integer fillId) { - this.fillId = fillId; - } - - public Integer getFillId() { - return fillId; - } -} diff --git a/src/test/java/com/ibiz/excel/picture/support/CellWidthTest.java b/src/test/java/com/ibiz/excel/picture/support/CellWidthTest.java deleted file mode 100644 index 2769309..0000000 --- a/src/test/java/com/ibiz/excel/picture/support/CellWidthTest.java +++ /dev/null @@ -1,75 +0,0 @@ -package com.ibiz.excel.picture.support; - -import cn.hutool.core.io.FileUtil; -import com.ibiz.excel.picture.support.model.*; - -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.IOException; -import java.util.*; - -/** - * 单元格自定义宽度 - * - * @author MinWeikai - * @date 2021-01-19 14:47:39 - */ -public class CellWidthTest { - - static final String CURRENT_PATH = "E:\\test\\"; - - public static void main(String[] args) throws IOException { - Date start = new Date(); - Workbook workBook = Workbook.getInstance(1); - Sheet sheet = workBook.createSheet("测试"); - // 设置宽度 - sheet.setColumnWidth(1, 50); - - // 第一行表头 - Row row = sheet.createRow(0); - String[] excelName = {"文本1", "文本2", "图片1", "图片2", "图片3"}; - sheet.getMergeCells().add(new MergeCell(0, 0, 0, excelName.length - 1)); - row.setCells(Collections.singletonList(new Cell(0, 0).setValue("表头"))); - - // 第二行放标题 - row = sheet.createRow(1) - //配置该行颜色,现在默认只有绿色 - .setCellStyle(new CellStyle(StyleEnum.GREEN_B)); - List cells = new ArrayList<>(); - for (int i = 0; i < excelName.length; i++) { - Cell cell = new Cell(1, i).setValue(excelName[i]); - cells.add(cell); - } - row.setCells(cells); - - // 第三行放内容 - row = sheet.createRow(2); - cells = new ArrayList<>(); - for (int i = 0; i < excelName.length; i++) { - Cell cell = new Cell(2, i).setValue("文本" + i); - cells.add(cell); - } - row.setCells(cells); - - - File file = createFile(); - BufferedOutputStream os = FileUtil.getOutputStream(file); - workBook.write(os); - workBook.close(); - Date end = new Date(); - System.out.println("file capital :" + (file.length() / 1024 / 1024) + "M name :" + file.getName()); - System.out.println("file cost time :" + (end.getTime() - start.getTime())); - os.close(); - } - - - private static File createFile() { - String dir = CURRENT_PATH + "excel/"; - File file = new File(dir); - if (!file.exists()) { - file.mkdir(); - } - String name = CURRENT_PATH + "excel/" + UUID.randomUUID() + ".xlsx"; - return new File(name); - } -} diff --git a/src/test/java/com/ibiz/excel/picture/support/FontTest.java b/src/test/java/com/ibiz/excel/picture/support/FontTest.java deleted file mode 100644 index 5d9bde3..0000000 --- a/src/test/java/com/ibiz/excel/picture/support/FontTest.java +++ /dev/null @@ -1,99 +0,0 @@ -package com.ibiz.excel.picture.support; - -import cn.hutool.core.io.FileUtil; -import com.ibiz.excel.picture.support.model.*; - -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.IOException; -import java.util.*; - -/** - * 字体控制 - * - * @author MinWeikai - * @date 2021/1/20 11:45 - */ -public class FontTest { - - private static final String CURRENT_PATH = "E:\\test\\"; - - private final static String IMG_PATH = CURRENT_PATH + "img\\"; - - private final static String IMG_PATH_1 = IMG_PATH + "1.jpg"; - private final static String IMG_PATH_2 = IMG_PATH + "2.jpg"; - - public static void main(String[] args) throws IOException { - Date start = new Date(); - Workbook workBook = Workbook.getInstance(1); - Sheet sheet = workBook.createSheet("测试"); - - // 需要在创建行前预设宽度 - sheet.setColumnWidth(1, 10) - .setColumnWidth(3, 50) - .setColumnWidth(4, 50); - - // 第一行表头 - Row row = sheet.createRow(0) - //字体20 - .setCellStyle(new CellStyle(StyleEnum.F20)) - ; - String[] excelName = {"序号", "文本2", "图片1", "图片2", "图片3"}; - sheet.getMergeCells().add(new MergeCell(0, 0, 0, excelName.length - 1)); - row.setCells(Collections.singletonList(new Cell(0, 0).setValue("表头"))); - - // 第二行放标题 - row = sheet.createRow(1) - //配置该行颜色,现在默认只有绿色 - .setCellStyle(new CellStyle(StyleEnum.GREEN_B)); - List cells = new ArrayList<>(); - for (int i = 0; i < excelName.length; i++) { - Cell cell = new Cell(1, i).setValue(excelName[i]); - cells.add(cell); - } - row.setCells(cells); - - // 第三行放内容和图片 - row = sheet.createRow(2); - - cells = new ArrayList<>(); - List pictures = sheet.getPictures(); - //序号 - cells.add(new Cell(2, 0).setValue("1")); - for (int i = 0; i < excelName.length; i++) { - if (i == 1) { - cells.add(new Cell(2, i).setValue("文本" + i)); - } else { - //有图片的行,行高设置为100 - row.setHeight(80); - //每个单元格增加一个图片 - //pictures.add(new Picture(i, row.getRowNumber(),1000000 , IMG_PATH_1)); - //在第三列添加多张图片 - pictures.add(new Picture(row.getRowNumber(), 3, 1000000, IMG_PATH_1)); - pictures.add(new Picture(row.getRowNumber(),2, 1000000, IMG_PATH_2)); - } - } - row.setCells(cells); - - - File file = createFile(); - BufferedOutputStream os = FileUtil.getOutputStream(file); - workBook.write(os); - workBook.close(); - Date end = new Date(); - System.out.println("file capital :" + (file.length() / 1024 / 1024) + "M name :" + file.getName()); - System.out.println("file cost time :" + (end.getTime() - start.getTime())); - os.close(); - } - - - private static File createFile() { - String dir = CURRENT_PATH + "excel/"; - File file = new File(dir); - if (!file.exists()) { - file.mkdir(); - } - String name = CURRENT_PATH + "excel/" + UUID.randomUUID() + ".xlsx"; - return new File(name); - } -} diff --git a/src/test/java/com/ibiz/excel/picture/support/PictureCellWidthTest.java b/src/test/java/com/ibiz/excel/picture/support/PictureCellWidthTest.java deleted file mode 100644 index 74ddb8d..0000000 --- a/src/test/java/com/ibiz/excel/picture/support/PictureCellWidthTest.java +++ /dev/null @@ -1,94 +0,0 @@ -package com.ibiz.excel.picture.support; - -import cn.hutool.core.io.FileUtil; -import com.ibiz.excel.picture.support.model.*; - -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.IOException; -import java.util.*; - -/** - * 图片放在一个单元格宽度 - * - * @author MinWeikai - * @date 2021-01-19 16:03:21 - */ -public class PictureCellWidthTest { - - private static final String CURRENT_PATH = "E:\\test\\"; - - private final static String IMG_PATH = CURRENT_PATH + "img\\"; - - private final static String IMG_PATH_1 = IMG_PATH + "ia_1900002528.jpeg"; - - public static void main(String[] args) throws IOException { - Date start = new Date(); - Workbook workBook = Workbook.getInstance(1); - Sheet sheet = workBook.createSheet("测试"); - - // 需要在创建行前预设宽度 - sheet.setColumnWidth(1, 10) - .setColumnWidth(3, 50) - .setColumnWidth(4, 50); - - // 第一行表头 - Row row = sheet.createRow(0); - String[] excelName = {"序号", "文本2", "图片1", "图片2", "图片3"}; - sheet.getMergeCells().add(new MergeCell(0, 0, 0, excelName.length - 1)); - row.setCells(Collections.singletonList(new Cell(0, 0).setValue("表头"))); - - // 第二行放标题 - row = sheet.createRow(1) - //配置该行颜色,现在默认只有绿色 - .setCellStyle(new CellStyle(StyleEnum.GREEN_B)); - List cells = new ArrayList<>(); - for (int i = 0; i < excelName.length; i++) { - Cell cell = new Cell(1, i).setValue(excelName[i]); - cells.add(cell); - } - row.setCells(cells); - - // 第三行放内容和图片 - row = sheet.createRow(2); - - cells = new ArrayList<>(); - List pictures = sheet.getPictures(); - //序号 - cells.add(new Cell(2, 0).setValue("1")); - for (int i = 0; i < excelName.length; i++) { - if (i < 2) { - cells.add(new Cell(2, i).setValue("文本" + i)); - } else { - //有图片的行,行高设置为100 - row.setHeight(80); - //每个单元格增加一个图片 - //pictures.add(new Picture(i, row.getRowNumber(),1000000 , IMG_PATH_1)); - //在第三列添加多张图片 - pictures.add(new Picture( row.getRowNumber(), 3,1000000, IMG_PATH_1)); - } - } - row.setCells(cells); - - - File file = createFile(); - BufferedOutputStream os = FileUtil.getOutputStream(file); - workBook.write(os); - workBook.close(); - Date end = new Date(); - System.out.println("file capital :" + (file.length() / 1024 / 1024) + "M name :" + file.getName()); - System.out.println("file cost time :" + (end.getTime() - start.getTime())); - os.close(); - } - - - private static File createFile() { - String dir = CURRENT_PATH + "excel/"; - File file = new File(dir); - if (!file.exists()) { - file.mkdir(); - } - String name = CURRENT_PATH + "excel/" + UUID.randomUUID() + ".xlsx"; - return new File(name); - } -} diff --git a/src/test/java/com/ibiz/excel/picture/support/PicturesDemo.java b/src/test/java/com/ibiz/excel/picture/support/PicturesDemo.java deleted file mode 100644 index 21cf91b..0000000 --- a/src/test/java/com/ibiz/excel/picture/support/PicturesDemo.java +++ /dev/null @@ -1,84 +0,0 @@ -package com.ibiz.excel.picture.support; - -import cn.hutool.core.io.FileUtil; -import com.ibiz.excel.picture.support.model.CellStyle; -import com.ibiz.excel.picture.support.model.Sheet; -import com.ibiz.excel.picture.support.model.StyleEnum; -import com.ibiz.excel.picture.support.model.Workbook; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.Date; -import java.util.UUID; - -/** - * 多图片导入测试 - * - * @author MinWeikai - * @date 2021-01-15 09:46:32 - */ -public class PicturesDemo { - static final String CURRENT_PATH = "E:\\test\\"; - - private final static String IMG_PATH = "E:\\test\\img\\"; - - private static Integer SUM = 0; - private static Integer N = 0; - private static Integer _COUNT = 0; - - public static void main(String[] args) throws IOException { - Date start = new Date(); - Workbook workBook = Workbook.getInstance(-1); - Sheet sheet = workBook.createSheet("测试"); - File[] files = FileUtil.ls(IMG_PATH); - SUM = files.length; - UserPicture u1; - for (int r = 0; r < 2; r++) { - if (N == 0) { - _COUNT = 0; - } - u1 = new UserPicture(); - u1.setAge(15); - u1.setName("测试-" + r); - u1.setPicture(files[getIndex(N, 0)].getAbsolutePath()); - sheet.createRow(u1); - - _COUNT++; - N = _COUNT * 9; - } - - sheet.getRows().get(0).setCellStyle(new CellStyle(StyleEnum.GREEN_B)); - - File file = createFile(); - OutputStream os = new FileOutputStream(file); - workBook.write(os); - workBook.close(); - Date end = new Date(); - System.out.println("file capital :" + (file.length() / 1024 / 1024) + "M name :" + file.getName()); - System.out.println("file cost time :" + (end.getTime() - start.getTime())); - os.close(); - } - - private static int getIndex(int i, int i1) { - int count = i + i1; - if (count >= SUM) { - N = 0; - count = 0; - _COUNT = 0; - } - return count; - } - - private static File createFile() { - String dir = CURRENT_PATH + "excel/"; - File file = new File(dir); - if (!file.exists()) { - file.mkdir(); - } - String name = CURRENT_PATH + "excel/" + UUID.randomUUID() + ".xlsx"; - return new File(name); - } - -} diff --git a/src/test/java/com/ibiz/excel/picture/support/RowFgColorTest.java b/src/test/java/com/ibiz/excel/picture/support/RowFgColorTest.java deleted file mode 100644 index 2acb667..0000000 --- a/src/test/java/com/ibiz/excel/picture/support/RowFgColorTest.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.ibiz.excel.picture.support; - -import cn.hutool.core.io.FileUtil; -import com.ibiz.excel.picture.support.model.*; - -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.IOException; -import java.util.*; - -/** - * 行填充色 - * - * @author MinWeikai - * @date 2021-01-19 13:58:14 - */ -public class RowFgColorTest { - - static final String CURRENT_PATH = "E:\\test\\"; - - public static void main(String[] args) throws IOException { - Date start = new Date(); - Workbook workBook = Workbook.getInstance(1); - Sheet sheet = workBook.createSheet("测试"); - - // 第一行表头 - Row row = sheet.createRow(0); - String[] excelName = {"文本1", "文本2", "图片1", "图片2", "图片3"}; - sheet.getMergeCells().add(new MergeCell(0, 0, 0, excelName.length - 1)); - row.setCells(Collections.singletonList(new Cell(0, 0).setValue("表头"))); - - // 第二行放标题 - row = sheet.createRow(1) - //配置该行颜色,现在默认只有绿色 - .setCellStyle(new CellStyle(StyleEnum.GREEN_B)); - List cells = new ArrayList<>(); - for (int i = 0; i < excelName.length; i++) { - Cell cell = new Cell(1, i).setValue(excelName[i]); - cells.add(cell); - } - row.setCells(cells); - - // 第三行放内容 - row = sheet.createRow(2); - cells = new ArrayList<>(); - for (int i = 0; i < excelName.length; i++) { - Cell cell = new Cell(2, i).setValue("文本" + i); - cells.add(cell); - } - row.setCells(cells); - - - File file = createFile(); - BufferedOutputStream os = FileUtil.getOutputStream(file); - workBook.write(os); - workBook.close(); - Date end = new Date(); - System.out.println("file capital :" + (file.length() / 1024 / 1024) + "M name :" + file.getName()); - System.out.println("file cost time :" + (end.getTime() - start.getTime())); - os.close(); - } - - - private static File createFile() { - String dir = CURRENT_PATH + "excel/"; - File file = new File(dir); - if (!file.exists()) { - file.mkdir(); - } - String name = CURRENT_PATH + "excel/" + UUID.randomUUID() + ".xlsx"; - return new File(name); - } -} diff --git a/src/test/java/com/ibiz/excel/picture/support/common/BaseJunitTest.java b/src/test/java/com/ibiz/excel/picture/support/common/BaseJunitTest.java index 6b7e44a..b2ca444 100644 --- a/src/test/java/com/ibiz/excel/picture/support/common/BaseJunitTest.java +++ b/src/test/java/com/ibiz/excel/picture/support/common/BaseJunitTest.java @@ -23,19 +23,23 @@ public class BaseJunitTest { protected final static String IMAGES_PATH = CURRENT_PATH + "images\\"; - // url图片测试集合 - protected final static List urls = new ArrayList<>(); + /** + * url图片测试集合 + */ + protected final static List URLS = new ArrayList<>(); - // 本地测试图片数组 - protected final static File[] localTestFiles; + /** + * 本地测试图片数组 + */ + protected final static File[] LOCAL_TEST_FILES; static { - urls.add("https://portrait.gitee.com/uploads/avatars/user/552/1657608_mwk719_1641537497.png"); - urls.add("https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.jj20.com%2Fup%2Fallimg%2F1114%2F060421091316%2F210604091316-6-1200.jpg&refer=http%3A%2F%2Fimg.jj20.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1644142768&t=82062e20360f72b0fd8d5fd7e2fc9885"); - urls.add("https://img2.baidu.com/it/u=121102239,1207969661&fm=253&fmt=auto&app=120&f=JPEG?w=1195&h=500"); - urls.add("https://img2.baidu.com/it/u=2602880481,728201544&fm=26&fmt=auto"); + URLS.add("https://portrait.gitee.com/uploads/avatars/user/552/1657608_mwk719_1641537497.png"); + URLS.add("https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.jj20.com%2Fup%2Fallimg%2F1114%2F060421091316%2F210604091316-6-1200.jpg&refer=http%3A%2F%2Fimg.jj20.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1644142768&t=82062e20360f72b0fd8d5fd7e2fc9885"); + URLS.add("https://img2.baidu.com/it/u=121102239,1207969661&fm=253&fmt=auto&app=120&f=JPEG?w=1195&h=500"); + URLS.add("https://img2.baidu.com/it/u=2602880481,728201544&fm=26&fmt=auto"); - localTestFiles = FileUtil.ls(IMAGES_PATH); + LOCAL_TEST_FILES = FileUtil.ls(IMAGES_PATH); } @@ -45,18 +49,18 @@ public class BaseJunitTest { * @param getCount 获取图片的数量 * @return */ - protected static List getPictures(File[] files, int getCount) { + protected static List getPictures(int getCount) { List list = new ArrayList<>(getCount); for (int i = 0; i < getCount; i++) { - int index = new Random().nextInt(files.length); - list.add(files[index].getAbsolutePath()); + int index = new Random().nextInt(LOCAL_TEST_FILES.length); + list.add(LOCAL_TEST_FILES[index].getAbsolutePath()); } return list; } protected static String getUrl() { - int index = new Random().nextInt(urls.size()); - return urls.get(index); + int index = new Random().nextInt(URLS.size()); + return URLS.get(index); } protected static List getUrls(int getCount) { diff --git a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java index 1504081..68aadd2 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java @@ -33,7 +33,7 @@ public class AnnotationPicturesExportExample extends BaseJunitTest { userPicture.setPicture(IMG_PATH_1); userPicture.setHeaderPicture(getUrl()); // 根据图片数组和要获取图片的数量,随机从本地测试图片数组中取出若干 - userPicture.setPictures(getPictures(localTestFiles, new Random().nextInt(5))); + userPicture.setPictures(getPictures(new Random().nextInt(5))); sheet.createRow(userPicture); // 不设置时,自适应图片的高度 // .setHeight(200); diff --git a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220110.java b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220110.java index 80f4c24..cb2143f 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220110.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220110.java @@ -34,7 +34,7 @@ public class ExportExample_20220110 extends BaseJunitTest { // 导出url单张图片 userPicture.setHeaderPicture(getUrl()); // 导出本地图片集合 - userPicture.setPictures(getPictures(localTestFiles, new Random().nextInt(5))); + userPicture.setPictures(getPictures(new Random().nextInt(5))); // 导出url图片集合 userPicture.setUrlPictures(getUrls(5)); sheet.createRow(userPicture); diff --git a/src/test/java/com/ibiz/excel/picture/support/simulation/SimulateRealBusinessExportExample.java b/src/test/java/com/ibiz/excel/picture/support/simulation/SimulateRealBusinessExportExample.java index 374f737..2030772 100644 --- a/src/test/java/com/ibiz/excel/picture/support/simulation/SimulateRealBusinessExportExample.java +++ b/src/test/java/com/ibiz/excel/picture/support/simulation/SimulateRealBusinessExportExample.java @@ -44,7 +44,7 @@ public class SimulateRealBusinessExportExample extends BaseJunitTest { userPicture.setHeaderPicture(IMG_PATH_2); if(new Random().nextInt(10) > 5){ // 模拟场景2. 在业务数据集合中,有些数据没有图片对应的图片集合,没有则不设置值 - userPicture.setPictures(getPictures(localTestFiles, new Random().nextInt(10))); + userPicture.setPictures(getPictures(new Random().nextInt(10))); } sheet.createRow(userPicture); // 给标题行加上背景色,加颜色时,会对字体加粗 -- Gitee From 56bd87b718d677d80750cff35b0c59777e2411e9 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Tue, 11 Jan 2022 15:54:00 +0800 Subject: [PATCH 082/161] =?UTF-8?q?fix=20flushSize=3D1=E6=97=B6=E5=AF=BC?= =?UTF-8?q?=E5=87=BA=E6=A0=BC=E5=BC=8F=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 39 ++++++++++++ pom.xml | 4 +- .../picture/support/flush/StylesHandler.java | 63 ++++++++++--------- .../excel/picture/support/model/Workbook.java | 18 +++++- .../example/ExportExample_20220110.java | 4 +- 5 files changed, 92 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index 7a949e2..fb31e3e 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,45 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, 2. ### 示例 + - 最新使用示例代码 + + ```java + @GetMapping("/export/lastversion/{row}") + public void exportLastVersion(HttpServletResponse response, @PathVariable int row) throws IOException { + /* + 操作窗口 + 当写入excel数据行数大于flushSize时{@link Sheet.SheetHandler#createRow(int)}, + 会刷新数据到流,调用该方法 + {@link com.ibiz.excel.picture.support.flush.DrawingXmlRelsHandler#copyPictureAppendDrawingRelsXML(Sheet, Picture)} + 将图片刷新在磁盘中 + 不会占用内存空间 + flushSize = -1 时不刷新流 + */ + Workbook workBook = Workbook.getInstance(1); + Sheet sheet = workBook.createSheet("测试"); + // 给标题行加上背景色,加颜色时,会对字体加粗 + sheet.addCellStyle(new CellStyle(0, "66cc66")); + UserPicture userPicture; + for (int r = 0; r < row; r++) { + userPicture = new UserPicture(); + userPicture.setAge(15); + userPicture.setName("测试-" + r); + // 导出本地单张图片 + userPicture.setPicture("E:\\test\\img\\1.jpg"); + // 导出url单张图片 + userPicture.setHeaderPicture("https://portrait.gitee.com/uploads/avatars/user/552/1657608_mwk719_1641537497.png"); + // 导出本地图片集合 + userPicture.setPictures(Arrays.asList("E:\\test\\img\\1.jpg","E:\\test\\img\\2.jpg")); + // 导出url图片集合 + userPicture.setUrlPictures(Arrays.asList("https://portrait.gitee.com/uploads/avatars/user/552/1657608_mwk719_1641537497.png", + "https://img2.baidu.com/it/u=2602880481,728201544&fm=26&fmt=auto")); + sheet.createRow(userPicture); + } + WebUtil.writeExcel(workBook, "最新使用示例代码导出".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), response); + } + ``` + + - [excel含图片导出demo地址](https://gitee.com/mwk719/excel-batch-picture-support/tree/dev/src/test/java/com/ibiz/excel/picture/support/example),具体使用以后缀最新日期为准,其他示例仅供测试 - [微云-6767张图片共800mb资源.rar 可用于测试](https://minwk.top/big-size-img/) - [项目中导出下载excel使用示例](https://gitee.com/mwk719/spring-learn/blob/master/src/main/java/com/mwk/external/controller/ExcelController.java) diff --git a/pom.xml b/pom.xml index e3c449a..967fa10 100644 --- a/pom.xml +++ b/pom.xml @@ -2,9 +2,7 @@ 4.0.0 - - pom - + jar top.minwk excel-x 2.1.0 diff --git a/src/main/java/com/ibiz/excel/picture/support/flush/StylesHandler.java b/src/main/java/com/ibiz/excel/picture/support/flush/StylesHandler.java index 925e5e9..9d50573 100644 --- a/src/main/java/com/ibiz/excel/picture/support/flush/StylesHandler.java +++ b/src/main/java/com/ibiz/excel/picture/support/flush/StylesHandler.java @@ -21,31 +21,31 @@ public class StylesHandler implements InvocationHandler { this.target = proxy; } - private StringBuilder xfBefore = new StringBuilder("" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + // 填充色值坐标 - ""); + private final StringBuilder xfBefore = new StringBuilder("".concat( + "").concat( + "").concat( + "").concat( + "").concat( + "").concat( + "").concat( + "").concat( + "").concat( + "").concat( + "").concat( + "").concat( + "").concat( + "").concat( + "").concat( + "").concat( + "").concat( + "").concat( + "").concat( // 填充色值坐标 + "")); - private StringBuilder xfAfter = new StringBuilder("" + - "" + - "" + - ""); + private final StringBuilder xfAfter = new StringBuilder("".concat( + "").concat( + "").concat( + "")); @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { @@ -55,10 +55,6 @@ public class StylesHandler implements InvocationHandler { Sheet sheet = (Sheet) args[0]; List rows = sheet.getRows(); if (!rows.isEmpty()) { - // 判断是否最后 - if (sheet.getRowCount() % sheet.getFlushSize() - rows.size() % sheet.getFlushSize() == 1) { - last = false; - } rows.stream().forEach(row -> { CellStyle cellStyle = row.getCellStyle(); if (row.getCellStyle() != null) { @@ -69,8 +65,15 @@ public class StylesHandler implements InvocationHandler { } }); } + + int x = sheet.getRowCount() % sheet.getFlushSize(); + int y = rows.size() % sheet.getFlushSize(); + // 判断是否最后 + last = x - y != 1; + // 只写入一条数据需要特殊判断 + boolean one = y == 0 && sheet.hasFlush(); // 不是最后一块数据或者没有行数据,则不写入样式 - if (!last || rows.isEmpty()) { + if (!last || rows.isEmpty() || one) { return ""; } // 在Styles对象中追加样式 @@ -96,7 +99,7 @@ public class StylesHandler implements InvocationHandler { * @param cellStyle */ private void appendFill(CellStyle cellStyle) { - target.append(""); + target.append("")); } } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Workbook.java b/src/main/java/com/ibiz/excel/picture/support/model/Workbook.java index 72dd4b7..7329a16 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Workbook.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Workbook.java @@ -17,7 +17,12 @@ import java.util.*; public class Workbook { private Logger logger = LoggerFactory.getLogger(this.getClass()); /** - * 到达row行数就刷新流 + * 操作窗口 + * 当写入excel数据行数大于flushSize时{@link Sheet.SheetHandler#createRow(int)}, + * 会刷新数据到流,调用该方法 + * {@link com.ibiz.excel.picture.support.flush.DrawingXmlRelsHandler#copyPictureAppendDrawingRelsXML(Sheet, Picture)} + * 将图片刷新在磁盘中 + * 不会占用内存空间 * flushSize = -1 时不刷新流 */ private int flushSize; @@ -76,6 +81,17 @@ public class Workbook { return getInstance(100); } + /** + * 操作窗口 + * 当写入excel数据行数大于flushSize时{@link Sheet.SheetHandler#createRow(int)}, + * 会刷新数据到流,调用该方法 + * {@link com.ibiz.excel.picture.support.flush.DrawingXmlRelsHandler#copyPictureAppendDrawingRelsXML(Sheet, Picture)} + * 将图片刷新在磁盘中 + * 不会占用内存空间 + * flushSize = -1 时不刷新流 + * @param flushSize + * @return + */ public static Workbook getInstance(int flushSize) { return new Workbook(flushSize); } diff --git a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220110.java b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220110.java index cb2143f..812c24e 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220110.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220110.java @@ -20,12 +20,12 @@ public class ExportExample_20220110 extends BaseJunitTest { @Test public void export() { - Workbook workBook = Workbook.getInstance(); + Workbook workBook = Workbook.getInstance(3); Sheet sheet = workBook.createSheet("测试"); // 给标题行加上背景色,加颜色时,会对字体加粗 sheet.addCellStyle(new CellStyle(0, "66cc66")); UserPicture userPicture; - for (int r = 0; r < 101; r++) { + for (int r = 0; r < 16; r++) { userPicture = new UserPicture(); userPicture.setAge(15); userPicture.setName("测试-" + r); -- Gitee From ea6ce94748e0da7052d881634de72843ec4a555c Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Wed, 12 Jan 2022 09:35:45 +0800 Subject: [PATCH 083/161] =?UTF-8?q?fix=20=E5=9C=A8close=E6=97=B6=E5=86=99?= =?UTF-8?q?=E5=85=A5styles?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 172 ++++++++++++++---- .../picture/support/flush/StylesHandler.java | 16 +- .../example/ExportExample_20220110.java | 6 +- 3 files changed, 144 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index fb31e3e..6d93734 100644 --- a/README.md +++ b/README.md @@ -43,49 +43,155 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, 2. ### 示例 - - 最新使用示例代码 + - 最新使用示例代码 ```java @GetMapping("/export/lastversion/{row}") - public void exportLastVersion(HttpServletResponse response, @PathVariable int row) throws IOException { - /* - 操作窗口 - 当写入excel数据行数大于flushSize时{@link Sheet.SheetHandler#createRow(int)}, - 会刷新数据到流,调用该方法 - {@link com.ibiz.excel.picture.support.flush.DrawingXmlRelsHandler#copyPictureAppendDrawingRelsXML(Sheet, Picture)} - 将图片刷新在磁盘中 - 不会占用内存空间 - flushSize = -1 时不刷新流 - */ - Workbook workBook = Workbook.getInstance(1); - Sheet sheet = workBook.createSheet("测试"); - // 给标题行加上背景色,加颜色时,会对字体加粗 - sheet.addCellStyle(new CellStyle(0, "66cc66")); - UserPicture userPicture; - for (int r = 0; r < row; r++) { - userPicture = new UserPicture(); - userPicture.setAge(15); - userPicture.setName("测试-" + r); - // 导出本地单张图片 - userPicture.setPicture("E:\\test\\img\\1.jpg"); - // 导出url单张图片 - userPicture.setHeaderPicture("https://portrait.gitee.com/uploads/avatars/user/552/1657608_mwk719_1641537497.png"); - // 导出本地图片集合 - userPicture.setPictures(Arrays.asList("E:\\test\\img\\1.jpg","E:\\test\\img\\2.jpg")); - // 导出url图片集合 - userPicture.setUrlPictures(Arrays.asList("https://portrait.gitee.com/uploads/avatars/user/552/1657608_mwk719_1641537497.png", - "https://img2.baidu.com/it/u=2602880481,728201544&fm=26&fmt=auto")); - sheet.createRow(userPicture); - } - WebUtil.writeExcel(workBook, "最新使用示例代码导出".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), response); - } + public void exportLastVersion(HttpServletResponse response, @PathVariable int row) throws IOException { + /* + 操作窗口 + 当写入excel数据行数大于flushSize时{@link Sheet.SheetHandler#createRow(int)}, + 会刷新数据到流,调用该方法 + {@link com.ibiz.excel.picture.support.flush.DrawingXmlRelsHandler#copyPictureAppendDrawingRelsXML(Sheet, Picture)} + 将图片刷新在磁盘中 + 不会占用内存空间 + flushSize = -1 时不刷新流 + */ + Workbook workBook = Workbook.getInstance(1); + Sheet sheet = workBook.createSheet("测试"); + // 给标题行加上背景色,加颜色时,会对字体加粗 + sheet.addCellStyle(new CellStyle(0, "66cc66")); + UserPicture userPicture; + for (int r = 0; r < row; r++) { + userPicture = new UserPicture(); + userPicture.setAge(15); + userPicture.setName("测试-" + r); + // 导出本地单张图片 + userPicture.setPicture("E:\\test\\img\\1.jpg"); + // 导出url单张图片 + userPicture.setHeaderPicture("https://portrait.gitee.com/uploads/avatars/user/552/1657608_mwk719_1641537497.png"); + // 导出本地图片集合 + userPicture.setPictures(Arrays.asList("E:\\test\\img\\1.jpg","E:\\test\\img\\2.jpg")); + // 导出url图片集合 + userPicture.setUrlPictures(Arrays.asList("https://portrait.gitee.com/uploads/avatars/user/552/1657608_mwk719_1641537497.png", + "https://img2.baidu.com/it/u=2602880481,728201544&fm=26&fmt=auto")); + sheet.createRow(userPicture); + } + WebUtil.writeExcel(workBook, "最新使用示例代码导出".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), response); + } ``` + ```java + /** + * @auther 喻场 + * @date 2020/7/813:41 + */ + public class UserPicture { + + public UserPicture() { + } + + @ExportModel( sort = 0, title = "姓名") + private String name; + @ExportModel(sort = 1, title = "年龄") + private Integer age; + @ExportModel(sort = 3, title = "部门") + private String department; + @ExportModel(sort = 2, isPicture = true, title = "图片1") + private String picture; + @ExportModel(sort = 4, isPicture = true, title = "图片2") + private String headerPicture; + @ExportModel(sort = 5, isPicture = true, title = "多图片") + private List pictures; + @ExportModel(sort = 6, isPicture = true, title = "url多图片") + private List urlPictures; + + public UserPicture(String name, Integer age, String department, String picture) { + this.name = name; + this.age = age; + this.department = department; + this.picture = picture; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getAge() { + return age; + } + + public void setAge(Integer age) { + this.age = age; + } + + public String getDepartment() { + return department; + } + + public void setDepartment(String department) { + this.department = department; + } + + public String getPicture() { + return picture; + } + + public void setPicture(String picture) { + this.picture = picture; + } + + public String getHeaderPicture() { + return headerPicture; + } + + public void setHeaderPicture(String headerPicture) { + this.headerPicture = headerPicture; + } + + public List getPictures() { + return pictures; + } + + public void setPictures(List pictures) { + this.pictures = pictures; + } + + public List getUrlPictures() { + return urlPictures; + } + + public void setUrlPictures(List urlPictures) { + this.urlPictures = urlPictures; + } + } + + ``` - [excel含图片导出demo地址](https://gitee.com/mwk719/excel-batch-picture-support/tree/dev/src/test/java/com/ibiz/excel/picture/support/example),具体使用以后缀最新日期为准,其他示例仅供测试 + - [微云-6767张图片共800mb资源.rar 可用于测试](https://minwk.top/big-size-img/) + - [项目中导出下载excel使用示例](https://gitee.com/mwk719/spring-learn/blob/master/src/main/java/com/mwk/external/controller/ExcelController.java) + #### 项目中测试使用 + + 1. 设置项目jvm堆栈大小都是20m + + ```bash + -Xms20m -Xmx20m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:\log\springlearn.hprof + ``` + + 2. 复制上方 【最新使用示例代码】到项目中 + + 3. 找一堆图片随机添加到UserPicture中 + + 4. 导出一个5000条的记录,在最大堆栈占用为20m的情况下,导出excel大小为700m,未发生内存溢出情况 + 3. ### 版本更迭 #### 2.1.0(2022.01.14) diff --git a/src/main/java/com/ibiz/excel/picture/support/flush/StylesHandler.java b/src/main/java/com/ibiz/excel/picture/support/flush/StylesHandler.java index 9d50573..713ea91 100644 --- a/src/main/java/com/ibiz/excel/picture/support/flush/StylesHandler.java +++ b/src/main/java/com/ibiz/excel/picture/support/flush/StylesHandler.java @@ -49,8 +49,6 @@ public class StylesHandler implements InvocationHandler { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - // 因会写入磁盘,刷新sheet.getRows(),所以需要计算是否最后一块数据 - boolean last = true; if (method.getName().equals("write")) { Sheet sheet = (Sheet) args[0]; List rows = sheet.getRows(); @@ -65,18 +63,8 @@ public class StylesHandler implements InvocationHandler { } }); } - - int x = sheet.getRowCount() % sheet.getFlushSize(); - int y = rows.size() % sheet.getFlushSize(); - // 判断是否最后 - last = x - y != 1; - // 只写入一条数据需要特殊判断 - boolean one = y == 0 && sheet.hasFlush(); - // 不是最后一块数据或者没有行数据,则不写入样式 - if (!last || rows.isEmpty() || one) { - return ""; - } - // 在Styles对象中追加样式 + }else if (method.getName().equals("close")) { + // 关闭时将所有的样式追加在Styles对象中 target.append(xfBefore.append(xfAfter).toString()); } return method.invoke(target, args); diff --git a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220110.java b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220110.java index 812c24e..afb37a9 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220110.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220110.java @@ -20,12 +20,12 @@ public class ExportExample_20220110 extends BaseJunitTest { @Test public void export() { - Workbook workBook = Workbook.getInstance(3); + Workbook workBook = Workbook.getInstance(); Sheet sheet = workBook.createSheet("测试"); // 给标题行加上背景色,加颜色时,会对字体加粗 sheet.addCellStyle(new CellStyle(0, "66cc66")); UserPicture userPicture; - for (int r = 0; r < 16; r++) { + for (int r = 0; r < 101; r++) { userPicture = new UserPicture(); userPicture.setAge(15); userPicture.setName("测试-" + r); @@ -39,7 +39,7 @@ public class ExportExample_20220110 extends BaseJunitTest { userPicture.setUrlPictures(getUrls(5)); sheet.createRow(userPicture); } - WebUtil.writeExcelTest(workBook, "ExportExample_20220110_导出excel示例".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), TEMP_PATH); + WebUtil.writeExcelTest(workBook, "ExportExample_20220110_".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), TEMP_PATH); } } -- Gitee From 42ce7839374251479aedf7ed6fe5b9262bf04042 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Wed, 12 Jan 2022 14:21:37 +0800 Subject: [PATCH 084/161] =?UTF-8?q?add=20createRow=E9=9B=86=E5=90=88?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E7=94=9F=E6=88=90excel=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 5 ++- .../excel/picture/support/model/Sheet.java | 45 ++++++++++++++++++- .../excel/picture/support/UserPicture.java | 10 +++++ .../example/ExportExample_20220110.java | 28 ++++++++++++ 4 files changed, 86 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6d93734..88740ff 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,7 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, Sheet sheet = workBook.createSheet("测试"); // 给标题行加上背景色,加颜色时,会对字体加粗 sheet.addCellStyle(new CellStyle(0, "66cc66")); + List list = new ArrayList<>(); UserPicture userPicture; for (int r = 0; r < row; r++) { userPicture = new UserPicture(); @@ -75,8 +76,9 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, // 导出url图片集合 userPicture.setUrlPictures(Arrays.asList("https://portrait.gitee.com/uploads/avatars/user/552/1657608_mwk719_1641537497.png", "https://img2.baidu.com/it/u=2602880481,728201544&fm=26&fmt=auto")); - sheet.createRow(userPicture); + list.add(userPicture); } + sheet.write(UserPicture.class).createRow(list); WebUtil.writeExcel(workBook, "最新使用示例代码导出".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), response); } ``` @@ -197,6 +199,7 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, #### 2.1.0(2022.01.14) - 添加导出网络链接图片到excel中 + - 添加createRow集合列表生成excel方法 - 修改CellStyle样式的使用 #### 2.0.0(2021.12.30) diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java index 7bdaa75..43cea92 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java @@ -14,6 +14,7 @@ import com.ibiz.excel.picture.support.listener.FlushListener; import com.ibiz.excel.picture.support.listener.InitListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.util.CollectionUtils; import java.util.*; @@ -102,7 +103,7 @@ public class Sheet { /** * 创建行,单元格会根据t的属性自动填充 * - * @param t 列属性 只会读取com.ibiz.excelx.annotation.Model 注解的属性 + * @param t 列属性 只会读取{@link ExportModel} 注解的属性 * @param * @return Row */ @@ -110,10 +111,37 @@ public class Sheet { return SHEET_HANDLER.createRow(t); } + /** + * 创建集合行数据,单元格会根据t的属性自动填充 + * 需要调用{@link Sheet#write(Class)}写入excel信息 + * 否则 collections为空时,excel中没u有标题 + * 写法如: sheet.write(UserPicture.class).createRow(list); + * @param collections 集合列属性 只会读取{@link ExportModel} 注解的属性 + * @return + */ + public Sheet createRow(Collection collections) { + if(!CollectionUtils.isEmpty(collections)){ + collections.forEach(this::createRow); + } + return this; + } + public Row createRow(int rowNumber) { return SHEET_HANDLER.createRow(rowNumber); } + /** + * 构建并写入excel信息 + * + * @param + * @param head 标题 + * @return + */ + public Sheet write(Class head) { + SHEET_HANDLER.write(head); + return this; + } + /** * 刷新数据到流 */ @@ -395,6 +423,21 @@ public class Sheet { rows.addAll(list); pictures.clear(); } + + /** + * 构建并写入excel信息 + * + * @param head 标题类 + * @param + */ + public void write(Class head) { + try { + createRowAndCellStyle(head.newInstance() , true); + } catch (InstantiationException | IllegalAccessException e) { + throw new RuntimeException("写入标题异常", e); + } + } + } /** diff --git a/src/test/java/com/ibiz/excel/picture/support/UserPicture.java b/src/test/java/com/ibiz/excel/picture/support/UserPicture.java index 9ce134e..4febea8 100644 --- a/src/test/java/com/ibiz/excel/picture/support/UserPicture.java +++ b/src/test/java/com/ibiz/excel/picture/support/UserPicture.java @@ -29,6 +29,8 @@ public class UserPicture { @ExportModel(sort = 6, isPicture = true, title = "url多图片") private List urlPictures; + private String address; + public UserPicture(String name, Integer age, String department, String picture) { this.name = name; this.age = age; @@ -91,4 +93,12 @@ public class UserPicture { public void setUrlPictures(List urlPictures) { this.urlPictures = urlPictures; } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } } diff --git a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220110.java b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220110.java index afb37a9..8b69da3 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220110.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220110.java @@ -8,6 +8,8 @@ import com.ibiz.excel.picture.support.model.Workbook; import com.ibiz.excel.picture.support.util.WebUtil; import org.junit.Test; +import java.util.ArrayList; +import java.util.List; import java.util.Random; /** @@ -42,4 +44,30 @@ public class ExportExample_20220110 extends BaseJunitTest { WebUtil.writeExcelTest(workBook, "ExportExample_20220110_".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), TEMP_PATH); } + @Test + public void export1() { + Workbook workBook = Workbook.getInstance(); + Sheet sheet = workBook.createSheet("测试"); + // 给标题行加上背景色,加颜色时,会对字体加粗 + sheet.addCellStyle(new CellStyle(0, "66cc66")); + List list = new ArrayList<>(); + UserPicture userPicture; + for (int r = 0; r < 101; r++) { + userPicture = new UserPicture(); + userPicture.setAge(15); + userPicture.setName("测试-" + r); + // 导出本地单张图片 + userPicture.setPicture(IMG_PATH_1); + // 导出url单张图片 + userPicture.setHeaderPicture(getUrl()); + // 导出本地图片集合 + userPicture.setPictures(getPictures(new Random().nextInt(5))); + // 导出url图片集合 + userPicture.setUrlPictures(getUrls(5)); + list.add(userPicture); + } + sheet.write(UserPicture.class).createRow(list); + WebUtil.writeExcelTest(workBook, "ExportExample_20220110_".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), TEMP_PATH); + } + } -- Gitee From 1f895bd637698e32d912bcce483679c67aebd4e2 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Fri, 14 Jan 2022 09:26:54 +0800 Subject: [PATCH 085/161] =?UTF-8?q?add=20=E5=8F=91=E5=B8=83=E8=B7=B3?= =?UTF-8?q?=E8=BF=87=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .mvn/wrapper/MavenWrapperDownloader.java | 118 ------------------ .mvn/wrapper/maven-wrapper.jar | Bin 50710 -> 0 bytes .mvn/wrapper/maven-wrapper.properties | 2 - pom.xml | 18 +-- .../excel/picture/support/util/WebUtil.java | 3 +- .../AnnotationPicturesExportExample.java | 2 + .../example/ExportExample_20220110.java | 2 + .../SimulateRealBusinessExportExample.java | 12 +- 8 files changed, 17 insertions(+), 140 deletions(-) delete mode 100644 .mvn/wrapper/MavenWrapperDownloader.java delete mode 100644 .mvn/wrapper/maven-wrapper.jar delete mode 100644 .mvn/wrapper/maven-wrapper.properties diff --git a/.mvn/wrapper/MavenWrapperDownloader.java b/.mvn/wrapper/MavenWrapperDownloader.java deleted file mode 100644 index a45eb6b..0000000 --- a/.mvn/wrapper/MavenWrapperDownloader.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 2007-present the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import java.net.*; -import java.io.*; -import java.nio.channels.*; -import java.util.Properties; - -public class MavenWrapperDownloader { - - private static final String WRAPPER_VERSION = "0.5.6"; - /** - * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. - */ - private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" - + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; - - /** - * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to - * use instead of the default one. - */ - private static final String MAVEN_WRAPPER_PROPERTIES_PATH = - ".mvn/wrapper/maven-wrapper.properties"; - - /** - * Path where the maven-wrapper.jar will be saved to. - */ - private static final String MAVEN_WRAPPER_JAR_PATH = - ".mvn/wrapper/maven-wrapper.jar"; - - /** - * Name of the property which should be used to override the default download url for the wrapper. - */ - private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; - - public static void main(String args[]) { - System.out.println("- Downloader started"); - File baseDirectory = new File(args[0]); - System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); - - // If the maven-wrapper.properties exists, read it and check if it contains a custom - // wrapperUrl parameter. - File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); - String url = DEFAULT_DOWNLOAD_URL; - if (mavenWrapperPropertyFile.exists()) { - FileInputStream mavenWrapperPropertyFileInputStream = null; - try { - mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); - Properties mavenWrapperProperties = new Properties(); - mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); - url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); - } catch (IOException e) { - System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); - } finally { - try { - if (mavenWrapperPropertyFileInputStream != null) { - mavenWrapperPropertyFileInputStream.close(); - } - } catch (IOException e) { - // Ignore ... - } - } - } - System.out.println("- Downloading from: " + url); - - File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); - if (!outputFile.getParentFile().exists()) { - if (!outputFile.getParentFile().mkdirs()) { - System.out.println( - "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); - } - } - System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); - try { - downloadFileFromURL(url, outputFile); - System.out.println("Done"); - System.exit(0); - } catch (Throwable e) { - System.out.println("- Error downloading"); - e.printStackTrace(); - System.exit(1); - } - } - - private static void downloadFileFromURL(String urlString, File destination) throws Exception { - if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { - String username = System.getenv("MVNW_USERNAME"); - char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); - Authenticator.setDefault(new Authenticator() { - @Override - protected PasswordAuthentication getPasswordAuthentication() { - return new PasswordAuthentication(username, password); - } - }); - } - URL website = new URL(urlString); - ReadableByteChannel rbc; - rbc = Channels.newChannel(website.openStream()); - FileOutputStream fos = new FileOutputStream(destination); - fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); - fos.close(); - rbc.close(); - } - -} diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar deleted file mode 100644 index 2cc7d4a55c0cd0092912bf49ae38b3a9e3fd0054..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 50710 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 EfAhh=DF6Tf diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties deleted file mode 100644 index 642d572..0000000 --- a/.mvn/wrapper/maven-wrapper.properties +++ /dev/null @@ -1,2 +0,0 @@ -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip -wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar diff --git a/pom.xml b/pom.xml index 967fa10..a12a6aa 100644 --- a/pom.xml +++ b/pom.xml @@ -2,23 +2,18 @@ 4.0.0 - jar top.minwk excel-x 2.1.0 excel-x - excel-x + 支持excel中批量导出图片 https://gitee.com/mwk719/excel-batch-picture-support - - org.sonatype.oss - oss-parent - 9 - utf-8 utf-8 - + + true 8 1.8 @@ -126,6 +121,11 @@ + + + none + + @@ -171,7 +171,7 @@ html xml - + diff --git a/src/main/java/com/ibiz/excel/picture/support/util/WebUtil.java b/src/main/java/com/ibiz/excel/picture/support/util/WebUtil.java index 87f36bb..aefa9bb 100644 --- a/src/main/java/com/ibiz/excel/picture/support/util/WebUtil.java +++ b/src/main/java/com/ibiz/excel/picture/support/util/WebUtil.java @@ -36,11 +36,12 @@ public class WebUtil { File file = FileUtil.touch(tempPath.concat(fileName)); try (BufferedOutputStream os = FileUtil.getOutputStream(file)) { wb.write(os); - wb.close(); } catch (Exception e) { // 报错时删除文件 FileUtil.del(file); log.error("测试导出excel异常", e); + }finally { + wb.close(); } log.debug("测试导出excel路径:{}", file.getAbsolutePath()); } diff --git a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java index 68aadd2..75c9cae 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java @@ -6,6 +6,7 @@ import com.ibiz.excel.picture.support.model.CellStyle; import com.ibiz.excel.picture.support.model.Sheet; import com.ibiz.excel.picture.support.model.Workbook; import com.ibiz.excel.picture.support.util.WebUtil; +import org.junit.Ignore; import org.junit.Test; import java.util.Random; @@ -16,6 +17,7 @@ import java.util.Random; * @author MinWeikai * @date 2021/12/14 10:36 */ +@Ignore public class AnnotationPicturesExportExample extends BaseJunitTest { @Test diff --git a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220110.java b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220110.java index 8b69da3..88d6d36 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220110.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220110.java @@ -6,6 +6,7 @@ import com.ibiz.excel.picture.support.model.CellStyle; import com.ibiz.excel.picture.support.model.Sheet; import com.ibiz.excel.picture.support.model.Workbook; import com.ibiz.excel.picture.support.util.WebUtil; +import org.junit.Ignore; import org.junit.Test; import java.util.ArrayList; @@ -18,6 +19,7 @@ import java.util.Random; * @author MinWeikai * @date 2022-01-10 10:08:03 */ +@Ignore public class ExportExample_20220110 extends BaseJunitTest { @Test diff --git a/src/test/java/com/ibiz/excel/picture/support/simulation/SimulateRealBusinessExportExample.java b/src/test/java/com/ibiz/excel/picture/support/simulation/SimulateRealBusinessExportExample.java index 2030772..a610f09 100644 --- a/src/test/java/com/ibiz/excel/picture/support/simulation/SimulateRealBusinessExportExample.java +++ b/src/test/java/com/ibiz/excel/picture/support/simulation/SimulateRealBusinessExportExample.java @@ -6,6 +6,7 @@ import com.ibiz.excel.picture.support.model.CellStyle; import com.ibiz.excel.picture.support.model.Sheet; import com.ibiz.excel.picture.support.model.Workbook; import com.ibiz.excel.picture.support.util.WebUtil; +import org.junit.Ignore; import org.junit.Test; import java.util.Random; @@ -16,18 +17,9 @@ import java.util.Random; * @author MinWeikai * @date 2021-12-22 15:36:46 */ +@Ignore public class SimulateRealBusinessExportExample extends BaseJunitTest { - static final String CURRENT_PATH = "E:\\test\\"; - private static final String TEMP_PATH = CURRENT_PATH + "excel\\"; - private final static String IMG_PATH = "E:\\test\\img\\"; - - private final static String IMG_PATH_1 = IMG_PATH + "1.jpg"; - private final static String IMG_PATH_2 = IMG_PATH + "2.jpg"; - private final static String IMG_PATH_3 = IMG_PATH + "3.jpg"; - - private final static String IMAGES_PATH = CURRENT_PATH + "images\\"; - @Test public void export() { Workbook workBook = Workbook.getInstance(50); -- Gitee From 8e0fa7a6f6d9aa93c438090ba3e2302cff0a7b70 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Fri, 14 Jan 2022 09:35:40 +0800 Subject: [PATCH 086/161] release 2.1.0 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 88740ff..9c9e499 100644 --- a/README.md +++ b/README.md @@ -198,7 +198,7 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, #### 2.1.0(2022.01.14) - - 添加导出网络链接图片到excel中 + - [添加导出网络链接图片到excel中](https://gitee.com/mwk719/spring-learn/blob/master/src/main/java/com/mwk/external/controller/ExcelController.java) - 添加createRow集合列表生成excel方法 - 修改CellStyle样式的使用 -- Gitee From 60464c5c9f8e237d6fdd032419fcd4e6db7c6308 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Fri, 14 Jan 2022 09:35:40 +0800 Subject: [PATCH 087/161] release 2.1.0 (cherry picked from commit 8e0fa7a6f6d9aa93c438090ba3e2302cff0a7b70) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 88740ff..9c9e499 100644 --- a/README.md +++ b/README.md @@ -198,7 +198,7 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, #### 2.1.0(2022.01.14) - - 添加导出网络链接图片到excel中 + - [添加导出网络链接图片到excel中](https://gitee.com/mwk719/spring-learn/blob/master/src/main/java/com/mwk/external/controller/ExcelController.java) - 添加createRow集合列表生成excel方法 - 修改CellStyle样式的使用 -- Gitee From 3f6639535b1dd0e47deaa72cbe0bffbebf8f2126 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Fri, 14 Jan 2022 10:07:28 +0800 Subject: [PATCH 088/161] =?UTF-8?q?add=20.mvn=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .mvn/wrapper/MavenWrapperDownloader.java | 118 +++++++++++++++++++++++ .mvn/wrapper/maven-wrapper.properties | 2 + 2 files changed, 120 insertions(+) create mode 100644 .mvn/wrapper/MavenWrapperDownloader.java create mode 100644 .mvn/wrapper/maven-wrapper.properties diff --git a/.mvn/wrapper/MavenWrapperDownloader.java b/.mvn/wrapper/MavenWrapperDownloader.java new file mode 100644 index 0000000..a45eb6b --- /dev/null +++ b/.mvn/wrapper/MavenWrapperDownloader.java @@ -0,0 +1,118 @@ +/* + * Copyright 2007-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.net.*; +import java.io.*; +import java.nio.channels.*; +import java.util.Properties; + +public class MavenWrapperDownloader { + + private static final String WRAPPER_VERSION = "0.5.6"; + /** + * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. + */ + private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" + + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; + + /** + * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to + * use instead of the default one. + */ + private static final String MAVEN_WRAPPER_PROPERTIES_PATH = + ".mvn/wrapper/maven-wrapper.properties"; + + /** + * Path where the maven-wrapper.jar will be saved to. + */ + private static final String MAVEN_WRAPPER_JAR_PATH = + ".mvn/wrapper/maven-wrapper.jar"; + + /** + * Name of the property which should be used to override the default download url for the wrapper. + */ + private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; + + public static void main(String args[]) { + System.out.println("- Downloader started"); + File baseDirectory = new File(args[0]); + System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); + + // If the maven-wrapper.properties exists, read it and check if it contains a custom + // wrapperUrl parameter. + File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); + String url = DEFAULT_DOWNLOAD_URL; + if (mavenWrapperPropertyFile.exists()) { + FileInputStream mavenWrapperPropertyFileInputStream = null; + try { + mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); + Properties mavenWrapperProperties = new Properties(); + mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); + url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); + } catch (IOException e) { + System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); + } finally { + try { + if (mavenWrapperPropertyFileInputStream != null) { + mavenWrapperPropertyFileInputStream.close(); + } + } catch (IOException e) { + // Ignore ... + } + } + } + System.out.println("- Downloading from: " + url); + + File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); + if (!outputFile.getParentFile().exists()) { + if (!outputFile.getParentFile().mkdirs()) { + System.out.println( + "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); + } + } + System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); + try { + downloadFileFromURL(url, outputFile); + System.out.println("Done"); + System.exit(0); + } catch (Throwable e) { + System.out.println("- Error downloading"); + e.printStackTrace(); + System.exit(1); + } + } + + private static void downloadFileFromURL(String urlString, File destination) throws Exception { + if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { + String username = System.getenv("MVNW_USERNAME"); + char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); + Authenticator.setDefault(new Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(username, password); + } + }); + } + URL website = new URL(urlString); + ReadableByteChannel rbc; + rbc = Channels.newChannel(website.openStream()); + FileOutputStream fos = new FileOutputStream(destination); + fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); + fos.close(); + rbc.close(); + } + +} diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000..642d572 --- /dev/null +++ b/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,2 @@ +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar -- Gitee From 0488dee368fe8e2afa31de7902f5bb2556e99524 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Fri, 14 Jan 2022 10:07:28 +0800 Subject: [PATCH 089/161] =?UTF-8?q?add=20.mvn=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .mvn/wrapper/MavenWrapperDownloader.java | 118 +++++++++++++++++++++++ .mvn/wrapper/maven-wrapper.properties | 2 + 2 files changed, 120 insertions(+) create mode 100644 .mvn/wrapper/MavenWrapperDownloader.java create mode 100644 .mvn/wrapper/maven-wrapper.properties diff --git a/.mvn/wrapper/MavenWrapperDownloader.java b/.mvn/wrapper/MavenWrapperDownloader.java new file mode 100644 index 0000000..a45eb6b --- /dev/null +++ b/.mvn/wrapper/MavenWrapperDownloader.java @@ -0,0 +1,118 @@ +/* + * Copyright 2007-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.net.*; +import java.io.*; +import java.nio.channels.*; +import java.util.Properties; + +public class MavenWrapperDownloader { + + private static final String WRAPPER_VERSION = "0.5.6"; + /** + * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. + */ + private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" + + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; + + /** + * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to + * use instead of the default one. + */ + private static final String MAVEN_WRAPPER_PROPERTIES_PATH = + ".mvn/wrapper/maven-wrapper.properties"; + + /** + * Path where the maven-wrapper.jar will be saved to. + */ + private static final String MAVEN_WRAPPER_JAR_PATH = + ".mvn/wrapper/maven-wrapper.jar"; + + /** + * Name of the property which should be used to override the default download url for the wrapper. + */ + private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; + + public static void main(String args[]) { + System.out.println("- Downloader started"); + File baseDirectory = new File(args[0]); + System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); + + // If the maven-wrapper.properties exists, read it and check if it contains a custom + // wrapperUrl parameter. + File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); + String url = DEFAULT_DOWNLOAD_URL; + if (mavenWrapperPropertyFile.exists()) { + FileInputStream mavenWrapperPropertyFileInputStream = null; + try { + mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); + Properties mavenWrapperProperties = new Properties(); + mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); + url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); + } catch (IOException e) { + System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); + } finally { + try { + if (mavenWrapperPropertyFileInputStream != null) { + mavenWrapperPropertyFileInputStream.close(); + } + } catch (IOException e) { + // Ignore ... + } + } + } + System.out.println("- Downloading from: " + url); + + File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); + if (!outputFile.getParentFile().exists()) { + if (!outputFile.getParentFile().mkdirs()) { + System.out.println( + "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); + } + } + System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); + try { + downloadFileFromURL(url, outputFile); + System.out.println("Done"); + System.exit(0); + } catch (Throwable e) { + System.out.println("- Error downloading"); + e.printStackTrace(); + System.exit(1); + } + } + + private static void downloadFileFromURL(String urlString, File destination) throws Exception { + if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { + String username = System.getenv("MVNW_USERNAME"); + char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); + Authenticator.setDefault(new Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(username, password); + } + }); + } + URL website = new URL(urlString); + ReadableByteChannel rbc; + rbc = Channels.newChannel(website.openStream()); + FileOutputStream fos = new FileOutputStream(destination); + fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); + fos.close(); + rbc.close(); + } + +} diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000..642d572 --- /dev/null +++ b/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,2 @@ +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar -- Gitee From 8b3bfd800c064d0189cef0af9aaad40e64c0e914 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Mon, 17 Jan 2022 14:40:40 +0800 Subject: [PATCH 090/161] =?UTF-8?q?add=20demo=E6=96=B9=E6=B3=95=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E5=AE=9A=E4=BD=8D=E5=88=B0=E8=A1=8C=E5=8F=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9c9e499..9a3863e 100644 --- a/README.md +++ b/README.md @@ -198,8 +198,8 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, #### 2.1.0(2022.01.14) - - [添加导出网络链接图片到excel中](https://gitee.com/mwk719/spring-learn/blob/master/src/main/java/com/mwk/external/controller/ExcelController.java) - - 添加createRow集合列表生成excel方法 + - [添加导出网络链接图片到excel中](https://gitee.com/mwk719/spring-learn/blob/master/src/main/java/com/mwk/external/controller/ExcelController.java#L146) + - [添加createRow集合列表生成excel方法](https://gitee.com/mwk719/spring-learn/blob/master/src/main/java/com/mwk/external/controller/ExcelController.java#L191) - 修改CellStyle样式的使用 #### 2.0.0(2021.12.30) -- Gitee From 1cabf7f30014fb111730c6069333980098980d2e Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Mon, 17 Jan 2022 14:40:40 +0800 Subject: [PATCH 091/161] =?UTF-8?q?add=20demo=E6=96=B9=E6=B3=95=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E5=AE=9A=E4=BD=8D=E5=88=B0=E8=A1=8C=E5=8F=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9c9e499..9a3863e 100644 --- a/README.md +++ b/README.md @@ -198,8 +198,8 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, #### 2.1.0(2022.01.14) - - [添加导出网络链接图片到excel中](https://gitee.com/mwk719/spring-learn/blob/master/src/main/java/com/mwk/external/controller/ExcelController.java) - - 添加createRow集合列表生成excel方法 + - [添加导出网络链接图片到excel中](https://gitee.com/mwk719/spring-learn/blob/master/src/main/java/com/mwk/external/controller/ExcelController.java#L146) + - [添加createRow集合列表生成excel方法](https://gitee.com/mwk719/spring-learn/blob/master/src/main/java/com/mwk/external/controller/ExcelController.java#L191) - 修改CellStyle样式的使用 #### 2.0.0(2021.12.30) -- Gitee From 1f4ef2c9030b19d651256891a7644975aeda0b3c Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Thu, 27 Jan 2022 14:57:59 +0800 Subject: [PATCH 092/161] =?UTF-8?q?add=20=E5=AF=BC=E5=87=BAexcel=E4=B8=AD?= =?UTF-8?q?=E5=AD=97=E4=BD=93=E8=AE=BE=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 + pom.xml | 2 +- .../picture/support/flush/Sheet1Handler.java | 6 +- .../picture/support/flush/StylesHandler.java | 91 +++++++++++++------ .../picture/support/flush/StylesIndex.java | 53 +++++++++-- .../picture/support/model/CellStyle.java | 45 ++++++++- .../excel/picture/support/model/Font.java | 86 ++++++++++++++++++ .../excel/picture/support/module/Styles.java | 62 +------------ .../example/AnnotationTextExportExample.java | 19 ++-- .../example/ExportExample_20220127.java | 71 +++++++++++++++ 10 files changed, 328 insertions(+), 111 deletions(-) create mode 100644 src/main/java/com/ibiz/excel/picture/support/model/Font.java create mode 100644 src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220127.java diff --git a/README.md b/README.md index 9a3863e..fbbfd39 100644 --- a/README.md +++ b/README.md @@ -196,6 +196,10 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, 3. ### 版本更迭 + #### 2.2.0(2022.01.27) + + - [添加导出excel中字体设置]() + #### 2.1.0(2022.01.14) - [添加导出网络链接图片到excel中](https://gitee.com/mwk719/spring-learn/blob/master/src/main/java/com/mwk/external/controller/ExcelController.java#L146) diff --git a/pom.xml b/pom.xml index a12a6aa..8b94c36 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 top.minwk excel-x - 2.1.0 + 2.2.0 excel-x 支持excel中批量导出图片 https://gitee.com/mwk719/excel-batch-picture-support diff --git a/src/main/java/com/ibiz/excel/picture/support/flush/Sheet1Handler.java b/src/main/java/com/ibiz/excel/picture/support/flush/Sheet1Handler.java index b9abe1e..00233fc 100644 --- a/src/main/java/com/ibiz/excel/picture/support/flush/Sheet1Handler.java +++ b/src/main/java/com/ibiz/excel/picture/support/flush/Sheet1Handler.java @@ -17,9 +17,11 @@ import java.util.Set; * @auther 喻场 * @date 2020/7/618:33 */ -public class Sheet1Handler extends StylesIndex implements InvocationHandler { +public class Sheet1Handler implements InvocationHandler { private IRepository target; + private StylesIndex stylesIndex = new StylesIndex(); + public Sheet1Handler(IRepository proxy) { this.target = proxy; } @@ -157,7 +159,7 @@ public class Sheet1Handler extends StylesIndex implements InvocationHandler { CellStyle cellStyle = row.getCellStyle(); if(cellStyle != null){ // 设置cellStyle样式下标 - this.addCellStyle(cellStyle); + stylesIndex.addCellStyle(cellStyle); } row.getCells().forEach(c -> content.append("".concat( - "").concat( - "").concat( - "").concat( - "").concat( - "").concat( - "").concat( - "").concat( - "").concat( - "").concat( - "").concat( - "").concat( - "").concat( - "").concat( + /** + * 字体 + */ + private final StringBuilder fonts = new StringBuilder("" + + ""); + + + /** + * 填充色 + */ + private final StringBuilder fills = new StringBuilder("" + + "" + + ""); + + + /** + * 样式调用 + */ + private final StringBuilder cellXfs = new StringBuilder(("" + + "" + + "" + + "" + + "" + + "").concat( "").concat( - "").concat( - "").concat( - "").concat( - "").concat( // 填充色值坐标 - "")); + "").concat( + "") + ); - private final StringBuilder xfAfter = new StringBuilder("".concat( - "").concat( - "").concat( - "")); + private final StringBuilder cellStyles = new StringBuilder("".concat( + "")); @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { @@ -56,6 +65,8 @@ public class StylesHandler implements InvocationHandler { rows.stream().forEach(row -> { CellStyle cellStyle = row.getCellStyle(); if (row.getCellStyle() != null) { + // 追加字体 + this.appendFont(cellStyle.getFont()); // 追加背景色样式 this.appendFill(cellStyle); // 追加调用下标样式 @@ -65,7 +76,7 @@ public class StylesHandler implements InvocationHandler { } }else if (method.getName().equals("close")) { // 关闭时将所有的样式追加在Styles对象中 - target.append(xfBefore.append(xfAfter).toString()); + target.append(fonts.append(fills).append(cellXfs).append(cellStyles).toString()); } return method.invoke(target, args); } @@ -76,7 +87,10 @@ public class StylesHandler implements InvocationHandler { * @param cellStyle */ private void appendXf(CellStyle cellStyle) { - xfBefore.append(""); } @@ -87,7 +101,32 @@ public class StylesHandler implements InvocationHandler { * @param cellStyle */ private void appendFill(CellStyle cellStyle) { - target.append("")); + if(StringUtils.isNotBlank(cellStyle.getFgColorRgb())){ + fills.append(""); + } + } + + /** + * 追加字体 + * @param font + */ + private void appendFont(Font font) { + if(font != null){ + fonts.append(""); + // 加粗标志 + if(font.isBoldWeight()){ + fonts.append(""); + } + fonts.append(""); + } } } diff --git a/src/main/java/com/ibiz/excel/picture/support/flush/StylesIndex.java b/src/main/java/com/ibiz/excel/picture/support/flush/StylesIndex.java index 55a52d3..3ecfa92 100644 --- a/src/main/java/com/ibiz/excel/picture/support/flush/StylesIndex.java +++ b/src/main/java/com/ibiz/excel/picture/support/flush/StylesIndex.java @@ -1,6 +1,8 @@ package com.ibiz.excel.picture.support.flush; import com.ibiz.excel.picture.support.model.CellStyle; +import com.ibiz.excel.picture.support.model.Font; +import com.ibiz.excel.picture.support.util.StringUtils; /** * 样式下标取值 @@ -14,12 +16,22 @@ public class StylesIndex { * 默认已有fill样式 * 与对应{@link com.ibiz.excel.picture.support.module.Styles} */ - private int fillId = 33; + private int fillId = 0; /** * 默认已有cellStyles样式 */ - private int s = 4; + private int s = 1; + + /** + * 字体id + */ + private int fontId = 0; + + /** + * 是否设置字体 + */ + private boolean isSetFont; /** * 设置下标样式 @@ -27,15 +39,32 @@ public class StylesIndex { * @param cellStyle */ protected void addCellStyle(CellStyle cellStyle) { - this.addIndex(); - cellStyle.setFillId(fillId); + // 字体 + Font font = cellStyle.getFont(); + if(font != null){ + this.isSetFont = true; + }else { + this.isSetFont = false; + } + this.addIndex(cellStyle); + if(StringUtils.isNotBlank(cellStyle.getFgColorRgb())){ + cellStyle.setFillId(fillId); + } cellStyle.setS(s); + if(font != null){ + font.setFontId(fontId); + } } - protected void addIndex() { + protected void addIndex(CellStyle cellStyle) { // fillId+1,生成下一个编号 - fillId = fillId + 1; + if(StringUtils.isNotBlank(cellStyle.getFgColorRgb())){ + fillId = (fillId == 0 ? 1 : fillId) + 1; + } s = s + 1; + if(isSetFont){ + fontId = fontId + 1; + } } public int getFillId() { @@ -53,4 +82,16 @@ public class StylesIndex { public void setS(int s) { this.s = s; } + + public int getFontId() { + return fontId; + } + + public void setFontId(int fontId) { + this.fontId = fontId; + } + + public void setSetFont(boolean setFont) { + isSetFont = setFont; + } } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java b/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java index 0f25627..be63d28 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java @@ -1,14 +1,23 @@ package com.ibiz.excel.picture.support.model; -import com.ibiz.excel.picture.support.flush.StylesIndex; - /** * 控制该行样式 * * @author MinWeikai * @date 2021/1/19 14:04 */ -public class CellStyle extends StylesIndex { +public class CellStyle{ + + /** + * 默认已有fill样式 + * 与对应{@link com.ibiz.excel.picture.support.module.Styles} + */ + private int fillId = 0; + + /** + * 默认已有cellStyles样式 + */ + private int s = 1; /** * 行号 @@ -21,9 +30,22 @@ public class CellStyle extends StylesIndex { */ private String fgColorRgb; + /** + * 字体 + */ + private Font font; + public CellStyle() { } + public Font getFont() { + return font; + } + + public void setFont(Font font) { + this.font = font; + } + /** * 创建单元格前景色 * @@ -36,7 +58,7 @@ public class CellStyle extends StylesIndex { /** * 根据行号设置颜色 * @param rowNumber - * @param fgColorRgb + * @param fgColorRgb RGB网页颜色在线取色器 https://link.fobshanghai.com/rgbcolor.htm */ public CellStyle(int rowNumber, String fgColorRgb) { this.rowNumber = rowNumber; @@ -67,4 +89,19 @@ public class CellStyle extends StylesIndex { this.rowNumber = rowNumber; } + public int getFillId() { + return fillId; + } + + public void setFillId(int fillId) { + this.fillId = fillId; + } + + public int getS() { + return s; + } + + public void setS(int s) { + this.s = s; + } } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Font.java b/src/main/java/com/ibiz/excel/picture/support/model/Font.java new file mode 100644 index 0000000..38d3c9b --- /dev/null +++ b/src/main/java/com/ibiz/excel/picture/support/model/Font.java @@ -0,0 +1,86 @@ +package com.ibiz.excel.picture.support.model; + +/** + * 字体 + * + * @author MinWeikai + * @date 2022/1/27 11:47 + */ +public class Font{ + + /** + * 字体id + */ + private int fontId = 0; + + /** + * 设置字体的名称 + */ + private String fontName = "宋体"; + + /** + * 是否加粗,默认不加粗 + */ + private boolean boldWeight = false; + + /** + * 字体颜色 + */ + private String color; + + /** + * 字体大小 + */ + private short fontHeightInPoints = 11; + + public static Font build() { + return new Font(); + } + + public String getFontName() { + return fontName; + } + + public Font setFontName(String fontName) { + this.fontName = fontName; + return this; + } + + public boolean isBoldWeight() { + return boldWeight; + } + + public Font setBoldWeight(boolean boldWeight) { + this.boldWeight = boldWeight; + return this; + } + + public String getColor() { + return color; + } + + public Font setColor(String color) { + this.color = color; + return this; + } + + public short getFontHeightInPoints() { + return fontHeightInPoints; + } + + public Font setFontHeightInPoints(short fontHeightInPoints) { + this.fontHeightInPoints = fontHeightInPoints; + return this; + } + + public int getFontId() { + return fontId; + } + + public void setFontId(int fontId) { + this.fontId = fontId; + } + + + +} diff --git a/src/main/java/com/ibiz/excel/picture/support/module/Styles.java b/src/main/java/com/ibiz/excel/picture/support/module/Styles.java index 657a5d1..02319d3 100644 --- a/src/main/java/com/ibiz/excel/picture/support/module/Styles.java +++ b/src/main/java/com/ibiz/excel/picture/support/module/Styles.java @@ -16,67 +16,7 @@ import com.ibiz.excel.picture.support.constants.Alias; public class Styles { @AutoFile(fileName = "styles.xml", alias = Alias.STYLES) String content() { - return "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - ""; // 绿色背景,后续可在此追加 + return ""; } } diff --git a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationTextExportExample.java b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationTextExportExample.java index 825a0d3..1334e2b 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationTextExportExample.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationTextExportExample.java @@ -1,11 +1,12 @@ package com.ibiz.excel.picture.support.example; import com.ibiz.excel.picture.support.UserPicture; +import com.ibiz.excel.picture.support.common.BaseJunitTest; +import com.ibiz.excel.picture.support.model.CellStyle; import com.ibiz.excel.picture.support.model.Sheet; import com.ibiz.excel.picture.support.model.Workbook; import com.ibiz.excel.picture.support.util.WebUtil; - -import java.io.IOException; +import org.junit.Test; /** * 注解无图导出示例 @@ -13,19 +14,15 @@ import java.io.IOException; * @author MinWeikai * @date 2021-12-08 11:18:49 */ -public class AnnotationTextExportExample { - static final String CURRENT_PATH = "E:\\test\\"; - private static final String TEMP_PATH = CURRENT_PATH + "excel\\"; - private final static String IMG_PATH = "E:\\test\\img\\"; - - private final static String IMG_PATH_1 = IMG_PATH + "1.jpg"; - private final static String IMG_PATH_2 = IMG_PATH + "2.jpg"; - +public class AnnotationTextExportExample extends BaseJunitTest { - public static void main(String[] args) throws IOException { + @Test + public void export() { Workbook workBook = Workbook.getInstance(); Sheet sheet = workBook.createSheet("测试"); UserPicture u1; + // 给标题行加上背景色,加颜色时,会对字体加粗 + sheet.addCellStyle(new CellStyle(0, "66cc66")); for (int r = 0; r < 5; r++) { u1 = new UserPicture(); u1.setAge(15); diff --git a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220127.java b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220127.java new file mode 100644 index 0000000..a57acce --- /dev/null +++ b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220127.java @@ -0,0 +1,71 @@ +package com.ibiz.excel.picture.support.example; + +import com.ibiz.excel.picture.support.UserPicture; +import com.ibiz.excel.picture.support.common.BaseJunitTest; +import com.ibiz.excel.picture.support.model.CellStyle; +import com.ibiz.excel.picture.support.model.Font; +import com.ibiz.excel.picture.support.model.Sheet; +import com.ibiz.excel.picture.support.model.Workbook; +import com.ibiz.excel.picture.support.util.WebUtil; +import org.junit.Ignore; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +/** + * 导出excel示例 + * 字体设置 + * @author MinWeikai + * @date 2022-01-10 10:08:03 + */ +@Ignore +public class ExportExample_20220127 extends BaseJunitTest { + + @Test + public void export() { + Workbook workBook = Workbook.getInstance(); + Sheet sheet = workBook.createSheet("测试"); + // 给第一行加上背景色和字体配置 + CellStyle cellStyle = new CellStyle(0, "F0F0F0"); + Font font = Font.build() + .setFontName("黑体") + .setFontHeightInPoints((short) 15) + .setColor("FF4040") + .setBoldWeight(true); + cellStyle.setFont(font); + sheet.addCellStyle(cellStyle); + + // 给第三行字体放大到18 + CellStyle cellStyle1 = new CellStyle(); + Font font1 = new Font(); + font1.setFontHeightInPoints((short) 18); + cellStyle1.setRowNumber(2); + cellStyle1.setFont(font1); + sheet.addCellStyle(cellStyle1); + + // 给第五行加上背景色 + sheet.addCellStyle(new CellStyle(4, "AB82FF")); + + List list = new ArrayList<>(); + UserPicture userPicture; + for (int r = 0; r < 5; r++) { + userPicture = new UserPicture(); + userPicture.setAge(15); + userPicture.setName("测试-" + r); + // 导出本地单张图片 + userPicture.setPicture(IMG_PATH_1); + // 导出url单张图片 + userPicture.setHeaderPicture(getUrl()); + // 导出本地图片集合 + userPicture.setPictures(getPictures(new Random().nextInt(5))); + // 导出url图片集合 + userPicture.setUrlPictures(getUrls(5)); + list.add(userPicture); + } + sheet.write(UserPicture.class).createRow(list); + WebUtil.writeExcelTest(workBook, "ExportExample_20220127_".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), TEMP_PATH); + } + +} -- Gitee From d8e5872f201cc7ff6d22a48ac7ccd11841e4092a Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Thu, 27 Jan 2022 14:57:59 +0800 Subject: [PATCH 093/161] =?UTF-8?q?add=20=E5=AF=BC=E5=87=BAexcel=E4=B8=AD?= =?UTF-8?q?=E5=AD=97=E4=BD=93=E8=AE=BE=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 + pom.xml | 2 +- .../picture/support/flush/Sheet1Handler.java | 6 +- .../picture/support/flush/StylesHandler.java | 91 +++++++++++++------ .../picture/support/flush/StylesIndex.java | 53 +++++++++-- .../picture/support/model/CellStyle.java | 45 ++++++++- .../excel/picture/support/model/Font.java | 86 ++++++++++++++++++ .../excel/picture/support/module/Styles.java | 62 +------------ .../example/AnnotationTextExportExample.java | 19 ++-- .../example/ExportExample_20220127.java | 71 +++++++++++++++ 10 files changed, 328 insertions(+), 111 deletions(-) create mode 100644 src/main/java/com/ibiz/excel/picture/support/model/Font.java create mode 100644 src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220127.java diff --git a/README.md b/README.md index 9a3863e..fbbfd39 100644 --- a/README.md +++ b/README.md @@ -196,6 +196,10 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, 3. ### 版本更迭 + #### 2.2.0(2022.01.27) + + - [添加导出excel中字体设置]() + #### 2.1.0(2022.01.14) - [添加导出网络链接图片到excel中](https://gitee.com/mwk719/spring-learn/blob/master/src/main/java/com/mwk/external/controller/ExcelController.java#L146) diff --git a/pom.xml b/pom.xml index a12a6aa..8b94c36 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 top.minwk excel-x - 2.1.0 + 2.2.0 excel-x 支持excel中批量导出图片 https://gitee.com/mwk719/excel-batch-picture-support diff --git a/src/main/java/com/ibiz/excel/picture/support/flush/Sheet1Handler.java b/src/main/java/com/ibiz/excel/picture/support/flush/Sheet1Handler.java index b9abe1e..00233fc 100644 --- a/src/main/java/com/ibiz/excel/picture/support/flush/Sheet1Handler.java +++ b/src/main/java/com/ibiz/excel/picture/support/flush/Sheet1Handler.java @@ -17,9 +17,11 @@ import java.util.Set; * @auther 喻场 * @date 2020/7/618:33 */ -public class Sheet1Handler extends StylesIndex implements InvocationHandler { +public class Sheet1Handler implements InvocationHandler { private IRepository target; + private StylesIndex stylesIndex = new StylesIndex(); + public Sheet1Handler(IRepository proxy) { this.target = proxy; } @@ -157,7 +159,7 @@ public class Sheet1Handler extends StylesIndex implements InvocationHandler { CellStyle cellStyle = row.getCellStyle(); if(cellStyle != null){ // 设置cellStyle样式下标 - this.addCellStyle(cellStyle); + stylesIndex.addCellStyle(cellStyle); } row.getCells().forEach(c -> content.append("".concat( - "").concat( - "").concat( - "").concat( - "").concat( - "").concat( - "").concat( - "").concat( - "").concat( - "").concat( - "").concat( - "").concat( - "").concat( - "").concat( + /** + * 字体 + */ + private final StringBuilder fonts = new StringBuilder("" + + ""); + + + /** + * 填充色 + */ + private final StringBuilder fills = new StringBuilder("" + + "" + + ""); + + + /** + * 样式调用 + */ + private final StringBuilder cellXfs = new StringBuilder(("" + + "" + + "" + + "" + + "" + + "").concat( "").concat( - "").concat( - "").concat( - "").concat( - "").concat( // 填充色值坐标 - "")); + "").concat( + "") + ); - private final StringBuilder xfAfter = new StringBuilder("".concat( - "").concat( - "").concat( - "")); + private final StringBuilder cellStyles = new StringBuilder("".concat( + "")); @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { @@ -56,6 +65,8 @@ public class StylesHandler implements InvocationHandler { rows.stream().forEach(row -> { CellStyle cellStyle = row.getCellStyle(); if (row.getCellStyle() != null) { + // 追加字体 + this.appendFont(cellStyle.getFont()); // 追加背景色样式 this.appendFill(cellStyle); // 追加调用下标样式 @@ -65,7 +76,7 @@ public class StylesHandler implements InvocationHandler { } }else if (method.getName().equals("close")) { // 关闭时将所有的样式追加在Styles对象中 - target.append(xfBefore.append(xfAfter).toString()); + target.append(fonts.append(fills).append(cellXfs).append(cellStyles).toString()); } return method.invoke(target, args); } @@ -76,7 +87,10 @@ public class StylesHandler implements InvocationHandler { * @param cellStyle */ private void appendXf(CellStyle cellStyle) { - xfBefore.append(""); } @@ -87,7 +101,32 @@ public class StylesHandler implements InvocationHandler { * @param cellStyle */ private void appendFill(CellStyle cellStyle) { - target.append("")); + if(StringUtils.isNotBlank(cellStyle.getFgColorRgb())){ + fills.append(""); + } + } + + /** + * 追加字体 + * @param font + */ + private void appendFont(Font font) { + if(font != null){ + fonts.append(""); + // 加粗标志 + if(font.isBoldWeight()){ + fonts.append(""); + } + fonts.append(""); + } } } diff --git a/src/main/java/com/ibiz/excel/picture/support/flush/StylesIndex.java b/src/main/java/com/ibiz/excel/picture/support/flush/StylesIndex.java index 55a52d3..3ecfa92 100644 --- a/src/main/java/com/ibiz/excel/picture/support/flush/StylesIndex.java +++ b/src/main/java/com/ibiz/excel/picture/support/flush/StylesIndex.java @@ -1,6 +1,8 @@ package com.ibiz.excel.picture.support.flush; import com.ibiz.excel.picture.support.model.CellStyle; +import com.ibiz.excel.picture.support.model.Font; +import com.ibiz.excel.picture.support.util.StringUtils; /** * 样式下标取值 @@ -14,12 +16,22 @@ public class StylesIndex { * 默认已有fill样式 * 与对应{@link com.ibiz.excel.picture.support.module.Styles} */ - private int fillId = 33; + private int fillId = 0; /** * 默认已有cellStyles样式 */ - private int s = 4; + private int s = 1; + + /** + * 字体id + */ + private int fontId = 0; + + /** + * 是否设置字体 + */ + private boolean isSetFont; /** * 设置下标样式 @@ -27,15 +39,32 @@ public class StylesIndex { * @param cellStyle */ protected void addCellStyle(CellStyle cellStyle) { - this.addIndex(); - cellStyle.setFillId(fillId); + // 字体 + Font font = cellStyle.getFont(); + if(font != null){ + this.isSetFont = true; + }else { + this.isSetFont = false; + } + this.addIndex(cellStyle); + if(StringUtils.isNotBlank(cellStyle.getFgColorRgb())){ + cellStyle.setFillId(fillId); + } cellStyle.setS(s); + if(font != null){ + font.setFontId(fontId); + } } - protected void addIndex() { + protected void addIndex(CellStyle cellStyle) { // fillId+1,生成下一个编号 - fillId = fillId + 1; + if(StringUtils.isNotBlank(cellStyle.getFgColorRgb())){ + fillId = (fillId == 0 ? 1 : fillId) + 1; + } s = s + 1; + if(isSetFont){ + fontId = fontId + 1; + } } public int getFillId() { @@ -53,4 +82,16 @@ public class StylesIndex { public void setS(int s) { this.s = s; } + + public int getFontId() { + return fontId; + } + + public void setFontId(int fontId) { + this.fontId = fontId; + } + + public void setSetFont(boolean setFont) { + isSetFont = setFont; + } } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java b/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java index 0f25627..be63d28 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java @@ -1,14 +1,23 @@ package com.ibiz.excel.picture.support.model; -import com.ibiz.excel.picture.support.flush.StylesIndex; - /** * 控制该行样式 * * @author MinWeikai * @date 2021/1/19 14:04 */ -public class CellStyle extends StylesIndex { +public class CellStyle{ + + /** + * 默认已有fill样式 + * 与对应{@link com.ibiz.excel.picture.support.module.Styles} + */ + private int fillId = 0; + + /** + * 默认已有cellStyles样式 + */ + private int s = 1; /** * 行号 @@ -21,9 +30,22 @@ public class CellStyle extends StylesIndex { */ private String fgColorRgb; + /** + * 字体 + */ + private Font font; + public CellStyle() { } + public Font getFont() { + return font; + } + + public void setFont(Font font) { + this.font = font; + } + /** * 创建单元格前景色 * @@ -36,7 +58,7 @@ public class CellStyle extends StylesIndex { /** * 根据行号设置颜色 * @param rowNumber - * @param fgColorRgb + * @param fgColorRgb RGB网页颜色在线取色器 https://link.fobshanghai.com/rgbcolor.htm */ public CellStyle(int rowNumber, String fgColorRgb) { this.rowNumber = rowNumber; @@ -67,4 +89,19 @@ public class CellStyle extends StylesIndex { this.rowNumber = rowNumber; } + public int getFillId() { + return fillId; + } + + public void setFillId(int fillId) { + this.fillId = fillId; + } + + public int getS() { + return s; + } + + public void setS(int s) { + this.s = s; + } } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Font.java b/src/main/java/com/ibiz/excel/picture/support/model/Font.java new file mode 100644 index 0000000..38d3c9b --- /dev/null +++ b/src/main/java/com/ibiz/excel/picture/support/model/Font.java @@ -0,0 +1,86 @@ +package com.ibiz.excel.picture.support.model; + +/** + * 字体 + * + * @author MinWeikai + * @date 2022/1/27 11:47 + */ +public class Font{ + + /** + * 字体id + */ + private int fontId = 0; + + /** + * 设置字体的名称 + */ + private String fontName = "宋体"; + + /** + * 是否加粗,默认不加粗 + */ + private boolean boldWeight = false; + + /** + * 字体颜色 + */ + private String color; + + /** + * 字体大小 + */ + private short fontHeightInPoints = 11; + + public static Font build() { + return new Font(); + } + + public String getFontName() { + return fontName; + } + + public Font setFontName(String fontName) { + this.fontName = fontName; + return this; + } + + public boolean isBoldWeight() { + return boldWeight; + } + + public Font setBoldWeight(boolean boldWeight) { + this.boldWeight = boldWeight; + return this; + } + + public String getColor() { + return color; + } + + public Font setColor(String color) { + this.color = color; + return this; + } + + public short getFontHeightInPoints() { + return fontHeightInPoints; + } + + public Font setFontHeightInPoints(short fontHeightInPoints) { + this.fontHeightInPoints = fontHeightInPoints; + return this; + } + + public int getFontId() { + return fontId; + } + + public void setFontId(int fontId) { + this.fontId = fontId; + } + + + +} diff --git a/src/main/java/com/ibiz/excel/picture/support/module/Styles.java b/src/main/java/com/ibiz/excel/picture/support/module/Styles.java index 657a5d1..02319d3 100644 --- a/src/main/java/com/ibiz/excel/picture/support/module/Styles.java +++ b/src/main/java/com/ibiz/excel/picture/support/module/Styles.java @@ -16,67 +16,7 @@ import com.ibiz.excel.picture.support.constants.Alias; public class Styles { @AutoFile(fileName = "styles.xml", alias = Alias.STYLES) String content() { - return "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - ""; // 绿色背景,后续可在此追加 + return ""; } } diff --git a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationTextExportExample.java b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationTextExportExample.java index 825a0d3..1334e2b 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationTextExportExample.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationTextExportExample.java @@ -1,11 +1,12 @@ package com.ibiz.excel.picture.support.example; import com.ibiz.excel.picture.support.UserPicture; +import com.ibiz.excel.picture.support.common.BaseJunitTest; +import com.ibiz.excel.picture.support.model.CellStyle; import com.ibiz.excel.picture.support.model.Sheet; import com.ibiz.excel.picture.support.model.Workbook; import com.ibiz.excel.picture.support.util.WebUtil; - -import java.io.IOException; +import org.junit.Test; /** * 注解无图导出示例 @@ -13,19 +14,15 @@ import java.io.IOException; * @author MinWeikai * @date 2021-12-08 11:18:49 */ -public class AnnotationTextExportExample { - static final String CURRENT_PATH = "E:\\test\\"; - private static final String TEMP_PATH = CURRENT_PATH + "excel\\"; - private final static String IMG_PATH = "E:\\test\\img\\"; - - private final static String IMG_PATH_1 = IMG_PATH + "1.jpg"; - private final static String IMG_PATH_2 = IMG_PATH + "2.jpg"; - +public class AnnotationTextExportExample extends BaseJunitTest { - public static void main(String[] args) throws IOException { + @Test + public void export() { Workbook workBook = Workbook.getInstance(); Sheet sheet = workBook.createSheet("测试"); UserPicture u1; + // 给标题行加上背景色,加颜色时,会对字体加粗 + sheet.addCellStyle(new CellStyle(0, "66cc66")); for (int r = 0; r < 5; r++) { u1 = new UserPicture(); u1.setAge(15); diff --git a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220127.java b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220127.java new file mode 100644 index 0000000..a57acce --- /dev/null +++ b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220127.java @@ -0,0 +1,71 @@ +package com.ibiz.excel.picture.support.example; + +import com.ibiz.excel.picture.support.UserPicture; +import com.ibiz.excel.picture.support.common.BaseJunitTest; +import com.ibiz.excel.picture.support.model.CellStyle; +import com.ibiz.excel.picture.support.model.Font; +import com.ibiz.excel.picture.support.model.Sheet; +import com.ibiz.excel.picture.support.model.Workbook; +import com.ibiz.excel.picture.support.util.WebUtil; +import org.junit.Ignore; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +/** + * 导出excel示例 + * 字体设置 + * @author MinWeikai + * @date 2022-01-10 10:08:03 + */ +@Ignore +public class ExportExample_20220127 extends BaseJunitTest { + + @Test + public void export() { + Workbook workBook = Workbook.getInstance(); + Sheet sheet = workBook.createSheet("测试"); + // 给第一行加上背景色和字体配置 + CellStyle cellStyle = new CellStyle(0, "F0F0F0"); + Font font = Font.build() + .setFontName("黑体") + .setFontHeightInPoints((short) 15) + .setColor("FF4040") + .setBoldWeight(true); + cellStyle.setFont(font); + sheet.addCellStyle(cellStyle); + + // 给第三行字体放大到18 + CellStyle cellStyle1 = new CellStyle(); + Font font1 = new Font(); + font1.setFontHeightInPoints((short) 18); + cellStyle1.setRowNumber(2); + cellStyle1.setFont(font1); + sheet.addCellStyle(cellStyle1); + + // 给第五行加上背景色 + sheet.addCellStyle(new CellStyle(4, "AB82FF")); + + List list = new ArrayList<>(); + UserPicture userPicture; + for (int r = 0; r < 5; r++) { + userPicture = new UserPicture(); + userPicture.setAge(15); + userPicture.setName("测试-" + r); + // 导出本地单张图片 + userPicture.setPicture(IMG_PATH_1); + // 导出url单张图片 + userPicture.setHeaderPicture(getUrl()); + // 导出本地图片集合 + userPicture.setPictures(getPictures(new Random().nextInt(5))); + // 导出url图片集合 + userPicture.setUrlPictures(getUrls(5)); + list.add(userPicture); + } + sheet.write(UserPicture.class).createRow(list); + WebUtil.writeExcelTest(workBook, "ExportExample_20220127_".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), TEMP_PATH); + } + +} -- Gitee From 8eaff59802eb60a44a71df828a5ba776b4807d0c Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Thu, 27 Jan 2022 15:45:30 +0800 Subject: [PATCH 094/161] release 2.2.0 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fbbfd39..4534818 100644 --- a/README.md +++ b/README.md @@ -198,7 +198,7 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, #### 2.2.0(2022.01.27) - - [添加导出excel中字体设置]() + - [添加导出excel中字体设置](https://gitee.com/mwk719/spring-learn/blob/master/src/main/java/com/mwk/external/controller/ExcelController.java#L243) #### 2.1.0(2022.01.14) -- Gitee From ce9456fca8c3d14ebb9f7fc08beed01e9d9fdcb9 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Thu, 27 Jan 2022 15:45:30 +0800 Subject: [PATCH 095/161] release 2.2.0 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fbbfd39..4534818 100644 --- a/README.md +++ b/README.md @@ -198,7 +198,7 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, #### 2.2.0(2022.01.27) - - [添加导出excel中字体设置]() + - [添加导出excel中字体设置](https://gitee.com/mwk719/spring-learn/blob/master/src/main/java/com/mwk/external/controller/ExcelController.java#L243) #### 2.1.0(2022.01.14) -- Gitee From 2632c6bbe1fafaf0c663f94d4a6e6afe6bce36bd Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Fri, 28 Jan 2022 17:48:22 +0800 Subject: [PATCH 096/161] =?UTF-8?q?perf=20=E5=AF=B9=E5=90=88=E5=B9=B6?= =?UTF-8?q?=E5=8D=95=E5=85=83=E6=A0=BC=E7=9A=84=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 ++ .../excel/picture/support/model/Cell.java | 5 ++ .../ibiz/excel/picture/support/model/Row.java | 12 ++++ .../excel/picture/support/model/Sheet.java | 31 ++++++-- .../support/example/EasyUseExample4.java | 8 ++- .../example/ExportExample_20220128.java | 72 +++++++++++++++++++ 6 files changed, 125 insertions(+), 7 deletions(-) create mode 100644 src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220128.java diff --git a/README.md b/README.md index 4534818..46ba153 100644 --- a/README.md +++ b/README.md @@ -196,6 +196,10 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, 3. ### 版本更迭 + #### 2.2.1(2022.01.28) + + - 优化对合并单元格的处理 + #### 2.2.0(2022.01.27) - [添加导出excel中字体设置](https://gitee.com/mwk719/spring-learn/blob/master/src/main/java/com/mwk/external/controller/ExcelController.java#L243) diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Cell.java b/src/main/java/com/ibiz/excel/picture/support/model/Cell.java index 7669160..ed25f57 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Cell.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Cell.java @@ -24,6 +24,11 @@ public class Cell { this.autoSetCell(rowNumber, cellNumber); } + public Cell(int cellNumber, String value) { + this.cellNumber = cellNumber; + this.value = value; + } + /** * 自动设置Cell顺序 * diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Row.java b/src/main/java/com/ibiz/excel/picture/support/model/Row.java index fbb9ef0..c835372 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Row.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Row.java @@ -1,6 +1,7 @@ package com.ibiz.excel.picture.support.model; import java.util.ArrayList; +import java.util.Collections; import java.util.List; /** @@ -87,4 +88,15 @@ public class Row { this.cellStyle = cellStyle; return this; } + + /** + * 添加行中单元格元素 + * + * @param cell + * @return + */ + public Row addCell(Cell cell) { + autoRowCells(Collections.singletonList(cell)); + return this; + } } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java index 43cea92..7d51169 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java @@ -130,6 +130,17 @@ public class Sheet { return SHEET_HANDLER.createRow(rowNumber); } + /** + * 开始行号 + * + * @param startRowNumber 表示从第几行开始写入数据 + * @return + */ + public Sheet startRow(int startRowNumber) { + writeRow = --startRowNumber; + return this; + } + /** * 构建并写入excel信息 * @@ -394,10 +405,13 @@ public class Sheet { private Row createRowAndCellStyle(T t, final boolean isHead) { // 创建行数据 Row row = create(t, isHead); - // 获取样式 - CellStyle cellStyle = cellStyleMap.get(row.getRowNumber()); - if(cellStyle != null){ - row.setCellStyle(cellStyle); + // 最小单元配置优先,所以优先取Row中设置的样式 + if(Objects.isNull(row.getCellStyle())){ + // 获取样式 + CellStyle cellStyle = cellStyleMap.get(row.getRowNumber()); + if(cellStyle != null){ + row.setCellStyle(cellStyle); + } } return row; } @@ -483,4 +497,13 @@ public class Sheet { this.cellStyleMap.put(cellStyle.getRowNumber(), cellStyle); return this; } + + /** + * 添加元素的合并 + * + * @param mergeCell + */ + public void addMergeCell(MergeCell mergeCell) { + this.getMergeCells().add(mergeCell); + } } diff --git a/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample4.java b/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample4.java index c8553e4..c9c0fd0 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample4.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample4.java @@ -4,8 +4,10 @@ import com.ibiz.excel.picture.support.constants.WorkbookConstant; import com.ibiz.excel.picture.support.model.*; import com.ibiz.excel.picture.support.util.WebUtil; -import java.io.IOException; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.UUID; /** * 简化设置EasyUseExample4 @@ -28,7 +30,7 @@ public class EasyUseExample4 { private final static String IMG_PATH_2 = IMG_PATH + "2.jpg"; - public static void main(String[] args) throws IOException { + public static void main(String[] args) { Workbook workBook = Workbook.getInstance(100); Sheet sheet = workBook.createSheet("测试"); diff --git a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220128.java b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220128.java new file mode 100644 index 0000000..407135b --- /dev/null +++ b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220128.java @@ -0,0 +1,72 @@ +package com.ibiz.excel.picture.support.example; + +import com.ibiz.excel.picture.support.UserPicture; +import com.ibiz.excel.picture.support.common.BaseJunitTest; +import com.ibiz.excel.picture.support.model.*; +import com.ibiz.excel.picture.support.util.WebUtil; +import org.junit.Ignore; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +/** + * 导出excel示例 + * 字体设置|合并标题 + * + * @author MinWeikai + * @date 2022-01-10 10:08:03 + */ +@Ignore +public class ExportExample_20220128 extends BaseJunitTest { + + @Test + public void export() { + Workbook workBook = Workbook.getInstance(); + Sheet sheet = workBook.createSheet("测试"); + + // 标题样式 + CellStyle cellStyle = new CellStyle("F0F0F0"); + Font font = Font.build() + .setFontName("黑体") + .setFontHeightInPoints((short) 15) + .setBoldWeight(true); + cellStyle.setFont(font); + + // 标题信息 + sheet.createRow(0) + .addCell(new Cell(0, "测试标题")) + .setCellStyle(cellStyle) + .setHeight(30); + sheet.addMergeCell(new MergeCell(0, 0, 0, 6)); + + // 表头样式 + CellStyle cellStyle1 = new CellStyle(1, "66CC66"); + Font font1 = Font.build() + .setFontHeightInPoints((short) 13) + .setBoldWeight(true); + cellStyle1.setFont(font1); + sheet.addCellStyle(cellStyle1); + + List list = new ArrayList<>(); + UserPicture userPicture; + for (int r = 0; r < 5; r++) { + userPicture = new UserPicture(); + userPicture.setAge(15); + userPicture.setName("测试-" + r); + // 导出本地单张图片 + userPicture.setPicture(IMG_PATH_1); + // 导出url单张图片 + userPicture.setHeaderPicture(getUrl()); + // 导出本地图片集合 + userPicture.setPictures(getPictures(new Random().nextInt(5))); + // 导出url图片集合 + userPicture.setUrlPictures(getUrls(5)); + list.add(userPicture); + } + sheet.startRow(1).write(UserPicture.class).createRow(list); + WebUtil.writeExcelTest(workBook, "ExportExample_20220127_".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), TEMP_PATH); + } + +} -- Gitee From 4738040f17e39a17f489e8e9850d1d00a7cd4111 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Fri, 28 Jan 2022 17:49:32 +0800 Subject: [PATCH 097/161] release 2.2.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8b94c36..74f0a50 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 top.minwk excel-x - 2.2.0 + 2.2.1 excel-x 支持excel中批量导出图片 https://gitee.com/mwk719/excel-batch-picture-support -- Gitee From 27edbd5696b94a293ed64b406b37de27b9e1ec39 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Fri, 28 Jan 2022 17:48:22 +0800 Subject: [PATCH 098/161] =?UTF-8?q?perf=20=E5=AF=B9=E5=90=88=E5=B9=B6?= =?UTF-8?q?=E5=8D=95=E5=85=83=E6=A0=BC=E7=9A=84=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 ++ .../excel/picture/support/model/Cell.java | 5 ++ .../ibiz/excel/picture/support/model/Row.java | 12 ++++ .../excel/picture/support/model/Sheet.java | 31 ++++++-- .../support/example/EasyUseExample4.java | 8 ++- .../example/ExportExample_20220128.java | 72 +++++++++++++++++++ 6 files changed, 125 insertions(+), 7 deletions(-) create mode 100644 src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220128.java diff --git a/README.md b/README.md index 4534818..46ba153 100644 --- a/README.md +++ b/README.md @@ -196,6 +196,10 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, 3. ### 版本更迭 + #### 2.2.1(2022.01.28) + + - 优化对合并单元格的处理 + #### 2.2.0(2022.01.27) - [添加导出excel中字体设置](https://gitee.com/mwk719/spring-learn/blob/master/src/main/java/com/mwk/external/controller/ExcelController.java#L243) diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Cell.java b/src/main/java/com/ibiz/excel/picture/support/model/Cell.java index 7669160..ed25f57 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Cell.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Cell.java @@ -24,6 +24,11 @@ public class Cell { this.autoSetCell(rowNumber, cellNumber); } + public Cell(int cellNumber, String value) { + this.cellNumber = cellNumber; + this.value = value; + } + /** * 自动设置Cell顺序 * diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Row.java b/src/main/java/com/ibiz/excel/picture/support/model/Row.java index fbb9ef0..c835372 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Row.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Row.java @@ -1,6 +1,7 @@ package com.ibiz.excel.picture.support.model; import java.util.ArrayList; +import java.util.Collections; import java.util.List; /** @@ -87,4 +88,15 @@ public class Row { this.cellStyle = cellStyle; return this; } + + /** + * 添加行中单元格元素 + * + * @param cell + * @return + */ + public Row addCell(Cell cell) { + autoRowCells(Collections.singletonList(cell)); + return this; + } } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java index 43cea92..7d51169 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java @@ -130,6 +130,17 @@ public class Sheet { return SHEET_HANDLER.createRow(rowNumber); } + /** + * 开始行号 + * + * @param startRowNumber 表示从第几行开始写入数据 + * @return + */ + public Sheet startRow(int startRowNumber) { + writeRow = --startRowNumber; + return this; + } + /** * 构建并写入excel信息 * @@ -394,10 +405,13 @@ public class Sheet { private Row createRowAndCellStyle(T t, final boolean isHead) { // 创建行数据 Row row = create(t, isHead); - // 获取样式 - CellStyle cellStyle = cellStyleMap.get(row.getRowNumber()); - if(cellStyle != null){ - row.setCellStyle(cellStyle); + // 最小单元配置优先,所以优先取Row中设置的样式 + if(Objects.isNull(row.getCellStyle())){ + // 获取样式 + CellStyle cellStyle = cellStyleMap.get(row.getRowNumber()); + if(cellStyle != null){ + row.setCellStyle(cellStyle); + } } return row; } @@ -483,4 +497,13 @@ public class Sheet { this.cellStyleMap.put(cellStyle.getRowNumber(), cellStyle); return this; } + + /** + * 添加元素的合并 + * + * @param mergeCell + */ + public void addMergeCell(MergeCell mergeCell) { + this.getMergeCells().add(mergeCell); + } } diff --git a/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample4.java b/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample4.java index c8553e4..c9c0fd0 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample4.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample4.java @@ -4,8 +4,10 @@ import com.ibiz.excel.picture.support.constants.WorkbookConstant; import com.ibiz.excel.picture.support.model.*; import com.ibiz.excel.picture.support.util.WebUtil; -import java.io.IOException; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.UUID; /** * 简化设置EasyUseExample4 @@ -28,7 +30,7 @@ public class EasyUseExample4 { private final static String IMG_PATH_2 = IMG_PATH + "2.jpg"; - public static void main(String[] args) throws IOException { + public static void main(String[] args) { Workbook workBook = Workbook.getInstance(100); Sheet sheet = workBook.createSheet("测试"); diff --git a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220128.java b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220128.java new file mode 100644 index 0000000..407135b --- /dev/null +++ b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220128.java @@ -0,0 +1,72 @@ +package com.ibiz.excel.picture.support.example; + +import com.ibiz.excel.picture.support.UserPicture; +import com.ibiz.excel.picture.support.common.BaseJunitTest; +import com.ibiz.excel.picture.support.model.*; +import com.ibiz.excel.picture.support.util.WebUtil; +import org.junit.Ignore; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +/** + * 导出excel示例 + * 字体设置|合并标题 + * + * @author MinWeikai + * @date 2022-01-10 10:08:03 + */ +@Ignore +public class ExportExample_20220128 extends BaseJunitTest { + + @Test + public void export() { + Workbook workBook = Workbook.getInstance(); + Sheet sheet = workBook.createSheet("测试"); + + // 标题样式 + CellStyle cellStyle = new CellStyle("F0F0F0"); + Font font = Font.build() + .setFontName("黑体") + .setFontHeightInPoints((short) 15) + .setBoldWeight(true); + cellStyle.setFont(font); + + // 标题信息 + sheet.createRow(0) + .addCell(new Cell(0, "测试标题")) + .setCellStyle(cellStyle) + .setHeight(30); + sheet.addMergeCell(new MergeCell(0, 0, 0, 6)); + + // 表头样式 + CellStyle cellStyle1 = new CellStyle(1, "66CC66"); + Font font1 = Font.build() + .setFontHeightInPoints((short) 13) + .setBoldWeight(true); + cellStyle1.setFont(font1); + sheet.addCellStyle(cellStyle1); + + List list = new ArrayList<>(); + UserPicture userPicture; + for (int r = 0; r < 5; r++) { + userPicture = new UserPicture(); + userPicture.setAge(15); + userPicture.setName("测试-" + r); + // 导出本地单张图片 + userPicture.setPicture(IMG_PATH_1); + // 导出url单张图片 + userPicture.setHeaderPicture(getUrl()); + // 导出本地图片集合 + userPicture.setPictures(getPictures(new Random().nextInt(5))); + // 导出url图片集合 + userPicture.setUrlPictures(getUrls(5)); + list.add(userPicture); + } + sheet.startRow(1).write(UserPicture.class).createRow(list); + WebUtil.writeExcelTest(workBook, "ExportExample_20220127_".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), TEMP_PATH); + } + +} -- Gitee From d2e8a4ba99e5a25ffc20a96d694da60bfe160302 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Fri, 28 Jan 2022 17:49:32 +0800 Subject: [PATCH 099/161] release 2.2.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8b94c36..74f0a50 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 top.minwk excel-x - 2.2.0 + 2.2.1 excel-x 支持excel中批量导出图片 https://gitee.com/mwk719/excel-batch-picture-support -- Gitee From bb688c8f0b940482d1fe0243e118fe266f0b7e9c Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Fri, 28 Jan 2022 17:58:54 +0800 Subject: [PATCH 100/161] =?UTF-8?q?add=202.2.1=E7=A4=BA=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 46ba153..5931413 100644 --- a/README.md +++ b/README.md @@ -198,7 +198,7 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, #### 2.2.1(2022.01.28) - - 优化对合并单元格的处理 + - [优化对合并单元格的处理](https://gitee.com/mwk719/excel-batch-picture-support/blob/master/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220128.java#L30) #### 2.2.0(2022.01.27) -- Gitee From 6c6b03fd8b37dc4a03e80c0227e584f91cc93429 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Fri, 28 Jan 2022 17:58:54 +0800 Subject: [PATCH 101/161] =?UTF-8?q?add=202.2.1=E7=A4=BA=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit bb688c8f0b940482d1fe0243e118fe266f0b7e9c) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 46ba153..5931413 100644 --- a/README.md +++ b/README.md @@ -198,7 +198,7 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, #### 2.2.1(2022.01.28) - - 优化对合并单元格的处理 + - [优化对合并单元格的处理](https://gitee.com/mwk719/excel-batch-picture-support/blob/master/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220128.java#L30) #### 2.2.0(2022.01.27) -- Gitee From 1b747b6d89c7fb116bf52fbebfbe8a62017aa33b Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Tue, 8 Feb 2022 11:15:44 +0800 Subject: [PATCH 102/161] =?UTF-8?q?fix=20bug=E5=90=88=E5=B9=B6=E5=90=8E?= =?UTF-8?q?=E7=9A=84=E5=8D=95=E5=85=83=E6=A0=BC=E6=B2=A1=E6=9C=89=E8=BE=B9?= =?UTF-8?q?=E6=A1=86=E7=BA=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../excel/picture/support/model/Cell.java | 1 + .../ibiz/excel/picture/support/model/Row.java | 5 +++-- .../excel/picture/support/model/Sheet.java | 19 +++++++++++++++++++ .../example/ExportExample_20220128.java | 2 +- 4 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Cell.java b/src/main/java/com/ibiz/excel/picture/support/model/Cell.java index ed25f57..d75f5cc 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Cell.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Cell.java @@ -42,6 +42,7 @@ public class Cell { colNumber += "A"; } col += colNumber + CELL_NUMBER_LINE[line]; + colNumber = ""; colNumber += CELL_NUMBER_LINE[line] + (rowNumber + 1); } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Row.java b/src/main/java/com/ibiz/excel/picture/support/model/Row.java index c835372..e89e2c8 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Row.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Row.java @@ -1,7 +1,6 @@ package com.ibiz.excel.picture.support.model; import java.util.ArrayList; -import java.util.Collections; import java.util.List; /** @@ -96,7 +95,9 @@ public class Row { * @return */ public Row addCell(Cell cell) { - autoRowCells(Collections.singletonList(cell)); + List cells = new ArrayList<>(); + cells.add(cell); + autoRowCells(cells); return this; } } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java index 7d51169..7fc8f98 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java @@ -504,6 +504,25 @@ public class Sheet { * @param mergeCell */ public void addMergeCell(MergeCell mergeCell) { + // 对合并的单元格添加空元素 + addFillSpace(mergeCell); this.getMergeCells().add(mergeCell); } + + /** + * 对合并的单元个添加填充占位 + * + * @param mergeCell + */ + private void addFillSpace(MergeCell mergeCell) { + List cells = new ArrayList<>(); + for (int i = mergeCell.getFirstRow(); i < mergeCell.getLastRow() + 1; i++) { + for (int j = mergeCell.getFirstCol() + 1; j < mergeCell.getLastCol() + 1; j++) { + cells.add(new Cell(j, "")); + } + List rowCell = this.getRow(i).getCells(); + rowCell.addAll(cells); + this.getRow(i).autoRowCells(rowCell); + } + } } diff --git a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220128.java b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220128.java index 407135b..9a76487 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220128.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220128.java @@ -66,7 +66,7 @@ public class ExportExample_20220128 extends BaseJunitTest { list.add(userPicture); } sheet.startRow(1).write(UserPicture.class).createRow(list); - WebUtil.writeExcelTest(workBook, "ExportExample_20220127_".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), TEMP_PATH); + WebUtil.writeExcelTest(workBook, "ExportExample_20220128_".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), TEMP_PATH); } } -- Gitee From 4cf0b83ec6580110616644bd976ffea30f9020e1 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Tue, 8 Feb 2022 11:24:50 +0800 Subject: [PATCH 103/161] =?UTF-8?q?update=20=E5=90=88=E5=B9=B6=E5=8D=95?= =?UTF-8?q?=E5=85=83=E6=A0=BC=E4=BD=BF=E7=94=A8=E7=A4=BA=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/ibiz/excel/picture/support/model/Sheet.java | 1 + .../com/ibiz/excel/picture/support/ColMergeCellTest.java | 4 ++-- .../ibiz/excel/picture/support/example/EasyUseExample4.java | 5 ++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java index 7fc8f98..e76e6b5 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java @@ -500,6 +500,7 @@ public class Sheet { /** * 添加元素的合并 + * 必须放在对元素赋值之后 * * @param mergeCell */ diff --git a/src/test/java/com/ibiz/excel/picture/support/ColMergeCellTest.java b/src/test/java/com/ibiz/excel/picture/support/ColMergeCellTest.java index e76cb4c..9b3f97d 100644 --- a/src/test/java/com/ibiz/excel/picture/support/ColMergeCellTest.java +++ b/src/test/java/com/ibiz/excel/picture/support/ColMergeCellTest.java @@ -26,8 +26,8 @@ public class ColMergeCellTest { // 第一行表头 Row row = sheet.createRow(0); String[] excelName = {"文本1", "文本2", "图片1", "图片2", "图片3"}; - sheet.getMergeCells().add(new MergeCell(0, 0, 0, excelName.length - 1)); - row.setCells(Collections.singletonList(new Cell(0, 0).setValue("表头"))); + row.addCell(new Cell(0, 0).setValue("表头")); + sheet.addMergeCell(new MergeCell(0, 0, 0, excelName.length - 1)); // 第二行放标题 row = sheet.createRow(1); diff --git a/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample4.java b/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample4.java index c9c0fd0..ab1f806 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample4.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample4.java @@ -5,7 +5,6 @@ import com.ibiz.excel.picture.support.model.*; import com.ibiz.excel.picture.support.util.WebUtil; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.UUID; @@ -42,12 +41,12 @@ public class EasyUseExample4 { // 第一行表头 Row row = sheet.createRow(0).setCellStyle(new CellStyle("cc3300")); - row.autoRowCells(Collections.singletonList(new Cell(0).setValue("表头"))); + row.addCell(new Cell(0).setValue("表头")); // 第二行放标题 String[] excelName = {"文本1", "文本2", "图片1", "图片2", "图片3"}; //要进行合并的列 - sheet.getMergeCells().add(new MergeCell(0, 0, 0, excelName.length - 1)); + sheet.addMergeCell(new MergeCell(0, 0, 0, excelName.length - 1)); row = sheet.createRow(1).setCellStyle(new CellStyle("996699")); List cells = new ArrayList<>(); -- Gitee From 26cffa187a5c928bf405f192385948375ed59ec6 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Tue, 8 Feb 2022 11:27:51 +0800 Subject: [PATCH 104/161] release 2.2.2 --- README.md | 4 ++++ pom.xml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5931413..019d0ee 100644 --- a/README.md +++ b/README.md @@ -196,6 +196,10 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, 3. ### 版本更迭 + #### 2.2.2(2022.02.08) + + - 修复合并后的单元格没有边框线 + #### 2.2.1(2022.01.28) - [优化对合并单元格的处理](https://gitee.com/mwk719/excel-batch-picture-support/blob/master/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220128.java#L30) diff --git a/pom.xml b/pom.xml index 74f0a50..219035e 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 top.minwk excel-x - 2.2.1 + 2.2.2 excel-x 支持excel中批量导出图片 https://gitee.com/mwk719/excel-batch-picture-support -- Gitee From 0e4413b1e7ba81c29d9c6667ce110e82da9a3947 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Tue, 8 Feb 2022 11:15:44 +0800 Subject: [PATCH 105/161] =?UTF-8?q?fix=20bug=E5=90=88=E5=B9=B6=E5=90=8E?= =?UTF-8?q?=E7=9A=84=E5=8D=95=E5=85=83=E6=A0=BC=E6=B2=A1=E6=9C=89=E8=BE=B9?= =?UTF-8?q?=E6=A1=86=E7=BA=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../excel/picture/support/model/Cell.java | 1 + .../ibiz/excel/picture/support/model/Row.java | 5 +++-- .../excel/picture/support/model/Sheet.java | 19 +++++++++++++++++++ .../example/ExportExample_20220128.java | 2 +- 4 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Cell.java b/src/main/java/com/ibiz/excel/picture/support/model/Cell.java index ed25f57..d75f5cc 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Cell.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Cell.java @@ -42,6 +42,7 @@ public class Cell { colNumber += "A"; } col += colNumber + CELL_NUMBER_LINE[line]; + colNumber = ""; colNumber += CELL_NUMBER_LINE[line] + (rowNumber + 1); } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Row.java b/src/main/java/com/ibiz/excel/picture/support/model/Row.java index c835372..e89e2c8 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Row.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Row.java @@ -1,7 +1,6 @@ package com.ibiz.excel.picture.support.model; import java.util.ArrayList; -import java.util.Collections; import java.util.List; /** @@ -96,7 +95,9 @@ public class Row { * @return */ public Row addCell(Cell cell) { - autoRowCells(Collections.singletonList(cell)); + List cells = new ArrayList<>(); + cells.add(cell); + autoRowCells(cells); return this; } } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java index 7d51169..7fc8f98 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java @@ -504,6 +504,25 @@ public class Sheet { * @param mergeCell */ public void addMergeCell(MergeCell mergeCell) { + // 对合并的单元格添加空元素 + addFillSpace(mergeCell); this.getMergeCells().add(mergeCell); } + + /** + * 对合并的单元个添加填充占位 + * + * @param mergeCell + */ + private void addFillSpace(MergeCell mergeCell) { + List cells = new ArrayList<>(); + for (int i = mergeCell.getFirstRow(); i < mergeCell.getLastRow() + 1; i++) { + for (int j = mergeCell.getFirstCol() + 1; j < mergeCell.getLastCol() + 1; j++) { + cells.add(new Cell(j, "")); + } + List rowCell = this.getRow(i).getCells(); + rowCell.addAll(cells); + this.getRow(i).autoRowCells(rowCell); + } + } } diff --git a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220128.java b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220128.java index 407135b..9a76487 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220128.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220128.java @@ -66,7 +66,7 @@ public class ExportExample_20220128 extends BaseJunitTest { list.add(userPicture); } sheet.startRow(1).write(UserPicture.class).createRow(list); - WebUtil.writeExcelTest(workBook, "ExportExample_20220127_".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), TEMP_PATH); + WebUtil.writeExcelTest(workBook, "ExportExample_20220128_".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), TEMP_PATH); } } -- Gitee From d4cc17738fa14a8d5aaae20e23706c42b229d1c9 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Tue, 8 Feb 2022 11:24:50 +0800 Subject: [PATCH 106/161] =?UTF-8?q?update=20=E5=90=88=E5=B9=B6=E5=8D=95?= =?UTF-8?q?=E5=85=83=E6=A0=BC=E4=BD=BF=E7=94=A8=E7=A4=BA=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/ibiz/excel/picture/support/model/Sheet.java | 1 + .../com/ibiz/excel/picture/support/ColMergeCellTest.java | 4 ++-- .../ibiz/excel/picture/support/example/EasyUseExample4.java | 5 ++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java index 7fc8f98..e76e6b5 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java @@ -500,6 +500,7 @@ public class Sheet { /** * 添加元素的合并 + * 必须放在对元素赋值之后 * * @param mergeCell */ diff --git a/src/test/java/com/ibiz/excel/picture/support/ColMergeCellTest.java b/src/test/java/com/ibiz/excel/picture/support/ColMergeCellTest.java index e76cb4c..9b3f97d 100644 --- a/src/test/java/com/ibiz/excel/picture/support/ColMergeCellTest.java +++ b/src/test/java/com/ibiz/excel/picture/support/ColMergeCellTest.java @@ -26,8 +26,8 @@ public class ColMergeCellTest { // 第一行表头 Row row = sheet.createRow(0); String[] excelName = {"文本1", "文本2", "图片1", "图片2", "图片3"}; - sheet.getMergeCells().add(new MergeCell(0, 0, 0, excelName.length - 1)); - row.setCells(Collections.singletonList(new Cell(0, 0).setValue("表头"))); + row.addCell(new Cell(0, 0).setValue("表头")); + sheet.addMergeCell(new MergeCell(0, 0, 0, excelName.length - 1)); // 第二行放标题 row = sheet.createRow(1); diff --git a/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample4.java b/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample4.java index c9c0fd0..ab1f806 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample4.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/EasyUseExample4.java @@ -5,7 +5,6 @@ import com.ibiz.excel.picture.support.model.*; import com.ibiz.excel.picture.support.util.WebUtil; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.UUID; @@ -42,12 +41,12 @@ public class EasyUseExample4 { // 第一行表头 Row row = sheet.createRow(0).setCellStyle(new CellStyle("cc3300")); - row.autoRowCells(Collections.singletonList(new Cell(0).setValue("表头"))); + row.addCell(new Cell(0).setValue("表头")); // 第二行放标题 String[] excelName = {"文本1", "文本2", "图片1", "图片2", "图片3"}; //要进行合并的列 - sheet.getMergeCells().add(new MergeCell(0, 0, 0, excelName.length - 1)); + sheet.addMergeCell(new MergeCell(0, 0, 0, excelName.length - 1)); row = sheet.createRow(1).setCellStyle(new CellStyle("996699")); List cells = new ArrayList<>(); -- Gitee From f5df91d4cded973c02696cae9ef13162422a4a68 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Tue, 8 Feb 2022 11:27:51 +0800 Subject: [PATCH 107/161] release 2.2.2 --- README.md | 4 ++++ pom.xml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5931413..019d0ee 100644 --- a/README.md +++ b/README.md @@ -196,6 +196,10 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, 3. ### 版本更迭 + #### 2.2.2(2022.02.08) + + - 修复合并后的单元格没有边框线 + #### 2.2.1(2022.01.28) - [优化对合并单元格的处理](https://gitee.com/mwk719/excel-batch-picture-support/blob/master/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220128.java#L30) diff --git a/pom.xml b/pom.xml index 74f0a50..219035e 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 top.minwk excel-x - 2.2.1 + 2.2.2 excel-x 支持excel中批量导出图片 https://gitee.com/mwk719/excel-batch-picture-support -- Gitee From 48e8fb8ecba9163d0b7bb9449c20bbaf25649dbd Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Wed, 9 Feb 2022 10:06:57 +0800 Subject: [PATCH 108/161] =?UTF-8?q?add=20=E5=8A=A8=E6=80=81=E6=A0=87?= =?UTF-8?q?=E9=A2=98=E5=AF=BC=E5=87=BA=E6=B5=8B=E8=AF=95=E4=BD=BF=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../support/model/BizExcelPojoInterface.java | 11 +++ .../picture/support/model/BizExcelRel.java | 92 +++++++++++++++++++ .../excel/picture/support/util/BeanUtil.java | 87 ++++++++++++++++++ .../com/ibiz/excel/picture/support/Demo.java | 1 + .../AnnotationPictureExportExample.java | 2 +- .../AnnotationPicturesExportExample.java | 2 +- .../example/AnnotationTextExportExample.java | 2 +- .../example/ExportExample_20220110.java | 2 +- .../example/ExportExample_20220127.java | 2 +- .../example/ExportExample_20220128.java | 2 +- .../example/ExportExample_20220208.java | 73 +++++++++++++++ .../excel/picture/support/pojo/Student.java | 35 +++++++ .../picture/support/{ => pojo}/User.java | 2 +- .../support/{ => pojo}/UserPicture.java | 2 +- .../SimulateRealBusinessExportExample.java | 2 +- 15 files changed, 308 insertions(+), 9 deletions(-) create mode 100644 src/main/java/com/ibiz/excel/picture/support/model/BizExcelPojoInterface.java create mode 100644 src/main/java/com/ibiz/excel/picture/support/model/BizExcelRel.java create mode 100644 src/main/java/com/ibiz/excel/picture/support/util/BeanUtil.java create mode 100644 src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220208.java create mode 100644 src/test/java/com/ibiz/excel/picture/support/pojo/Student.java rename src/test/java/com/ibiz/excel/picture/support/{ => pojo}/User.java (98%) rename src/test/java/com/ibiz/excel/picture/support/{ => pojo}/UserPicture.java (98%) diff --git a/src/main/java/com/ibiz/excel/picture/support/model/BizExcelPojoInterface.java b/src/main/java/com/ibiz/excel/picture/support/model/BizExcelPojoInterface.java new file mode 100644 index 0000000..cc9c5e2 --- /dev/null +++ b/src/main/java/com/ibiz/excel/picture/support/model/BizExcelPojoInterface.java @@ -0,0 +1,11 @@ +package com.ibiz.excel.picture.support.model; + +/** + * 动态导出pojo接口 + * 目前在动态导出时需要实现该接口 + * + * @author MinWeikai + * @date 2022/2/9 9:45 + */ +public interface BizExcelPojoInterface { +} diff --git a/src/main/java/com/ibiz/excel/picture/support/model/BizExcelRel.java b/src/main/java/com/ibiz/excel/picture/support/model/BizExcelRel.java new file mode 100644 index 0000000..178c470 --- /dev/null +++ b/src/main/java/com/ibiz/excel/picture/support/model/BizExcelRel.java @@ -0,0 +1,92 @@ +package com.ibiz.excel.picture.support.model; + +/** + * Excel导出配置 + * + * @author MinWeikai + * @date 2022/2/8 14:45 + */ +public class BizExcelRel { + + public BizExcelRel() { + } + + public BizExcelRel(String excelName, String field, int orderNo) { + this.excelName = excelName; + this.field = field; + this.orderNo = orderNo; + } + + public BizExcelRel(String excelName, String field, boolean isEnum, String lookupCode, int orderNo) { + this.excelName = excelName; + this.field = field; + this.isEnum = isEnum; + this.lookupCode = lookupCode; + this.orderNo = orderNo; + } + + /** + * excel显示的字段名称 + */ + private String excelName; + + /** + * 字段 + */ + private String field; + + /** + * 是否是枚举 + */ + private boolean isEnum = false; + + /** + * 数据字典code + */ + private String lookupCode; + + /** + * 排序 + */ + private int orderNo = 0; + + public String getExcelName() { + return excelName; + } + + public void setExcelName(String excelName) { + this.excelName = excelName; + } + + public String getField() { + return field; + } + + public void setField(String field) { + this.field = field; + } + + public boolean isEnum() { + return isEnum; + } + + public void setEnum(boolean anEnum) { + isEnum = anEnum; + } + + public String getLookupCode() { + return lookupCode; + } + + public void setLookupCode(String lookupCode) { + this.lookupCode = lookupCode; + } + + public int getOrderNo() { + return orderNo; + } + + public void setOrderNo(int orderNo) { + this.orderNo = orderNo; + } +} diff --git a/src/main/java/com/ibiz/excel/picture/support/util/BeanUtil.java b/src/main/java/com/ibiz/excel/picture/support/util/BeanUtil.java new file mode 100644 index 0000000..2219744 --- /dev/null +++ b/src/main/java/com/ibiz/excel/picture/support/util/BeanUtil.java @@ -0,0 +1,87 @@ +package com.ibiz.excel.picture.support.util; + +import java.beans.PropertyDescriptor; +import java.lang.reflect.InvocationTargetException; +import java.util.Collection; +import java.util.Map; + +/** + * @author MinWeikai + * @date 2022/2/9 9:31 + */ +public class BeanUtil { + + /** + * 反射获取对象属性,支持嵌套 + * 例如: + * User user = new User(); + * Position position = new Position(); + * position.setName("fjjffj"); + * user.setPositionList(Lists.newArrayList(position)); + * Organization organization = new Organization(); + * organization.setName("1111111"); + * user.setOrganization(organization); + * BaseCriteria criteria = new BaseCriteria(); + * Map map = Maps.newHashMap(); + * map.put("bb","aaaaaaaaaaaaaaaa"); + * criteria.setStrValue(map); + * user.setCriteria(criteria); + * Object obj = getPropertyValue(user, "organization.name"); + * System.out.println(obj); + * obj = getPropertyValue(user, "positionList[0].name"); + * System.out.println(obj); + * obj = getPropertyValue(user, "criteria.strValue[bb]"); + * System.out.println(obj); + * @param obj + * @param key + * @return + * @throws InvocationTargetException + * @throws IllegalAccessException + */ + public static Object getPropertyValue(Object obj, String key){ + if (key.contains(".")){ + int dotMarkIndex = key.indexOf("."); + String prefixKey = key.substring(0, dotMarkIndex); + Object prefixObj = getSimplePropertyValue(obj, prefixKey); + String suffixKey = key.substring(dotMarkIndex+1); + return getPropertyValue(prefixObj, suffixKey); + } + return getSimplePropertyValue(obj, key); + } + + private static Object getSimplePropertyValue(Object obj, String key){ + String prefixKey ; + String suffixKey = null; + Object returnValue ; + if(key.matches("(\\w+)\\[(\\w+)\\]$")){ + int endIndex = key.indexOf("["); + prefixKey = key.substring(0, endIndex); + suffixKey = key.substring(endIndex+1, key.length() -1); + }else{ + prefixKey = key; + } + if(obj instanceof Map){ + returnValue = ((Map) obj).get(prefixKey); + }else {// obj instanceof Object + PropertyDescriptor propertyDescriptor = org.springframework.beans.BeanUtils.getPropertyDescriptor(obj.getClass(), prefixKey); + try { + assert propertyDescriptor != null; + returnValue = propertyDescriptor.getReadMethod().invoke(obj); + } catch (InvocationTargetException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + if (StringUtils.isNotBlank(suffixKey)){ + try { + int index = Integer.parseInt(suffixKey);//数字 -->> 数组/集合 + if(returnValue instanceof Collection){//集合转数组 + returnValue = ((Collection) returnValue).toArray(new Object[0]); + } + returnValue = ((Object[])returnValue)[index]; + }catch (NumberFormatException e){//字符串 -->> 对象 + returnValue = getPropertyValue(returnValue, suffixKey); + } + } + return returnValue; + } +} diff --git a/src/test/java/com/ibiz/excel/picture/support/Demo.java b/src/test/java/com/ibiz/excel/picture/support/Demo.java index 17cf8aa..8b35dc9 100644 --- a/src/test/java/com/ibiz/excel/picture/support/Demo.java +++ b/src/test/java/com/ibiz/excel/picture/support/Demo.java @@ -2,6 +2,7 @@ package com.ibiz.excel.picture.support; import com.ibiz.excel.picture.support.model.Sheet; import com.ibiz.excel.picture.support.model.Workbook; +import com.ibiz.excel.picture.support.pojo.User; import java.io.*; import java.util.Date; diff --git a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPictureExportExample.java b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPictureExportExample.java index 6ac17ff..33468d3 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPictureExportExample.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPictureExportExample.java @@ -1,6 +1,6 @@ package com.ibiz.excel.picture.support.example; -import com.ibiz.excel.picture.support.UserPicture; +import com.ibiz.excel.picture.support.pojo.UserPicture; import com.ibiz.excel.picture.support.model.Sheet; import com.ibiz.excel.picture.support.model.Workbook; import com.ibiz.excel.picture.support.util.WebUtil; diff --git a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java index 75c9cae..6498cbf 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java @@ -1,6 +1,6 @@ package com.ibiz.excel.picture.support.example; -import com.ibiz.excel.picture.support.UserPicture; +import com.ibiz.excel.picture.support.pojo.UserPicture; import com.ibiz.excel.picture.support.common.BaseJunitTest; import com.ibiz.excel.picture.support.model.CellStyle; import com.ibiz.excel.picture.support.model.Sheet; diff --git a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationTextExportExample.java b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationTextExportExample.java index 1334e2b..8ca4cce 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationTextExportExample.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationTextExportExample.java @@ -1,6 +1,6 @@ package com.ibiz.excel.picture.support.example; -import com.ibiz.excel.picture.support.UserPicture; +import com.ibiz.excel.picture.support.pojo.UserPicture; import com.ibiz.excel.picture.support.common.BaseJunitTest; import com.ibiz.excel.picture.support.model.CellStyle; import com.ibiz.excel.picture.support.model.Sheet; diff --git a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220110.java b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220110.java index 88d6d36..410f935 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220110.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220110.java @@ -1,6 +1,6 @@ package com.ibiz.excel.picture.support.example; -import com.ibiz.excel.picture.support.UserPicture; +import com.ibiz.excel.picture.support.pojo.UserPicture; import com.ibiz.excel.picture.support.common.BaseJunitTest; import com.ibiz.excel.picture.support.model.CellStyle; import com.ibiz.excel.picture.support.model.Sheet; diff --git a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220127.java b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220127.java index a57acce..b28f929 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220127.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220127.java @@ -1,6 +1,6 @@ package com.ibiz.excel.picture.support.example; -import com.ibiz.excel.picture.support.UserPicture; +import com.ibiz.excel.picture.support.pojo.UserPicture; import com.ibiz.excel.picture.support.common.BaseJunitTest; import com.ibiz.excel.picture.support.model.CellStyle; import com.ibiz.excel.picture.support.model.Font; diff --git a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220128.java b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220128.java index 9a76487..6331102 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220128.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220128.java @@ -1,6 +1,6 @@ package com.ibiz.excel.picture.support.example; -import com.ibiz.excel.picture.support.UserPicture; +import com.ibiz.excel.picture.support.pojo.UserPicture; import com.ibiz.excel.picture.support.common.BaseJunitTest; import com.ibiz.excel.picture.support.model.*; import com.ibiz.excel.picture.support.util.WebUtil; diff --git a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220208.java b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220208.java new file mode 100644 index 0000000..32074db --- /dev/null +++ b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220208.java @@ -0,0 +1,73 @@ +package com.ibiz.excel.picture.support.example; + +import cn.hutool.core.bean.BeanUtil; +import com.ibiz.excel.picture.support.common.BaseJunitTest; +import com.ibiz.excel.picture.support.model.*; +import com.ibiz.excel.picture.support.pojo.Student; +import com.ibiz.excel.picture.support.util.WebUtil; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; + +/** + * @author MinWeikai + * @date 2022/2/8 14:49 + */ +public class ExportExample_20220208 extends BaseJunitTest { + + @Test + public void export() { + List students = new ArrayList<>(); + students.add(new Student("李四", 16)); + students.add(new Student("张三", 17)); + + Workbook workBook = Workbook.getInstance(100); + Sheet sheet = workBook.createSheet("测试"); + + List excels = new ArrayList<>(); + excels.add(new BizExcelRel("姓名", "name", 1)); + excels.add(new BizExcelRel("年龄", "age", 2)); + + + buildExcel(sheet, excels, students); + + WebUtil.writeExcelTest(workBook, "ExportExample_20220208_".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), TEMP_PATH); + } + + /** + * 构建excel + * + * @param sheet excel + * @param excels excel属性配置 + * @param list 需要导出的集合对象 + */ + private static void buildExcel(Sheet sheet, List excels, List list) { + // 开始行放标题 + int startRow = 0; + Row row = sheet.createRow(startRow); + List cells = new ArrayList<>(); + for (int i = 0; i < excels.size(); i++) { + cells.add(new Cell(i).setValue(excels.get(i).getExcelName())); + } + row.autoRowCells(cells); + int num; + List pictures = sheet.getPictures(); + for (int j = 0; j < list.size(); j++) { + // 开始行的下一行放内容 + num = j + 1; + row = sheet.createRow(num); + cells = new ArrayList<>(); + int index = 0; + BizExcelPojoInterface excelPojoInterface = list.get(j); + excels = excels.stream().sorted(Comparator.comparing(BizExcelRel::getOrderNo)).collect(Collectors.toList()); + for (BizExcelRel excel : excels) { + Object propertyValue = BeanUtil.getFieldValue(excelPojoInterface, excel.getField()); + cells.add(new Cell(num, index++).setValue(propertyValue == null ? "" : propertyValue.toString())); + row.setCells(cells); + } + } + } +} diff --git a/src/test/java/com/ibiz/excel/picture/support/pojo/Student.java b/src/test/java/com/ibiz/excel/picture/support/pojo/Student.java new file mode 100644 index 0000000..38c9ff3 --- /dev/null +++ b/src/test/java/com/ibiz/excel/picture/support/pojo/Student.java @@ -0,0 +1,35 @@ +package com.ibiz.excel.picture.support.pojo; + +import com.ibiz.excel.picture.support.model.BizExcelPojoInterface; + +/** + * @author MinWeikai + * @date 2022/2/9 9:21 + */ +public class Student implements BizExcelPojoInterface { + + public Student(String name, Integer age) { + this.name = name; + this.age = age; + } + + private String name; + + private Integer age; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getAge() { + return age; + } + + public void setAge(Integer age) { + this.age = age; + } +} diff --git a/src/test/java/com/ibiz/excel/picture/support/User.java b/src/test/java/com/ibiz/excel/picture/support/pojo/User.java similarity index 98% rename from src/test/java/com/ibiz/excel/picture/support/User.java rename to src/test/java/com/ibiz/excel/picture/support/pojo/User.java index 3956c77..a1be8a9 100644 --- a/src/test/java/com/ibiz/excel/picture/support/User.java +++ b/src/test/java/com/ibiz/excel/picture/support/pojo/User.java @@ -1,4 +1,4 @@ -package com.ibiz.excel.picture.support; +package com.ibiz.excel.picture.support.pojo; import com.ibiz.excel.picture.support.annotation.ExportModel; diff --git a/src/test/java/com/ibiz/excel/picture/support/UserPicture.java b/src/test/java/com/ibiz/excel/picture/support/pojo/UserPicture.java similarity index 98% rename from src/test/java/com/ibiz/excel/picture/support/UserPicture.java rename to src/test/java/com/ibiz/excel/picture/support/pojo/UserPicture.java index 4febea8..de67a94 100644 --- a/src/test/java/com/ibiz/excel/picture/support/UserPicture.java +++ b/src/test/java/com/ibiz/excel/picture/support/pojo/UserPicture.java @@ -1,4 +1,4 @@ -package com.ibiz.excel.picture.support; +package com.ibiz.excel.picture.support.pojo; import com.ibiz.excel.picture.support.annotation.ExportModel; import com.ibiz.excel.picture.support.constants.PictureSourceContent; diff --git a/src/test/java/com/ibiz/excel/picture/support/simulation/SimulateRealBusinessExportExample.java b/src/test/java/com/ibiz/excel/picture/support/simulation/SimulateRealBusinessExportExample.java index a610f09..8ba154d 100644 --- a/src/test/java/com/ibiz/excel/picture/support/simulation/SimulateRealBusinessExportExample.java +++ b/src/test/java/com/ibiz/excel/picture/support/simulation/SimulateRealBusinessExportExample.java @@ -1,6 +1,6 @@ package com.ibiz.excel.picture.support.simulation; -import com.ibiz.excel.picture.support.UserPicture; +import com.ibiz.excel.picture.support.pojo.UserPicture; import com.ibiz.excel.picture.support.common.BaseJunitTest; import com.ibiz.excel.picture.support.model.CellStyle; import com.ibiz.excel.picture.support.model.Sheet; -- Gitee From 3f1e2ea788dccdaf3638129125101cd726e2db59 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Wed, 9 Feb 2022 16:27:11 +0800 Subject: [PATCH 109/161] =?UTF-8?q?add=20=E5=AE=8C=E5=96=84=E5=8A=A8?= =?UTF-8?q?=E6=80=81=E6=A0=87=E9=A2=98=E5=AF=BC=E5=87=BA=E6=96=B9=E6=B3=95?= =?UTF-8?q?=E8=B0=83=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../picture/support/model/BizExcelRel.java | 20 ++++ .../support/model/ExcelTableProcessor.java | 97 +++++++++++++++++++ .../example/ExportExample_20220208.java | 46 ++------- .../excel/picture/support/pojo/Student.java | 16 +++ 4 files changed, 140 insertions(+), 39 deletions(-) create mode 100644 src/main/java/com/ibiz/excel/picture/support/model/ExcelTableProcessor.java diff --git a/src/main/java/com/ibiz/excel/picture/support/model/BizExcelRel.java b/src/main/java/com/ibiz/excel/picture/support/model/BizExcelRel.java index 178c470..a8a7bb6 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/BizExcelRel.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/BizExcelRel.java @@ -17,6 +17,13 @@ public class BizExcelRel { this.orderNo = orderNo; } + public BizExcelRel(String excelName, String field, int orderNo, boolean isPicture) { + this.excelName = excelName; + this.field = field; + this.orderNo = orderNo; + this.isPicture = isPicture; + } + public BizExcelRel(String excelName, String field, boolean isEnum, String lookupCode, int orderNo) { this.excelName = excelName; this.field = field; @@ -50,6 +57,19 @@ public class BizExcelRel { */ private int orderNo = 0; + /** + * 是否是图片 + */ + private boolean isPicture = false; + + public boolean isPicture() { + return isPicture; + } + + public void setPicture(boolean picture) { + isPicture = picture; + } + public String getExcelName() { return excelName; } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/ExcelTableProcessor.java b/src/main/java/com/ibiz/excel/picture/support/model/ExcelTableProcessor.java new file mode 100644 index 0000000..74af0e8 --- /dev/null +++ b/src/main/java/com/ibiz/excel/picture/support/model/ExcelTableProcessor.java @@ -0,0 +1,97 @@ +package com.ibiz.excel.picture.support.model; + +import cn.hutool.core.bean.BeanUtil; +import com.ibiz.excel.picture.support.constants.WorkbookConstant; +import com.ibiz.excel.picture.support.util.StringUtils; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; + +/** + * @author MinWeikai + * @date 2022/2/9 11:22 + */ +public class ExcelTableProcessor { + + public ExcelTableProcessor(Sheet sheet) { + this.sheet = sheet; + } + + public static ExcelTableProcessor build(Sheet sheet) { + return new ExcelTableProcessor(sheet); + } + + /** + * 行高 + */ + private int rowHeight = WorkbookConstant.PICTURE_ROW_HEIGHT; + + private final Sheet sheet; + + /** + * 标题样式 + */ + private CellStyle titleCellStyle; + + /** + * 开始行号 + */ + private int startRow = 0; + + /** + * 构建excel + * + * @param excels excel属性配置 + * @param list 需要导出的集合对象 该对象必须实现接口{@link BizExcelPojoInterface} + */ + public void buildExcel(List excels, List list) { + // 开始行放标题 + Row row = sheet.createRow(startRow).setCellStyle(titleCellStyle); + List cells = new ArrayList<>(); + for (int i = 0; i < excels.size(); i++) { + cells.add(new Cell(i).setValue(excels.get(i).getExcelName())); + } + row.autoRowCells(cells); + int num; + List pictures = sheet.getPictures(); + for (int j = 0; j < list.size(); j++) { + // 开始行的下一行放内容 + num = startRow + j + 1; + row = sheet.createRow(num); + cells = new ArrayList<>(); + int index = 0; + BizExcelPojoInterface excelPojoInterface = list.get(j); + excels = excels.stream().sorted(Comparator.comparing(BizExcelRel::getOrderNo)).collect(Collectors.toList()); + for (BizExcelRel excel : excels) { + Object propertyValue = BeanUtil.getFieldValue(excelPojoInterface, excel.getField()); + String value = propertyValue == null ? "" : propertyValue.toString(); + // 是图片 + if (excel.isPicture() && StringUtils.isNotBlank(value)) { + pictures.add(new Picture(row.getRowNumber(), excel.getOrderNo() - 1, WorkbookConstant.PICTURE_WEIGHT, value)); + value = ""; + } + row.setHeight(rowHeight); + cells.add(new Cell(num, index++).setValue(value)); + row.setCells(cells); + + } + } + } + + public ExcelTableProcessor setRowHeight(int rowHeight) { + this.rowHeight = rowHeight; + return this; + } + + public ExcelTableProcessor setTitleCellStyle(CellStyle titleCellStyle) { + this.titleCellStyle = titleCellStyle; + return this; + } + + public ExcelTableProcessor setStartRow(int startRow) { + this.startRow = startRow; + return this; + } +} diff --git a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220208.java b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220208.java index 32074db..18a60ac 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220208.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220208.java @@ -1,6 +1,5 @@ package com.ibiz.excel.picture.support.example; -import cn.hutool.core.bean.BeanUtil; import com.ibiz.excel.picture.support.common.BaseJunitTest; import com.ibiz.excel.picture.support.model.*; import com.ibiz.excel.picture.support.pojo.Student; @@ -8,9 +7,7 @@ import com.ibiz.excel.picture.support.util.WebUtil; import org.junit.Test; import java.util.ArrayList; -import java.util.Comparator; import java.util.List; -import java.util.stream.Collectors; /** * @author MinWeikai @@ -23,6 +20,7 @@ public class ExportExample_20220208 extends BaseJunitTest { List students = new ArrayList<>(); students.add(new Student("李四", 16)); students.add(new Student("张三", 17)); + students.add(new Student("王五", 15, IMG_PATH_1)); Workbook workBook = Workbook.getInstance(100); Sheet sheet = workBook.createSheet("测试"); @@ -30,44 +28,14 @@ public class ExportExample_20220208 extends BaseJunitTest { List excels = new ArrayList<>(); excels.add(new BizExcelRel("姓名", "name", 1)); excels.add(new BizExcelRel("年龄", "age", 2)); - - - buildExcel(sheet, excels, students); + excels.add(new BizExcelRel("头像", "headPicture", 3, true)); + CellStyle cellStyle = new CellStyle("F0F0F0"); + ExcelTableProcessor.build(sheet) + .setTitleCellStyle(cellStyle) + .buildExcel(excels, students); WebUtil.writeExcelTest(workBook, "ExportExample_20220208_".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), TEMP_PATH); } - /** - * 构建excel - * - * @param sheet excel - * @param excels excel属性配置 - * @param list 需要导出的集合对象 - */ - private static void buildExcel(Sheet sheet, List excels, List list) { - // 开始行放标题 - int startRow = 0; - Row row = sheet.createRow(startRow); - List cells = new ArrayList<>(); - for (int i = 0; i < excels.size(); i++) { - cells.add(new Cell(i).setValue(excels.get(i).getExcelName())); - } - row.autoRowCells(cells); - int num; - List pictures = sheet.getPictures(); - for (int j = 0; j < list.size(); j++) { - // 开始行的下一行放内容 - num = j + 1; - row = sheet.createRow(num); - cells = new ArrayList<>(); - int index = 0; - BizExcelPojoInterface excelPojoInterface = list.get(j); - excels = excels.stream().sorted(Comparator.comparing(BizExcelRel::getOrderNo)).collect(Collectors.toList()); - for (BizExcelRel excel : excels) { - Object propertyValue = BeanUtil.getFieldValue(excelPojoInterface, excel.getField()); - cells.add(new Cell(num, index++).setValue(propertyValue == null ? "" : propertyValue.toString())); - row.setCells(cells); - } - } - } + } diff --git a/src/test/java/com/ibiz/excel/picture/support/pojo/Student.java b/src/test/java/com/ibiz/excel/picture/support/pojo/Student.java index 38c9ff3..fb48240 100644 --- a/src/test/java/com/ibiz/excel/picture/support/pojo/Student.java +++ b/src/test/java/com/ibiz/excel/picture/support/pojo/Student.java @@ -13,10 +13,26 @@ public class Student implements BizExcelPojoInterface { this.age = age; } + public Student(String name, Integer age, String headPicture) { + this.name = name; + this.age = age; + this.headPicture = headPicture; + } + private String name; private Integer age; + private String headPicture; + + public String getHeadPicture() { + return headPicture; + } + + public void setHeadPicture(String headPicture) { + this.headPicture = headPicture; + } + public String getName() { return name; } -- Gitee From 9cc67666d4ffd4b3b4120a4d7a33d010fe3f6491 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Thu, 10 Feb 2022 13:51:37 +0800 Subject: [PATCH 110/161] =?UTF-8?q?add=20=E5=8A=A8=E6=80=81=E6=A0=87?= =?UTF-8?q?=E9=A2=98=E5=AF=BC=E5=87=BA=E5=8F=AF=E8=B0=83=E5=8D=95=E5=85=83?= =?UTF-8?q?=E6=A0=BC=E5=AE=BD=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../picture/support/model/BizExcelRel.java | 21 ++++++++ .../support/model/ExcelTableProcessor.java | 53 ++++++++++++++----- .../example/ExportExample_20220208.java | 7 +-- 3 files changed, 65 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/ibiz/excel/picture/support/model/BizExcelRel.java b/src/main/java/com/ibiz/excel/picture/support/model/BizExcelRel.java index a8a7bb6..cd98a45 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/BizExcelRel.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/BizExcelRel.java @@ -24,6 +24,14 @@ public class BizExcelRel { this.isPicture = isPicture; } + public BizExcelRel(String excelName, String field, int orderNo, boolean isPicture, double cellWeight) { + this.excelName = excelName; + this.field = field; + this.orderNo = orderNo; + this.isPicture = isPicture; + this.cellWeight = cellWeight; + } + public BizExcelRel(String excelName, String field, boolean isEnum, String lookupCode, int orderNo) { this.excelName = excelName; this.field = field; @@ -62,6 +70,11 @@ public class BizExcelRel { */ private boolean isPicture = false; + /** + * 单元格宽度 + */ + private double cellWeight = -1; + public boolean isPicture() { return isPicture; } @@ -109,4 +122,12 @@ public class BizExcelRel { public void setOrderNo(int orderNo) { this.orderNo = orderNo; } + + public double getCellWeight() { + return cellWeight; + } + + public void setCellWeight(double cellWeight) { + this.cellWeight = cellWeight; + } } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/ExcelTableProcessor.java b/src/main/java/com/ibiz/excel/picture/support/model/ExcelTableProcessor.java index 74af0e8..fe70aa2 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/ExcelTableProcessor.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/ExcelTableProcessor.java @@ -4,9 +4,7 @@ import cn.hutool.core.bean.BeanUtil; import com.ibiz.excel.picture.support.constants.WorkbookConstant; import com.ibiz.excel.picture.support.util.StringUtils; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; +import java.util.*; import java.util.stream.Collectors; /** @@ -31,14 +29,14 @@ public class ExcelTableProcessor { private final Sheet sheet; /** - * 标题样式 + * 开始行号 */ - private CellStyle titleCellStyle; + private int startRow = 0; /** - * 开始行号 + * 样式 */ - private int startRow = 0; + private final Map cellStyleMap = new HashMap<>(); /** * 构建excel @@ -48,10 +46,13 @@ public class ExcelTableProcessor { */ public void buildExcel(List excels, List list) { // 开始行放标题 - Row row = sheet.createRow(startRow).setCellStyle(titleCellStyle); + Row row = sheet.createRow(startRow).setCellStyle(cellStyleMap.get(startRow)); List cells = new ArrayList<>(); for (int i = 0; i < excels.size(); i++) { - cells.add(new Cell(i).setValue(excels.get(i).getExcelName())); + BizExcelRel rel = excels.get(i); + cells.add(new Cell(i).setValue(rel.getExcelName())); + // 设置单元格宽度 + sheet.setColumnWidth(rel.getOrderNo(), rel.getCellWeight()); } row.autoRowCells(cells); int num; @@ -59,7 +60,7 @@ public class ExcelTableProcessor { for (int j = 0; j < list.size(); j++) { // 开始行的下一行放内容 num = startRow + j + 1; - row = sheet.createRow(num); + row = sheet.createRow(num).setCellStyle(cellStyleMap.get(num)); cells = new ArrayList<>(); int index = 0; BizExcelPojoInterface excelPojoInterface = list.get(j); @@ -75,21 +76,47 @@ public class ExcelTableProcessor { row.setHeight(rowHeight); cells.add(new Cell(num, index++).setValue(value)); row.setCells(cells); - } + } } + /** + * 设置行高 + * + * @param rowHeight + * @return + */ public ExcelTableProcessor setRowHeight(int rowHeight) { this.rowHeight = rowHeight; return this; } - public ExcelTableProcessor setTitleCellStyle(CellStyle titleCellStyle) { - this.titleCellStyle = titleCellStyle; + /** + * 批量添加样式 + * + * @param cellStyles + */ + public void addCellStyle(List cellStyles) { + cellStyles.forEach(cellStyle-> this.cellStyleMap.put(cellStyle.getRowNumber(), cellStyle)); + } + + /** + * 添加样式 + * @param cellStyle + * @return + */ + public ExcelTableProcessor addCellStyle(CellStyle cellStyle) { + this.cellStyleMap.put(cellStyle.getRowNumber(), cellStyle); return this; } + /** + * 设置写入数据开始行号 + * + * @param startRow + * @return + */ public ExcelTableProcessor setStartRow(int startRow) { this.startRow = startRow; return this; diff --git a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220208.java b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220208.java index 18a60ac..1195085 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220208.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220208.java @@ -28,10 +28,11 @@ public class ExportExample_20220208 extends BaseJunitTest { List excels = new ArrayList<>(); excels.add(new BizExcelRel("姓名", "name", 1)); excels.add(new BizExcelRel("年龄", "age", 2)); - excels.add(new BizExcelRel("头像", "headPicture", 3, true)); - CellStyle cellStyle = new CellStyle("F0F0F0"); + excels.add(new BizExcelRel("头像", "headPicture", 3, true, 20)); + CellStyle cellStyle = new CellStyle(0,"F0F0F0"); + ExcelTableProcessor.build(sheet) - .setTitleCellStyle(cellStyle) + .addCellStyle(cellStyle) .buildExcel(excels, students); WebUtil.writeExcelTest(workBook, "ExportExample_20220208_".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), TEMP_PATH); -- Gitee From c1fb0f22c12ad71f70cee26571177d1d21605e75 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Fri, 11 Feb 2022 14:21:02 +0800 Subject: [PATCH 111/161] =?UTF-8?q?add=20=E6=B7=BB=E5=8A=A0=E5=9B=BE?= =?UTF-8?q?=E7=89=87=E5=A4=84=E7=90=86=E5=99=A8=E6=8E=A7=E5=88=B6=E5=A4=9A?= =?UTF-8?q?=E5=9B=BE=E7=89=87=E6=97=B6=E5=8D=95=E5=85=83=E6=A0=BC=E5=AE=BD?= =?UTF-8?q?=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../excel/picture/support/model/Sheet.java | 3 +- .../ExcelTableProcessor.java | 19 +-- .../support/processor/PictureProcessor.java | 114 ++++++++++++++++++ .../example/ExportExample_20220208.java | 8 +- .../excel/picture/support/pojo/Student.java | 21 ++++ 5 files changed, 156 insertions(+), 9 deletions(-) rename src/main/java/com/ibiz/excel/picture/support/{model => processor}/ExcelTableProcessor.java (80%) create mode 100644 src/main/java/com/ibiz/excel/picture/support/processor/PictureProcessor.java diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java index e76e6b5..6344b25 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java @@ -12,6 +12,7 @@ import com.ibiz.excel.picture.support.listener.CloseListener; import com.ibiz.excel.picture.support.listener.ContentListener; import com.ibiz.excel.picture.support.listener.FlushListener; import com.ibiz.excel.picture.support.listener.InitListener; +import com.ibiz.excel.picture.support.processor.PictureProcessor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.util.CollectionUtils; @@ -317,7 +318,7 @@ public class Sheet { // 不是标题 并且 是图片 并且 值不为空 if (isPicture && value != null) { // 添加图片 - this.addPictures(row, cell.getCellNumber(), value, model); + PictureProcessor.build(Sheet.this).addPictures(row, cell.getCellNumber(), value, model); } else { cell.setValue(value == null ? "" : String.valueOf(value)); } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/ExcelTableProcessor.java b/src/main/java/com/ibiz/excel/picture/support/processor/ExcelTableProcessor.java similarity index 80% rename from src/main/java/com/ibiz/excel/picture/support/model/ExcelTableProcessor.java rename to src/main/java/com/ibiz/excel/picture/support/processor/ExcelTableProcessor.java index fe70aa2..a8dfd4e 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/ExcelTableProcessor.java +++ b/src/main/java/com/ibiz/excel/picture/support/processor/ExcelTableProcessor.java @@ -1,8 +1,8 @@ -package com.ibiz.excel.picture.support.model; +package com.ibiz.excel.picture.support.processor; import cn.hutool.core.bean.BeanUtil; import com.ibiz.excel.picture.support.constants.WorkbookConstant; -import com.ibiz.excel.picture.support.util.StringUtils; +import com.ibiz.excel.picture.support.model.*; import java.util.*; import java.util.stream.Collectors; @@ -41,7 +41,7 @@ public class ExcelTableProcessor { /** * 构建excel * - * @param excels excel属性配置 + * @param excels excel属性配置,会根据excels中的field属性反射取出list中的值 * @param list 需要导出的集合对象 该对象必须实现接口{@link BizExcelPojoInterface} */ public void buildExcel(List excels, List list) { @@ -67,11 +67,15 @@ public class ExcelTableProcessor { excels = excels.stream().sorted(Comparator.comparing(BizExcelRel::getOrderNo)).collect(Collectors.toList()); for (BizExcelRel excel : excels) { Object propertyValue = BeanUtil.getFieldValue(excelPojoInterface, excel.getField()); - String value = propertyValue == null ? "" : propertyValue.toString(); + String value; // 是图片 - if (excel.isPicture() && StringUtils.isNotBlank(value)) { - pictures.add(new Picture(row.getRowNumber(), excel.getOrderNo() - 1, WorkbookConstant.PICTURE_WEIGHT, value)); + if (excel.isPicture() && Objects.nonNull(propertyValue)) { + // 添加图片 + PictureProcessor.build(sheet).addPictures(row, excel.getOrderNo() - 1, propertyValue, + 0, WorkbookConstant.PICTURE_WEIGHT, WorkbookConstant.PICTURE_HEIGHT); value = ""; + } else { + value = propertyValue == null ? "" : propertyValue.toString(); } row.setHeight(rowHeight); cells.add(new Cell(num, index++).setValue(value)); @@ -98,11 +102,12 @@ public class ExcelTableProcessor { * @param cellStyles */ public void addCellStyle(List cellStyles) { - cellStyles.forEach(cellStyle-> this.cellStyleMap.put(cellStyle.getRowNumber(), cellStyle)); + cellStyles.forEach(cellStyle -> this.cellStyleMap.put(cellStyle.getRowNumber(), cellStyle)); } /** * 添加样式 + * * @param cellStyle * @return */ diff --git a/src/main/java/com/ibiz/excel/picture/support/processor/PictureProcessor.java b/src/main/java/com/ibiz/excel/picture/support/processor/PictureProcessor.java new file mode 100644 index 0000000..b341f91 --- /dev/null +++ b/src/main/java/com/ibiz/excel/picture/support/processor/PictureProcessor.java @@ -0,0 +1,114 @@ +package com.ibiz.excel.picture.support.processor; + +import com.ibiz.excel.picture.support.annotation.ExportModel; +import com.ibiz.excel.picture.support.model.Picture; +import com.ibiz.excel.picture.support.model.Row; +import com.ibiz.excel.picture.support.model.Sheet; + +import java.util.ArrayList; +import java.util.List; + +/** + * excel中图片处理器 + * + * @author MinWeikai + * @date 2022/2/11 13:55 + */ +public class PictureProcessor { + + public PictureProcessor(Sheet sheet) { + this.sheet = sheet; + } + + public static PictureProcessor build(Sheet sheet) { + return new PictureProcessor(sheet); + } + + private final Sheet sheet; + + /** + * 添加图片 + * + * @param row + * @param cellNumber + * @param value + * @param model + */ + public void addPictures(Row row, int cellNumber, Object value, ExportModel model) { + // 图片所在单元格宽度,图片和单元格宽度一致 + int width = model.width(); + // 图片所在单元格行高度 + int height = model.height(); + addPictures(row, cellNumber, value, model.pictureSource(), width, height); + } + + /** + * 添加图片 + * + * @param row + * @param cellNumber + * @param value + * @param pictureSource + * @param width + * @param height + */ + public void addPictures(Row row, int cellNumber, Object value, int pictureSource, int width, int height) { + List values = getValues(value); + // 计算行高 + calculateRowHeight(row, height); + // 计算单元格宽度根据单元格中值的数量 + calculateColumnWidth(cellNumber, width, values.size()); + //增加图片 + values.forEach(val -> + sheet.getPictures().add( + new Picture(row.getRowNumber(), cellNumber, width, height, val, pictureSource) + // 自动设置图片来源 + .autoPictureSourceByPath() + )); + } + + /** + * 获取value集合 + * + * @param value + * @return + */ + private List getValues(Object value) { + List values = new ArrayList<>(); + if (value instanceof List) { + values = (List) value; + } else { + values.add(String.valueOf(value)); + } + return values; + } + + /** + * 计算行高 + * + * @param row + * @param height + */ + private void calculateRowHeight(Row row, int height) { + // 设置行高自适应于图片的高度 + row.setHeight((height / 12600) - 1); + } + + /** + * 计算单元格宽度根据单元格中值的数量 + * + * @param cellNumber + * @param width + * @param valuesSize 图片数 + */ + private void calculateColumnWidth(int cellNumber, int width, int valuesSize) { + // 实际宽 + int actualWidth = width / 76923; + // + // 数组为空时,给默认值1,否则单元格宽度会被计算成0 + valuesSize = valuesSize == 0 ? 1 : valuesSize; + // 设置单元格宽度,单元格宽度 = 图片宽*图片数量 + double columnWidth = actualWidth * valuesSize + valuesSize / 1.5; + sheet.setColumnWidth(cellNumber + 1, columnWidth); + } +} diff --git a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220208.java b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220208.java index 1195085..80868fb 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220208.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220208.java @@ -3,6 +3,7 @@ package com.ibiz.excel.picture.support.example; import com.ibiz.excel.picture.support.common.BaseJunitTest; import com.ibiz.excel.picture.support.model.*; import com.ibiz.excel.picture.support.pojo.Student; +import com.ibiz.excel.picture.support.processor.ExcelTableProcessor; import com.ibiz.excel.picture.support.util.WebUtil; import org.junit.Test; @@ -19,7 +20,7 @@ public class ExportExample_20220208 extends BaseJunitTest { public void export() { List students = new ArrayList<>(); students.add(new Student("李四", 16)); - students.add(new Student("张三", 17)); + students.add(new Student("张三", 17, getPictures(5))); students.add(new Student("王五", 15, IMG_PATH_1)); Workbook workBook = Workbook.getInstance(100); @@ -29,10 +30,15 @@ public class ExportExample_20220208 extends BaseJunitTest { excels.add(new BizExcelRel("姓名", "name", 1)); excels.add(new BizExcelRel("年龄", "age", 2)); excels.add(new BizExcelRel("头像", "headPicture", 3, true, 20)); + excels.add(new BizExcelRel("相册", "album", 4, true)); + // 样式 CellStyle cellStyle = new CellStyle(0,"F0F0F0"); + // 构建sheet ExcelTableProcessor.build(sheet) + // 添加样式 .addCellStyle(cellStyle) + // 构建excel .buildExcel(excels, students); WebUtil.writeExcelTest(workBook, "ExportExample_20220208_".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), TEMP_PATH); diff --git a/src/test/java/com/ibiz/excel/picture/support/pojo/Student.java b/src/test/java/com/ibiz/excel/picture/support/pojo/Student.java index fb48240..f0da995 100644 --- a/src/test/java/com/ibiz/excel/picture/support/pojo/Student.java +++ b/src/test/java/com/ibiz/excel/picture/support/pojo/Student.java @@ -2,6 +2,8 @@ package com.ibiz.excel.picture.support.pojo; import com.ibiz.excel.picture.support.model.BizExcelPojoInterface; +import java.util.List; + /** * @author MinWeikai * @date 2022/2/9 9:21 @@ -19,12 +21,31 @@ public class Student implements BizExcelPojoInterface { this.headPicture = headPicture; } + public Student(String name, Integer age, List album) { + this.name = name; + this.age = age; + this.album = album; + } + private String name; private Integer age; private String headPicture; + /** + * 相册 + */ + private List album; + + public List getAlbum() { + return album; + } + + public void setAlbum(List album) { + this.album = album; + } + public String getHeadPicture() { return headPicture; } -- Gitee From adbe468890adaabe039750eff18b455331603045 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Fri, 11 Feb 2022 14:23:13 +0800 Subject: [PATCH 112/161] =?UTF-8?q?update=20=E5=B0=81=E8=A3=85excel?= =?UTF-8?q?=E4=B8=AD=E6=B7=BB=E5=8A=A0=E5=9B=BE=E7=89=87=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../excel/picture/support/model/Sheet.java | 65 ------------------- 1 file changed, 65 deletions(-) diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java index 6344b25..8ff9148 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java @@ -331,71 +331,6 @@ public class Sheet { return row; } - /** - * 添加图片 - * @param row - * @param cellNumber - * @param value - * @param model - */ - private void addPictures(Row row, int cellNumber, Object value, ExportModel model) { - // 图片所在单元格宽度,图片和单元格宽度一致 - int width = model.width(); - // 图片所在单元格行高度 - int height = model.height(); - List values = getValues(value); - // 计算行高 - calculateRowHeight(row, height); - // 计算单元格宽度根据单元格中值的数量 - calculateColumnWidth(cellNumber, width, values.size()); - //增加图片 - values.forEach(val -> - pictures.add( - new Picture(row.getRowNumber(), cellNumber, width, height, val, model.pictureSource()) - // 自动设置图片来源 - .autoPictureSourceByPath() - )); - } - - private List getValues(Object value) { - List values = new ArrayList<>(); - if (value instanceof List) { - values = (List) value; - } else { - values.add(String.valueOf(value)); - } - return values; - } - - /** - * 计算行高 - * - * @param row - * @param height - */ - private void calculateRowHeight(Row row, int height) { - // 设置行高自适应于图片的高度 - row.setHeight((height / 12600) - 1); - } - - /** - * 计算单元格宽度根据单元格中值的数量 - * - * @param cellNumber - * @param width - * @param valuesSize 图片数 - */ - private void calculateColumnWidth(int cellNumber, int width, int valuesSize) { - // 实际宽 - int actualWidth = width / 76923; - // - // 数组为空时,给默认值1,否则单元格宽度会被计算成0 - valuesSize = valuesSize == 0 ? 1 : valuesSize; - // 设置单元格宽度,单元格宽度 = 图片宽*图片数量 - double columnWidth = actualWidth * valuesSize + valuesSize / 1.5; - setColumnWidth(cellNumber + 1, columnWidth); - } - Row createRow(T t) { if (!hasWriteHead) { createRowAndCellStyle(t, true); -- Gitee From 6e2a722afac11e76d56a594ec1fc376783aa3f81 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Fri, 11 Feb 2022 15:28:36 +0800 Subject: [PATCH 113/161] =?UTF-8?q?add=20ExcelTableProcessor=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E6=95=B0=E6=8D=AE=E5=AD=97=E5=85=B8=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../picture/support/model/BizExcelRel.java | 34 ----------- .../processor/ExcelTableProcessor.java | 59 +++++++++++++++++-- .../example/ExportExample_20220208.java | 33 ++++++++--- .../excel/picture/support/pojo/Student.java | 17 +++++- 4 files changed, 95 insertions(+), 48 deletions(-) diff --git a/src/main/java/com/ibiz/excel/picture/support/model/BizExcelRel.java b/src/main/java/com/ibiz/excel/picture/support/model/BizExcelRel.java index cd98a45..8a29464 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/BizExcelRel.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/BizExcelRel.java @@ -32,14 +32,6 @@ public class BizExcelRel { this.cellWeight = cellWeight; } - public BizExcelRel(String excelName, String field, boolean isEnum, String lookupCode, int orderNo) { - this.excelName = excelName; - this.field = field; - this.isEnum = isEnum; - this.lookupCode = lookupCode; - this.orderNo = orderNo; - } - /** * excel显示的字段名称 */ @@ -50,16 +42,6 @@ public class BizExcelRel { */ private String field; - /** - * 是否是枚举 - */ - private boolean isEnum = false; - - /** - * 数据字典code - */ - private String lookupCode; - /** * 排序 */ @@ -99,22 +81,6 @@ public class BizExcelRel { this.field = field; } - public boolean isEnum() { - return isEnum; - } - - public void setEnum(boolean anEnum) { - isEnum = anEnum; - } - - public String getLookupCode() { - return lookupCode; - } - - public void setLookupCode(String lookupCode) { - this.lookupCode = lookupCode; - } - public int getOrderNo() { return orderNo; } diff --git a/src/main/java/com/ibiz/excel/picture/support/processor/ExcelTableProcessor.java b/src/main/java/com/ibiz/excel/picture/support/processor/ExcelTableProcessor.java index a8dfd4e..8d06f27 100644 --- a/src/main/java/com/ibiz/excel/picture/support/processor/ExcelTableProcessor.java +++ b/src/main/java/com/ibiz/excel/picture/support/processor/ExcelTableProcessor.java @@ -1,6 +1,7 @@ package com.ibiz.excel.picture.support.processor; import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.map.MapUtil; import com.ibiz.excel.picture.support.constants.WorkbookConstant; import com.ibiz.excel.picture.support.model.*; @@ -33,11 +34,22 @@ public class ExcelTableProcessor { */ private int startRow = 0; + /** + * 开始单元格 + */ + private int startCell = 0; + /** * 样式 */ private final Map cellStyleMap = new HashMap<>(); + /** + * key : 对象的field属性名称 + * value : 此属性value相关的数据字典 + */ + private Map> fieldEnumMap = new HashMap<>(); + /** * 构建excel * @@ -48,7 +60,7 @@ public class ExcelTableProcessor { // 开始行放标题 Row row = sheet.createRow(startRow).setCellStyle(cellStyleMap.get(startRow)); List cells = new ArrayList<>(); - for (int i = 0; i < excels.size(); i++) { + for (int i = startCell; i < excels.size(); i++) { BizExcelRel rel = excels.get(i); cells.add(new Cell(i).setValue(rel.getExcelName())); // 设置单元格宽度 @@ -56,13 +68,12 @@ public class ExcelTableProcessor { } row.autoRowCells(cells); int num; - List pictures = sheet.getPictures(); for (int j = 0; j < list.size(); j++) { // 开始行的下一行放内容 num = startRow + j + 1; row = sheet.createRow(num).setCellStyle(cellStyleMap.get(num)); cells = new ArrayList<>(); - int index = 0; + int index = startCell; BizExcelPojoInterface excelPojoInterface = list.get(j); excels = excels.stream().sorted(Comparator.comparing(BizExcelRel::getOrderNo)).collect(Collectors.toList()); for (BizExcelRel excel : excels) { @@ -71,13 +82,15 @@ public class ExcelTableProcessor { // 是图片 if (excel.isPicture() && Objects.nonNull(propertyValue)) { // 添加图片 - PictureProcessor.build(sheet).addPictures(row, excel.getOrderNo() - 1, propertyValue, + PictureProcessor.build(sheet).addPictures(row, index, propertyValue, 0, WorkbookConstant.PICTURE_WEIGHT, WorkbookConstant.PICTURE_HEIGHT); value = ""; } else { value = propertyValue == null ? "" : propertyValue.toString(); } row.setHeight(rowHeight); + // 数据字典值获取 + value = getValueByFiledEnumMap(excel.getField(), value); cells.add(new Cell(num, index++).setValue(value)); row.setCells(cells); } @@ -85,6 +98,21 @@ public class ExcelTableProcessor { } } + /** + * 数据字典值获取 + * + * @param field + * @param value + * @return + */ + private String getValueByFiledEnumMap(String field, String value) { + Map enumMap = fieldEnumMap.get(field); + if (MapUtil.isNotEmpty(enumMap)) { + return enumMap.get(value); + } + return value; + } + /** * 设置行高 * @@ -126,4 +154,27 @@ public class ExcelTableProcessor { this.startRow = startRow; return this; } + + /** + * 设置写入数据开始单元格 + * + * @param startCell + * @return + */ + public ExcelTableProcessor setStartCell(int startCell) { + this.startCell = startCell; + return this; + } + + /** + * 注入属性字典值 + * + * @param field 属性名 + * @param enumMap 数据字典值 + * @return + */ + public ExcelTableProcessor registryEnumMap(String field, Map enumMap) { + fieldEnumMap.put(field, enumMap); + return this; + } } diff --git a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220208.java b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220208.java index 80868fb..7919e76 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220208.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220208.java @@ -1,16 +1,23 @@ package com.ibiz.excel.picture.support.example; import com.ibiz.excel.picture.support.common.BaseJunitTest; -import com.ibiz.excel.picture.support.model.*; +import com.ibiz.excel.picture.support.model.BizExcelRel; +import com.ibiz.excel.picture.support.model.CellStyle; +import com.ibiz.excel.picture.support.model.Sheet; +import com.ibiz.excel.picture.support.model.Workbook; import com.ibiz.excel.picture.support.pojo.Student; import com.ibiz.excel.picture.support.processor.ExcelTableProcessor; import com.ibiz.excel.picture.support.util.WebUtil; import org.junit.Test; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** + * 动态标题excel导出 + * * @author MinWeikai * @date 2022/2/8 14:49 */ @@ -19,25 +26,33 @@ public class ExportExample_20220208 extends BaseJunitTest { @Test public void export() { List students = new ArrayList<>(); - students.add(new Student("李四", 16)); - students.add(new Student("张三", 17, getPictures(5))); - students.add(new Student("王五", 15, IMG_PATH_1)); + students.add(new Student("李四", 16, null, null, 0)); + students.add(new Student("张三", 17, null, getPictures(5), 1)); + students.add(new Student("王五", 15, IMG_PATH_1, null, 2)); Workbook workBook = Workbook.getInstance(100); Sheet sheet = workBook.createSheet("测试"); List excels = new ArrayList<>(); - excels.add(new BizExcelRel("姓名", "name", 1)); - excels.add(new BizExcelRel("年龄", "age", 2)); - excels.add(new BizExcelRel("头像", "headPicture", 3, true, 20)); - excels.add(new BizExcelRel("相册", "album", 4, true)); + excels.add(new BizExcelRel("姓名", "name", 2)); + excels.add(new BizExcelRel("年龄", "age", 3)); + excels.add(new BizExcelRel("表现", "performance", 4)); + excels.add(new BizExcelRel("头像", "headPicture", 5, true, 20)); + excels.add(new BizExcelRel("相册", "album", 6, true)); // 样式 - CellStyle cellStyle = new CellStyle(0,"F0F0F0"); + CellStyle cellStyle = new CellStyle(0, "F0F0F0"); + + Map performanceMap = new HashMap<>(); + performanceMap.put("0", "一般"); + performanceMap.put("1", "良好"); + performanceMap.put("2", "优秀"); // 构建sheet ExcelTableProcessor.build(sheet) // 添加样式 .addCellStyle(cellStyle) + // 添加数据字典 + .registryEnumMap("performance", performanceMap) // 构建excel .buildExcel(excels, students); diff --git a/src/test/java/com/ibiz/excel/picture/support/pojo/Student.java b/src/test/java/com/ibiz/excel/picture/support/pojo/Student.java index f0da995..a5468ca 100644 --- a/src/test/java/com/ibiz/excel/picture/support/pojo/Student.java +++ b/src/test/java/com/ibiz/excel/picture/support/pojo/Student.java @@ -21,10 +21,12 @@ public class Student implements BizExcelPojoInterface { this.headPicture = headPicture; } - public Student(String name, Integer age, List album) { + public Student(String name, Integer age, String headPicture, List album, Integer performance) { this.name = name; this.age = age; + this.headPicture = headPicture; this.album = album; + this.performance = performance; } private String name; @@ -38,6 +40,19 @@ public class Student implements BizExcelPojoInterface { */ private List album; + /** + * 表现 0一般;1良好;2优秀 + */ + private Integer performance; + + public Integer getPerformance() { + return performance; + } + + public void setPerformance(Integer performance) { + this.performance = performance; + } + public List getAlbum() { return album; } -- Gitee From c52bbd79bc3fbda3da26c297a9a64e37fadfa1f8 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Wed, 9 Feb 2022 10:06:57 +0800 Subject: [PATCH 114/161] =?UTF-8?q?add=20=E5=8A=A8=E6=80=81=E6=A0=87?= =?UTF-8?q?=E9=A2=98=E5=AF=BC=E5=87=BA=E6=B5=8B=E8=AF=95=E4=BD=BF=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../support/model/BizExcelPojoInterface.java | 11 +++ .../picture/support/model/BizExcelRel.java | 92 +++++++++++++++++++ .../excel/picture/support/util/BeanUtil.java | 87 ++++++++++++++++++ .../com/ibiz/excel/picture/support/Demo.java | 1 + .../AnnotationPictureExportExample.java | 2 +- .../AnnotationPicturesExportExample.java | 2 +- .../example/AnnotationTextExportExample.java | 2 +- .../example/ExportExample_20220110.java | 2 +- .../example/ExportExample_20220127.java | 2 +- .../example/ExportExample_20220128.java | 2 +- .../example/ExportExample_20220208.java | 73 +++++++++++++++ .../excel/picture/support/pojo/Student.java | 35 +++++++ .../picture/support/{ => pojo}/User.java | 2 +- .../support/{ => pojo}/UserPicture.java | 2 +- .../SimulateRealBusinessExportExample.java | 2 +- 15 files changed, 308 insertions(+), 9 deletions(-) create mode 100644 src/main/java/com/ibiz/excel/picture/support/model/BizExcelPojoInterface.java create mode 100644 src/main/java/com/ibiz/excel/picture/support/model/BizExcelRel.java create mode 100644 src/main/java/com/ibiz/excel/picture/support/util/BeanUtil.java create mode 100644 src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220208.java create mode 100644 src/test/java/com/ibiz/excel/picture/support/pojo/Student.java rename src/test/java/com/ibiz/excel/picture/support/{ => pojo}/User.java (98%) rename src/test/java/com/ibiz/excel/picture/support/{ => pojo}/UserPicture.java (98%) diff --git a/src/main/java/com/ibiz/excel/picture/support/model/BizExcelPojoInterface.java b/src/main/java/com/ibiz/excel/picture/support/model/BizExcelPojoInterface.java new file mode 100644 index 0000000..cc9c5e2 --- /dev/null +++ b/src/main/java/com/ibiz/excel/picture/support/model/BizExcelPojoInterface.java @@ -0,0 +1,11 @@ +package com.ibiz.excel.picture.support.model; + +/** + * 动态导出pojo接口 + * 目前在动态导出时需要实现该接口 + * + * @author MinWeikai + * @date 2022/2/9 9:45 + */ +public interface BizExcelPojoInterface { +} diff --git a/src/main/java/com/ibiz/excel/picture/support/model/BizExcelRel.java b/src/main/java/com/ibiz/excel/picture/support/model/BizExcelRel.java new file mode 100644 index 0000000..178c470 --- /dev/null +++ b/src/main/java/com/ibiz/excel/picture/support/model/BizExcelRel.java @@ -0,0 +1,92 @@ +package com.ibiz.excel.picture.support.model; + +/** + * Excel导出配置 + * + * @author MinWeikai + * @date 2022/2/8 14:45 + */ +public class BizExcelRel { + + public BizExcelRel() { + } + + public BizExcelRel(String excelName, String field, int orderNo) { + this.excelName = excelName; + this.field = field; + this.orderNo = orderNo; + } + + public BizExcelRel(String excelName, String field, boolean isEnum, String lookupCode, int orderNo) { + this.excelName = excelName; + this.field = field; + this.isEnum = isEnum; + this.lookupCode = lookupCode; + this.orderNo = orderNo; + } + + /** + * excel显示的字段名称 + */ + private String excelName; + + /** + * 字段 + */ + private String field; + + /** + * 是否是枚举 + */ + private boolean isEnum = false; + + /** + * 数据字典code + */ + private String lookupCode; + + /** + * 排序 + */ + private int orderNo = 0; + + public String getExcelName() { + return excelName; + } + + public void setExcelName(String excelName) { + this.excelName = excelName; + } + + public String getField() { + return field; + } + + public void setField(String field) { + this.field = field; + } + + public boolean isEnum() { + return isEnum; + } + + public void setEnum(boolean anEnum) { + isEnum = anEnum; + } + + public String getLookupCode() { + return lookupCode; + } + + public void setLookupCode(String lookupCode) { + this.lookupCode = lookupCode; + } + + public int getOrderNo() { + return orderNo; + } + + public void setOrderNo(int orderNo) { + this.orderNo = orderNo; + } +} diff --git a/src/main/java/com/ibiz/excel/picture/support/util/BeanUtil.java b/src/main/java/com/ibiz/excel/picture/support/util/BeanUtil.java new file mode 100644 index 0000000..2219744 --- /dev/null +++ b/src/main/java/com/ibiz/excel/picture/support/util/BeanUtil.java @@ -0,0 +1,87 @@ +package com.ibiz.excel.picture.support.util; + +import java.beans.PropertyDescriptor; +import java.lang.reflect.InvocationTargetException; +import java.util.Collection; +import java.util.Map; + +/** + * @author MinWeikai + * @date 2022/2/9 9:31 + */ +public class BeanUtil { + + /** + * 反射获取对象属性,支持嵌套 + * 例如: + * User user = new User(); + * Position position = new Position(); + * position.setName("fjjffj"); + * user.setPositionList(Lists.newArrayList(position)); + * Organization organization = new Organization(); + * organization.setName("1111111"); + * user.setOrganization(organization); + * BaseCriteria criteria = new BaseCriteria(); + * Map map = Maps.newHashMap(); + * map.put("bb","aaaaaaaaaaaaaaaa"); + * criteria.setStrValue(map); + * user.setCriteria(criteria); + * Object obj = getPropertyValue(user, "organization.name"); + * System.out.println(obj); + * obj = getPropertyValue(user, "positionList[0].name"); + * System.out.println(obj); + * obj = getPropertyValue(user, "criteria.strValue[bb]"); + * System.out.println(obj); + * @param obj + * @param key + * @return + * @throws InvocationTargetException + * @throws IllegalAccessException + */ + public static Object getPropertyValue(Object obj, String key){ + if (key.contains(".")){ + int dotMarkIndex = key.indexOf("."); + String prefixKey = key.substring(0, dotMarkIndex); + Object prefixObj = getSimplePropertyValue(obj, prefixKey); + String suffixKey = key.substring(dotMarkIndex+1); + return getPropertyValue(prefixObj, suffixKey); + } + return getSimplePropertyValue(obj, key); + } + + private static Object getSimplePropertyValue(Object obj, String key){ + String prefixKey ; + String suffixKey = null; + Object returnValue ; + if(key.matches("(\\w+)\\[(\\w+)\\]$")){ + int endIndex = key.indexOf("["); + prefixKey = key.substring(0, endIndex); + suffixKey = key.substring(endIndex+1, key.length() -1); + }else{ + prefixKey = key; + } + if(obj instanceof Map){ + returnValue = ((Map) obj).get(prefixKey); + }else {// obj instanceof Object + PropertyDescriptor propertyDescriptor = org.springframework.beans.BeanUtils.getPropertyDescriptor(obj.getClass(), prefixKey); + try { + assert propertyDescriptor != null; + returnValue = propertyDescriptor.getReadMethod().invoke(obj); + } catch (InvocationTargetException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + if (StringUtils.isNotBlank(suffixKey)){ + try { + int index = Integer.parseInt(suffixKey);//数字 -->> 数组/集合 + if(returnValue instanceof Collection){//集合转数组 + returnValue = ((Collection) returnValue).toArray(new Object[0]); + } + returnValue = ((Object[])returnValue)[index]; + }catch (NumberFormatException e){//字符串 -->> 对象 + returnValue = getPropertyValue(returnValue, suffixKey); + } + } + return returnValue; + } +} diff --git a/src/test/java/com/ibiz/excel/picture/support/Demo.java b/src/test/java/com/ibiz/excel/picture/support/Demo.java index 17cf8aa..8b35dc9 100644 --- a/src/test/java/com/ibiz/excel/picture/support/Demo.java +++ b/src/test/java/com/ibiz/excel/picture/support/Demo.java @@ -2,6 +2,7 @@ package com.ibiz.excel.picture.support; import com.ibiz.excel.picture.support.model.Sheet; import com.ibiz.excel.picture.support.model.Workbook; +import com.ibiz.excel.picture.support.pojo.User; import java.io.*; import java.util.Date; diff --git a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPictureExportExample.java b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPictureExportExample.java index 6ac17ff..33468d3 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPictureExportExample.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPictureExportExample.java @@ -1,6 +1,6 @@ package com.ibiz.excel.picture.support.example; -import com.ibiz.excel.picture.support.UserPicture; +import com.ibiz.excel.picture.support.pojo.UserPicture; import com.ibiz.excel.picture.support.model.Sheet; import com.ibiz.excel.picture.support.model.Workbook; import com.ibiz.excel.picture.support.util.WebUtil; diff --git a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java index 75c9cae..6498cbf 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java @@ -1,6 +1,6 @@ package com.ibiz.excel.picture.support.example; -import com.ibiz.excel.picture.support.UserPicture; +import com.ibiz.excel.picture.support.pojo.UserPicture; import com.ibiz.excel.picture.support.common.BaseJunitTest; import com.ibiz.excel.picture.support.model.CellStyle; import com.ibiz.excel.picture.support.model.Sheet; diff --git a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationTextExportExample.java b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationTextExportExample.java index 1334e2b..8ca4cce 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/AnnotationTextExportExample.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/AnnotationTextExportExample.java @@ -1,6 +1,6 @@ package com.ibiz.excel.picture.support.example; -import com.ibiz.excel.picture.support.UserPicture; +import com.ibiz.excel.picture.support.pojo.UserPicture; import com.ibiz.excel.picture.support.common.BaseJunitTest; import com.ibiz.excel.picture.support.model.CellStyle; import com.ibiz.excel.picture.support.model.Sheet; diff --git a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220110.java b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220110.java index 88d6d36..410f935 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220110.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220110.java @@ -1,6 +1,6 @@ package com.ibiz.excel.picture.support.example; -import com.ibiz.excel.picture.support.UserPicture; +import com.ibiz.excel.picture.support.pojo.UserPicture; import com.ibiz.excel.picture.support.common.BaseJunitTest; import com.ibiz.excel.picture.support.model.CellStyle; import com.ibiz.excel.picture.support.model.Sheet; diff --git a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220127.java b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220127.java index a57acce..b28f929 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220127.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220127.java @@ -1,6 +1,6 @@ package com.ibiz.excel.picture.support.example; -import com.ibiz.excel.picture.support.UserPicture; +import com.ibiz.excel.picture.support.pojo.UserPicture; import com.ibiz.excel.picture.support.common.BaseJunitTest; import com.ibiz.excel.picture.support.model.CellStyle; import com.ibiz.excel.picture.support.model.Font; diff --git a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220128.java b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220128.java index 9a76487..6331102 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220128.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220128.java @@ -1,6 +1,6 @@ package com.ibiz.excel.picture.support.example; -import com.ibiz.excel.picture.support.UserPicture; +import com.ibiz.excel.picture.support.pojo.UserPicture; import com.ibiz.excel.picture.support.common.BaseJunitTest; import com.ibiz.excel.picture.support.model.*; import com.ibiz.excel.picture.support.util.WebUtil; diff --git a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220208.java b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220208.java new file mode 100644 index 0000000..32074db --- /dev/null +++ b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220208.java @@ -0,0 +1,73 @@ +package com.ibiz.excel.picture.support.example; + +import cn.hutool.core.bean.BeanUtil; +import com.ibiz.excel.picture.support.common.BaseJunitTest; +import com.ibiz.excel.picture.support.model.*; +import com.ibiz.excel.picture.support.pojo.Student; +import com.ibiz.excel.picture.support.util.WebUtil; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; + +/** + * @author MinWeikai + * @date 2022/2/8 14:49 + */ +public class ExportExample_20220208 extends BaseJunitTest { + + @Test + public void export() { + List students = new ArrayList<>(); + students.add(new Student("李四", 16)); + students.add(new Student("张三", 17)); + + Workbook workBook = Workbook.getInstance(100); + Sheet sheet = workBook.createSheet("测试"); + + List excels = new ArrayList<>(); + excels.add(new BizExcelRel("姓名", "name", 1)); + excels.add(new BizExcelRel("年龄", "age", 2)); + + + buildExcel(sheet, excels, students); + + WebUtil.writeExcelTest(workBook, "ExportExample_20220208_".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), TEMP_PATH); + } + + /** + * 构建excel + * + * @param sheet excel + * @param excels excel属性配置 + * @param list 需要导出的集合对象 + */ + private static void buildExcel(Sheet sheet, List excels, List list) { + // 开始行放标题 + int startRow = 0; + Row row = sheet.createRow(startRow); + List cells = new ArrayList<>(); + for (int i = 0; i < excels.size(); i++) { + cells.add(new Cell(i).setValue(excels.get(i).getExcelName())); + } + row.autoRowCells(cells); + int num; + List pictures = sheet.getPictures(); + for (int j = 0; j < list.size(); j++) { + // 开始行的下一行放内容 + num = j + 1; + row = sheet.createRow(num); + cells = new ArrayList<>(); + int index = 0; + BizExcelPojoInterface excelPojoInterface = list.get(j); + excels = excels.stream().sorted(Comparator.comparing(BizExcelRel::getOrderNo)).collect(Collectors.toList()); + for (BizExcelRel excel : excels) { + Object propertyValue = BeanUtil.getFieldValue(excelPojoInterface, excel.getField()); + cells.add(new Cell(num, index++).setValue(propertyValue == null ? "" : propertyValue.toString())); + row.setCells(cells); + } + } + } +} diff --git a/src/test/java/com/ibiz/excel/picture/support/pojo/Student.java b/src/test/java/com/ibiz/excel/picture/support/pojo/Student.java new file mode 100644 index 0000000..38c9ff3 --- /dev/null +++ b/src/test/java/com/ibiz/excel/picture/support/pojo/Student.java @@ -0,0 +1,35 @@ +package com.ibiz.excel.picture.support.pojo; + +import com.ibiz.excel.picture.support.model.BizExcelPojoInterface; + +/** + * @author MinWeikai + * @date 2022/2/9 9:21 + */ +public class Student implements BizExcelPojoInterface { + + public Student(String name, Integer age) { + this.name = name; + this.age = age; + } + + private String name; + + private Integer age; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getAge() { + return age; + } + + public void setAge(Integer age) { + this.age = age; + } +} diff --git a/src/test/java/com/ibiz/excel/picture/support/User.java b/src/test/java/com/ibiz/excel/picture/support/pojo/User.java similarity index 98% rename from src/test/java/com/ibiz/excel/picture/support/User.java rename to src/test/java/com/ibiz/excel/picture/support/pojo/User.java index 3956c77..a1be8a9 100644 --- a/src/test/java/com/ibiz/excel/picture/support/User.java +++ b/src/test/java/com/ibiz/excel/picture/support/pojo/User.java @@ -1,4 +1,4 @@ -package com.ibiz.excel.picture.support; +package com.ibiz.excel.picture.support.pojo; import com.ibiz.excel.picture.support.annotation.ExportModel; diff --git a/src/test/java/com/ibiz/excel/picture/support/UserPicture.java b/src/test/java/com/ibiz/excel/picture/support/pojo/UserPicture.java similarity index 98% rename from src/test/java/com/ibiz/excel/picture/support/UserPicture.java rename to src/test/java/com/ibiz/excel/picture/support/pojo/UserPicture.java index 4febea8..de67a94 100644 --- a/src/test/java/com/ibiz/excel/picture/support/UserPicture.java +++ b/src/test/java/com/ibiz/excel/picture/support/pojo/UserPicture.java @@ -1,4 +1,4 @@ -package com.ibiz.excel.picture.support; +package com.ibiz.excel.picture.support.pojo; import com.ibiz.excel.picture.support.annotation.ExportModel; import com.ibiz.excel.picture.support.constants.PictureSourceContent; diff --git a/src/test/java/com/ibiz/excel/picture/support/simulation/SimulateRealBusinessExportExample.java b/src/test/java/com/ibiz/excel/picture/support/simulation/SimulateRealBusinessExportExample.java index a610f09..8ba154d 100644 --- a/src/test/java/com/ibiz/excel/picture/support/simulation/SimulateRealBusinessExportExample.java +++ b/src/test/java/com/ibiz/excel/picture/support/simulation/SimulateRealBusinessExportExample.java @@ -1,6 +1,6 @@ package com.ibiz.excel.picture.support.simulation; -import com.ibiz.excel.picture.support.UserPicture; +import com.ibiz.excel.picture.support.pojo.UserPicture; import com.ibiz.excel.picture.support.common.BaseJunitTest; import com.ibiz.excel.picture.support.model.CellStyle; import com.ibiz.excel.picture.support.model.Sheet; -- Gitee From d3a8125edeefb271933577b06c85c3dd2ba68790 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Wed, 9 Feb 2022 16:27:11 +0800 Subject: [PATCH 115/161] =?UTF-8?q?add=20=E5=AE=8C=E5=96=84=E5=8A=A8?= =?UTF-8?q?=E6=80=81=E6=A0=87=E9=A2=98=E5=AF=BC=E5=87=BA=E6=96=B9=E6=B3=95?= =?UTF-8?q?=E8=B0=83=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../picture/support/model/BizExcelRel.java | 20 ++++ .../support/model/ExcelTableProcessor.java | 97 +++++++++++++++++++ .../example/ExportExample_20220208.java | 46 ++------- .../excel/picture/support/pojo/Student.java | 16 +++ 4 files changed, 140 insertions(+), 39 deletions(-) create mode 100644 src/main/java/com/ibiz/excel/picture/support/model/ExcelTableProcessor.java diff --git a/src/main/java/com/ibiz/excel/picture/support/model/BizExcelRel.java b/src/main/java/com/ibiz/excel/picture/support/model/BizExcelRel.java index 178c470..a8a7bb6 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/BizExcelRel.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/BizExcelRel.java @@ -17,6 +17,13 @@ public class BizExcelRel { this.orderNo = orderNo; } + public BizExcelRel(String excelName, String field, int orderNo, boolean isPicture) { + this.excelName = excelName; + this.field = field; + this.orderNo = orderNo; + this.isPicture = isPicture; + } + public BizExcelRel(String excelName, String field, boolean isEnum, String lookupCode, int orderNo) { this.excelName = excelName; this.field = field; @@ -50,6 +57,19 @@ public class BizExcelRel { */ private int orderNo = 0; + /** + * 是否是图片 + */ + private boolean isPicture = false; + + public boolean isPicture() { + return isPicture; + } + + public void setPicture(boolean picture) { + isPicture = picture; + } + public String getExcelName() { return excelName; } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/ExcelTableProcessor.java b/src/main/java/com/ibiz/excel/picture/support/model/ExcelTableProcessor.java new file mode 100644 index 0000000..74af0e8 --- /dev/null +++ b/src/main/java/com/ibiz/excel/picture/support/model/ExcelTableProcessor.java @@ -0,0 +1,97 @@ +package com.ibiz.excel.picture.support.model; + +import cn.hutool.core.bean.BeanUtil; +import com.ibiz.excel.picture.support.constants.WorkbookConstant; +import com.ibiz.excel.picture.support.util.StringUtils; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; + +/** + * @author MinWeikai + * @date 2022/2/9 11:22 + */ +public class ExcelTableProcessor { + + public ExcelTableProcessor(Sheet sheet) { + this.sheet = sheet; + } + + public static ExcelTableProcessor build(Sheet sheet) { + return new ExcelTableProcessor(sheet); + } + + /** + * 行高 + */ + private int rowHeight = WorkbookConstant.PICTURE_ROW_HEIGHT; + + private final Sheet sheet; + + /** + * 标题样式 + */ + private CellStyle titleCellStyle; + + /** + * 开始行号 + */ + private int startRow = 0; + + /** + * 构建excel + * + * @param excels excel属性配置 + * @param list 需要导出的集合对象 该对象必须实现接口{@link BizExcelPojoInterface} + */ + public void buildExcel(List excels, List list) { + // 开始行放标题 + Row row = sheet.createRow(startRow).setCellStyle(titleCellStyle); + List cells = new ArrayList<>(); + for (int i = 0; i < excels.size(); i++) { + cells.add(new Cell(i).setValue(excels.get(i).getExcelName())); + } + row.autoRowCells(cells); + int num; + List pictures = sheet.getPictures(); + for (int j = 0; j < list.size(); j++) { + // 开始行的下一行放内容 + num = startRow + j + 1; + row = sheet.createRow(num); + cells = new ArrayList<>(); + int index = 0; + BizExcelPojoInterface excelPojoInterface = list.get(j); + excels = excels.stream().sorted(Comparator.comparing(BizExcelRel::getOrderNo)).collect(Collectors.toList()); + for (BizExcelRel excel : excels) { + Object propertyValue = BeanUtil.getFieldValue(excelPojoInterface, excel.getField()); + String value = propertyValue == null ? "" : propertyValue.toString(); + // 是图片 + if (excel.isPicture() && StringUtils.isNotBlank(value)) { + pictures.add(new Picture(row.getRowNumber(), excel.getOrderNo() - 1, WorkbookConstant.PICTURE_WEIGHT, value)); + value = ""; + } + row.setHeight(rowHeight); + cells.add(new Cell(num, index++).setValue(value)); + row.setCells(cells); + + } + } + } + + public ExcelTableProcessor setRowHeight(int rowHeight) { + this.rowHeight = rowHeight; + return this; + } + + public ExcelTableProcessor setTitleCellStyle(CellStyle titleCellStyle) { + this.titleCellStyle = titleCellStyle; + return this; + } + + public ExcelTableProcessor setStartRow(int startRow) { + this.startRow = startRow; + return this; + } +} diff --git a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220208.java b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220208.java index 32074db..18a60ac 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220208.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220208.java @@ -1,6 +1,5 @@ package com.ibiz.excel.picture.support.example; -import cn.hutool.core.bean.BeanUtil; import com.ibiz.excel.picture.support.common.BaseJunitTest; import com.ibiz.excel.picture.support.model.*; import com.ibiz.excel.picture.support.pojo.Student; @@ -8,9 +7,7 @@ import com.ibiz.excel.picture.support.util.WebUtil; import org.junit.Test; import java.util.ArrayList; -import java.util.Comparator; import java.util.List; -import java.util.stream.Collectors; /** * @author MinWeikai @@ -23,6 +20,7 @@ public class ExportExample_20220208 extends BaseJunitTest { List students = new ArrayList<>(); students.add(new Student("李四", 16)); students.add(new Student("张三", 17)); + students.add(new Student("王五", 15, IMG_PATH_1)); Workbook workBook = Workbook.getInstance(100); Sheet sheet = workBook.createSheet("测试"); @@ -30,44 +28,14 @@ public class ExportExample_20220208 extends BaseJunitTest { List excels = new ArrayList<>(); excels.add(new BizExcelRel("姓名", "name", 1)); excels.add(new BizExcelRel("年龄", "age", 2)); - - - buildExcel(sheet, excels, students); + excels.add(new BizExcelRel("头像", "headPicture", 3, true)); + CellStyle cellStyle = new CellStyle("F0F0F0"); + ExcelTableProcessor.build(sheet) + .setTitleCellStyle(cellStyle) + .buildExcel(excels, students); WebUtil.writeExcelTest(workBook, "ExportExample_20220208_".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), TEMP_PATH); } - /** - * 构建excel - * - * @param sheet excel - * @param excels excel属性配置 - * @param list 需要导出的集合对象 - */ - private static void buildExcel(Sheet sheet, List excels, List list) { - // 开始行放标题 - int startRow = 0; - Row row = sheet.createRow(startRow); - List cells = new ArrayList<>(); - for (int i = 0; i < excels.size(); i++) { - cells.add(new Cell(i).setValue(excels.get(i).getExcelName())); - } - row.autoRowCells(cells); - int num; - List pictures = sheet.getPictures(); - for (int j = 0; j < list.size(); j++) { - // 开始行的下一行放内容 - num = j + 1; - row = sheet.createRow(num); - cells = new ArrayList<>(); - int index = 0; - BizExcelPojoInterface excelPojoInterface = list.get(j); - excels = excels.stream().sorted(Comparator.comparing(BizExcelRel::getOrderNo)).collect(Collectors.toList()); - for (BizExcelRel excel : excels) { - Object propertyValue = BeanUtil.getFieldValue(excelPojoInterface, excel.getField()); - cells.add(new Cell(num, index++).setValue(propertyValue == null ? "" : propertyValue.toString())); - row.setCells(cells); - } - } - } + } diff --git a/src/test/java/com/ibiz/excel/picture/support/pojo/Student.java b/src/test/java/com/ibiz/excel/picture/support/pojo/Student.java index 38c9ff3..fb48240 100644 --- a/src/test/java/com/ibiz/excel/picture/support/pojo/Student.java +++ b/src/test/java/com/ibiz/excel/picture/support/pojo/Student.java @@ -13,10 +13,26 @@ public class Student implements BizExcelPojoInterface { this.age = age; } + public Student(String name, Integer age, String headPicture) { + this.name = name; + this.age = age; + this.headPicture = headPicture; + } + private String name; private Integer age; + private String headPicture; + + public String getHeadPicture() { + return headPicture; + } + + public void setHeadPicture(String headPicture) { + this.headPicture = headPicture; + } + public String getName() { return name; } -- Gitee From 6bce80b71c2e63cc34c7103946008722c51e13e7 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Thu, 10 Feb 2022 13:51:37 +0800 Subject: [PATCH 116/161] =?UTF-8?q?add=20=E5=8A=A8=E6=80=81=E6=A0=87?= =?UTF-8?q?=E9=A2=98=E5=AF=BC=E5=87=BA=E5=8F=AF=E8=B0=83=E5=8D=95=E5=85=83?= =?UTF-8?q?=E6=A0=BC=E5=AE=BD=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../picture/support/model/BizExcelRel.java | 21 ++++++++ .../support/model/ExcelTableProcessor.java | 53 ++++++++++++++----- .../example/ExportExample_20220208.java | 7 +-- 3 files changed, 65 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/ibiz/excel/picture/support/model/BizExcelRel.java b/src/main/java/com/ibiz/excel/picture/support/model/BizExcelRel.java index a8a7bb6..cd98a45 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/BizExcelRel.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/BizExcelRel.java @@ -24,6 +24,14 @@ public class BizExcelRel { this.isPicture = isPicture; } + public BizExcelRel(String excelName, String field, int orderNo, boolean isPicture, double cellWeight) { + this.excelName = excelName; + this.field = field; + this.orderNo = orderNo; + this.isPicture = isPicture; + this.cellWeight = cellWeight; + } + public BizExcelRel(String excelName, String field, boolean isEnum, String lookupCode, int orderNo) { this.excelName = excelName; this.field = field; @@ -62,6 +70,11 @@ public class BizExcelRel { */ private boolean isPicture = false; + /** + * 单元格宽度 + */ + private double cellWeight = -1; + public boolean isPicture() { return isPicture; } @@ -109,4 +122,12 @@ public class BizExcelRel { public void setOrderNo(int orderNo) { this.orderNo = orderNo; } + + public double getCellWeight() { + return cellWeight; + } + + public void setCellWeight(double cellWeight) { + this.cellWeight = cellWeight; + } } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/ExcelTableProcessor.java b/src/main/java/com/ibiz/excel/picture/support/model/ExcelTableProcessor.java index 74af0e8..fe70aa2 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/ExcelTableProcessor.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/ExcelTableProcessor.java @@ -4,9 +4,7 @@ import cn.hutool.core.bean.BeanUtil; import com.ibiz.excel.picture.support.constants.WorkbookConstant; import com.ibiz.excel.picture.support.util.StringUtils; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; +import java.util.*; import java.util.stream.Collectors; /** @@ -31,14 +29,14 @@ public class ExcelTableProcessor { private final Sheet sheet; /** - * 标题样式 + * 开始行号 */ - private CellStyle titleCellStyle; + private int startRow = 0; /** - * 开始行号 + * 样式 */ - private int startRow = 0; + private final Map cellStyleMap = new HashMap<>(); /** * 构建excel @@ -48,10 +46,13 @@ public class ExcelTableProcessor { */ public void buildExcel(List excels, List list) { // 开始行放标题 - Row row = sheet.createRow(startRow).setCellStyle(titleCellStyle); + Row row = sheet.createRow(startRow).setCellStyle(cellStyleMap.get(startRow)); List cells = new ArrayList<>(); for (int i = 0; i < excels.size(); i++) { - cells.add(new Cell(i).setValue(excels.get(i).getExcelName())); + BizExcelRel rel = excels.get(i); + cells.add(new Cell(i).setValue(rel.getExcelName())); + // 设置单元格宽度 + sheet.setColumnWidth(rel.getOrderNo(), rel.getCellWeight()); } row.autoRowCells(cells); int num; @@ -59,7 +60,7 @@ public class ExcelTableProcessor { for (int j = 0; j < list.size(); j++) { // 开始行的下一行放内容 num = startRow + j + 1; - row = sheet.createRow(num); + row = sheet.createRow(num).setCellStyle(cellStyleMap.get(num)); cells = new ArrayList<>(); int index = 0; BizExcelPojoInterface excelPojoInterface = list.get(j); @@ -75,21 +76,47 @@ public class ExcelTableProcessor { row.setHeight(rowHeight); cells.add(new Cell(num, index++).setValue(value)); row.setCells(cells); - } + } } + /** + * 设置行高 + * + * @param rowHeight + * @return + */ public ExcelTableProcessor setRowHeight(int rowHeight) { this.rowHeight = rowHeight; return this; } - public ExcelTableProcessor setTitleCellStyle(CellStyle titleCellStyle) { - this.titleCellStyle = titleCellStyle; + /** + * 批量添加样式 + * + * @param cellStyles + */ + public void addCellStyle(List cellStyles) { + cellStyles.forEach(cellStyle-> this.cellStyleMap.put(cellStyle.getRowNumber(), cellStyle)); + } + + /** + * 添加样式 + * @param cellStyle + * @return + */ + public ExcelTableProcessor addCellStyle(CellStyle cellStyle) { + this.cellStyleMap.put(cellStyle.getRowNumber(), cellStyle); return this; } + /** + * 设置写入数据开始行号 + * + * @param startRow + * @return + */ public ExcelTableProcessor setStartRow(int startRow) { this.startRow = startRow; return this; diff --git a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220208.java b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220208.java index 18a60ac..1195085 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220208.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220208.java @@ -28,10 +28,11 @@ public class ExportExample_20220208 extends BaseJunitTest { List excels = new ArrayList<>(); excels.add(new BizExcelRel("姓名", "name", 1)); excels.add(new BizExcelRel("年龄", "age", 2)); - excels.add(new BizExcelRel("头像", "headPicture", 3, true)); - CellStyle cellStyle = new CellStyle("F0F0F0"); + excels.add(new BizExcelRel("头像", "headPicture", 3, true, 20)); + CellStyle cellStyle = new CellStyle(0,"F0F0F0"); + ExcelTableProcessor.build(sheet) - .setTitleCellStyle(cellStyle) + .addCellStyle(cellStyle) .buildExcel(excels, students); WebUtil.writeExcelTest(workBook, "ExportExample_20220208_".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), TEMP_PATH); -- Gitee From 2ab552dd1c8281534a1b5e4b7b49bab75adb46af Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Fri, 11 Feb 2022 14:21:02 +0800 Subject: [PATCH 117/161] =?UTF-8?q?add=20=E6=B7=BB=E5=8A=A0=E5=9B=BE?= =?UTF-8?q?=E7=89=87=E5=A4=84=E7=90=86=E5=99=A8=E6=8E=A7=E5=88=B6=E5=A4=9A?= =?UTF-8?q?=E5=9B=BE=E7=89=87=E6=97=B6=E5=8D=95=E5=85=83=E6=A0=BC=E5=AE=BD?= =?UTF-8?q?=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../excel/picture/support/model/Sheet.java | 3 +- .../ExcelTableProcessor.java | 19 +-- .../support/processor/PictureProcessor.java | 114 ++++++++++++++++++ .../example/ExportExample_20220208.java | 8 +- .../excel/picture/support/pojo/Student.java | 21 ++++ 5 files changed, 156 insertions(+), 9 deletions(-) rename src/main/java/com/ibiz/excel/picture/support/{model => processor}/ExcelTableProcessor.java (80%) create mode 100644 src/main/java/com/ibiz/excel/picture/support/processor/PictureProcessor.java diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java index e76e6b5..6344b25 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java @@ -12,6 +12,7 @@ import com.ibiz.excel.picture.support.listener.CloseListener; import com.ibiz.excel.picture.support.listener.ContentListener; import com.ibiz.excel.picture.support.listener.FlushListener; import com.ibiz.excel.picture.support.listener.InitListener; +import com.ibiz.excel.picture.support.processor.PictureProcessor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.util.CollectionUtils; @@ -317,7 +318,7 @@ public class Sheet { // 不是标题 并且 是图片 并且 值不为空 if (isPicture && value != null) { // 添加图片 - this.addPictures(row, cell.getCellNumber(), value, model); + PictureProcessor.build(Sheet.this).addPictures(row, cell.getCellNumber(), value, model); } else { cell.setValue(value == null ? "" : String.valueOf(value)); } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/ExcelTableProcessor.java b/src/main/java/com/ibiz/excel/picture/support/processor/ExcelTableProcessor.java similarity index 80% rename from src/main/java/com/ibiz/excel/picture/support/model/ExcelTableProcessor.java rename to src/main/java/com/ibiz/excel/picture/support/processor/ExcelTableProcessor.java index fe70aa2..a8dfd4e 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/ExcelTableProcessor.java +++ b/src/main/java/com/ibiz/excel/picture/support/processor/ExcelTableProcessor.java @@ -1,8 +1,8 @@ -package com.ibiz.excel.picture.support.model; +package com.ibiz.excel.picture.support.processor; import cn.hutool.core.bean.BeanUtil; import com.ibiz.excel.picture.support.constants.WorkbookConstant; -import com.ibiz.excel.picture.support.util.StringUtils; +import com.ibiz.excel.picture.support.model.*; import java.util.*; import java.util.stream.Collectors; @@ -41,7 +41,7 @@ public class ExcelTableProcessor { /** * 构建excel * - * @param excels excel属性配置 + * @param excels excel属性配置,会根据excels中的field属性反射取出list中的值 * @param list 需要导出的集合对象 该对象必须实现接口{@link BizExcelPojoInterface} */ public void buildExcel(List excels, List list) { @@ -67,11 +67,15 @@ public class ExcelTableProcessor { excels = excels.stream().sorted(Comparator.comparing(BizExcelRel::getOrderNo)).collect(Collectors.toList()); for (BizExcelRel excel : excels) { Object propertyValue = BeanUtil.getFieldValue(excelPojoInterface, excel.getField()); - String value = propertyValue == null ? "" : propertyValue.toString(); + String value; // 是图片 - if (excel.isPicture() && StringUtils.isNotBlank(value)) { - pictures.add(new Picture(row.getRowNumber(), excel.getOrderNo() - 1, WorkbookConstant.PICTURE_WEIGHT, value)); + if (excel.isPicture() && Objects.nonNull(propertyValue)) { + // 添加图片 + PictureProcessor.build(sheet).addPictures(row, excel.getOrderNo() - 1, propertyValue, + 0, WorkbookConstant.PICTURE_WEIGHT, WorkbookConstant.PICTURE_HEIGHT); value = ""; + } else { + value = propertyValue == null ? "" : propertyValue.toString(); } row.setHeight(rowHeight); cells.add(new Cell(num, index++).setValue(value)); @@ -98,11 +102,12 @@ public class ExcelTableProcessor { * @param cellStyles */ public void addCellStyle(List cellStyles) { - cellStyles.forEach(cellStyle-> this.cellStyleMap.put(cellStyle.getRowNumber(), cellStyle)); + cellStyles.forEach(cellStyle -> this.cellStyleMap.put(cellStyle.getRowNumber(), cellStyle)); } /** * 添加样式 + * * @param cellStyle * @return */ diff --git a/src/main/java/com/ibiz/excel/picture/support/processor/PictureProcessor.java b/src/main/java/com/ibiz/excel/picture/support/processor/PictureProcessor.java new file mode 100644 index 0000000..b341f91 --- /dev/null +++ b/src/main/java/com/ibiz/excel/picture/support/processor/PictureProcessor.java @@ -0,0 +1,114 @@ +package com.ibiz.excel.picture.support.processor; + +import com.ibiz.excel.picture.support.annotation.ExportModel; +import com.ibiz.excel.picture.support.model.Picture; +import com.ibiz.excel.picture.support.model.Row; +import com.ibiz.excel.picture.support.model.Sheet; + +import java.util.ArrayList; +import java.util.List; + +/** + * excel中图片处理器 + * + * @author MinWeikai + * @date 2022/2/11 13:55 + */ +public class PictureProcessor { + + public PictureProcessor(Sheet sheet) { + this.sheet = sheet; + } + + public static PictureProcessor build(Sheet sheet) { + return new PictureProcessor(sheet); + } + + private final Sheet sheet; + + /** + * 添加图片 + * + * @param row + * @param cellNumber + * @param value + * @param model + */ + public void addPictures(Row row, int cellNumber, Object value, ExportModel model) { + // 图片所在单元格宽度,图片和单元格宽度一致 + int width = model.width(); + // 图片所在单元格行高度 + int height = model.height(); + addPictures(row, cellNumber, value, model.pictureSource(), width, height); + } + + /** + * 添加图片 + * + * @param row + * @param cellNumber + * @param value + * @param pictureSource + * @param width + * @param height + */ + public void addPictures(Row row, int cellNumber, Object value, int pictureSource, int width, int height) { + List values = getValues(value); + // 计算行高 + calculateRowHeight(row, height); + // 计算单元格宽度根据单元格中值的数量 + calculateColumnWidth(cellNumber, width, values.size()); + //增加图片 + values.forEach(val -> + sheet.getPictures().add( + new Picture(row.getRowNumber(), cellNumber, width, height, val, pictureSource) + // 自动设置图片来源 + .autoPictureSourceByPath() + )); + } + + /** + * 获取value集合 + * + * @param value + * @return + */ + private List getValues(Object value) { + List values = new ArrayList<>(); + if (value instanceof List) { + values = (List) value; + } else { + values.add(String.valueOf(value)); + } + return values; + } + + /** + * 计算行高 + * + * @param row + * @param height + */ + private void calculateRowHeight(Row row, int height) { + // 设置行高自适应于图片的高度 + row.setHeight((height / 12600) - 1); + } + + /** + * 计算单元格宽度根据单元格中值的数量 + * + * @param cellNumber + * @param width + * @param valuesSize 图片数 + */ + private void calculateColumnWidth(int cellNumber, int width, int valuesSize) { + // 实际宽 + int actualWidth = width / 76923; + // + // 数组为空时,给默认值1,否则单元格宽度会被计算成0 + valuesSize = valuesSize == 0 ? 1 : valuesSize; + // 设置单元格宽度,单元格宽度 = 图片宽*图片数量 + double columnWidth = actualWidth * valuesSize + valuesSize / 1.5; + sheet.setColumnWidth(cellNumber + 1, columnWidth); + } +} diff --git a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220208.java b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220208.java index 1195085..80868fb 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220208.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220208.java @@ -3,6 +3,7 @@ package com.ibiz.excel.picture.support.example; import com.ibiz.excel.picture.support.common.BaseJunitTest; import com.ibiz.excel.picture.support.model.*; import com.ibiz.excel.picture.support.pojo.Student; +import com.ibiz.excel.picture.support.processor.ExcelTableProcessor; import com.ibiz.excel.picture.support.util.WebUtil; import org.junit.Test; @@ -19,7 +20,7 @@ public class ExportExample_20220208 extends BaseJunitTest { public void export() { List students = new ArrayList<>(); students.add(new Student("李四", 16)); - students.add(new Student("张三", 17)); + students.add(new Student("张三", 17, getPictures(5))); students.add(new Student("王五", 15, IMG_PATH_1)); Workbook workBook = Workbook.getInstance(100); @@ -29,10 +30,15 @@ public class ExportExample_20220208 extends BaseJunitTest { excels.add(new BizExcelRel("姓名", "name", 1)); excels.add(new BizExcelRel("年龄", "age", 2)); excels.add(new BizExcelRel("头像", "headPicture", 3, true, 20)); + excels.add(new BizExcelRel("相册", "album", 4, true)); + // 样式 CellStyle cellStyle = new CellStyle(0,"F0F0F0"); + // 构建sheet ExcelTableProcessor.build(sheet) + // 添加样式 .addCellStyle(cellStyle) + // 构建excel .buildExcel(excels, students); WebUtil.writeExcelTest(workBook, "ExportExample_20220208_".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), TEMP_PATH); diff --git a/src/test/java/com/ibiz/excel/picture/support/pojo/Student.java b/src/test/java/com/ibiz/excel/picture/support/pojo/Student.java index fb48240..f0da995 100644 --- a/src/test/java/com/ibiz/excel/picture/support/pojo/Student.java +++ b/src/test/java/com/ibiz/excel/picture/support/pojo/Student.java @@ -2,6 +2,8 @@ package com.ibiz.excel.picture.support.pojo; import com.ibiz.excel.picture.support.model.BizExcelPojoInterface; +import java.util.List; + /** * @author MinWeikai * @date 2022/2/9 9:21 @@ -19,12 +21,31 @@ public class Student implements BizExcelPojoInterface { this.headPicture = headPicture; } + public Student(String name, Integer age, List album) { + this.name = name; + this.age = age; + this.album = album; + } + private String name; private Integer age; private String headPicture; + /** + * 相册 + */ + private List album; + + public List getAlbum() { + return album; + } + + public void setAlbum(List album) { + this.album = album; + } + public String getHeadPicture() { return headPicture; } -- Gitee From 4d0fe2a3d010c69799701605c9fa44511357deb8 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Fri, 11 Feb 2022 14:23:13 +0800 Subject: [PATCH 118/161] =?UTF-8?q?update=20=E5=B0=81=E8=A3=85excel?= =?UTF-8?q?=E4=B8=AD=E6=B7=BB=E5=8A=A0=E5=9B=BE=E7=89=87=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../excel/picture/support/model/Sheet.java | 65 ------------------- 1 file changed, 65 deletions(-) diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java index 6344b25..8ff9148 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java @@ -331,71 +331,6 @@ public class Sheet { return row; } - /** - * 添加图片 - * @param row - * @param cellNumber - * @param value - * @param model - */ - private void addPictures(Row row, int cellNumber, Object value, ExportModel model) { - // 图片所在单元格宽度,图片和单元格宽度一致 - int width = model.width(); - // 图片所在单元格行高度 - int height = model.height(); - List values = getValues(value); - // 计算行高 - calculateRowHeight(row, height); - // 计算单元格宽度根据单元格中值的数量 - calculateColumnWidth(cellNumber, width, values.size()); - //增加图片 - values.forEach(val -> - pictures.add( - new Picture(row.getRowNumber(), cellNumber, width, height, val, model.pictureSource()) - // 自动设置图片来源 - .autoPictureSourceByPath() - )); - } - - private List getValues(Object value) { - List values = new ArrayList<>(); - if (value instanceof List) { - values = (List) value; - } else { - values.add(String.valueOf(value)); - } - return values; - } - - /** - * 计算行高 - * - * @param row - * @param height - */ - private void calculateRowHeight(Row row, int height) { - // 设置行高自适应于图片的高度 - row.setHeight((height / 12600) - 1); - } - - /** - * 计算单元格宽度根据单元格中值的数量 - * - * @param cellNumber - * @param width - * @param valuesSize 图片数 - */ - private void calculateColumnWidth(int cellNumber, int width, int valuesSize) { - // 实际宽 - int actualWidth = width / 76923; - // - // 数组为空时,给默认值1,否则单元格宽度会被计算成0 - valuesSize = valuesSize == 0 ? 1 : valuesSize; - // 设置单元格宽度,单元格宽度 = 图片宽*图片数量 - double columnWidth = actualWidth * valuesSize + valuesSize / 1.5; - setColumnWidth(cellNumber + 1, columnWidth); - } - Row createRow(T t) { if (!hasWriteHead) { createRowAndCellStyle(t, true); -- Gitee From 65748dc9edd90ed77c4a3228fee40f96df6a39f5 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Fri, 11 Feb 2022 15:28:36 +0800 Subject: [PATCH 119/161] =?UTF-8?q?add=20ExcelTableProcessor=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E6=95=B0=E6=8D=AE=E5=AD=97=E5=85=B8=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../picture/support/model/BizExcelRel.java | 34 ----------- .../processor/ExcelTableProcessor.java | 59 +++++++++++++++++-- .../example/ExportExample_20220208.java | 33 ++++++++--- .../excel/picture/support/pojo/Student.java | 17 +++++- 4 files changed, 95 insertions(+), 48 deletions(-) diff --git a/src/main/java/com/ibiz/excel/picture/support/model/BizExcelRel.java b/src/main/java/com/ibiz/excel/picture/support/model/BizExcelRel.java index cd98a45..8a29464 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/BizExcelRel.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/BizExcelRel.java @@ -32,14 +32,6 @@ public class BizExcelRel { this.cellWeight = cellWeight; } - public BizExcelRel(String excelName, String field, boolean isEnum, String lookupCode, int orderNo) { - this.excelName = excelName; - this.field = field; - this.isEnum = isEnum; - this.lookupCode = lookupCode; - this.orderNo = orderNo; - } - /** * excel显示的字段名称 */ @@ -50,16 +42,6 @@ public class BizExcelRel { */ private String field; - /** - * 是否是枚举 - */ - private boolean isEnum = false; - - /** - * 数据字典code - */ - private String lookupCode; - /** * 排序 */ @@ -99,22 +81,6 @@ public class BizExcelRel { this.field = field; } - public boolean isEnum() { - return isEnum; - } - - public void setEnum(boolean anEnum) { - isEnum = anEnum; - } - - public String getLookupCode() { - return lookupCode; - } - - public void setLookupCode(String lookupCode) { - this.lookupCode = lookupCode; - } - public int getOrderNo() { return orderNo; } diff --git a/src/main/java/com/ibiz/excel/picture/support/processor/ExcelTableProcessor.java b/src/main/java/com/ibiz/excel/picture/support/processor/ExcelTableProcessor.java index a8dfd4e..8d06f27 100644 --- a/src/main/java/com/ibiz/excel/picture/support/processor/ExcelTableProcessor.java +++ b/src/main/java/com/ibiz/excel/picture/support/processor/ExcelTableProcessor.java @@ -1,6 +1,7 @@ package com.ibiz.excel.picture.support.processor; import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.map.MapUtil; import com.ibiz.excel.picture.support.constants.WorkbookConstant; import com.ibiz.excel.picture.support.model.*; @@ -33,11 +34,22 @@ public class ExcelTableProcessor { */ private int startRow = 0; + /** + * 开始单元格 + */ + private int startCell = 0; + /** * 样式 */ private final Map cellStyleMap = new HashMap<>(); + /** + * key : 对象的field属性名称 + * value : 此属性value相关的数据字典 + */ + private Map> fieldEnumMap = new HashMap<>(); + /** * 构建excel * @@ -48,7 +60,7 @@ public class ExcelTableProcessor { // 开始行放标题 Row row = sheet.createRow(startRow).setCellStyle(cellStyleMap.get(startRow)); List cells = new ArrayList<>(); - for (int i = 0; i < excels.size(); i++) { + for (int i = startCell; i < excels.size(); i++) { BizExcelRel rel = excels.get(i); cells.add(new Cell(i).setValue(rel.getExcelName())); // 设置单元格宽度 @@ -56,13 +68,12 @@ public class ExcelTableProcessor { } row.autoRowCells(cells); int num; - List pictures = sheet.getPictures(); for (int j = 0; j < list.size(); j++) { // 开始行的下一行放内容 num = startRow + j + 1; row = sheet.createRow(num).setCellStyle(cellStyleMap.get(num)); cells = new ArrayList<>(); - int index = 0; + int index = startCell; BizExcelPojoInterface excelPojoInterface = list.get(j); excels = excels.stream().sorted(Comparator.comparing(BizExcelRel::getOrderNo)).collect(Collectors.toList()); for (BizExcelRel excel : excels) { @@ -71,13 +82,15 @@ public class ExcelTableProcessor { // 是图片 if (excel.isPicture() && Objects.nonNull(propertyValue)) { // 添加图片 - PictureProcessor.build(sheet).addPictures(row, excel.getOrderNo() - 1, propertyValue, + PictureProcessor.build(sheet).addPictures(row, index, propertyValue, 0, WorkbookConstant.PICTURE_WEIGHT, WorkbookConstant.PICTURE_HEIGHT); value = ""; } else { value = propertyValue == null ? "" : propertyValue.toString(); } row.setHeight(rowHeight); + // 数据字典值获取 + value = getValueByFiledEnumMap(excel.getField(), value); cells.add(new Cell(num, index++).setValue(value)); row.setCells(cells); } @@ -85,6 +98,21 @@ public class ExcelTableProcessor { } } + /** + * 数据字典值获取 + * + * @param field + * @param value + * @return + */ + private String getValueByFiledEnumMap(String field, String value) { + Map enumMap = fieldEnumMap.get(field); + if (MapUtil.isNotEmpty(enumMap)) { + return enumMap.get(value); + } + return value; + } + /** * 设置行高 * @@ -126,4 +154,27 @@ public class ExcelTableProcessor { this.startRow = startRow; return this; } + + /** + * 设置写入数据开始单元格 + * + * @param startCell + * @return + */ + public ExcelTableProcessor setStartCell(int startCell) { + this.startCell = startCell; + return this; + } + + /** + * 注入属性字典值 + * + * @param field 属性名 + * @param enumMap 数据字典值 + * @return + */ + public ExcelTableProcessor registryEnumMap(String field, Map enumMap) { + fieldEnumMap.put(field, enumMap); + return this; + } } diff --git a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220208.java b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220208.java index 80868fb..7919e76 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220208.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220208.java @@ -1,16 +1,23 @@ package com.ibiz.excel.picture.support.example; import com.ibiz.excel.picture.support.common.BaseJunitTest; -import com.ibiz.excel.picture.support.model.*; +import com.ibiz.excel.picture.support.model.BizExcelRel; +import com.ibiz.excel.picture.support.model.CellStyle; +import com.ibiz.excel.picture.support.model.Sheet; +import com.ibiz.excel.picture.support.model.Workbook; import com.ibiz.excel.picture.support.pojo.Student; import com.ibiz.excel.picture.support.processor.ExcelTableProcessor; import com.ibiz.excel.picture.support.util.WebUtil; import org.junit.Test; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** + * 动态标题excel导出 + * * @author MinWeikai * @date 2022/2/8 14:49 */ @@ -19,25 +26,33 @@ public class ExportExample_20220208 extends BaseJunitTest { @Test public void export() { List students = new ArrayList<>(); - students.add(new Student("李四", 16)); - students.add(new Student("张三", 17, getPictures(5))); - students.add(new Student("王五", 15, IMG_PATH_1)); + students.add(new Student("李四", 16, null, null, 0)); + students.add(new Student("张三", 17, null, getPictures(5), 1)); + students.add(new Student("王五", 15, IMG_PATH_1, null, 2)); Workbook workBook = Workbook.getInstance(100); Sheet sheet = workBook.createSheet("测试"); List excels = new ArrayList<>(); - excels.add(new BizExcelRel("姓名", "name", 1)); - excels.add(new BizExcelRel("年龄", "age", 2)); - excels.add(new BizExcelRel("头像", "headPicture", 3, true, 20)); - excels.add(new BizExcelRel("相册", "album", 4, true)); + excels.add(new BizExcelRel("姓名", "name", 2)); + excels.add(new BizExcelRel("年龄", "age", 3)); + excels.add(new BizExcelRel("表现", "performance", 4)); + excels.add(new BizExcelRel("头像", "headPicture", 5, true, 20)); + excels.add(new BizExcelRel("相册", "album", 6, true)); // 样式 - CellStyle cellStyle = new CellStyle(0,"F0F0F0"); + CellStyle cellStyle = new CellStyle(0, "F0F0F0"); + + Map performanceMap = new HashMap<>(); + performanceMap.put("0", "一般"); + performanceMap.put("1", "良好"); + performanceMap.put("2", "优秀"); // 构建sheet ExcelTableProcessor.build(sheet) // 添加样式 .addCellStyle(cellStyle) + // 添加数据字典 + .registryEnumMap("performance", performanceMap) // 构建excel .buildExcel(excels, students); diff --git a/src/test/java/com/ibiz/excel/picture/support/pojo/Student.java b/src/test/java/com/ibiz/excel/picture/support/pojo/Student.java index f0da995..a5468ca 100644 --- a/src/test/java/com/ibiz/excel/picture/support/pojo/Student.java +++ b/src/test/java/com/ibiz/excel/picture/support/pojo/Student.java @@ -21,10 +21,12 @@ public class Student implements BizExcelPojoInterface { this.headPicture = headPicture; } - public Student(String name, Integer age, List album) { + public Student(String name, Integer age, String headPicture, List album, Integer performance) { this.name = name; this.age = age; + this.headPicture = headPicture; this.album = album; + this.performance = performance; } private String name; @@ -38,6 +40,19 @@ public class Student implements BizExcelPojoInterface { */ private List album; + /** + * 表现 0一般;1良好;2优秀 + */ + private Integer performance; + + public Integer getPerformance() { + return performance; + } + + public void setPerformance(Integer performance) { + this.performance = performance; + } + public List getAlbum() { return album; } -- Gitee From 24fec7ef7999df9123af8e8127e16ce9cde75232 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Wed, 23 Feb 2022 14:05:25 +0800 Subject: [PATCH 120/161] =?UTF-8?q?add=20=E5=AE=8C=E5=96=84=E6=B3=A8?= =?UTF-8?q?=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../processor/ExcelTableProcessor.java | 5 ++++- .../example/ExportExample_20220208.java | 19 +++++++++++-------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/ibiz/excel/picture/support/processor/ExcelTableProcessor.java b/src/main/java/com/ibiz/excel/picture/support/processor/ExcelTableProcessor.java index 8d06f27..736746e 100644 --- a/src/main/java/com/ibiz/excel/picture/support/processor/ExcelTableProcessor.java +++ b/src/main/java/com/ibiz/excel/picture/support/processor/ExcelTableProcessor.java @@ -9,6 +9,9 @@ import java.util.*; import java.util.stream.Collectors; /** + * excel表格处理器 + * 简化并辅助解决动态表头导出问题 + * * @author MinWeikai * @date 2022/2/9 11:22 */ @@ -18,7 +21,7 @@ public class ExcelTableProcessor { this.sheet = sheet; } - public static ExcelTableProcessor build(Sheet sheet) { + public static ExcelTableProcessor sheet(Sheet sheet) { return new ExcelTableProcessor(sheet); } diff --git a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220208.java b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220208.java index 7919e76..249aa9d 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220208.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220208.java @@ -16,7 +16,7 @@ import java.util.List; import java.util.Map; /** - * 动态标题excel导出 + * 动态配置表头excel导出 * * @author MinWeikai * @date 2022/2/8 14:49 @@ -25,33 +25,36 @@ public class ExportExample_20220208 extends BaseJunitTest { @Test public void export() { + // 模拟需要导出的数据集合 List students = new ArrayList<>(); students.add(new Student("李四", 16, null, null, 0)); students.add(new Student("张三", 17, null, getPictures(5), 1)); students.add(new Student("王五", 15, IMG_PATH_1, null, 2)); - Workbook workBook = Workbook.getInstance(100); - Sheet sheet = workBook.createSheet("测试"); - + // 配置导出excel的表头、顺序、对应导出的数据集合的字段、是否是图片、单元格宽度等 List excels = new ArrayList<>(); excels.add(new BizExcelRel("姓名", "name", 2)); excels.add(new BizExcelRel("年龄", "age", 3)); excels.add(new BizExcelRel("表现", "performance", 4)); excels.add(new BizExcelRel("头像", "headPicture", 5, true, 20)); excels.add(new BizExcelRel("相册", "album", 6, true)); - // 样式 - CellStyle cellStyle = new CellStyle(0, "F0F0F0"); + // 创建excel + Workbook workBook = Workbook.getInstance(100); + Sheet sheet = workBook.createSheet("测试"); + // 创建样式 + CellStyle cellStyle = new CellStyle(0, "F0F0F0"); + // 创建数据字典 Map performanceMap = new HashMap<>(); performanceMap.put("0", "一般"); performanceMap.put("1", "良好"); performanceMap.put("2", "优秀"); // 构建sheet - ExcelTableProcessor.build(sheet) + ExcelTableProcessor.sheet(sheet) // 添加样式 .addCellStyle(cellStyle) - // 添加数据字典 + // 添加对应属性字段的数据字典 .registryEnumMap("performance", performanceMap) // 构建excel .buildExcel(excels, students); -- Gitee From d07a46257a3bf6222a4b3a2246112dd3c9cc5a7d Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Wed, 23 Feb 2022 14:11:54 +0800 Subject: [PATCH 121/161] =?UTF-8?q?add=20=E5=8A=A8=E6=80=81=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E8=A1=A8=E5=A4=B4excel=E5=AF=BC=E5=87=BA=E7=A4=BA?= =?UTF-8?q?=E4=BE=8B=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 128 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 127 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 019d0ee..5e2a0de 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, 2. ### 示例 - - 最新使用示例代码 + - #### 注解使用示例代码 ```java @GetMapping("/export/lastversion/{row}") @@ -174,6 +174,132 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, ``` + - #### 动态配置表头excel导出示例代码 + + *实体对象需要实现BizExcelPojoInterface接口* + + ```java + @GetMapping("/export/dynamic-config-header") + public void exportDynamicConfigHeader(HttpServletResponse response) throws IOException { + // 模拟需要导出的数据集合 + List students = new ArrayList<>(); + students.add(new Student("李四", 16, null, null, 0)); + students.add(new Student("张三", 17, null, + Arrays.asList("https://portrait.gitee.com/uploads/avatars/user/552/1657608_mwk719_1641537497.png", + "https://img2.baidu.com/it/u=2602880481,728201544&fm=26&fmt=auto"), 1)); + students.add(new Student("王五", 15, IMG_PATH_1, null, 2)); + + // 配置导出excel的表头、顺序、对应导出的数据集合的字段、是否是图片、单元格宽度等 + List excels = new ArrayList<>(); + excels.add(new BizExcelRel("姓名", "name", 2)); + excels.add(new BizExcelRel("年龄", "age", 3)); + excels.add(new BizExcelRel("表现", "performance", 4)); + excels.add(new BizExcelRel("头像", "headPicture", 5, true, 20)); + excels.add(new BizExcelRel("相册", "album", 6, true)); + + // 创建excel + Workbook workBook = Workbook.getInstance(100); + Sheet sheet = workBook.createSheet("测试"); + // 创建样式 + CellStyle cellStyle = new CellStyle(0, "F0F0F0"); + // 创建数据字典 + Map performanceMap = new HashMap<>(3); + performanceMap.put("0", "一般"); + performanceMap.put("1", "良好"); + performanceMap.put("2", "优秀"); + + // 构建sheet + ExcelTableProcessor.sheet(sheet) + // 添加样式 + .addCellStyle(cellStyle) + // 添加对应属性字段的数据字典 + .registryEnumMap("performance", performanceMap) + // 构建excel + .buildExcel(excels, students); + WebUtil.writeExcel(workBook, "ExportExampleDynamicConfigHeader".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), response); + } + ``` + + ```java + public class Student implements BizExcelPojoInterface { + + public Student(String name, Integer age) { + this.name = name; + this.age = age; + } + + public Student(String name, Integer age, String headPicture) { + this.name = name; + this.age = age; + this.headPicture = headPicture; + } + + public Student(String name, Integer age, String headPicture, List album, Integer performance) { + this.name = name; + this.age = age; + this.headPicture = headPicture; + this.album = album; + this.performance = performance; + } + + private String name; + + private Integer age; + + private String headPicture; + + /** + * 相册 + */ + private List album; + + /** + * 表现 0一般;1良好;2优秀 + */ + private Integer performance; + + public Integer getPerformance() { + return performance; + } + + public void setPerformance(Integer performance) { + this.performance = performance; + } + + public List getAlbum() { + return album; + } + + public void setAlbum(List album) { + this.album = album; + } + + public String getHeadPicture() { + return headPicture; + } + + public void setHeadPicture(String headPicture) { + this.headPicture = headPicture; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getAge() { + return age; + } + + public void setAge(Integer age) { + this.age = age; + } + } + ``` + - [excel含图片导出demo地址](https://gitee.com/mwk719/excel-batch-picture-support/tree/dev/src/test/java/com/ibiz/excel/picture/support/example),具体使用以后缀最新日期为准,其他示例仅供测试 - [微云-6767张图片共800mb资源.rar 可用于测试](https://minwk.top/big-size-img/) -- Gitee From 054bee34c72007256d5f76bc50a6c7a1b37bc7be Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Wed, 23 Feb 2022 14:19:25 +0800 Subject: [PATCH 122/161] release 2.3.0 --- README.md | 4 ++++ pom.xml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5e2a0de..2f9545a 100644 --- a/README.md +++ b/README.md @@ -322,6 +322,10 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, 3. ### 版本更迭 + #### 2.3.0(2022.02.23) + + - [添加可动态配置表头excel导出](https://gitee.com/mwk719/spring-learn/blob/master/src/main/java/com/mwk/external/controller/ExcelController.java#L285) + #### 2.2.2(2022.02.08) - 修复合并后的单元格没有边框线 diff --git a/pom.xml b/pom.xml index 219035e..5e54551 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 top.minwk excel-x - 2.2.2 + 2.3.0 excel-x 支持excel中批量导出图片 https://gitee.com/mwk719/excel-batch-picture-support -- Gitee From 5b849d114b2dc5b3286a2e9e919e23ea167f1190 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Wed, 23 Feb 2022 14:05:25 +0800 Subject: [PATCH 123/161] =?UTF-8?q?add=20=E5=AE=8C=E5=96=84=E6=B3=A8?= =?UTF-8?q?=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../processor/ExcelTableProcessor.java | 5 ++++- .../example/ExportExample_20220208.java | 19 +++++++++++-------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/ibiz/excel/picture/support/processor/ExcelTableProcessor.java b/src/main/java/com/ibiz/excel/picture/support/processor/ExcelTableProcessor.java index 8d06f27..736746e 100644 --- a/src/main/java/com/ibiz/excel/picture/support/processor/ExcelTableProcessor.java +++ b/src/main/java/com/ibiz/excel/picture/support/processor/ExcelTableProcessor.java @@ -9,6 +9,9 @@ import java.util.*; import java.util.stream.Collectors; /** + * excel表格处理器 + * 简化并辅助解决动态表头导出问题 + * * @author MinWeikai * @date 2022/2/9 11:22 */ @@ -18,7 +21,7 @@ public class ExcelTableProcessor { this.sheet = sheet; } - public static ExcelTableProcessor build(Sheet sheet) { + public static ExcelTableProcessor sheet(Sheet sheet) { return new ExcelTableProcessor(sheet); } diff --git a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220208.java b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220208.java index 7919e76..249aa9d 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220208.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220208.java @@ -16,7 +16,7 @@ import java.util.List; import java.util.Map; /** - * 动态标题excel导出 + * 动态配置表头excel导出 * * @author MinWeikai * @date 2022/2/8 14:49 @@ -25,33 +25,36 @@ public class ExportExample_20220208 extends BaseJunitTest { @Test public void export() { + // 模拟需要导出的数据集合 List students = new ArrayList<>(); students.add(new Student("李四", 16, null, null, 0)); students.add(new Student("张三", 17, null, getPictures(5), 1)); students.add(new Student("王五", 15, IMG_PATH_1, null, 2)); - Workbook workBook = Workbook.getInstance(100); - Sheet sheet = workBook.createSheet("测试"); - + // 配置导出excel的表头、顺序、对应导出的数据集合的字段、是否是图片、单元格宽度等 List excels = new ArrayList<>(); excels.add(new BizExcelRel("姓名", "name", 2)); excels.add(new BizExcelRel("年龄", "age", 3)); excels.add(new BizExcelRel("表现", "performance", 4)); excels.add(new BizExcelRel("头像", "headPicture", 5, true, 20)); excels.add(new BizExcelRel("相册", "album", 6, true)); - // 样式 - CellStyle cellStyle = new CellStyle(0, "F0F0F0"); + // 创建excel + Workbook workBook = Workbook.getInstance(100); + Sheet sheet = workBook.createSheet("测试"); + // 创建样式 + CellStyle cellStyle = new CellStyle(0, "F0F0F0"); + // 创建数据字典 Map performanceMap = new HashMap<>(); performanceMap.put("0", "一般"); performanceMap.put("1", "良好"); performanceMap.put("2", "优秀"); // 构建sheet - ExcelTableProcessor.build(sheet) + ExcelTableProcessor.sheet(sheet) // 添加样式 .addCellStyle(cellStyle) - // 添加数据字典 + // 添加对应属性字段的数据字典 .registryEnumMap("performance", performanceMap) // 构建excel .buildExcel(excels, students); -- Gitee From 4be782acca974e4f2c199864101f3c18205f8432 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Wed, 23 Feb 2022 14:11:54 +0800 Subject: [PATCH 124/161] =?UTF-8?q?add=20=E5=8A=A8=E6=80=81=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E8=A1=A8=E5=A4=B4excel=E5=AF=BC=E5=87=BA=E7=A4=BA?= =?UTF-8?q?=E4=BE=8B=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 128 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 127 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 019d0ee..5e2a0de 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, 2. ### 示例 - - 最新使用示例代码 + - #### 注解使用示例代码 ```java @GetMapping("/export/lastversion/{row}") @@ -174,6 +174,132 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, ``` + - #### 动态配置表头excel导出示例代码 + + *实体对象需要实现BizExcelPojoInterface接口* + + ```java + @GetMapping("/export/dynamic-config-header") + public void exportDynamicConfigHeader(HttpServletResponse response) throws IOException { + // 模拟需要导出的数据集合 + List students = new ArrayList<>(); + students.add(new Student("李四", 16, null, null, 0)); + students.add(new Student("张三", 17, null, + Arrays.asList("https://portrait.gitee.com/uploads/avatars/user/552/1657608_mwk719_1641537497.png", + "https://img2.baidu.com/it/u=2602880481,728201544&fm=26&fmt=auto"), 1)); + students.add(new Student("王五", 15, IMG_PATH_1, null, 2)); + + // 配置导出excel的表头、顺序、对应导出的数据集合的字段、是否是图片、单元格宽度等 + List excels = new ArrayList<>(); + excels.add(new BizExcelRel("姓名", "name", 2)); + excels.add(new BizExcelRel("年龄", "age", 3)); + excels.add(new BizExcelRel("表现", "performance", 4)); + excels.add(new BizExcelRel("头像", "headPicture", 5, true, 20)); + excels.add(new BizExcelRel("相册", "album", 6, true)); + + // 创建excel + Workbook workBook = Workbook.getInstance(100); + Sheet sheet = workBook.createSheet("测试"); + // 创建样式 + CellStyle cellStyle = new CellStyle(0, "F0F0F0"); + // 创建数据字典 + Map performanceMap = new HashMap<>(3); + performanceMap.put("0", "一般"); + performanceMap.put("1", "良好"); + performanceMap.put("2", "优秀"); + + // 构建sheet + ExcelTableProcessor.sheet(sheet) + // 添加样式 + .addCellStyle(cellStyle) + // 添加对应属性字段的数据字典 + .registryEnumMap("performance", performanceMap) + // 构建excel + .buildExcel(excels, students); + WebUtil.writeExcel(workBook, "ExportExampleDynamicConfigHeader".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), response); + } + ``` + + ```java + public class Student implements BizExcelPojoInterface { + + public Student(String name, Integer age) { + this.name = name; + this.age = age; + } + + public Student(String name, Integer age, String headPicture) { + this.name = name; + this.age = age; + this.headPicture = headPicture; + } + + public Student(String name, Integer age, String headPicture, List album, Integer performance) { + this.name = name; + this.age = age; + this.headPicture = headPicture; + this.album = album; + this.performance = performance; + } + + private String name; + + private Integer age; + + private String headPicture; + + /** + * 相册 + */ + private List album; + + /** + * 表现 0一般;1良好;2优秀 + */ + private Integer performance; + + public Integer getPerformance() { + return performance; + } + + public void setPerformance(Integer performance) { + this.performance = performance; + } + + public List getAlbum() { + return album; + } + + public void setAlbum(List album) { + this.album = album; + } + + public String getHeadPicture() { + return headPicture; + } + + public void setHeadPicture(String headPicture) { + this.headPicture = headPicture; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getAge() { + return age; + } + + public void setAge(Integer age) { + this.age = age; + } + } + ``` + - [excel含图片导出demo地址](https://gitee.com/mwk719/excel-batch-picture-support/tree/dev/src/test/java/com/ibiz/excel/picture/support/example),具体使用以后缀最新日期为准,其他示例仅供测试 - [微云-6767张图片共800mb资源.rar 可用于测试](https://minwk.top/big-size-img/) -- Gitee From 21e1de6b8cc5022109a19b8fbf132d84c2551ad5 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Wed, 23 Feb 2022 14:19:25 +0800 Subject: [PATCH 125/161] release 2.3.0 --- README.md | 4 ++++ pom.xml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5e2a0de..2f9545a 100644 --- a/README.md +++ b/README.md @@ -322,6 +322,10 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, 3. ### 版本更迭 + #### 2.3.0(2022.02.23) + + - [添加可动态配置表头excel导出](https://gitee.com/mwk719/spring-learn/blob/master/src/main/java/com/mwk/external/controller/ExcelController.java#L285) + #### 2.2.2(2022.02.08) - 修复合并后的单元格没有边框线 diff --git a/pom.xml b/pom.xml index 219035e..5e54551 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 top.minwk excel-x - 2.2.2 + 2.3.0 excel-x 支持excel中批量导出图片 https://gitee.com/mwk719/excel-batch-picture-support -- Gitee From 3f5813298786ba118a5ab11d63eacc5fbbfe08e0 Mon Sep 17 00:00:00 2001 From: Hccake Date: Wed, 28 Sep 2022 22:14:00 +0800 Subject: [PATCH 126/161] =?UTF-8?q?:bug:=20=E4=BF=AE=E5=A4=8D=E6=9C=AA?= =?UTF-8?q?=E6=8C=87=E5=AE=9A=E7=BC=96=E7=A0=81=E5=AF=BC=E8=87=B4=E7=9A=84?= =?UTF-8?q?=E4=B9=B1=E7=A0=81=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../support/factory/RepositoryFactory.java | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/ibiz/excel/picture/support/factory/RepositoryFactory.java b/src/main/java/com/ibiz/excel/picture/support/factory/RepositoryFactory.java index 166e3fe..e329b28 100644 --- a/src/main/java/com/ibiz/excel/picture/support/factory/RepositoryFactory.java +++ b/src/main/java/com/ibiz/excel/picture/support/factory/RepositoryFactory.java @@ -1,14 +1,22 @@ package com.ibiz.excel.picture.support.factory; -import com.ibiz.excel.picture.support.flush.*; import com.ibiz.excel.picture.support.constants.Alias; +import com.ibiz.excel.picture.support.flush.Drawing1Handler; +import com.ibiz.excel.picture.support.flush.DrawingXmlRelsHandler; +import com.ibiz.excel.picture.support.flush.IRepository; +import com.ibiz.excel.picture.support.flush.Repository; +import com.ibiz.excel.picture.support.flush.SharedStringXmlHandler; +import com.ibiz.excel.picture.support.flush.Sheet1Handler; +import com.ibiz.excel.picture.support.flush.StylesHandler; import com.ibiz.excel.picture.support.util.StringUtils; import java.io.BufferedWriter; import java.io.File; -import java.io.FileWriter; import java.io.IOException; +import java.io.OutputStreamWriter; import java.lang.reflect.Proxy; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; /** * @auther 喻场 @@ -19,9 +27,9 @@ public class RepositoryFactory { public static IRepository getNewInstance(String alisa, File file, String content, String endContent, boolean writeXmlHead) throws IOException { Repository instance = new Repository(); String name = file.getName(); - if (name.indexOf(".") > -1) { + if (name.contains(".")) { //加这个判断因为media是一个目录,不是文件 - instance.setWrite(new BufferedWriter(new FileWriter(file))); + instance.setWrite(new BufferedWriter(new OutputStreamWriter(Files.newOutputStream(file.toPath()), StandardCharsets.UTF_8))); } instance.setFile(file); instance.setWriteXmlHead(writeXmlHead); @@ -29,15 +37,15 @@ public class RepositoryFactory { instance.setEndContent(endContent); IRepository repository = instance; if (StringUtils.equals(alisa, Alias.DRAWING1_XML_RELS)) { - repository = (IRepository)Proxy.newProxyInstance(RepositoryFactory.class.getClassLoader(), new Class[]{IRepository.class}, new DrawingXmlRelsHandler(instance)); + repository = (IRepository) Proxy.newProxyInstance(RepositoryFactory.class.getClassLoader(), new Class[]{IRepository.class}, new DrawingXmlRelsHandler(instance)); } else if (StringUtils.equals(alisa, Alias.DRAWING1)) { - repository = (IRepository)Proxy.newProxyInstance(RepositoryFactory.class.getClassLoader(), new Class[]{IRepository.class}, new Drawing1Handler(instance)); + repository = (IRepository) Proxy.newProxyInstance(RepositoryFactory.class.getClassLoader(), new Class[]{IRepository.class}, new Drawing1Handler(instance)); } else if (StringUtils.equals(alisa, Alias.SHARED_STRING_XML)) { - repository = (IRepository)Proxy.newProxyInstance(RepositoryFactory.class.getClassLoader(), new Class[]{IRepository.class}, new SharedStringXmlHandler(instance)); + repository = (IRepository) Proxy.newProxyInstance(RepositoryFactory.class.getClassLoader(), new Class[]{IRepository.class}, new SharedStringXmlHandler(instance)); } else if (StringUtils.equals(alisa, Alias.SHEET1)) { - repository = (IRepository)Proxy.newProxyInstance(RepositoryFactory.class.getClassLoader(), new Class[]{IRepository.class}, new Sheet1Handler(instance)); - } else if (StringUtils.equals(alisa, Alias.STYLES)) { - repository = (IRepository)Proxy.newProxyInstance(RepositoryFactory.class.getClassLoader(), new Class[]{IRepository.class}, new StylesHandler(instance)); + repository = (IRepository) Proxy.newProxyInstance(RepositoryFactory.class.getClassLoader(), new Class[]{IRepository.class}, new Sheet1Handler(instance)); + } else if (StringUtils.equals(alisa, Alias.STYLES)) { + repository = (IRepository) Proxy.newProxyInstance(RepositoryFactory.class.getClassLoader(), new Class[]{IRepository.class}, new StylesHandler(instance)); } return repository; } -- Gitee From 1957633787424fef684aa6551032ebf5f7c96784 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Mon, 19 Dec 2022 15:33:08 +0800 Subject: [PATCH 127/161] =?UTF-8?q?fix=20=E6=B8=B2=E6=9F=93=E7=94=9F?= =?UTF-8?q?=E6=88=90=E5=88=97=E5=85=83=E7=B4=A0A-Z=E5=9D=90=E6=A0=87?= =?UTF-8?q?=E6=97=B6=EF=BC=8C=E4=BD=BF=E7=94=A8=E5=88=B0Z=E6=97=B6?= =?UTF-8?q?=EF=BC=8C=E4=B8=8B=E4=B8=80=E5=88=97=E4=BB=8EAA=E5=BC=80?= =?UTF-8?q?=E5=A7=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/ibiz/excel/picture/support/model/Cell.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Cell.java b/src/main/java/com/ibiz/excel/picture/support/model/Cell.java index d75f5cc..ed25f57 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Cell.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Cell.java @@ -42,7 +42,6 @@ public class Cell { colNumber += "A"; } col += colNumber + CELL_NUMBER_LINE[line]; - colNumber = ""; colNumber += CELL_NUMBER_LINE[line] + (rowNumber + 1); } -- Gitee From fff6fa59b5f1ac3cda11e62a7be4249db3f79b73 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Mon, 19 Dec 2022 15:34:15 +0800 Subject: [PATCH 128/161] =?UTF-8?q?fix=20=E8=A1=8C=E5=85=83=E7=B4=A0?= =?UTF-8?q?=E4=B8=BA=E7=A9=BA=E6=97=B6=E5=90=88=E5=B9=B6=E5=8D=95=E5=85=83?= =?UTF-8?q?=E6=A0=BC=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/ibiz/excel/picture/support/model/Sheet.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java index 8ff9148..2036f82 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java @@ -1,5 +1,6 @@ package com.ibiz.excel.picture.support.model; +import cn.hutool.core.collection.CollectionUtil; import com.ibiz.excel.picture.support.SheetContext; import com.ibiz.excel.picture.support.annotation.ExportModel; import com.ibiz.excel.picture.support.constants.Alias; @@ -457,9 +458,12 @@ public class Sheet { for (int j = mergeCell.getFirstCol() + 1; j < mergeCell.getLastCol() + 1; j++) { cells.add(new Cell(j, "")); } - List rowCell = this.getRow(i).getCells(); - rowCell.addAll(cells); - this.getRow(i).autoRowCells(rowCell); + if(CollectionUtil.isNotEmpty(this.rows)){ + List rowCell = this.getRow(i).getCells(); + rowCell.addAll(cells); + this.getRow(i).autoRowCells(rowCell); + } + } } } -- Gitee From 742fa53c42326edfaa6e87009f58bcdb5e419405 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Mon, 19 Dec 2022 15:42:54 +0800 Subject: [PATCH 129/161] =?UTF-8?q?add=20=E6=B5=8B=E8=AF=95=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E7=A4=BA=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/ExportExample_20221219.java | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20221219.java diff --git a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20221219.java b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20221219.java new file mode 100644 index 0000000..30afbed --- /dev/null +++ b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20221219.java @@ -0,0 +1,71 @@ +package com.ibiz.excel.picture.support.example; + +import com.ibiz.excel.picture.support.common.BaseJunitTest; +import com.ibiz.excel.picture.support.model.*; +import com.ibiz.excel.picture.support.pojo.Student; +import com.ibiz.excel.picture.support.processor.ExcelTableProcessor; +import com.ibiz.excel.picture.support.util.WebUtil; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @author MinWeikai + * @date 2022-12-19 15:15:44 + * @description bug https://gitee.com/mwk719/excel-batch-picture-support/issues/I669N5 测试 + */ +public class ExportExample_20221219 extends BaseJunitTest { + + @Test + public void export() { + // 模拟需要导出的数据集合 + List students = new ArrayList<>(); + students.add(new Student("李四", 16, null, null, 0)); + students.add(new Student("张三", 17, null, getPictures(5), 1)); + students.add(new Student("王五", 15, IMG_PATH_1, null, 2)); + + // 配置导出excel的表头、顺序、对应导出的数据集合的字段、是否是图片、单元格宽度等 + List excels = new ArrayList<>(); + for (int i = 0; i < 31; i++) { + int orderNo = 2 + i; + // 给第5列设置为图片 + if(orderNo == 5){ + excels.add(new BizExcelRel("相册", "album", orderNo, true)); + }else { + excels.add(new BizExcelRel("姓名" + i, "name", orderNo)); + } + } + + + // 创建excel + Workbook workBook = Workbook.getInstance(100); + Sheet sheet = workBook.createSheet("测试"); + + //要进行合并的列 + sheet.addMergeCell(new MergeCell(0, 0, 0, 2)); + + // 创建样式 + CellStyle cellStyle = new CellStyle(0, "F0F0F0"); + // 创建数据字典 + Map performanceMap = new HashMap<>(); + performanceMap.put("0", "一般"); + performanceMap.put("1", "良好"); + performanceMap.put("2", "优秀"); + + // 构建sheet + ExcelTableProcessor.sheet(sheet) + // 添加样式 + .addCellStyle(cellStyle) + // 添加对应属性字段的数据字典 + .registryEnumMap("performance", performanceMap) + // 构建excel + .buildExcel(excels, students); + + WebUtil.writeExcelTest(workBook, "ExportExample_20221219_".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), TEMP_PATH); + } + + +} -- Gitee From f90eb8f5ed48a4d58288529d3bd00c2ac8d9101b Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Mon, 19 Dec 2022 16:54:07 +0800 Subject: [PATCH 130/161] =?UTF-8?q?merge=20=E5=86=B2=E7=AA=81=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../excel/picture/support/model/Sheet.java | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java index b360fee..2036f82 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Sheet.java @@ -132,6 +132,29 @@ public class Sheet { return SHEET_HANDLER.createRow(rowNumber); } + /** + * 开始行号 + * + * @param startRowNumber 表示从第几行开始写入数据 + * @return + */ + public Sheet startRow(int startRowNumber) { + writeRow = --startRowNumber; + return this; + } + + /** + * 构建并写入excel信息 + * + * @param + * @param head 标题 + * @return + */ + public Sheet write(Class head) { + SHEET_HANDLER.write(head); + return this; + } + /** * 刷新数据到流 */ -- Gitee From 4e711df6408b5c449a5671c260efd4733b5c549a Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Mon, 19 Dec 2022 16:57:21 +0800 Subject: [PATCH 131/161] release 2.3.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5e54551..5b83795 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 top.minwk excel-x - 2.3.0 + 2.3.1 excel-x 支持excel中批量导出图片 https://gitee.com/mwk719/excel-batch-picture-support -- Gitee From e23d56c26622d61c1d940c8a75ce2ed67668bb2d Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Mon, 19 Dec 2022 17:15:56 +0800 Subject: [PATCH 132/161] =?UTF-8?q?add=20README.md=E9=97=AE=E9=A2=98?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 2f9545a..c5e2b4b 100644 --- a/README.md +++ b/README.md @@ -322,6 +322,11 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, 3. ### 版本更迭 + #### 2.3.0(2022.12.19) + + - 修复渲染生成列元素A-Z坐标时,使用到Z时,下一列从AA开始 + - 修复行元素为空时合并单元格错误 + #### 2.3.0(2022.02.23) - [添加可动态配置表头excel导出](https://gitee.com/mwk719/spring-learn/blob/master/src/main/java/com/mwk/external/controller/ExcelController.java#L285) -- Gitee From 0b00c4e840d58a89c88686076c64b2d998b15250 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Mon, 19 Dec 2022 18:25:12 +0800 Subject: [PATCH 133/161] =?UTF-8?q?update=20README.md=E9=97=AE=E9=A2=98?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=9C=80=E6=96=B0=E7=89=88=E6=9C=AC=E5=8F=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c5e2b4b..0656e18 100644 --- a/README.md +++ b/README.md @@ -322,7 +322,7 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, 3. ### 版本更迭 - #### 2.3.0(2022.12.19) + #### 2.3.1(2022.12.19) - 修复渲染生成列元素A-Z坐标时,使用到Z时,下一列从AA开始 - 修复行元素为空时合并单元格错误 -- Gitee From 3e09c2287ee037f01150c09aaacfea675b35a8b0 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Mon, 19 Dec 2022 18:38:05 +0800 Subject: [PATCH 134/161] =?UTF-8?q?add=20=E5=BF=BD=E7=95=A5=E6=96=87?= =?UTF-8?q?=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 ++ excel-x.iml | 24 ++++++++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 .gitignore create mode 100644 excel-x.iml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d81f12e --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +/.idea diff --git a/excel-x.iml b/excel-x.iml new file mode 100644 index 0000000..9471f3b --- /dev/null +++ b/excel-x.iml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file -- Gitee From e55553341b8673f288d610fecb6b0bce5435ada2 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Wed, 28 Dec 2022 11:55:42 +0800 Subject: [PATCH 135/161] =?UTF-8?q?add=20=E5=BF=BD=E7=95=A5=E4=B8=8D?= =?UTF-8?q?=E9=9C=80=E8=A6=81=E7=9A=84=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index d81f12e..1b74b13 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ /target /.idea +/*.iml +/.mvn/ -- Gitee From c651628fe5baad16874066e8a2dd9095c0e70952 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Tue, 10 Jan 2023 18:49:58 +0800 Subject: [PATCH 136/161] =?UTF-8?q?add=20=E6=94=AF=E6=8C=81=E7=BB=99?= =?UTF-8?q?=E5=8D=95=E4=B8=AA=E5=8D=95=E5=85=83=E6=A0=BC=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E6=A0=B7=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../support/constants/WorkbookConstant.java | 5 + .../picture/support/flush/Sheet1Handler.java | 311 +++++++++--------- .../picture/support/flush/StylesHandler.java | 29 +- .../picture/support/flush/StylesIndex.java | 32 +- .../excel/picture/support/model/Cell.java | 20 ++ .../picture/support/model/CellStyle.java | 23 +- .../ibiz/excel/picture/support/model/Row.java | 32 +- .../processor/ExcelTableProcessor.java | 4 +- .../example/ExportExample_20230110.java | 95 ++++++ 9 files changed, 365 insertions(+), 186 deletions(-) create mode 100644 src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20230110.java diff --git a/src/main/java/com/ibiz/excel/picture/support/constants/WorkbookConstant.java b/src/main/java/com/ibiz/excel/picture/support/constants/WorkbookConstant.java index 3e4be6f..1f32870 100644 --- a/src/main/java/com/ibiz/excel/picture/support/constants/WorkbookConstant.java +++ b/src/main/java/com/ibiz/excel/picture/support/constants/WorkbookConstant.java @@ -30,4 +30,9 @@ public class WorkbookConstant { * 下载网络图片超时时间 */ public static final int DOWNLOAD_PICTURE_TIME_OUT = 10 * 1000; + + /** + * 默认已有cellStyles样式 + */ + public static final int S = 1; } diff --git a/src/main/java/com/ibiz/excel/picture/support/flush/Sheet1Handler.java b/src/main/java/com/ibiz/excel/picture/support/flush/Sheet1Handler.java index 00233fc..be0ffa3 100644 --- a/src/main/java/com/ibiz/excel/picture/support/flush/Sheet1Handler.java +++ b/src/main/java/com/ibiz/excel/picture/support/flush/Sheet1Handler.java @@ -8,6 +8,7 @@ import org.springframework.util.CollectionUtils; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.util.List; +import java.util.Objects; import java.util.Optional; import java.util.Set; @@ -18,161 +19,175 @@ import java.util.Set; * @date 2020/7/618:33 */ public class Sheet1Handler implements InvocationHandler { - private IRepository target; + private IRepository target; - private StylesIndex stylesIndex = new StylesIndex(); + private StylesIndex stylesIndex = new StylesIndex(); - public Sheet1Handler(IRepository proxy) { - this.target = proxy; - } + public Sheet1Handler(IRepository proxy) { + this.target = proxy; + } - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - Sheet sheet = (Sheet) args[0]; - if (method.getName().equals("write")) { - List rows = sheet.getRows(); - if (!rows.isEmpty()) { - //未刷新过说明没有写入过流,这里主要为了写表头 - //如果写过了,则从脚标1开始,原因是为了对比合并单元格在row1中保存上一次刷新的最后一条数据 - int subIndex = !sheet.hasFlush() ? 0 : 1; - this.setMergeCell(sheet, rows); - //设置宽度 - this.setColumnWidth(sheet, subIndex); - rows.subList(subIndex, rows.size()).stream().forEach(r -> writeSheetXML(r)); - } - } else if (method.getName().equals("close")) { - setEndSheetData(); - setMergeContent(sheet); - } - return method.invoke(target, args); - } + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + Sheet sheet = (Sheet) args[0]; + if (method.getName().equals("write")) { + List rows = sheet.getRows(); + if (!rows.isEmpty()) { + //未刷新过说明没有写入过流,这里主要为了写表头 + //如果写过了,则从脚标1开始,原因是为了对比合并单元格在row1中保存上一次刷新的最后一条数据 + int subIndex = !sheet.hasFlush() ? 0 : 1; + this.setMergeCell(sheet, rows); + //设置宽度 + this.setColumnWidth(sheet, subIndex); + rows.subList(subIndex, rows.size()).stream().forEach(r -> writeSheetXML(r)); + } + } else if (method.getName().equals("close")) { + setEndSheetData(); + setMergeContent(sheet); + } + return method.invoke(target, args); + } - /** - * 设置列宽度 - * - * @param sheet - * @param subIndex - */ - private void setColumnWidth(Sheet sheet, int subIndex) { - if (subIndex == 0) { - StringBuilder content = new StringBuilder(); - content.append("") - // 默认宽度 - .append(""); - // 自定义的宽度 - sheet.getColumnHelperMap().entrySet().forEach(column -> - content.append("")); - content.append(""); - target.append(content.toString()); - } - } + /** + * 设置列宽度 + * + * @param sheet + * @param subIndex + */ + private void setColumnWidth(Sheet sheet, int subIndex) { + if (subIndex == 0) { + StringBuilder content = new StringBuilder(); + content.append("") + // 默认宽度 + .append(""); + // 自定义的宽度 + sheet.getColumnHelperMap().entrySet().forEach(column -> + content.append("")); + content.append(""); + target.append(content.toString()); + } + } - /** - * 增加合并列内容 - * - * @param sheet - */ - private void setMergeContent(Sheet sheet) { - Set colCells = sheet.getColCells(); - StringBuilder content = new StringBuilder(); - if (sheet.isAutoMergeCell() && !sheet.getMergeCells().isEmpty()) { - content.append(""); - sheet.getMergeCells().stream().forEach(m -> { - if (CollectionUtils.isEmpty(colCells)) { - //增加合并行内容 - Cell start = new Cell(m.getFirstRow(), m.getFirstCol()); - Cell end = new Cell(m.getLastRow(), m.getLastCol()); - content.append(""); - } else { - colCells.forEach(c -> content - .append("")); - } - }); - content.append(""); - } - target.append(content.toString()); - } + /** + * 增加合并列内容 + * + * @param sheet + */ + private void setMergeContent(Sheet sheet) { + Set colCells = sheet.getColCells(); + StringBuilder content = new StringBuilder(); + if (sheet.isAutoMergeCell() && !sheet.getMergeCells().isEmpty()) { + content.append(""); + sheet.getMergeCells().stream().forEach(m -> { + if (CollectionUtils.isEmpty(colCells)) { + //增加合并行内容 + Cell start = new Cell(m.getFirstRow(), m.getFirstCol()); + Cell end = new Cell(m.getLastRow(), m.getLastCol()); + content.append(""); + } else { + colCells.forEach(c -> content + .append("")); + } + }); + content.append(""); + } + target.append(content.toString()); + } - /** - * 列结尾 - */ - private void setEndSheetData() { - target.append(""); - } + /** + * 列结尾 + */ + private void setEndSheetData() { + target.append(""); + } - private void setMergeCell(Sheet sheet, List rows) { - String oldValue = ""; - for (int i = 0; i < rows.size(); i++) { - Row row = rows.get(i); - if (null == row) { - continue; - } - List cells = row.getCells(); - int mergeCellNumber = sheet.getMergeCellNumber(); - if (mergeCellNumber >= cells.size()) { - //合并列超出范围,不进行合并 - break; - } - Cell cell = cells.get(mergeCellNumber); - if (StringUtils.isNotBlank(oldValue) && oldValue.equals(cell.getValue())) { - MergeCell mergeCell = null; - if (!sheet.getMergeCells().isEmpty()) { - mergeCell = sheet.getMergeCells().getLast(); - } - if (null == mergeCell) { - mergeCell = new MergeCell(); - } - int endRowNumber = mergeCell.getLastRow(); - if (row.getRowNumber() == endRowNumber) { - //与上一个合并对象合并 - mergeCell.setLastRow(++endRowNumber); - } else { - mergeCell = new MergeCell().setFirstRow(row.getRowNumber()).setLastRow(row.getRowNumber() + 1); - sheet.getMergeCells().add(mergeCell); - } - } - oldValue = StringUtils.isBlank(cell.getValue()) ? "" : cell.getValue(); - } - } + private void setMergeCell(Sheet sheet, List rows) { + String oldValue = ""; + for (int i = 0; i < rows.size(); i++) { + Row row = rows.get(i); + if (null == row) { + continue; + } + List cells = row.getCells(); + int mergeCellNumber = sheet.getMergeCellNumber(); + if (mergeCellNumber >= cells.size()) { + //合并列超出范围,不进行合并 + break; + } + Cell cell = cells.get(mergeCellNumber); + if (StringUtils.isNotBlank(oldValue) && oldValue.equals(cell.getValue())) { + MergeCell mergeCell = null; + if (!sheet.getMergeCells().isEmpty()) { + mergeCell = sheet.getMergeCells().getLast(); + } + if (null == mergeCell) { + mergeCell = new MergeCell(); + } + int endRowNumber = mergeCell.getLastRow(); + if (row.getRowNumber() == endRowNumber) { + //与上一个合并对象合并 + mergeCell.setLastRow(++endRowNumber); + } else { + mergeCell = new MergeCell().setFirstRow(row.getRowNumber()).setLastRow(row.getRowNumber() + 1); + sheet.getMergeCells().add(mergeCell); + } + } + oldValue = StringUtils.isBlank(cell.getValue()) ? "" : cell.getValue(); + } + } - private void writeSheetXML(Row row) { - StringBuilder content = new StringBuilder(); - //customHeight=1 使用自定义高度 - content.append(""); - CellStyle cellStyle = row.getCellStyle(); - if(cellStyle != null){ - // 设置cellStyle样式下标 - stylesIndex.addCellStyle(cellStyle); - } - row.getCells().forEach(c -> content.append("") - .append("") - .append(c.getColDataNumber()) - .append("") - ); - content.append(""); - target.append(content.toString()); - } + private void writeSheetXML(Row row) { + StringBuilder content = new StringBuilder(); + //customHeight=1 使用自定义高度 + content.append(""); + CellStyle rowCellStyle = row.getCellStyle(); + // 设置cellStyle样式下标 + stylesIndex.addCellStyle(rowCellStyle); + + int colNumber = Optional.ofNullable(rowCellStyle).map(CellStyle::getColNumber).orElse(-1); + CellStyle cellStyle = rowCellStyle; + for (Cell c : row.getCells()) { + CellStyle cellCellStyle = c.getCellStyle(); + stylesIndex.addCellStyle(cellCellStyle); + if (Objects.nonNull(cellCellStyle)) { + cellStyle = cellCellStyle; + colNumber = c.getCellNumber(); + } + + int s; + if(colNumber == -1 || c.getCellNumber() == colNumber){ + s = Optional.ofNullable(cellStyle).map(CellStyle::getS).orElse(WorkbookConstant.S); + }else { + s = WorkbookConstant.S; + } + content.append("") + .append("") + .append(c.getColDataNumber()) + .append(""); + } + content.append(""); + target.append(content.toString()); + } } diff --git a/src/main/java/com/ibiz/excel/picture/support/flush/StylesHandler.java b/src/main/java/com/ibiz/excel/picture/support/flush/StylesHandler.java index e2a6845..ed6a75f 100644 --- a/src/main/java/com/ibiz/excel/picture/support/flush/StylesHandler.java +++ b/src/main/java/com/ibiz/excel/picture/support/flush/StylesHandler.java @@ -1,9 +1,6 @@ package com.ibiz.excel.picture.support.flush; -import com.ibiz.excel.picture.support.model.CellStyle; -import com.ibiz.excel.picture.support.model.Font; -import com.ibiz.excel.picture.support.model.Row; -import com.ibiz.excel.picture.support.model.Sheet; +import com.ibiz.excel.picture.support.model.*; import com.ibiz.excel.picture.support.util.StringUtils; import java.lang.reflect.InvocationHandler; @@ -62,16 +59,9 @@ public class StylesHandler implements InvocationHandler { Sheet sheet = (Sheet) args[0]; List rows = sheet.getRows(); if (!rows.isEmpty()) { - rows.stream().forEach(row -> { - CellStyle cellStyle = row.getCellStyle(); - if (row.getCellStyle() != null) { - // 追加字体 - this.appendFont(cellStyle.getFont()); - // 追加背景色样式 - this.appendFill(cellStyle); - // 追加调用下标样式 - this.appendXf(cellStyle); - } + rows.forEach(row -> { + addCellStyle(row.getCellStyle()); + row.getCells().forEach(cell -> addCellStyle(cell.getCellStyle())); }); } }else if (method.getName().equals("close")) { @@ -81,6 +71,17 @@ public class StylesHandler implements InvocationHandler { return method.invoke(target, args); } + private void addCellStyle(CellStyle cellStyle) { + if (cellStyle != null) { + // 追加字体 + this.appendFont(cellStyle.getFont()); + // 追加背景色样式 + this.appendFill(cellStyle); + // 追加调用下标样式 + this.appendXf(cellStyle); + } + } + /** * 追加调用下标样式 * diff --git a/src/main/java/com/ibiz/excel/picture/support/flush/StylesIndex.java b/src/main/java/com/ibiz/excel/picture/support/flush/StylesIndex.java index 3ecfa92..2a3f1bf 100644 --- a/src/main/java/com/ibiz/excel/picture/support/flush/StylesIndex.java +++ b/src/main/java/com/ibiz/excel/picture/support/flush/StylesIndex.java @@ -4,6 +4,8 @@ import com.ibiz.excel.picture.support.model.CellStyle; import com.ibiz.excel.picture.support.model.Font; import com.ibiz.excel.picture.support.util.StringUtils; +import java.util.Objects; + /** * 样式下标取值 * @@ -39,20 +41,22 @@ public class StylesIndex { * @param cellStyle */ protected void addCellStyle(CellStyle cellStyle) { - // 字体 - Font font = cellStyle.getFont(); - if(font != null){ - this.isSetFont = true; - }else { - this.isSetFont = false; - } - this.addIndex(cellStyle); - if(StringUtils.isNotBlank(cellStyle.getFgColorRgb())){ - cellStyle.setFillId(fillId); - } - cellStyle.setS(s); - if(font != null){ - font.setFontId(fontId); + if(Objects.nonNull(cellStyle)){ + // 字体 + Font font = cellStyle.getFont(); + if(font != null){ + this.isSetFont = true; + }else { + this.isSetFont = false; + } + this.addIndex(cellStyle); + if(StringUtils.isNotBlank(cellStyle.getFgColorRgb())){ + cellStyle.setFillId(fillId); + } + cellStyle.setS(s); + if(font != null){ + font.setFontId(fontId); + } } } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Cell.java b/src/main/java/com/ibiz/excel/picture/support/model/Cell.java index d75f5cc..d0a6284 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Cell.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Cell.java @@ -13,6 +13,11 @@ public class Cell { private int colDataNumber; //列对应值序号 private String value; //单元格值 + /** + * 该单元格样式 + */ + private CellStyle cellStyle; + public Cell(int cellNumber) { this.cellNumber = cellNumber; } @@ -96,4 +101,19 @@ public class Cell { public void setCellNumber(int cellNumber) { this.cellNumber = cellNumber; } + + /** + * 设置该单元格样式 + * + * @param cellStyle + * @return + */ + public Cell setCellStyle(CellStyle cellStyle) { + this.cellStyle = cellStyle; + return this; + } + + public CellStyle getCellStyle() { + return cellStyle; + } } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java b/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java index be63d28..28c076b 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java @@ -1,5 +1,7 @@ package com.ibiz.excel.picture.support.model; +import com.ibiz.excel.picture.support.constants.WorkbookConstant; + /** * 控制该行样式 * @@ -17,13 +19,18 @@ public class CellStyle{ /** * 默认已有cellStyles样式 */ - private int s = 1; + private int s = WorkbookConstant.S; /** * 行号 */ private int rowNumber; + /** + * 列号 + */ + private Integer colNumber; + /** * fgColor rgb颜色 * RGB网页颜色在线取色器 https://link.fobshanghai.com/rgbcolor.htm @@ -65,6 +72,12 @@ public class CellStyle{ this.fgColorRgb = fgColorRgb; } + public CellStyle(int rowNumber, int colNumber, String fgColorRgb) { + this.rowNumber = rowNumber; + this.colNumber = colNumber; + this.fgColorRgb = fgColorRgb; + } + public CellStyle(CellStyle cellStyle) { this.fgColorRgb = cellStyle.fgColorRgb; } @@ -104,4 +117,12 @@ public class CellStyle{ public void setS(int s) { this.s = s; } + + public Integer getColNumber() { + return colNumber; + } + + public void setColNumber(Integer colNumber) { + this.colNumber = colNumber; + } } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Row.java b/src/main/java/com/ibiz/excel/picture/support/model/Row.java index e89e2c8..d522951 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Row.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Row.java @@ -8,13 +8,13 @@ import java.util.List; * @date 2020/7/217:33 */ public class Row { - private int rowNumber; //行号 + private int rowNumber; //行号 private int autoHeight = 30; //默认行高 /** * 默认列头为30 * setHeight后使用设置的值,必须大于0 */ - private int height; //列高 + private int height; //列高 private List cells = new ArrayList<>(); /** @@ -22,26 +22,31 @@ public class Row { */ private CellStyle cellStyle; - public Row(){ + public Row() { this(1); } - public Row(int rowNumber){ + + public Row(int rowNumber) { this.rowNumber = rowNumber; } + public int getHeight() { return height <= 0 ? autoHeight : height; } /** * 设置行高 + * * @param height */ public void setHeight(int height) { this.height = height; } + public int getRowNumber() { return rowNumber; } + public void setRowNumber(int rowNumber) { this.rowNumber = rowNumber; } @@ -60,17 +65,17 @@ public class Row { * @param cells */ public void autoRowCells(List cells) { - cells.parallelStream().forEach(cell-> cell.autoSetRowNumber(rowNumber)); + cells.parallelStream().forEach(cell -> cell.autoSetRowNumber(rowNumber)); this.cells = cells; } - public Cell createCell(int cellNumber){ - Cell cell = new Cell(rowNumber,cellNumber); + public Cell createCell(int cellNumber) { + Cell cell = new Cell(rowNumber, cellNumber); cells.add(cell); return cell; } - public void clear(){ + public void clear() { this.cells.clear(); } @@ -80,6 +85,7 @@ public class Row { /** * 设置行样式 + * * @param cellStyle * @return */ @@ -100,4 +106,14 @@ public class Row { autoRowCells(cells); return this; } + + /** + * 获取单元格 + * + * @param num 单元格号 + * @return + */ + public Cell getCell(int num) { + return this.getCells().get(num); + } } diff --git a/src/main/java/com/ibiz/excel/picture/support/processor/ExcelTableProcessor.java b/src/main/java/com/ibiz/excel/picture/support/processor/ExcelTableProcessor.java index 736746e..6e88d05 100644 --- a/src/main/java/com/ibiz/excel/picture/support/processor/ExcelTableProcessor.java +++ b/src/main/java/com/ibiz/excel/picture/support/processor/ExcelTableProcessor.java @@ -131,9 +131,11 @@ public class ExcelTableProcessor { * 批量添加样式 * * @param cellStyles + * @return */ - public void addCellStyle(List cellStyles) { + public ExcelTableProcessor addCellStyle(List cellStyles) { cellStyles.forEach(cellStyle -> this.cellStyleMap.put(cellStyle.getRowNumber(), cellStyle)); + return this; } /** diff --git a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20230110.java b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20230110.java new file mode 100644 index 0000000..1c8ed54 --- /dev/null +++ b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20230110.java @@ -0,0 +1,95 @@ +package com.ibiz.excel.picture.support.example; + +import com.ibiz.excel.picture.support.common.BaseJunitTest; +import com.ibiz.excel.picture.support.model.*; +import com.ibiz.excel.picture.support.pojo.Student; +import com.ibiz.excel.picture.support.pojo.UserPicture; +import com.ibiz.excel.picture.support.processor.ExcelTableProcessor; +import com.ibiz.excel.picture.support.util.WebUtil; +import org.junit.Ignore; +import org.junit.Test; + +import java.util.*; + +/** + * @author MinWeikai + * @date 2023-01-10 17:07:51 + * @description 单个单元格添加样式示例 + */ +@Ignore +public class ExportExample_20230110 extends BaseJunitTest { + + @Test + public void export() { + Workbook workBook = Workbook.getInstance(); + Sheet sheet = workBook.createSheet("测试"); + // 给标题行加上背景色,加颜色时,会对字体加粗 + sheet.addCellStyle(new CellStyle(0, "66cc66")); + UserPicture userPicture; + for (int r = 0; r < 5; r++) { + userPicture = new UserPicture(); + userPicture.setAge(15); + userPicture.setName("测试-" + r); + // 导出本地单张图片 + userPicture.setPicture(IMG_PATH_1); + // 导出url单张图片 + userPicture.setHeaderPicture(getUrl()); + // 导出本地图片集合 + userPicture.setPictures(getPictures(new Random().nextInt(5))); + // 导出url图片集合 + userPicture.setUrlPictures(getUrls(5)); +// sheet.createRow(userPicture); + sheet.createRow(userPicture).getCell(0).setCellStyle(new CellStyle("9F79EE")); + } + WebUtil.writeExcelTest(workBook, "ExportExample_20230110_".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), TEMP_PATH); + } + + @Test + public void export1() { + // 模拟需要导出的数据集合 + List students = new ArrayList<>(); + students.add(new Student("李四", 16, null, null, 0)); + students.add(new Student("张三", 17, null, getPictures(5), 1)); + students.add(new Student("王五", 15, IMG_PATH_1, null, 2)); + + // 配置导出excel的表头、顺序、对应导出的数据集合的字段、是否是图片、单元格宽度等 + List excels = new ArrayList<>(); + excels.add(new BizExcelRel("姓名", "name", 2)); + excels.add(new BizExcelRel("年龄", "age", 3)); + excels.add(new BizExcelRel("表现", "performance", 4)); + excels.add(new BizExcelRel("头像", "headPicture", 5, true, 20)); + excels.add(new BizExcelRel("相册", "album", 6, true)); + + + // 创建excel + Workbook workBook = Workbook.getInstance(100); + Sheet sheet = workBook.createSheet("测试"); + + //要进行合并的列 + sheet.addMergeCell(new MergeCell(0, 0, 0, 2)); + + // 创建样式 + CellStyle cellStyle = new CellStyle(0, "66cc66"); + + List cellStyles = Arrays.asList(cellStyle); + + // 创建数据字典 + Map performanceMap = new HashMap<>(); + performanceMap.put("0", "一般"); + performanceMap.put("1", "良好"); + performanceMap.put("2", "优秀"); + + // 构建sheet + ExcelTableProcessor.sheet(sheet) + // 添加样式 + .addCellStyle(cellStyles) + // 添加对应属性字段的数据字典 + .registryEnumMap("performance", performanceMap) + // 构建excel + .buildExcel(excels, students); + + WebUtil.writeExcelTest(workBook, "ExportExample_20230110_".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), TEMP_PATH); + } + + +} -- Gitee From 7403d1ac0565fd6266e02471a689e5171418b531 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Thu, 12 Jan 2023 17:12:27 +0800 Subject: [PATCH 137/161] =?UTF-8?q?perf=20=E7=BB=99=E5=8D=95=E4=B8=AA?= =?UTF-8?q?=E5=8D=95=E5=85=83=E6=A0=BC=E6=B7=BB=E5=8A=A0=E6=A0=B7=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../picture/support/flush/Sheet1Handler.java | 19 +++++------------- .../picture/support/model/CellStyle.java | 6 +++--- .../processor/ExcelTableProcessor.java | 20 ++++++++++++------- .../example/ExportExample_20230110.java | 11 +++++++--- 4 files changed, 29 insertions(+), 27 deletions(-) diff --git a/src/main/java/com/ibiz/excel/picture/support/flush/Sheet1Handler.java b/src/main/java/com/ibiz/excel/picture/support/flush/Sheet1Handler.java index be0ffa3..0a24db7 100644 --- a/src/main/java/com/ibiz/excel/picture/support/flush/Sheet1Handler.java +++ b/src/main/java/com/ibiz/excel/picture/support/flush/Sheet1Handler.java @@ -161,26 +161,17 @@ public class Sheet1Handler implements InvocationHandler { // 设置cellStyle样式下标 stylesIndex.addCellStyle(rowCellStyle); - int colNumber = Optional.ofNullable(rowCellStyle).map(CellStyle::getColNumber).orElse(-1); - CellStyle cellStyle = rowCellStyle; for (Cell c : row.getCells()) { - CellStyle cellCellStyle = c.getCellStyle(); - stylesIndex.addCellStyle(cellCellStyle); - if (Objects.nonNull(cellCellStyle)) { - cellStyle = cellCellStyle; - colNumber = c.getCellNumber(); + CellStyle cellStyle = c.getCellStyle(); + stylesIndex.addCellStyle(cellStyle); + if (Objects.isNull(cellStyle)) { + cellStyle = rowCellStyle; } - int s; - if(colNumber == -1 || c.getCellNumber() == colNumber){ - s = Optional.ofNullable(cellStyle).map(CellStyle::getS).orElse(WorkbookConstant.S); - }else { - s = WorkbookConstant.S; - } content.append("") .append("") .append(c.getColDataNumber()) diff --git a/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java b/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java index 28c076b..e0405cf 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java @@ -24,7 +24,7 @@ public class CellStyle{ /** * 行号 */ - private int rowNumber; + private Integer rowNumber; /** * 列号 @@ -94,11 +94,11 @@ public class CellStyle{ this.fgColorRgb = fgColorRgb; } - public int getRowNumber() { + public Integer getRowNumber() { return rowNumber; } - public void setRowNumber(int rowNumber) { + public void setRowNumber(Integer rowNumber) { this.rowNumber = rowNumber; } diff --git a/src/main/java/com/ibiz/excel/picture/support/processor/ExcelTableProcessor.java b/src/main/java/com/ibiz/excel/picture/support/processor/ExcelTableProcessor.java index 6e88d05..7429127 100644 --- a/src/main/java/com/ibiz/excel/picture/support/processor/ExcelTableProcessor.java +++ b/src/main/java/com/ibiz/excel/picture/support/processor/ExcelTableProcessor.java @@ -45,7 +45,7 @@ public class ExcelTableProcessor { /** * 样式 */ - private final Map cellStyleMap = new HashMap<>(); + private final List cellStyles = new ArrayList<>(); /** * key : 对象的field属性名称 @@ -61,11 +61,11 @@ public class ExcelTableProcessor { */ public void buildExcel(List excels, List list) { // 开始行放标题 - Row row = sheet.createRow(startRow).setCellStyle(cellStyleMap.get(startRow)); + Row row = sheet.createRow(startRow).setCellStyle(getCellStyle(startRow, null)); List cells = new ArrayList<>(); for (int i = startCell; i < excels.size(); i++) { BizExcelRel rel = excels.get(i); - cells.add(new Cell(i).setValue(rel.getExcelName())); + cells.add(new Cell(i).setValue(rel.getExcelName()).setCellStyle(getCellStyle(startRow, i))); // 设置单元格宽度 sheet.setColumnWidth(rel.getOrderNo(), rel.getCellWeight()); } @@ -74,7 +74,7 @@ public class ExcelTableProcessor { for (int j = 0; j < list.size(); j++) { // 开始行的下一行放内容 num = startRow + j + 1; - row = sheet.createRow(num).setCellStyle(cellStyleMap.get(num)); + row = sheet.createRow(num).setCellStyle(getCellStyle(num, null)); cells = new ArrayList<>(); int index = startCell; BizExcelPojoInterface excelPojoInterface = list.get(j); @@ -94,13 +94,19 @@ public class ExcelTableProcessor { row.setHeight(rowHeight); // 数据字典值获取 value = getValueByFiledEnumMap(excel.getField(), value); - cells.add(new Cell(num, index++).setValue(value)); + cells.add(new Cell(num, index++).setValue(value).setCellStyle(getCellStyle(num, index))); row.setCells(cells); } } } + private CellStyle getCellStyle(Integer row, Integer col) { + return this.cellStyles.stream() + .filter(c -> Objects.equals(c.getRowNumber(), row) && Objects.equals(col, c.getColNumber())) + .findFirst().orElse(null); + } + /** * 数据字典值获取 * @@ -134,7 +140,7 @@ public class ExcelTableProcessor { * @return */ public ExcelTableProcessor addCellStyle(List cellStyles) { - cellStyles.forEach(cellStyle -> this.cellStyleMap.put(cellStyle.getRowNumber(), cellStyle)); + this.cellStyles.addAll(cellStyles); return this; } @@ -145,7 +151,7 @@ public class ExcelTableProcessor { * @return */ public ExcelTableProcessor addCellStyle(CellStyle cellStyle) { - this.cellStyleMap.put(cellStyle.getRowNumber(), cellStyle); + this.cellStyles.add(cellStyle); return this; } diff --git a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20230110.java b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20230110.java index 1c8ed54..450a836 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20230110.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20230110.java @@ -69,9 +69,14 @@ public class ExportExample_20230110 extends BaseJunitTest { sheet.addMergeCell(new MergeCell(0, 0, 0, 2)); // 创建样式 - CellStyle cellStyle = new CellStyle(0, "66cc66"); - - List cellStyles = Arrays.asList(cellStyle); + List cellStyles = Arrays.asList( + new CellStyle(0, "66cc66"), + new CellStyle(0, 3, "9F79EE"), + new CellStyle(1, 2, "9F79EE"), + new CellStyle(2, 0, "9F79EE"), + new CellStyle(2, 1, "9F79EE"), + new CellStyle(3, 2, "66cc66") + ); // 创建数据字典 Map performanceMap = new HashMap<>(); -- Gitee From 96078ae0158d22dee5ae123a0ee810f29eb25eee Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Thu, 12 Jan 2023 17:20:32 +0800 Subject: [PATCH 138/161] =?UTF-8?q?add=202.4.0=E7=89=88=E6=9C=AC=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 0656e18..273452e 100644 --- a/README.md +++ b/README.md @@ -322,6 +322,12 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, 3. ### 版本更迭 + *点击可跳转链接可以查看功能使用示例* + + #### 2.4.0(2022.01.12) + + - [添加可以给单个单元格设置样式](https://gitee.com/mwk719/excel-batch-picture-support/blob/dev/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20230110.java) + #### 2.3.1(2022.12.19) - 修复渲染生成列元素A-Z坐标时,使用到Z时,下一列从AA开始 -- Gitee From e9c60f0f4e823d3fc327d76193841f87926c98a5 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Thu, 12 Jan 2023 17:21:54 +0800 Subject: [PATCH 139/161] =?UTF-8?q?update=202.4.0=E7=89=88=E6=9C=AC?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=E8=AF=B4=E6=98=8E=E6=97=B6=E9=97=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 273452e..f4eca48 100644 --- a/README.md +++ b/README.md @@ -324,7 +324,7 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, *点击可跳转链接可以查看功能使用示例* - #### 2.4.0(2022.01.12) + #### 2.4.0(2023.01.12) - [添加可以给单个单元格设置样式](https://gitee.com/mwk719/excel-batch-picture-support/blob/dev/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20230110.java) -- Gitee From e815d45172142f958748592695f19d833e862c9f Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Thu, 12 Jan 2023 17:23:02 +0800 Subject: [PATCH 140/161] release 2.4.0 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 5b83795..ea3c69d 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 top.minwk excel-x - 2.3.1 + 2.4.0 excel-x 支持excel中批量导出图片 https://gitee.com/mwk719/excel-batch-picture-support @@ -34,7 +34,7 @@ minwk minweikai@gmail.com - 凯创未来科技 + 影落离风 https://minwk.top/ -- Gitee From b6fa35ebefaecac321760e9b144c1a7c7b2168f6 Mon Sep 17 00:00:00 2001 From: mwk719 Date: Fri, 13 Jan 2023 10:47:24 +0800 Subject: [PATCH 141/161] update org.springframework:spring-beans 5.3.14 to 5.3.15 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ea3c69d..c7f94be 100644 --- a/pom.xml +++ b/pom.xml @@ -17,7 +17,7 @@ 8 1.8 - 5.3.14 + 5.3.15 5.7.18 4.13.2 -- Gitee From eb1e2bb401271944e876b7a185803e8ac09a8264 Mon Sep 17 00:00:00 2001 From: mwk719 Date: Fri, 13 Jan 2023 10:48:33 +0800 Subject: [PATCH 142/161] update cn.hutool:hutool-http 5.7.18 to 5.7.19 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c7f94be..4382f6f 100644 --- a/pom.xml +++ b/pom.xml @@ -18,7 +18,7 @@ 8 1.8 5.3.15 - 5.7.18 + 5.7.19 4.13.2 -- Gitee From 1a2dbc209bec3298d7ca778087c09ad086b3bf09 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Fri, 13 Jan 2023 17:10:42 +0800 Subject: [PATCH 143/161] ignore excel-x.iml --- .gitignore | 2 +- excel-x.iml | 24 ------------------------ 2 files changed, 1 insertion(+), 25 deletions(-) delete mode 100644 excel-x.iml diff --git a/.gitignore b/.gitignore index 1b74b13..62120cd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ /target /.idea -/*.iml /.mvn/ +/*.iml diff --git a/excel-x.iml b/excel-x.iml deleted file mode 100644 index 9471f3b..0000000 --- a/excel-x.iml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file -- Gitee From 60c656095389e0f152a16c47290b73eb99765292 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Fri, 5 May 2023 10:54:44 +0800 Subject: [PATCH 144/161] =?UTF-8?q?add=20=E9=97=AE=E9=A2=98=E5=8F=8D?= =?UTF-8?q?=E9=A6=88=E5=85=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index f4eca48..2d944f5 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,10 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, 经测试,可以生成几个G的文件。(保证生成的文件没问题,文件是否能打开由使用者计算机决定) +## 问题反馈 + +- [Gitee issue](https://gitee.com/mwk719/excel-batch-picture-support/issues) + ## 快速使用 1. ### Maven导入 -- Gitee From 08edb629a5953ff13f0a07b0f0cdba1588391c45 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Thu, 25 May 2023 16:36:30 +0800 Subject: [PATCH 145/161] =?UTF-8?q?add=20=E8=AE=BE=E7=BD=AE=E8=BE=B9?= =?UTF-8?q?=E6=A1=86=E5=8A=A0=E7=B2=97=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../picture/support/constants/WorkbookConstant.java | 5 +++++ .../ibiz/excel/picture/support/flush/StylesHandler.java | 9 ++++++--- .../picture/support/example/ExportExample_20230110.java | 3 ++- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/ibiz/excel/picture/support/constants/WorkbookConstant.java b/src/main/java/com/ibiz/excel/picture/support/constants/WorkbookConstant.java index 1f32870..6b9770d 100644 --- a/src/main/java/com/ibiz/excel/picture/support/constants/WorkbookConstant.java +++ b/src/main/java/com/ibiz/excel/picture/support/constants/WorkbookConstant.java @@ -35,4 +35,9 @@ public class WorkbookConstant { * 默认已有cellStyles样式 */ public static final int S = 1; + + /** + * 边框加粗,默认为1加粗,0不加粗 + */ + public static int BORDER_BOLD = 1; } diff --git a/src/main/java/com/ibiz/excel/picture/support/flush/StylesHandler.java b/src/main/java/com/ibiz/excel/picture/support/flush/StylesHandler.java index ed6a75f..9c938b1 100644 --- a/src/main/java/com/ibiz/excel/picture/support/flush/StylesHandler.java +++ b/src/main/java/com/ibiz/excel/picture/support/flush/StylesHandler.java @@ -1,5 +1,6 @@ package com.ibiz.excel.picture.support.flush; +import com.ibiz.excel.picture.support.constants.WorkbookConstant; import com.ibiz.excel.picture.support.model.*; import com.ibiz.excel.picture.support.util.StringUtils; @@ -47,8 +48,8 @@ public class StylesHandler implements InvocationHandler { "").concat( "").concat( "").concat( - "") - ); + "")); private final StringBuilder cellStyles = new StringBuilder("".concat( "")); @@ -93,7 +94,9 @@ public class StylesHandler implements InvocationHandler { .append(Optional.ofNullable(font).map(Font::getFontId).orElse(0)) .append("\" fillId=\"") .append(cellStyle.getFillId()) - .append("\" borderId=\"1\" xfId=\"0\" applyFont=\"1\" applyAlignment=\"1\">"); + .append("\" borderId=\"") + .append(WorkbookConstant.BORDER_BOLD) + .append("\" xfId=\"0\" applyFont=\"1\" applyAlignment=\"1\">"); } /** diff --git a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20230110.java b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20230110.java index 450a836..1b5eda1 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20230110.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20230110.java @@ -60,7 +60,8 @@ public class ExportExample_20230110 extends BaseJunitTest { excels.add(new BizExcelRel("头像", "headPicture", 5, true, 20)); excels.add(new BizExcelRel("相册", "album", 6, true)); - +// // 设置边框不加粗 +// WorkbookConstant.BORDER_BOLD = 0; // 创建excel Workbook workBook = Workbook.getInstance(100); Sheet sheet = workBook.createSheet("测试"); -- Gitee From 2956f9f7d3a15d2fe9179029f03472f07a61db8d Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Thu, 25 May 2023 18:45:33 +0800 Subject: [PATCH 146/161] =?UTF-8?q?add=20=E5=AF=B9=E8=A1=8C=E6=A0=B7?= =?UTF-8?q?=E5=BC=8F=E8=AE=BE=E7=BD=AE=E8=BE=B9=E6=A1=86=E5=8A=A0=E7=B2=97?= =?UTF-8?q?=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../support/constants/WorkbookConstant.java | 12 +++++++- .../picture/support/flush/StylesHandler.java | 2 +- .../picture/support/model/CellStyle.java | 30 +++++++++++++++---- .../example/ExportExample_20230110.java | 8 ++--- 4 files changed, 41 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/ibiz/excel/picture/support/constants/WorkbookConstant.java b/src/main/java/com/ibiz/excel/picture/support/constants/WorkbookConstant.java index 6b9770d..460267d 100644 --- a/src/main/java/com/ibiz/excel/picture/support/constants/WorkbookConstant.java +++ b/src/main/java/com/ibiz/excel/picture/support/constants/WorkbookConstant.java @@ -9,7 +9,9 @@ public class WorkbookConstant { public static final String FILE_SEPARATOR = "/"; public static final String DEST_FILE_NAME_SUFFIX = ".xlsx"; public static final String MEDIA_IMAGE_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"; - /**有图片的行高设置为100*/ + /** + * 有图片的行高设置为100 + */ public static final int PICTURE_ROW_HEIGHT = 100; /** @@ -40,4 +42,12 @@ public class WorkbookConstant { * 边框加粗,默认为1加粗,0不加粗 */ public static int BORDER_BOLD = 1; + + /** + * 边框加粗,true加粗,false不加粗 + * @param borderBold + */ + public static void setBorderBold(boolean borderBold) { + BORDER_BOLD = borderBold ? 1 : 0; + } } diff --git a/src/main/java/com/ibiz/excel/picture/support/flush/StylesHandler.java b/src/main/java/com/ibiz/excel/picture/support/flush/StylesHandler.java index 9c938b1..be17f73 100644 --- a/src/main/java/com/ibiz/excel/picture/support/flush/StylesHandler.java +++ b/src/main/java/com/ibiz/excel/picture/support/flush/StylesHandler.java @@ -95,7 +95,7 @@ public class StylesHandler implements InvocationHandler { .append("\" fillId=\"") .append(cellStyle.getFillId()) .append("\" borderId=\"") - .append(WorkbookConstant.BORDER_BOLD) + .append(Optional.ofNullable(cellStyle.getBorderBold()).orElse(WorkbookConstant.BORDER_BOLD)) .append("\" xfId=\"0\" applyFont=\"1\" applyAlignment=\"1\">"); } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java b/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java index e0405cf..0f74db0 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java @@ -8,7 +8,7 @@ import com.ibiz.excel.picture.support.constants.WorkbookConstant; * @author MinWeikai * @date 2021/1/19 14:04 */ -public class CellStyle{ +public class CellStyle { /** * 默认已有fill样式 @@ -42,6 +42,8 @@ public class CellStyle{ */ private Font font; + private Integer borderBold; + public CellStyle() { } @@ -64,18 +66,27 @@ public class CellStyle{ /** * 根据行号设置颜色 + * * @param rowNumber * @param fgColorRgb RGB网页颜色在线取色器 https://link.fobshanghai.com/rgbcolor.htm */ - public CellStyle(int rowNumber, String fgColorRgb) { - this.rowNumber = rowNumber; - this.fgColorRgb = fgColorRgb; + public CellStyle(Integer rowNumber, String fgColorRgb) { + this(rowNumber, null, fgColorRgb, null); + } + + public CellStyle(Integer rowNumber, String fgColorRgb, Boolean borderBold) { + this(rowNumber, null, fgColorRgb, borderBold); } - public CellStyle(int rowNumber, int colNumber, String fgColorRgb) { + public CellStyle(Integer rowNumber, Integer colNumber, String fgColorRgb) { + this(rowNumber, colNumber, fgColorRgb, null); + } + + public CellStyle(Integer rowNumber, Integer colNumber, String fgColorRgb, Boolean borderBold) { this.rowNumber = rowNumber; this.colNumber = colNumber; this.fgColorRgb = fgColorRgb; + this.setBorderBold(borderBold); } public CellStyle(CellStyle cellStyle) { @@ -125,4 +136,13 @@ public class CellStyle{ public void setColNumber(Integer colNumber) { this.colNumber = colNumber; } + + public Integer getBorderBold() { + return this.borderBold; + } + + public void setBorderBold(Boolean borderBold) { + this.borderBold = borderBold != null ? (borderBold ? 1 : 0) : null; + ; + } } diff --git a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20230110.java b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20230110.java index 1b5eda1..3c9e84e 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20230110.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20230110.java @@ -1,6 +1,7 @@ package com.ibiz.excel.picture.support.example; import com.ibiz.excel.picture.support.common.BaseJunitTest; +import com.ibiz.excel.picture.support.constants.WorkbookConstant; import com.ibiz.excel.picture.support.model.*; import com.ibiz.excel.picture.support.pojo.Student; import com.ibiz.excel.picture.support.pojo.UserPicture; @@ -60,8 +61,7 @@ public class ExportExample_20230110 extends BaseJunitTest { excels.add(new BizExcelRel("头像", "headPicture", 5, true, 20)); excels.add(new BizExcelRel("相册", "album", 6, true)); -// // 设置边框不加粗 -// WorkbookConstant.BORDER_BOLD = 0; + WorkbookConstant.setBorderBold(false); // 创建excel Workbook workBook = Workbook.getInstance(100); Sheet sheet = workBook.createSheet("测试"); @@ -71,8 +71,8 @@ public class ExportExample_20230110 extends BaseJunitTest { // 创建样式 List cellStyles = Arrays.asList( - new CellStyle(0, "66cc66"), - new CellStyle(0, 3, "9F79EE"), + new CellStyle(0, "66cc66", true), + new CellStyle(0, 3, "9F79EE", true), new CellStyle(1, 2, "9F79EE"), new CellStyle(2, 0, "9F79EE"), new CellStyle(2, 1, "9F79EE"), -- Gitee From f57a3bbf79716e38b2c3c965d387d738da281891 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Fri, 2 Jun 2023 16:18:56 +0800 Subject: [PATCH 147/161] =?UTF-8?q?fix=20Microsoft=20Excel2010=E6=89=93?= =?UTF-8?q?=E5=BC=80=E5=8D=95=E5=85=83=E6=A0=BC=E8=B6=85=E5=AE=BD=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../excel/picture/support/processor/ExcelTableProcessor.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/ibiz/excel/picture/support/processor/ExcelTableProcessor.java b/src/main/java/com/ibiz/excel/picture/support/processor/ExcelTableProcessor.java index 7429127..0484855 100644 --- a/src/main/java/com/ibiz/excel/picture/support/processor/ExcelTableProcessor.java +++ b/src/main/java/com/ibiz/excel/picture/support/processor/ExcelTableProcessor.java @@ -67,7 +67,9 @@ public class ExcelTableProcessor { BizExcelRel rel = excels.get(i); cells.add(new Cell(i).setValue(rel.getExcelName()).setCellStyle(getCellStyle(startRow, i))); // 设置单元格宽度 - sheet.setColumnWidth(rel.getOrderNo(), rel.getCellWeight()); + if(rel.getCellWeight() > 0){ + sheet.setColumnWidth(rel.getOrderNo(), rel.getCellWeight()); + } } row.autoRowCells(cells); int num; -- Gitee From 8b0bbaf435b09d91b1ada0afc679c841282ffbae Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Fri, 2 Jun 2023 18:27:38 +0800 Subject: [PATCH 148/161] =?UTF-8?q?perf=20=E5=88=9B=E5=BB=BA=E6=A0=87?= =?UTF-8?q?=E9=A2=98=E6=97=B6=E6=8E=A7=E5=88=B6=E5=88=97=E9=A1=BA=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../excel/picture/support/model/BizExcelRel.java | 16 ++++++++++++++++ .../support/processor/ExcelTableProcessor.java | 8 +++++--- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/ibiz/excel/picture/support/model/BizExcelRel.java b/src/main/java/com/ibiz/excel/picture/support/model/BizExcelRel.java index 8a29464..1baaabc 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/BizExcelRel.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/BizExcelRel.java @@ -11,6 +11,22 @@ public class BizExcelRel { public BizExcelRel() { } + /** + * 创建标题,默认使用在列表中的添加顺序 + * @param excelName + * @param field + */ + public BizExcelRel(String excelName, String field) { + this.excelName = excelName; + this.field = field; + } + + /** + * 创建标题,可自定义列的顺序 + * @param excelName + * @param field + * @param orderNo + */ public BizExcelRel(String excelName, String field, int orderNo) { this.excelName = excelName; this.field = field; diff --git a/src/main/java/com/ibiz/excel/picture/support/processor/ExcelTableProcessor.java b/src/main/java/com/ibiz/excel/picture/support/processor/ExcelTableProcessor.java index 0484855..c8a719d 100644 --- a/src/main/java/com/ibiz/excel/picture/support/processor/ExcelTableProcessor.java +++ b/src/main/java/com/ibiz/excel/picture/support/processor/ExcelTableProcessor.java @@ -63,8 +63,10 @@ public class ExcelTableProcessor { // 开始行放标题 Row row = sheet.createRow(startRow).setCellStyle(getCellStyle(startRow, null)); List cells = new ArrayList<>(); + BizExcelRel rel; + excels = excels.stream().sorted(Comparator.comparing(BizExcelRel::getOrderNo)).collect(Collectors.toList()); for (int i = startCell; i < excels.size(); i++) { - BizExcelRel rel = excels.get(i); + rel = excels.get(i); cells.add(new Cell(i).setValue(rel.getExcelName()).setCellStyle(getCellStyle(startRow, i))); // 设置单元格宽度 if(rel.getCellWeight() > 0){ @@ -73,14 +75,14 @@ public class ExcelTableProcessor { } row.autoRowCells(cells); int num; + BizExcelPojoInterface excelPojoInterface; for (int j = 0; j < list.size(); j++) { // 开始行的下一行放内容 num = startRow + j + 1; row = sheet.createRow(num).setCellStyle(getCellStyle(num, null)); cells = new ArrayList<>(); int index = startCell; - BizExcelPojoInterface excelPojoInterface = list.get(j); - excels = excels.stream().sorted(Comparator.comparing(BizExcelRel::getOrderNo)).collect(Collectors.toList()); + excelPojoInterface = list.get(j); for (BizExcelRel excel : excels) { Object propertyValue = BeanUtil.getFieldValue(excelPojoInterface, excel.getField()); String value; -- Gitee From ddc1d3b794f9325b4222ed8463b5d5f302fd6842 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Tue, 6 Jun 2023 18:20:23 +0800 Subject: [PATCH 149/161] release 2.4.1 --- README.md | 6 ++++++ pom.xml | 2 +- .../picture/support/example/ExportExample_20230110.java | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f4eca48..7380b00 100644 --- a/README.md +++ b/README.md @@ -324,6 +324,12 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, *点击可跳转链接可以查看功能使用示例* + #### 2.4.1(2023.06.06) + + - [添加对全局边框进行加粗、对单元格边框加粗配置](https://gitee.com/mwk719/excel-batch-picture-support/blob/dev/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20230110.java#L64) + - 修复Microsoft Excel2010打开单元格超宽问题 + - 优化创建标题时控制列顺序 + #### 2.4.0(2023.01.12) - [添加可以给单个单元格设置样式](https://gitee.com/mwk719/excel-batch-picture-support/blob/dev/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20230110.java) diff --git a/pom.xml b/pom.xml index 4382f6f..db41d39 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 top.minwk excel-x - 2.4.0 + 2.4.1 excel-x 支持excel中批量导出图片 https://gitee.com/mwk719/excel-batch-picture-support diff --git a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20230110.java b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20230110.java index 3c9e84e..41496c3 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20230110.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20230110.java @@ -61,6 +61,7 @@ public class ExportExample_20230110 extends BaseJunitTest { excels.add(new BizExcelRel("头像", "headPicture", 5, true, 20)); excels.add(new BizExcelRel("相册", "album", 6, true)); + // 设置对全局操作边框是否加粗 WorkbookConstant.setBorderBold(false); // 创建excel Workbook workBook = Workbook.getInstance(100); -- Gitee From 8e57d7205fda41cfcc39a612e99fe815413da1f1 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Thu, 15 Jun 2023 14:33:58 +0800 Subject: [PATCH 150/161] =?UTF-8?q?fix=20=E5=BD=93=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=88=97=E8=B6=85=E8=BF=8752=E5=88=97=E6=97=B6=E5=87=BA?= =?UTF-8?q?=E7=8E=B0=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ibiz/excel/picture/support/model/Cell.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Cell.java b/src/main/java/com/ibiz/excel/picture/support/model/Cell.java index d0a6284..eb4afce 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Cell.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Cell.java @@ -5,7 +5,6 @@ package com.ibiz.excel.picture.support.model; * @date 2020/7/217:31 */ public class Cell { - private final String[] CELL_NUMBER_LINE = {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"}; private int cellNumber;//第几列 private int rowNumber;//行号 private String colNumber = "";//列号 例 A1 B1 @@ -41,14 +40,15 @@ public class Cell { * @param cellNumber */ public void autoSetCell(int rowNumber, int cellNumber) { - int line = cellNumber; - if (cellNumber >= CELL_NUMBER_LINE.length) { - line = cellNumber - CELL_NUMBER_LINE.length; - colNumber += "A"; + StringBuilder colName = new StringBuilder(); + int mod; + while (cellNumber > 0) { + mod = (cellNumber - 1) % 26; + colName.insert(0, (char) ('A' + mod)); + cellNumber = (cellNumber - 1) / 26; } - col += colNumber + CELL_NUMBER_LINE[line]; - colNumber = ""; - colNumber += CELL_NUMBER_LINE[line] + (rowNumber + 1); + colNumber = colName.toString(); + col += colNumber + (rowNumber + 1); } public String getColNumber() { -- Gitee From 3e529159f80f7c3ff974c0cbe4613a4d8708e2f6 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Thu, 13 Jul 2023 11:45:07 +0800 Subject: [PATCH 151/161] =?UTF-8?q?add=20=E5=86=85=E5=AE=B9=E5=AF=B9?= =?UTF-8?q?=E9=BD=90=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../support/constants/WorkbookConstant.java | 18 +++++ .../picture/support/flush/StylesHandler.java | 5 +- .../picture/support/model/CellStyle.java | 65 +++++++++++++++++-- .../support/model/abt/XmlAbstract.java | 23 +++++++ .../support/model/abt/XmlInterface.java | 11 ++++ .../support/model/style/Alignment.java | 65 +++++++++++++++++++ .../processor/ExcelTableProcessor.java | 2 +- .../excel/picture/support/util/XmlUtil.java | 35 ++++++++++ .../example/ExportExample_20230110.java | 14 ++-- 9 files changed, 223 insertions(+), 15 deletions(-) create mode 100644 src/main/java/com/ibiz/excel/picture/support/model/abt/XmlAbstract.java create mode 100644 src/main/java/com/ibiz/excel/picture/support/model/abt/XmlInterface.java create mode 100644 src/main/java/com/ibiz/excel/picture/support/model/style/Alignment.java create mode 100644 src/main/java/com/ibiz/excel/picture/support/util/XmlUtil.java diff --git a/src/main/java/com/ibiz/excel/picture/support/constants/WorkbookConstant.java b/src/main/java/com/ibiz/excel/picture/support/constants/WorkbookConstant.java index 460267d..e3ce3a7 100644 --- a/src/main/java/com/ibiz/excel/picture/support/constants/WorkbookConstant.java +++ b/src/main/java/com/ibiz/excel/picture/support/constants/WorkbookConstant.java @@ -43,6 +43,24 @@ public class WorkbookConstant { */ public static int BORDER_BOLD = 1; + /** + * 设置自动换行 + * 1表示自动换行 + */ + public static int WRAP_TEXT = 0; + + /** + * 垂直对齐方式 + * 默认居中对齐 + */ + public static String VERTICAL = "center"; + + /** + * 水平对齐方式 + * 默认居中对齐 + */ + public static String HORIZONTAL = "center"; + /** * 边框加粗,true加粗,false不加粗 * @param borderBold diff --git a/src/main/java/com/ibiz/excel/picture/support/flush/StylesHandler.java b/src/main/java/com/ibiz/excel/picture/support/flush/StylesHandler.java index be17f73..299d258 100644 --- a/src/main/java/com/ibiz/excel/picture/support/flush/StylesHandler.java +++ b/src/main/java/com/ibiz/excel/picture/support/flush/StylesHandler.java @@ -96,7 +96,10 @@ public class StylesHandler implements InvocationHandler { .append(cellStyle.getFillId()) .append("\" borderId=\"") .append(Optional.ofNullable(cellStyle.getBorderBold()).orElse(WorkbookConstant.BORDER_BOLD)) - .append("\" xfId=\"0\" applyFont=\"1\" applyAlignment=\"1\">"); + .append("\" xfId=\"0\" applyFont=\"1\" applyAlignment=\"1\">") + .append(cellStyle.getAlignmentNullDefault().toXmlString()) + .append(""); + } /** diff --git a/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java b/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java index 0f74db0..03f1b5b 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java @@ -1,6 +1,9 @@ package com.ibiz.excel.picture.support.model; import com.ibiz.excel.picture.support.constants.WorkbookConstant; +import com.ibiz.excel.picture.support.model.style.Alignment; + +import java.util.Optional; /** * 控制该行样式 @@ -10,6 +13,10 @@ import com.ibiz.excel.picture.support.constants.WorkbookConstant; */ public class CellStyle { + public static CellStyle builder() { + return new CellStyle(); + } + /** * 默认已有fill样式 * 与对应{@link com.ibiz.excel.picture.support.module.Styles} @@ -26,6 +33,11 @@ public class CellStyle { */ private Integer rowNumber; + /** + * 开始行 + */ + private Integer startRow; + /** * 列号 */ @@ -44,6 +56,11 @@ public class CellStyle { private Integer borderBold; + /** + * 设置内容对齐方式 + */ + private Alignment alignment; + public CellStyle() { } @@ -100,17 +117,21 @@ public class CellStyle { /** * fgColor rgb颜色 * RGB网页颜色在线取色器 https://link.fobshanghai.com/rgbcolor.htm + * + * @return */ - public void setFgColorRgb(String fgColorRgb) { + public CellStyle setFgColorRgb(String fgColorRgb) { this.fgColorRgb = fgColorRgb; + return this; } public Integer getRowNumber() { return rowNumber; } - public void setRowNumber(Integer rowNumber) { + public CellStyle setRowNumber(Integer rowNumber) { this.rowNumber = rowNumber; + return this; } public int getFillId() { @@ -133,16 +154,50 @@ public class CellStyle { return colNumber; } - public void setColNumber(Integer colNumber) { + public CellStyle setColNumber(Integer colNumber) { this.colNumber = colNumber; + return this; } public Integer getBorderBold() { return this.borderBold; } - public void setBorderBold(Boolean borderBold) { + /** + * 设置边框是否加粗 + * + * @param borderBold + * @return + */ + public CellStyle setBorderBold(Boolean borderBold) { this.borderBold = borderBold != null ? (borderBold ? 1 : 0) : null; - ; + return this; + } + + public Integer getStartRow() { + return startRow; + } + + public CellStyle setStartRow(Integer startRow) { + this.startRow = startRow; + return this; + } + + public Alignment getAlignment() { + return alignment; + } + + public Alignment getAlignmentNullDefault() { + return Optional.ofNullable(getAlignment()).orElse(new Alignment()); + } + + /** + * 设置内容对齐方式 + * @param alignment + * @return + */ + public CellStyle setAlignment(Alignment alignment) { + this.alignment = alignment; + return this; } } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/abt/XmlAbstract.java b/src/main/java/com/ibiz/excel/picture/support/model/abt/XmlAbstract.java new file mode 100644 index 0000000..0c4bac7 --- /dev/null +++ b/src/main/java/com/ibiz/excel/picture/support/model/abt/XmlAbstract.java @@ -0,0 +1,23 @@ +package com.ibiz.excel.picture.support.model.abt; + +import com.ibiz.excel.picture.support.util.XmlUtil; + +import javax.xml.bind.JAXBException; + +/** + * @author MinWeikai + * @date 2023/7/13 10:57 + * @description Xml抽象处理 + */ +public abstract class XmlAbstract implements XmlInterface { + + @Override + public String toXmlString() { + try { + return XmlUtil.objectToXmlStr(this, false, true); + } catch (JAXBException e) { + e.printStackTrace(); + } + return ""; + } +} diff --git a/src/main/java/com/ibiz/excel/picture/support/model/abt/XmlInterface.java b/src/main/java/com/ibiz/excel/picture/support/model/abt/XmlInterface.java new file mode 100644 index 0000000..b5edaaa --- /dev/null +++ b/src/main/java/com/ibiz/excel/picture/support/model/abt/XmlInterface.java @@ -0,0 +1,11 @@ +package com.ibiz.excel.picture.support.model.abt; + +/** + * @author MinWeikai + * @date 2023/7/13 10:55 + * @description xml接口类 + */ +public interface XmlInterface { + + String toXmlString(); +} diff --git a/src/main/java/com/ibiz/excel/picture/support/model/style/Alignment.java b/src/main/java/com/ibiz/excel/picture/support/model/style/Alignment.java new file mode 100644 index 0000000..8613c59 --- /dev/null +++ b/src/main/java/com/ibiz/excel/picture/support/model/style/Alignment.java @@ -0,0 +1,65 @@ +package com.ibiz.excel.picture.support.model.style; + +import com.ibiz.excel.picture.support.constants.WorkbookConstant; +import com.ibiz.excel.picture.support.model.abt.XmlAbstract; + +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlRootElement; + +/** + * @author MinWeikai + * @date 2023/7/7 18:09 + * @description excel 内容对齐 + */ +@XmlRootElement(name = "alignment") +public class Alignment extends XmlAbstract { + + public static Alignment builder() { + return new Alignment(); + } + + /** + * 自动换行 + */ + private Integer wrapText = WorkbookConstant.WRAP_TEXT; + + /** + * 垂直对齐方式 + */ + private String vertical = WorkbookConstant.VERTICAL; + + /** + * 水平对齐方式 + */ + private String horizontal = WorkbookConstant.HORIZONTAL; + + @XmlAttribute + public Integer getWrapText() { + return wrapText; + } + + public Alignment setWrapText(Integer wrapText) { + this.wrapText = wrapText; + return this; + } + + @XmlAttribute + public String getVertical() { + return vertical; + } + + public Alignment setVertical(String vertical) { + this.vertical = vertical; + return this; + } + + @XmlAttribute + public String getHorizontal() { + return horizontal; + } + + public Alignment setHorizontal(String horizontal) { + this.horizontal = horizontal; + return this; + } +} diff --git a/src/main/java/com/ibiz/excel/picture/support/processor/ExcelTableProcessor.java b/src/main/java/com/ibiz/excel/picture/support/processor/ExcelTableProcessor.java index c8a719d..241fbf7 100644 --- a/src/main/java/com/ibiz/excel/picture/support/processor/ExcelTableProcessor.java +++ b/src/main/java/com/ibiz/excel/picture/support/processor/ExcelTableProcessor.java @@ -51,7 +51,7 @@ public class ExcelTableProcessor { * key : 对象的field属性名称 * value : 此属性value相关的数据字典 */ - private Map> fieldEnumMap = new HashMap<>(); + private final Map> fieldEnumMap = new HashMap<>(); /** * 构建excel diff --git a/src/main/java/com/ibiz/excel/picture/support/util/XmlUtil.java b/src/main/java/com/ibiz/excel/picture/support/util/XmlUtil.java new file mode 100644 index 0000000..0331b62 --- /dev/null +++ b/src/main/java/com/ibiz/excel/picture/support/util/XmlUtil.java @@ -0,0 +1,35 @@ +package com.ibiz.excel.picture.support.util; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Marshaller; +import java.io.StringWriter; + +/** + * @author MinWeikai + * @date 2023-07-07 18:55:10 + * @description xml操作工具类 + */ +public class XmlUtil { + + /** + * 对象转xml字符串 + * @param object + * @param formatted 是否格式化 + * @param fragment 是否不生成XML声明 + * @param + * @return + * @throws JAXBException + */ + public static String objectToXmlStr(T object, boolean formatted, boolean fragment) throws JAXBException { + JAXBContext jaxbContext = JAXBContext.newInstance(object.getClass()); + Marshaller marshaller = jaxbContext.createMarshaller(); + // 格式化 + marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, formatted); + // 生成XML声明 + marshaller.setProperty(Marshaller.JAXB_FRAGMENT, fragment); + StringWriter writer = new StringWriter(); + marshaller.marshal(object, writer); + return writer.toString(); + } +} \ No newline at end of file diff --git a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20230110.java b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20230110.java index 41496c3..0eafdfc 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20230110.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20230110.java @@ -3,6 +3,7 @@ package com.ibiz.excel.picture.support.example; import com.ibiz.excel.picture.support.common.BaseJunitTest; import com.ibiz.excel.picture.support.constants.WorkbookConstant; import com.ibiz.excel.picture.support.model.*; +import com.ibiz.excel.picture.support.model.style.Alignment; import com.ibiz.excel.picture.support.pojo.Student; import com.ibiz.excel.picture.support.pojo.UserPicture; import com.ibiz.excel.picture.support.processor.ExcelTableProcessor; @@ -14,7 +15,7 @@ import java.util.*; /** * @author MinWeikai - * @date 2023-01-10 17:07:51 + * @date 2023-01-10 17:07:51 * @description 单个单元格添加样式示例 */ @Ignore @@ -49,7 +50,7 @@ public class ExportExample_20230110 extends BaseJunitTest { public void export1() { // 模拟需要导出的数据集合 List students = new ArrayList<>(); - students.add(new Student("李四", 16, null, null, 0)); + students.add(new Student("李四qweqweqweqweqwe12312312321", 16, null, null, 0)); students.add(new Student("张三", 17, null, getPictures(5), 1)); students.add(new Student("王五", 15, IMG_PATH_1, null, 2)); @@ -63,6 +64,7 @@ public class ExportExample_20230110 extends BaseJunitTest { // 设置对全局操作边框是否加粗 WorkbookConstant.setBorderBold(false); + WorkbookConstant.WRAP_TEXT = 1; // 创建excel Workbook workBook = Workbook.getInstance(100); Sheet sheet = workBook.createSheet("测试"); @@ -72,12 +74,8 @@ public class ExportExample_20230110 extends BaseJunitTest { // 创建样式 List cellStyles = Arrays.asList( - new CellStyle(0, "66cc66", true), - new CellStyle(0, 3, "9F79EE", true), - new CellStyle(1, 2, "9F79EE"), - new CellStyle(2, 0, "9F79EE"), - new CellStyle(2, 1, "9F79EE"), - new CellStyle(3, 2, "66cc66") + new CellStyle(0, "66cc66"), + CellStyle.builder().setColNumber(1).setRowNumber(1).setFgColorRgb("9F79EE").setAlignment(Alignment.builder().setWrapText(1)) ); // 创建数据字典 -- Gitee From 2ce1fc3651de47ad2bb354cd3291a26efb6e0c81 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Thu, 13 Jul 2023 19:06:41 +0800 Subject: [PATCH 152/161] =?UTF-8?q?add=20=E5=86=85=E5=AE=B9=E5=AF=B9?= =?UTF-8?q?=E9=BD=90=E5=AF=B9=E6=95=B4=E5=88=97=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../picture/support/flush/StylesHandler.java | 7 +- .../picture/support/flush/StylesIndex.java | 112 +++++++----------- .../picture/support/model/CellStyle.java | 18 ++- .../excel/picture/support/model/Font.java | 12 +- .../support/model/style/Alignment.java | 18 ++- .../processor/ExcelTableProcessor.java | 18 ++- .../example/ExportExample_20230110.java | 2 +- .../example/ExportExample_20230713.java | 96 +++++++++++++++ 8 files changed, 204 insertions(+), 79 deletions(-) create mode 100644 src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20230713.java diff --git a/src/main/java/com/ibiz/excel/picture/support/flush/StylesHandler.java b/src/main/java/com/ibiz/excel/picture/support/flush/StylesHandler.java index 299d258..67aa0c9 100644 --- a/src/main/java/com/ibiz/excel/picture/support/flush/StylesHandler.java +++ b/src/main/java/com/ibiz/excel/picture/support/flush/StylesHandler.java @@ -1,7 +1,10 @@ package com.ibiz.excel.picture.support.flush; import com.ibiz.excel.picture.support.constants.WorkbookConstant; -import com.ibiz.excel.picture.support.model.*; +import com.ibiz.excel.picture.support.model.CellStyle; +import com.ibiz.excel.picture.support.model.Font; +import com.ibiz.excel.picture.support.model.Row; +import com.ibiz.excel.picture.support.model.Sheet; import com.ibiz.excel.picture.support.util.StringUtils; import java.lang.reflect.InvocationHandler; @@ -73,7 +76,7 @@ public class StylesHandler implements InvocationHandler { } private void addCellStyle(CellStyle cellStyle) { - if (cellStyle != null) { + if (cellStyle != null && !cellStyle.isExist()) { // 追加字体 this.appendFont(cellStyle.getFont()); // 追加背景色样式 diff --git a/src/main/java/com/ibiz/excel/picture/support/flush/StylesIndex.java b/src/main/java/com/ibiz/excel/picture/support/flush/StylesIndex.java index 2a3f1bf..d5bbd96 100644 --- a/src/main/java/com/ibiz/excel/picture/support/flush/StylesIndex.java +++ b/src/main/java/com/ibiz/excel/picture/support/flush/StylesIndex.java @@ -2,9 +2,11 @@ package com.ibiz.excel.picture.support.flush; import com.ibiz.excel.picture.support.model.CellStyle; import com.ibiz.excel.picture.support.model.Font; +import com.ibiz.excel.picture.support.model.style.Alignment; import com.ibiz.excel.picture.support.util.StringUtils; -import java.util.Objects; +import java.util.HashMap; +import java.util.Map; /** * 样式下标取值 @@ -14,88 +16,58 @@ import java.util.Objects; */ public class StylesIndex { - /** - * 默认已有fill样式 - * 与对应{@link com.ibiz.excel.picture.support.module.Styles} - */ - private int fillId = 0; + private int fillId = 2; + private int s = 2; + private int fontId = 1; - /** - * 默认已有cellStyles样式 - */ - private int s = 1; + private final Map styleIndexMap = new HashMap<>(); - /** - * 字体id - */ - private int fontId = 0; - - /** - * 是否设置字体 - */ - private boolean isSetFont; - - /** - * 设置下标样式 - * - * @param cellStyle - */ protected void addCellStyle(CellStyle cellStyle) { - if(Objects.nonNull(cellStyle)){ - // 字体 - Font font = cellStyle.getFont(); - if(font != null){ - this.isSetFont = true; - }else { - this.isSetFont = false; - } - this.addIndex(cellStyle); - if(StringUtils.isNotBlank(cellStyle.getFgColorRgb())){ - cellStyle.setFillId(fillId); - } - cellStyle.setS(s); - if(font != null){ - font.setFontId(fontId); - } + if (cellStyle == null) { + return; } - } - protected void addIndex(CellStyle cellStyle) { - // fillId+1,生成下一个编号 - if(StringUtils.isNotBlank(cellStyle.getFgColorRgb())){ - fillId = (fillId == 0 ? 1 : fillId) + 1; - } - s = s + 1; - if(isSetFont){ - fontId = fontId + 1; + String styleKey = getStyleKey(cellStyle); + if (styleIndexMap.containsKey(styleKey)) { + CellStyle style = styleIndexMap.get(styleKey); + cellStyle.setS(style.getS()); + cellStyle.setFillId(style.getFillId()); + cellStyle.setExist(true); + return; } - } - public int getFillId() { - return fillId; - } + if (StringUtils.isNotBlank(cellStyle.getFgColorRgb())) { + cellStyle.setFillId(fillId); + fillId++; + } - public void setFillId(int fillId) { - this.fillId = fillId; - } + cellStyle.setS(s); + styleIndexMap.put(styleKey, cellStyle); + s++; - public int getS() { - return s; + Font font = cellStyle.getFont(); + if (font != null) { + font.setFontId(fontId); + fontId++; + } } - public void setS(int s) { - this.s = s; - } + private String getStyleKey(CellStyle cellStyle) { + StringBuilder builder = new StringBuilder(); + if (StringUtils.isNotBlank(cellStyle.getFgColorRgb())) { + builder.append(cellStyle.getFgColorRgb()); + } - public int getFontId() { - return fontId; - } + Font font = cellStyle.getFont(); + if (font != null) { + builder.append(font); + } - public void setFontId(int fontId) { - this.fontId = fontId; + Alignment alignment = cellStyle.getAlignment(); + if (alignment != null) { + builder.append(alignment); + } + return builder.toString(); } - public void setSetFont(boolean setFont) { - isSetFont = setFont; - } } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java b/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java index 03f1b5b..525aee0 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java @@ -13,7 +13,7 @@ import java.util.Optional; */ public class CellStyle { - public static CellStyle builder() { + public static CellStyle build() { return new CellStyle(); } @@ -56,6 +56,11 @@ public class CellStyle { private Integer borderBold; + /** + * 存在 + */ + private boolean exist = false; + /** * 设置内容对齐方式 */ @@ -68,8 +73,9 @@ public class CellStyle { return font; } - public void setFont(Font font) { + public CellStyle setFont(Font font) { this.font = font; + return this; } /** @@ -200,4 +206,12 @@ public class CellStyle { this.alignment = alignment; return this; } + + public boolean isExist() { + return exist; + } + + public void setExist(boolean exist) { + this.exist = exist; + } } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/Font.java b/src/main/java/com/ibiz/excel/picture/support/model/Font.java index 38d3c9b..1484901 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/Font.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/Font.java @@ -82,5 +82,15 @@ public class Font{ } - + @Override + public String toString() { + final StringBuffer sb = new StringBuffer("Font{"); + sb.append("fontId=").append(fontId); + sb.append(", fontName='").append(fontName).append('\''); + sb.append(", boldWeight=").append(boldWeight); + sb.append(", color='").append(color).append('\''); + sb.append(", fontHeightInPoints=").append(fontHeightInPoints); + sb.append('}'); + return sb.toString(); + } } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/style/Alignment.java b/src/main/java/com/ibiz/excel/picture/support/model/style/Alignment.java index 8613c59..16bce56 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/style/Alignment.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/style/Alignment.java @@ -14,7 +14,7 @@ import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement(name = "alignment") public class Alignment extends XmlAbstract { - public static Alignment builder() { + public static Alignment build() { return new Alignment(); } @@ -38,6 +38,12 @@ public class Alignment extends XmlAbstract { return wrapText; } + /** + * 1自动换行,0不换行 + * + * @param wrapText + * @return + */ public Alignment setWrapText(Integer wrapText) { this.wrapText = wrapText; return this; @@ -62,4 +68,14 @@ public class Alignment extends XmlAbstract { this.horizontal = horizontal; return this; } + + @Override + public String toString() { + final StringBuffer sb = new StringBuffer("Alignment{"); + sb.append("wrapText=").append(wrapText); + sb.append(", vertical='").append(vertical).append('\''); + sb.append(", horizontal='").append(horizontal).append('\''); + sb.append('}'); + return sb.toString(); + } } diff --git a/src/main/java/com/ibiz/excel/picture/support/processor/ExcelTableProcessor.java b/src/main/java/com/ibiz/excel/picture/support/processor/ExcelTableProcessor.java index 241fbf7..e405e18 100644 --- a/src/main/java/com/ibiz/excel/picture/support/processor/ExcelTableProcessor.java +++ b/src/main/java/com/ibiz/excel/picture/support/processor/ExcelTableProcessor.java @@ -69,13 +69,14 @@ public class ExcelTableProcessor { rel = excels.get(i); cells.add(new Cell(i).setValue(rel.getExcelName()).setCellStyle(getCellStyle(startRow, i))); // 设置单元格宽度 - if(rel.getCellWeight() > 0){ + if (rel.getCellWeight() > 0) { sheet.setColumnWidth(rel.getOrderNo(), rel.getCellWeight()); } } row.autoRowCells(cells); int num; BizExcelPojoInterface excelPojoInterface; + Map cellStyleMap = new HashMap<>(); for (int j = 0; j < list.size(); j++) { // 开始行的下一行放内容 num = startRow + j + 1; @@ -98,7 +99,20 @@ public class ExcelTableProcessor { row.setHeight(rowHeight); // 数据字典值获取 value = getValueByFiledEnumMap(excel.getField(), value); - cells.add(new Cell(num, index++).setValue(value).setCellStyle(getCellStyle(num, index))); + // 设置以下数据样式 + CellStyle cellStyle = getCellStyle(num, index); + Cell cell = new Cell(num, index++).setValue(value); + if (cellStyle != null && cellStyle.getStartRow() != null) { + cellStyleMap.put(index, cellStyle); + } + + CellStyle style = cellStyleMap.get(index); + if (style != null) { + style = BeanUtil.copyProperties(style, CellStyle.class); + }else { + style = cellStyle; + } + cells.add(cell.setCellStyle(style)); row.setCells(cells); } diff --git a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20230110.java b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20230110.java index 0eafdfc..7cd4ba7 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20230110.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20230110.java @@ -75,7 +75,7 @@ public class ExportExample_20230110 extends BaseJunitTest { // 创建样式 List cellStyles = Arrays.asList( new CellStyle(0, "66cc66"), - CellStyle.builder().setColNumber(1).setRowNumber(1).setFgColorRgb("9F79EE").setAlignment(Alignment.builder().setWrapText(1)) + CellStyle.build().setColNumber(0).setRowNumber(1).setFgColorRgb("9F79EE").setAlignment(Alignment.build().setWrapText(1)) ); // 创建数据字典 diff --git a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20230713.java b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20230713.java new file mode 100644 index 0000000..2a7e37e --- /dev/null +++ b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20230713.java @@ -0,0 +1,96 @@ +package com.ibiz.excel.picture.support.example; + +import com.ibiz.excel.picture.support.common.BaseJunitTest; +import com.ibiz.excel.picture.support.constants.WorkbookConstant; +import com.ibiz.excel.picture.support.model.*; +import com.ibiz.excel.picture.support.model.style.Alignment; +import com.ibiz.excel.picture.support.pojo.Student; +import com.ibiz.excel.picture.support.pojo.UserPicture; +import com.ibiz.excel.picture.support.processor.ExcelTableProcessor; +import com.ibiz.excel.picture.support.util.WebUtil; +import org.junit.Ignore; +import org.junit.Test; + +import java.util.*; + +@Ignore +public class ExportExample_20230713 extends BaseJunitTest { + + @Test + public void export() { + Workbook workBook = Workbook.getInstance(); + Sheet sheet = workBook.createSheet("测试"); + // 给标题行加上背景色,加颜色时,会对字体加粗 + sheet.addCellStyle(new CellStyle(0, "66cc66")); + UserPicture userPicture; + for (int r = 0; r < 5; r++) { + userPicture = new UserPicture(); + userPicture.setAge(15); + userPicture.setName("测试哈哈哈啊哈哈啊哈测试哈哈哈啊哈哈啊哈-" + r); + // 导出本地单张图片 + userPicture.setPicture(IMG_PATH_1); + // 导出url单张图片 +// userPicture.setHeaderPicture(getUrl()); + // 导出本地图片集合 +// userPicture.setPictures(getPictures(new Random().nextInt(5))); + // 导出url图片集合 +// userPicture.setUrlPictures(getUrls(5)); +// sheet.createRow(userPicture); + sheet.createRow(userPicture).getCell(0).setCellStyle(CellStyle.build().setColNumber(1).setRowNumber(1).setFgColorRgb("9F79EE") + .setAlignment(Alignment.build().setWrapText(1))); + } + WebUtil.writeExcelTest(workBook, "ExportExample_20230713_".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), TEMP_PATH); + } + + @Test + public void export1() { + // 模拟需要导出的数据集合 + List students = new ArrayList<>(); + students.add(new Student("李四qweqweqweqweqwe12312312321", 16, null, null, 0)); + students.add(new Student("张三", 17, null, getPictures(5), 1)); + students.add(new Student("王五", 15, IMG_PATH_1, null, 2)); + students.add(new Student("王五u五五五五五五五五五五呀呀呀呀呀呀呀", 18, IMG_PATH_1, null, 0)); + + // 配置导出excel的表头、顺序、对应导出的数据集合的字段、是否是图片、单元格宽度等 + List excels = new ArrayList<>(); + excels.add(new BizExcelRel("姓名", "name", 2)); + excels.add(new BizExcelRel("年龄", "age", 3)); + excels.add(new BizExcelRel("表现", "performance", 4)); + excels.add(new BizExcelRel("头像", "headPicture", 5, true, 20)); + excels.add(new BizExcelRel("相册", "album", 6, true)); + + // 设置对全局操作边框是否加粗 + WorkbookConstant.setBorderBold(false); + // 创建excel + Workbook workBook = Workbook.getInstance(100); + Sheet sheet = workBook.createSheet("测试"); + + //要进行合并的列 + sheet.addMergeCell(new MergeCell(0, 0, 0, 2)); + + // 创建样式 + List cellStyles = Arrays.asList( + new CellStyle(0, "66cc66") + , CellStyle.build().setColNumber(0).setRowNumber(1).setStartRow(1).setFgColorRgb("9F79EE") + ); + + // 创建数据字典 + Map performanceMap = new HashMap<>(); + performanceMap.put("0", "一般"); + performanceMap.put("1", "良好"); + performanceMap.put("2", "优秀"); + + // 构建sheet + ExcelTableProcessor.sheet(sheet) + // 添加样式 + .addCellStyle(cellStyles) + // 添加对应属性字段的数据字典 + .registryEnumMap("performance", performanceMap) + // 构建excel + .buildExcel(excels, students); + + WebUtil.writeExcelTest(workBook, "ExportExample_20230713_".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), TEMP_PATH); + } + + +} -- Gitee From e42c46b63d50a8b27451c75ca22ab5d6a88e5871 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Fri, 14 Jul 2023 14:53:14 +0800 Subject: [PATCH 153/161] =?UTF-8?q?perf=20=E6=8C=81=E7=BB=AD=E6=A0=B7?= =?UTF-8?q?=E5=BC=8F=E4=BD=BF=E7=94=A8=E6=8F=8F=E8=BF=B0=E3=80=81=E6=A0=B7?= =?UTF-8?q?=E5=BC=8F=E7=B4=A2=E5=BC=95=E7=94=9F=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../picture/support/flush/StylesIndex.java | 17 +------ .../picture/support/model/CellStyle.java | 44 +++++++++++++------ .../processor/ExcelTableProcessor.java | 2 +- .../example/ExportExample_20230713.java | 3 +- 4 files changed, 34 insertions(+), 32 deletions(-) diff --git a/src/main/java/com/ibiz/excel/picture/support/flush/StylesIndex.java b/src/main/java/com/ibiz/excel/picture/support/flush/StylesIndex.java index d5bbd96..86be2a6 100644 --- a/src/main/java/com/ibiz/excel/picture/support/flush/StylesIndex.java +++ b/src/main/java/com/ibiz/excel/picture/support/flush/StylesIndex.java @@ -2,7 +2,6 @@ package com.ibiz.excel.picture.support.flush; import com.ibiz.excel.picture.support.model.CellStyle; import com.ibiz.excel.picture.support.model.Font; -import com.ibiz.excel.picture.support.model.style.Alignment; import com.ibiz.excel.picture.support.util.StringUtils; import java.util.HashMap; @@ -53,21 +52,7 @@ public class StylesIndex { } private String getStyleKey(CellStyle cellStyle) { - StringBuilder builder = new StringBuilder(); - if (StringUtils.isNotBlank(cellStyle.getFgColorRgb())) { - builder.append(cellStyle.getFgColorRgb()); - } - - Font font = cellStyle.getFont(); - if (font != null) { - builder.append(font); - } - - Alignment alignment = cellStyle.getAlignment(); - if (alignment != null) { - builder.append(alignment); - } - return builder.toString(); + return cellStyle.toString(); } } diff --git a/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java b/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java index 525aee0..9b03c62 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/CellStyle.java @@ -28,15 +28,21 @@ public class CellStyle { */ private int s = WorkbookConstant.S; + /** + * 存在 + */ + private boolean exist = false; + + /** * 行号 */ private Integer rowNumber; /** - * 开始行 + * 是否持续向下该列样式 */ - private Integer startRow; + private boolean colLast; /** * 列号 @@ -54,12 +60,10 @@ public class CellStyle { */ private Font font; - private Integer borderBold; - /** - * 存在 + * 边框加粗,默认为1加粗,0不加粗 */ - private boolean exist = false; + private Integer borderBold; /** * 设置内容对齐方式 @@ -112,10 +116,6 @@ public class CellStyle { this.setBorderBold(borderBold); } - public CellStyle(CellStyle cellStyle) { - this.fgColorRgb = cellStyle.fgColorRgb; - } - public String getFgColorRgb() { return fgColorRgb; } @@ -180,12 +180,17 @@ public class CellStyle { return this; } - public Integer getStartRow() { - return startRow; + public boolean isColLast() { + return colLast; } - public CellStyle setStartRow(Integer startRow) { - this.startRow = startRow; + /** + * 是否持续向下该列样式 + * @param colLast + * @return + */ + public CellStyle setColLast(boolean colLast) { + this.colLast = colLast; return this; } @@ -214,4 +219,15 @@ public class CellStyle { public void setExist(boolean exist) { this.exist = exist; } + + @Override + public String toString() { + final StringBuffer sb = new StringBuffer("CellStyle{"); + sb.append("fgColorRgb='").append(fgColorRgb).append('\''); + sb.append(", font=").append(font); + sb.append(", borderBold=").append(borderBold); + sb.append(", alignment=").append(alignment); + sb.append('}'); + return sb.toString(); + } } diff --git a/src/main/java/com/ibiz/excel/picture/support/processor/ExcelTableProcessor.java b/src/main/java/com/ibiz/excel/picture/support/processor/ExcelTableProcessor.java index e405e18..a993b8c 100644 --- a/src/main/java/com/ibiz/excel/picture/support/processor/ExcelTableProcessor.java +++ b/src/main/java/com/ibiz/excel/picture/support/processor/ExcelTableProcessor.java @@ -102,7 +102,7 @@ public class ExcelTableProcessor { // 设置以下数据样式 CellStyle cellStyle = getCellStyle(num, index); Cell cell = new Cell(num, index++).setValue(value); - if (cellStyle != null && cellStyle.getStartRow() != null) { + if (cellStyle != null && cellStyle.isColLast()) { cellStyleMap.put(index, cellStyle); } diff --git a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20230713.java b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20230713.java index 2a7e37e..3da79b0 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20230713.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20230713.java @@ -71,7 +71,8 @@ public class ExportExample_20230713 extends BaseJunitTest { // 创建样式 List cellStyles = Arrays.asList( new CellStyle(0, "66cc66") - , CellStyle.build().setColNumber(0).setRowNumber(1).setStartRow(1).setFgColorRgb("9F79EE") + // 表示在excel中从第2列,第3行开始一直往下,该列都保持该样式背景色#9F79EE + , CellStyle.build().setColNumber(1).setRowNumber(2).setColLast(true).setFgColorRgb("9F79EE") ); // 创建数据字典 -- Gitee From 3b41f9868f87344fc04d4bfdeb2c5ed41eeb0ad0 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Mon, 17 Jul 2023 17:21:59 +0800 Subject: [PATCH 154/161] =?UTF-8?q?add=20=E5=AF=B9=E9=BD=90=E6=96=B9?= =?UTF-8?q?=E5=BC=8F=E5=B8=B8=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../excel/picture/support/model/style/Alignment.java | 9 +++++++++ .../picture/support/example/ExportExample_20230713.java | 3 +++ 2 files changed, 12 insertions(+) diff --git a/src/main/java/com/ibiz/excel/picture/support/model/style/Alignment.java b/src/main/java/com/ibiz/excel/picture/support/model/style/Alignment.java index 16bce56..15dc082 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/style/Alignment.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/style/Alignment.java @@ -14,6 +14,15 @@ import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement(name = "alignment") public class Alignment extends XmlAbstract { + /** + * 对齐方向默认值 + */ + public static final String CENTER = "center"; + public static final String LEFT = "left"; + public static final String RIGHT = "right"; + public static final String TOP = "top"; + public static final String BOTTOM = "bottom"; + public static Alignment build() { return new Alignment(); } diff --git a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20230713.java b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20230713.java index 3da79b0..48ab429 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20230713.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20230713.java @@ -71,6 +71,9 @@ public class ExportExample_20230713 extends BaseJunitTest { // 创建样式 List cellStyles = Arrays.asList( new CellStyle(0, "66cc66") + , CellStyle.build().setColNumber(0).setRowNumber(1).setColLast(true).setFgColorRgb("FFEFDB") + // 表示自动换行,左对齐+底端对齐 + .setAlignment(Alignment.build().setWrapText(1).setHorizontal(Alignment.LEFT).setVertical(Alignment.BOTTOM)) // 表示在excel中从第2列,第3行开始一直往下,该列都保持该样式背景色#9F79EE , CellStyle.build().setColNumber(1).setRowNumber(2).setColLast(true).setFgColorRgb("9F79EE") ); -- Gitee From 7ffb3b11a8f091556a2311227f43989a553d836d Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Mon, 17 Jul 2023 17:53:40 +0800 Subject: [PATCH 155/161] update README.md --- README.md | 670 +++++++++++++++++++++++++++--------------------------- 1 file changed, 336 insertions(+), 334 deletions(-) diff --git a/README.md b/README.md index 7380b00..c055720 100644 --- a/README.md +++ b/README.md @@ -29,9 +29,9 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, ## 快速使用 -1. ### Maven导入 +### Maven导入 - 在项目的pom.xml的dependencies中加入以下内容: 点击查看[最新版本 ${excel-x.version}](https://search.maven.org/artifact/top.minwk/excel-x) +在项目的pom.xml的dependencies中加入以下内容: 点击查看[最新版本 ${excel-x.version}](https://search.maven.org/artifact/top.minwk/excel-x) ```xml @@ -41,358 +41,360 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, ``` -2. ### 示例 - - - #### 注解使用示例代码 - - ```java - @GetMapping("/export/lastversion/{row}") - public void exportLastVersion(HttpServletResponse response, @PathVariable int row) throws IOException { - /* - 操作窗口 - 当写入excel数据行数大于flushSize时{@link Sheet.SheetHandler#createRow(int)}, - 会刷新数据到流,调用该方法 - {@link com.ibiz.excel.picture.support.flush.DrawingXmlRelsHandler#copyPictureAppendDrawingRelsXML(Sheet, Picture)} - 将图片刷新在磁盘中 - 不会占用内存空间 - flushSize = -1 时不刷新流 - */ - Workbook workBook = Workbook.getInstance(1); +### 示例 + +*[具体功能使用示例可见版本更迭](https://gitee.com/mwk719/excel-batch-picture-support#%E7%89%88%E6%9C%AC%E6%9B%B4%E8%BF%AD)* + +- #### 注解使用示例代码 + + ```java + @GetMapping("/export/lastversion/{row}") + public void exportLastVersion(HttpServletResponse response, @PathVariable int row) throws IOException { + /* + 操作窗口 + 当写入excel数据行数大于flushSize时{@link Sheet.SheetHandler#createRow(int)}, + 会刷新数据到流,调用该方法 + {@link com.ibiz.excel.picture.support.flush.DrawingXmlRelsHandler#copyPictureAppendDrawingRelsXML(Sheet, Picture)} + 将图片刷新在磁盘中 + 不会占用内存空间 + flushSize = -1 时不刷新流 + */ + Workbook workBook = Workbook.getInstance(1); + Sheet sheet = workBook.createSheet("测试"); + // 给标题行加上背景色,加颜色时,会对字体加粗 + sheet.addCellStyle(new CellStyle(0, "66cc66")); + List list = new ArrayList<>(); + UserPicture userPicture; + for (int r = 0; r < row; r++) { + userPicture = new UserPicture(); + userPicture.setAge(15); + userPicture.setName("测试-" + r); + // 导出本地单张图片 + userPicture.setPicture("E:\\test\\img\\1.jpg"); + // 导出url单张图片 + userPicture.setHeaderPicture("https://portrait.gitee.com/uploads/avatars/user/552/1657608_mwk719_1641537497.png"); + // 导出本地图片集合 + userPicture.setPictures(Arrays.asList("E:\\test\\img\\1.jpg","E:\\test\\img\\2.jpg")); + // 导出url图片集合 + userPicture.setUrlPictures(Arrays.asList("https://portrait.gitee.com/uploads/avatars/user/552/1657608_mwk719_1641537497.png", + "https://img2.baidu.com/it/u=2602880481,728201544&fm=26&fmt=auto")); + list.add(userPicture); + } + sheet.write(UserPicture.class).createRow(list); + WebUtil.writeExcel(workBook, "最新使用示例代码导出".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), response); + } + ``` + + ```java + /** + * @auther 喻场 + * @date 2020/7/813:41 + */ + public class UserPicture { + + public UserPicture() { + } + + @ExportModel( sort = 0, title = "姓名") + private String name; + @ExportModel(sort = 1, title = "年龄") + private Integer age; + @ExportModel(sort = 3, title = "部门") + private String department; + @ExportModel(sort = 2, isPicture = true, title = "图片1") + private String picture; + @ExportModel(sort = 4, isPicture = true, title = "图片2") + private String headerPicture; + @ExportModel(sort = 5, isPicture = true, title = "多图片") + private List pictures; + @ExportModel(sort = 6, isPicture = true, title = "url多图片") + private List urlPictures; + + public UserPicture(String name, Integer age, String department, String picture) { + this.name = name; + this.age = age; + this.department = department; + this.picture = picture; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getAge() { + return age; + } + + public void setAge(Integer age) { + this.age = age; + } + + public String getDepartment() { + return department; + } + + public void setDepartment(String department) { + this.department = department; + } + + public String getPicture() { + return picture; + } + + public void setPicture(String picture) { + this.picture = picture; + } + + public String getHeaderPicture() { + return headerPicture; + } + + public void setHeaderPicture(String headerPicture) { + this.headerPicture = headerPicture; + } + + public List getPictures() { + return pictures; + } + + public void setPictures(List pictures) { + this.pictures = pictures; + } + + public List getUrlPictures() { + return urlPictures; + } + + public void setUrlPictures(List urlPictures) { + this.urlPictures = urlPictures; + } + } + + ``` + +- #### 动态配置表头excel导出示例代码 + + *实体对象需要实现BizExcelPojoInterface接口* + + ```java + @GetMapping("/export/dynamic-config-header") + public void exportDynamicConfigHeader(HttpServletResponse response) throws IOException { + // 模拟需要导出的数据集合 + List students = new ArrayList<>(); + students.add(new Student("李四", 16, null, null, 0)); + students.add(new Student("张三", 17, null, + Arrays.asList("https://portrait.gitee.com/uploads/avatars/user/552/1657608_mwk719_1641537497.png", + "https://img2.baidu.com/it/u=2602880481,728201544&fm=26&fmt=auto"), 1)); + students.add(new Student("王五", 15, IMG_PATH_1, null, 2)); + + // 配置导出excel的表头、顺序、对应导出的数据集合的字段、是否是图片、单元格宽度等 + List excels = new ArrayList<>(); + excels.add(new BizExcelRel("姓名", "name", 2)); + excels.add(new BizExcelRel("年龄", "age", 3)); + excels.add(new BizExcelRel("表现", "performance", 4)); + excels.add(new BizExcelRel("头像", "headPicture", 5, true, 20)); + excels.add(new BizExcelRel("相册", "album", 6, true)); + + // 创建excel + Workbook workBook = Workbook.getInstance(100); Sheet sheet = workBook.createSheet("测试"); - // 给标题行加上背景色,加颜色时,会对字体加粗 - sheet.addCellStyle(new CellStyle(0, "66cc66")); - List list = new ArrayList<>(); - UserPicture userPicture; - for (int r = 0; r < row; r++) { - userPicture = new UserPicture(); - userPicture.setAge(15); - userPicture.setName("测试-" + r); - // 导出本地单张图片 - userPicture.setPicture("E:\\test\\img\\1.jpg"); - // 导出url单张图片 - userPicture.setHeaderPicture("https://portrait.gitee.com/uploads/avatars/user/552/1657608_mwk719_1641537497.png"); - // 导出本地图片集合 - userPicture.setPictures(Arrays.asList("E:\\test\\img\\1.jpg","E:\\test\\img\\2.jpg")); - // 导出url图片集合 - userPicture.setUrlPictures(Arrays.asList("https://portrait.gitee.com/uploads/avatars/user/552/1657608_mwk719_1641537497.png", - "https://img2.baidu.com/it/u=2602880481,728201544&fm=26&fmt=auto")); - list.add(userPicture); - } - sheet.write(UserPicture.class).createRow(list); - WebUtil.writeExcel(workBook, "最新使用示例代码导出".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), response); + // 创建样式 + CellStyle cellStyle = new CellStyle(0, "F0F0F0"); + // 创建数据字典 + Map performanceMap = new HashMap<>(3); + performanceMap.put("0", "一般"); + performanceMap.put("1", "良好"); + performanceMap.put("2", "优秀"); + + // 构建sheet + ExcelTableProcessor.sheet(sheet) + // 添加样式 + .addCellStyle(cellStyle) + // 添加对应属性字段的数据字典 + .registryEnumMap("performance", performanceMap) + // 构建excel + .buildExcel(excels, students); + WebUtil.writeExcel(workBook, "ExportExampleDynamicConfigHeader".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), response); + } + ``` + + ```java + public class Student implements BizExcelPojoInterface { + + public Student(String name, Integer age) { + this.name = name; + this.age = age; + } + + public Student(String name, Integer age, String headPicture) { + this.name = name; + this.age = age; + this.headPicture = headPicture; + } + + public Student(String name, Integer age, String headPicture, List album, Integer performance) { + this.name = name; + this.age = age; + this.headPicture = headPicture; + this.album = album; + this.performance = performance; + } + + private String name; + + private Integer age; + + private String headPicture; + + /** + * 相册 + */ + private List album; + + /** + * 表现 0一般;1良好;2优秀 + */ + private Integer performance; + + public Integer getPerformance() { + return performance; + } + + public void setPerformance(Integer performance) { + this.performance = performance; + } + + public List getAlbum() { + return album; + } + + public void setAlbum(List album) { + this.album = album; + } + + public String getHeadPicture() { + return headPicture; } - ``` - - ```java - /** - * @auther 喻场 - * @date 2020/7/813:41 - */ - public class UserPicture { - - public UserPicture() { - } - - @ExportModel( sort = 0, title = "姓名") - private String name; - @ExportModel(sort = 1, title = "年龄") - private Integer age; - @ExportModel(sort = 3, title = "部门") - private String department; - @ExportModel(sort = 2, isPicture = true, title = "图片1") - private String picture; - @ExportModel(sort = 4, isPicture = true, title = "图片2") - private String headerPicture; - @ExportModel(sort = 5, isPicture = true, title = "多图片") - private List pictures; - @ExportModel(sort = 6, isPicture = true, title = "url多图片") - private List urlPictures; - - public UserPicture(String name, Integer age, String department, String picture) { - this.name = name; - this.age = age; - this.department = department; - this.picture = picture; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public Integer getAge() { - return age; - } - - public void setAge(Integer age) { - this.age = age; - } - - public String getDepartment() { - return department; - } - - public void setDepartment(String department) { - this.department = department; - } - - public String getPicture() { - return picture; - } - - public void setPicture(String picture) { - this.picture = picture; - } - - public String getHeaderPicture() { - return headerPicture; - } - - public void setHeaderPicture(String headerPicture) { - this.headerPicture = headerPicture; - } - - public List getPictures() { - return pictures; - } - - public void setPictures(List pictures) { - this.pictures = pictures; - } - - public List getUrlPictures() { - return urlPictures; - } - - public void setUrlPictures(List urlPictures) { - this.urlPictures = urlPictures; - } - } - - ``` - - - #### 动态配置表头excel导出示例代码 - - *实体对象需要实现BizExcelPojoInterface接口* - - ```java - @GetMapping("/export/dynamic-config-header") - public void exportDynamicConfigHeader(HttpServletResponse response) throws IOException { - // 模拟需要导出的数据集合 - List students = new ArrayList<>(); - students.add(new Student("李四", 16, null, null, 0)); - students.add(new Student("张三", 17, null, - Arrays.asList("https://portrait.gitee.com/uploads/avatars/user/552/1657608_mwk719_1641537497.png", - "https://img2.baidu.com/it/u=2602880481,728201544&fm=26&fmt=auto"), 1)); - students.add(new Student("王五", 15, IMG_PATH_1, null, 2)); - - // 配置导出excel的表头、顺序、对应导出的数据集合的字段、是否是图片、单元格宽度等 - List excels = new ArrayList<>(); - excels.add(new BizExcelRel("姓名", "name", 2)); - excels.add(new BizExcelRel("年龄", "age", 3)); - excels.add(new BizExcelRel("表现", "performance", 4)); - excels.add(new BizExcelRel("头像", "headPicture", 5, true, 20)); - excels.add(new BizExcelRel("相册", "album", 6, true)); - - // 创建excel - Workbook workBook = Workbook.getInstance(100); - Sheet sheet = workBook.createSheet("测试"); - // 创建样式 - CellStyle cellStyle = new CellStyle(0, "F0F0F0"); - // 创建数据字典 - Map performanceMap = new HashMap<>(3); - performanceMap.put("0", "一般"); - performanceMap.put("1", "良好"); - performanceMap.put("2", "优秀"); - - // 构建sheet - ExcelTableProcessor.sheet(sheet) - // 添加样式 - .addCellStyle(cellStyle) - // 添加对应属性字段的数据字典 - .registryEnumMap("performance", performanceMap) - // 构建excel - .buildExcel(excels, students); - WebUtil.writeExcel(workBook, "ExportExampleDynamicConfigHeader".concat(String.valueOf(System.currentTimeMillis())).concat(".xlsx"), response); - } - ``` - - ```java - public class Student implements BizExcelPojoInterface { - - public Student(String name, Integer age) { - this.name = name; - this.age = age; - } - - public Student(String name, Integer age, String headPicture) { - this.name = name; - this.age = age; - this.headPicture = headPicture; - } - - public Student(String name, Integer age, String headPicture, List album, Integer performance) { - this.name = name; - this.age = age; - this.headPicture = headPicture; - this.album = album; - this.performance = performance; - } - - private String name; - - private Integer age; - - private String headPicture; - - /** - * 相册 - */ - private List album; - - /** - * 表现 0一般;1良好;2优秀 - */ - private Integer performance; - - public Integer getPerformance() { - return performance; - } - - public void setPerformance(Integer performance) { - this.performance = performance; - } - - public List getAlbum() { - return album; - } - - public void setAlbum(List album) { - this.album = album; - } - - public String getHeadPicture() { - return headPicture; - } - - public void setHeadPicture(String headPicture) { - this.headPicture = headPicture; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public Integer getAge() { - return age; - } - - public void setAge(Integer age) { - this.age = age; - } - } - ``` - - - [excel含图片导出demo地址](https://gitee.com/mwk719/excel-batch-picture-support/tree/dev/src/test/java/com/ibiz/excel/picture/support/example),具体使用以后缀最新日期为准,其他示例仅供测试 - - - [微云-6767张图片共800mb资源.rar 可用于测试](https://minwk.top/big-size-img/) - - - [项目中导出下载excel使用示例](https://gitee.com/mwk719/spring-learn/blob/master/src/main/java/com/mwk/external/controller/ExcelController.java) - - #### 项目中测试使用 - - 1. 设置项目jvm堆栈大小都是20m - - ```bash - -Xms20m -Xmx20m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:\log\springlearn.hprof - ``` - - 2. 复制上方 【最新使用示例代码】到项目中 - - 3. 找一堆图片随机添加到UserPicture中 - - 4. 导出一个5000条的记录,在最大堆栈占用为20m的情况下,导出excel大小为700m,未发生内存溢出情况 - -3. ### 版本更迭 - - *点击可跳转链接可以查看功能使用示例* - - #### 2.4.1(2023.06.06) - - - [添加对全局边框进行加粗、对单元格边框加粗配置](https://gitee.com/mwk719/excel-batch-picture-support/blob/dev/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20230110.java#L64) - - 修复Microsoft Excel2010打开单元格超宽问题 - - 优化创建标题时控制列顺序 - - #### 2.4.0(2023.01.12) - - - [添加可以给单个单元格设置样式](https://gitee.com/mwk719/excel-batch-picture-support/blob/dev/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20230110.java) - - #### 2.3.1(2022.12.19) - - - 修复渲染生成列元素A-Z坐标时,使用到Z时,下一列从AA开始 - - 修复行元素为空时合并单元格错误 - - #### 2.3.0(2022.02.23) - - - [添加可动态配置表头excel导出](https://gitee.com/mwk719/spring-learn/blob/master/src/main/java/com/mwk/external/controller/ExcelController.java#L285) + + public void setHeadPicture(String headPicture) { + this.headPicture = headPicture; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getAge() { + return age; + } + + public void setAge(Integer age) { + this.age = age; + } + } + ``` + +- [excel含图片导出demo地址](https://gitee.com/mwk719/excel-batch-picture-support/tree/dev/src/test/java/com/ibiz/excel/picture/support/example),具体使用以后缀最新日期为准,其他示例仅供测试 + +- [微云-6767张图片共800mb资源.rar 可用于测试](https://minwk.top/big-size-img/) + +- [项目中导出下载excel使用示例](https://gitee.com/mwk719/spring-learn/blob/master/src/main/java/com/mwk/external/controller/ExcelController.java) + +#### 项目中测试使用 + +1. 设置项目jvm堆栈大小都是20m + + ```bash + -Xms20m -Xmx20m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:\log\springlearn.hprof + ``` + +2. 复制上方 【最新使用示例代码】到项目中 + +3. 找一堆图片随机添加到UserPicture中 + +4. 导出一个5000条的记录,在最大堆栈占用为20m的情况下,导出excel大小为700m,未发生内存溢出情况 + +## 版本更迭 + +*点击可跳转链接可以查看功能使用示例* + +#### 2.4.1(2023.06.06) + +- [添加对全局边框进行加粗、对单元格边框加粗配置](https://gitee.com/mwk719/excel-batch-picture-support/blob/dev/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20230110.java#L64) +- 修复Microsoft Excel2010打开单元格超宽问题 +- 优化创建标题时控制列顺序 + +#### 2.4.0(2023.01.12) + +- [添加可以给单个单元格设置样式](https://gitee.com/mwk719/excel-batch-picture-support/blob/dev/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20230110.java) + +#### 2.3.1(2022.12.19) + +- 修复渲染生成列元素A-Z坐标时,使用到Z时,下一列从AA开始 +- 修复行元素为空时合并单元格错误 + +#### 2.3.0(2022.02.23) + +- [添加可动态配置表头excel导出](https://gitee.com/mwk719/spring-learn/blob/master/src/main/java/com/mwk/external/controller/ExcelController.java#L285) - #### 2.2.2(2022.02.08) +#### 2.2.2(2022.02.08) - - 修复合并后的单元格没有边框线 +- 修复合并后的单元格没有边框线 - #### 2.2.1(2022.01.28) +#### 2.2.1(2022.01.28) - - [优化对合并单元格的处理](https://gitee.com/mwk719/excel-batch-picture-support/blob/master/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220128.java#L30) +- [优化对合并单元格的处理](https://gitee.com/mwk719/excel-batch-picture-support/blob/master/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20220128.java#L30) - #### 2.2.0(2022.01.27) +#### 2.2.0(2022.01.27) - - [添加导出excel中字体设置](https://gitee.com/mwk719/spring-learn/blob/master/src/main/java/com/mwk/external/controller/ExcelController.java#L243) +- [添加导出excel中字体设置](https://gitee.com/mwk719/spring-learn/blob/master/src/main/java/com/mwk/external/controller/ExcelController.java#L243) - #### 2.1.0(2022.01.14) +#### 2.1.0(2022.01.14) - - [添加导出网络链接图片到excel中](https://gitee.com/mwk719/spring-learn/blob/master/src/main/java/com/mwk/external/controller/ExcelController.java#L146) - - [添加createRow集合列表生成excel方法](https://gitee.com/mwk719/spring-learn/blob/master/src/main/java/com/mwk/external/controller/ExcelController.java#L191) - - 修改CellStyle样式的使用 +- [添加导出网络链接图片到excel中](https://gitee.com/mwk719/spring-learn/blob/master/src/main/java/com/mwk/external/controller/ExcelController.java#L146) +- [添加createRow集合列表生成excel方法](https://gitee.com/mwk719/spring-learn/blob/master/src/main/java/com/mwk/external/controller/ExcelController.java#L191) +- 修改CellStyle样式的使用 - #### 2.0.0(2021.12.30) +#### 2.0.0(2021.12.30) - - [添加用户可自定义背景色样式](https://gitee.com/mwk719/excel-batch-picture-support/blob/dev/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java) - - [添加使用注解可对图片集合进行导出](https://gitee.com/mwk719/excel-batch-picture-support/blob/dev/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java) - - 添加自定义图片的高度;图片高度和单元格高度自适应 - - 修复导出图片集合变多时单元格宽度不够 - - 修复导出数据行数大于100 excel打开异常 - - 修复导出多组图片excel中缺失部分图片问题 +- [添加用户可自定义背景色样式](https://gitee.com/mwk719/excel-batch-picture-support/blob/dev/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java) +- [添加使用注解可对图片集合进行导出](https://gitee.com/mwk719/excel-batch-picture-support/blob/dev/src/test/java/com/ibiz/excel/picture/support/example/AnnotationPicturesExportExample.java) +- 添加自定义图片的高度;图片高度和单元格高度自适应 +- 修复导出图片集合变多时单元格宽度不够 +- 修复导出数据行数大于100 excel打开异常 +- 修复导出多组图片excel中缺失部分图片问题 - #### 1.0.4(2021.12.08) +#### 1.0.4(2021.12.08) - - 添加使用注解导出含图片或文本的使用示例 - - 修复图片遮挡所在单元格边框线 - - 修复f使用注解导出图片所在下边框不是加粗实线 +- 添加使用注解导出含图片或文本的使用示例 +- 修复图片遮挡所在单元格边框线 +- 修复f使用注解导出图片所在下边框不是加粗实线 - #### 1.0.3(2021.02.26) +#### 1.0.3(2021.02.26) - - 简化使用示例 - - 修复flushSize = -1 时不刷新流 - - 修复其他未知问题 +- 简化使用示例 +- 修复flushSize = -1 时不刷新流 +- 修复其他未知问题 - #### 1.0.2(2021.01.26) +#### 1.0.2(2021.01.26) - - 修复MD5时未关闭流 +- 修复MD5时未关闭流 - #### 1.0.1(2021.01.23) +#### 1.0.1(2021.01.23) - - 添加合并单元列值 - - 添加设置单元格背景色 - - 添加可自定义单元格宽度 - - 添加设置字体,目前有默认字体 - - 修复office打开提示需修复的问题 +- 添加合并单元列值 +- 添加设置单元格背景色 +- 添加可自定义单元格宽度 +- 添加设置字体,目前有默认字体 +- 修复office打开提示需修复的问题 ## 组件介绍 -- Gitee From 111f9f502dba7abeab793a0068293ef45ca41144 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Mon, 17 Jul 2023 18:13:41 +0800 Subject: [PATCH 156/161] =?UTF-8?q?add=202.4.2=E7=89=88=E6=9C=AC=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index a425e9d..f1e59db 100644 --- a/README.md +++ b/README.md @@ -330,6 +330,11 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, *点击可跳转链接可以查看功能使用示例* +#### 2.4.2(2023.07.17) + +- [添加内容对齐操作(自动换行、上下左右)](https://gitee.com/mwk719/excel-batch-picture-support/blob/master/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20230713.java#L74)([issues#I7IO5K](https://gitee.com/mwk719/excel-batch-picture-support/issues/I7IO5K)) +- 修复当添加列超过52列时出现异常 + #### 2.4.1(2023.06.06) - [添加对全局边框进行加粗、对单元格边框加粗配置](https://gitee.com/mwk719/excel-batch-picture-support/blob/dev/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20230110.java#L64) -- Gitee From 8de6d6fc41815acbca29970bd2d1908b1bf97f16 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Mon, 17 Jul 2023 18:15:09 +0800 Subject: [PATCH 157/161] release 2.4.2 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index db41d39..7faac9d 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 top.minwk excel-x - 2.4.1 + 2.4.2 excel-x 支持excel中批量导出图片 https://gitee.com/mwk719/excel-batch-picture-support -- Gitee From ee7913566aadc4c4b532f36a9d031f109cb1cd82 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Thu, 20 Jul 2023 17:22:58 +0800 Subject: [PATCH 158/161] =?UTF-8?q?fix=20=E5=90=88=E5=B9=B6=E5=8D=95?= =?UTF-8?q?=E5=85=83=E6=A0=BC=E9=94=99=E8=AF=AF=EF=BC=8C=E5=AF=BC=E8=87=B4?= =?UTF-8?q?=E6=89=93=E5=BC=80excel=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../picture/support/flush/Sheet1Handler.java | 4 +- .../picture/support/model/MergeCell.java | 97 ++++++++++--------- .../picture/support/common/BaseJunitTest.java | 2 - .../example/ExportExample_20230110.java | 6 +- 4 files changed, 54 insertions(+), 55 deletions(-) diff --git a/src/main/java/com/ibiz/excel/picture/support/flush/Sheet1Handler.java b/src/main/java/com/ibiz/excel/picture/support/flush/Sheet1Handler.java index 0a24db7..eb08971 100644 --- a/src/main/java/com/ibiz/excel/picture/support/flush/Sheet1Handler.java +++ b/src/main/java/com/ibiz/excel/picture/support/flush/Sheet1Handler.java @@ -90,9 +90,9 @@ public class Sheet1Handler implements InvocationHandler { Cell start = new Cell(m.getFirstRow(), m.getFirstCol()); Cell end = new Cell(m.getLastRow(), m.getLastCol()); content.append(""); } else { colCells.forEach(c -> content diff --git a/src/main/java/com/ibiz/excel/picture/support/model/MergeCell.java b/src/main/java/com/ibiz/excel/picture/support/model/MergeCell.java index ebe3e7a..9a514d9 100644 --- a/src/main/java/com/ibiz/excel/picture/support/model/MergeCell.java +++ b/src/main/java/com/ibiz/excel/picture/support/model/MergeCell.java @@ -8,63 +8,64 @@ package com.ibiz.excel.picture.support.model; */ public class MergeCell { - private int firstRow; - private int firstCol; - private int lastRow; - private int lastCol; + private int firstRow; + private int firstCol; + private int lastRow; + private int lastCol; - public MergeCell() { - } + public MergeCell() { + } - /** - * 构造此合并单元格对象可以进行合并 - * - * @param firstRow - * @param firstCol - * @param lastRow - * @param lastCol - */ - public MergeCell(int firstRow, int firstCol, int lastRow, int lastCol) { - this.firstRow = firstRow; - this.firstCol = firstCol; - this.lastRow = lastRow; - this.lastCol = lastCol; - } + /** + * 构造此合并单元格对象可以进行合并 + * 下标,从0开始 + * + * @param firstRow + * @param firstCol + * @param lastRow + * @param lastCol + */ + public MergeCell(int firstRow, int firstCol, int lastRow, int lastCol) { + this.firstRow = firstRow; + this.firstCol = firstCol; + this.lastRow = lastRow; + this.lastCol = lastCol; + } - public int getFirstRow() { - return firstRow; - } + public int getFirstRow() { + return firstRow; + } - public MergeCell setFirstRow(int firstRow) { - this.firstRow = firstRow; - return this; - } + public MergeCell setFirstRow(int firstRow) { + this.firstRow = firstRow; + return this; + } - public int getFirstCol() { - return firstCol; - } + public int getFirstCol() { + return firstCol + 1; + } - public MergeCell setFirstCol(int firstCol) { - this.firstCol = firstCol; - return this; - } + public MergeCell setFirstCol(int firstCol) { + this.firstCol = firstCol; + return this; + } - public int getLastRow() { - return lastRow; - } + public int getLastRow() { + return lastRow; + } - public MergeCell setLastRow(int lastRow) { - this.lastRow = lastRow; - return this; - } + public MergeCell setLastRow(int lastRow) { + this.lastRow = lastRow; + return this; + } - public int getLastCol() { - return lastCol; - } + public int getLastCol() { + return lastCol + 1; + } - public MergeCell setLastCol(int lastCol) { - this.lastCol = lastCol; - return this; - } + public MergeCell setLastCol(int lastCol) { + this.lastCol = lastCol; + return this; + } } diff --git a/src/test/java/com/ibiz/excel/picture/support/common/BaseJunitTest.java b/src/test/java/com/ibiz/excel/picture/support/common/BaseJunitTest.java index b2ca444..622e7c9 100644 --- a/src/test/java/com/ibiz/excel/picture/support/common/BaseJunitTest.java +++ b/src/test/java/com/ibiz/excel/picture/support/common/BaseJunitTest.java @@ -35,9 +35,7 @@ public class BaseJunitTest { static { URLS.add("https://portrait.gitee.com/uploads/avatars/user/552/1657608_mwk719_1641537497.png"); - URLS.add("https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.jj20.com%2Fup%2Fallimg%2F1114%2F060421091316%2F210604091316-6-1200.jpg&refer=http%3A%2F%2Fimg.jj20.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1644142768&t=82062e20360f72b0fd8d5fd7e2fc9885"); URLS.add("https://img2.baidu.com/it/u=121102239,1207969661&fm=253&fmt=auto&app=120&f=JPEG?w=1195&h=500"); - URLS.add("https://img2.baidu.com/it/u=2602880481,728201544&fm=26&fmt=auto"); LOCAL_TEST_FILES = FileUtil.ls(IMAGES_PATH); } diff --git a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20230110.java b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20230110.java index 7cd4ba7..eba6627 100644 --- a/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20230110.java +++ b/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20230110.java @@ -33,7 +33,7 @@ public class ExportExample_20230110 extends BaseJunitTest { userPicture.setAge(15); userPicture.setName("测试-" + r); // 导出本地单张图片 - userPicture.setPicture(IMG_PATH_1); +// userPicture.setPicture(IMG_PATH_1); // 导出url单张图片 userPicture.setHeaderPicture(getUrl()); // 导出本地图片集合 @@ -70,8 +70,8 @@ public class ExportExample_20230110 extends BaseJunitTest { Sheet sheet = workBook.createSheet("测试"); //要进行合并的列 - sheet.addMergeCell(new MergeCell(0, 0, 0, 2)); - + sheet.addMergeCell(new MergeCell(1, 0, 3, 0)); + sheet.addMergeCell(new MergeCell(0, 1, 0, 3)); // 创建样式 List cellStyles = Arrays.asList( new CellStyle(0, "66cc66"), -- Gitee From 38e9bd236aa666b0772d6a9a451cdb1841a5b698 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Thu, 20 Jul 2023 18:11:44 +0800 Subject: [PATCH 159/161] release 2.4.3 --- README.md | 4 ++++ pom.xml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f1e59db..5af4965 100644 --- a/README.md +++ b/README.md @@ -330,6 +330,10 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, *点击可跳转链接可以查看功能使用示例* +### 2.4.3(2023.07.20) + +- 修复单元格合并错误 + #### 2.4.2(2023.07.17) - [添加内容对齐操作(自动换行、上下左右)](https://gitee.com/mwk719/excel-batch-picture-support/blob/master/src/test/java/com/ibiz/excel/picture/support/example/ExportExample_20230713.java#L74)([issues#I7IO5K](https://gitee.com/mwk719/excel-batch-picture-support/issues/I7IO5K)) diff --git a/pom.xml b/pom.xml index 7faac9d..17efe6f 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 top.minwk excel-x - 2.4.2 + 2.4.3 excel-x 支持excel中批量导出图片 https://gitee.com/mwk719/excel-batch-picture-support -- Gitee From c0ade6767ff6d8acd9bf0950a84d80417220c58d Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Thu, 20 Jul 2023 18:14:13 +0800 Subject: [PATCH 160/161] =?UTF-8?q?update=202.4.3=E8=BF=AD=E4=BB=A3?= =?UTF-8?q?=E6=8F=8F=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5af4965..50097bc 100644 --- a/README.md +++ b/README.md @@ -330,7 +330,7 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, *点击可跳转链接可以查看功能使用示例* -### 2.4.3(2023.07.20) +#### 2.4.3(2023.07.20) - 修复单元格合并错误 -- Gitee From 8216c9f9ac1cd3881ecddff2b8c6ccd7ed2ede79 Mon Sep 17 00:00:00 2001 From: minwk <1294608448@qq.com> Date: Wed, 1 Nov 2023 08:16:22 +0000 Subject: [PATCH 161/161] =?UTF-8?q?update=20README.md.=20=E5=B7=A5?= =?UTF-8?q?=E5=85=B7=E5=8E=9F=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: minwk <1294608448@qq.com> --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 50097bc..04f95f2 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,10 @@ excel文件由声明,表数据,单元格数据,媒体文件等等组件组成, 这些组件分别对应了不同的数据单元.只要把数据分别写入对应的组件,最后构建成一个需要的excel文件. +### 原理 + +生成excel时先将读取到的图片缓存在磁盘上,然后逐步将磁盘上的图片写入到excel中。不像poi导出图片时它是把所有的图片数据放在内存里,然后写入到excel中。 + ## 功能 采用流式方法写入文件,不会导致内存堆积而占用太多系统资源,有效避免频繁GC问题 -- Gitee