From 93d33183d22da410f7c480d95370dd2a2e901cb7 Mon Sep 17 00:00:00 2001 From: tuqiang <437016993@qq.com> Date: Thu, 14 Nov 2024 15:33:08 +0800 Subject: [PATCH] first commit --- .idea/.gitignore | 8 + .idea/compiler.xml | 20 + .idea/encodings.xml | 7 + .idea/inspectionProfiles/Project_Default.xml | 36 ++ .idea/jarRepositories.xml | 20 + .idea/misc.xml | 14 + .idea/uiDesigner.xml | 124 ++++ .idea/vcs.xml | 6 + pom.xml | 540 ++++++++++++++++++ src/main/java/org/nl/demo/Demo1.java | 5 + src/main/java/org/nl/fill/FillData.java | 14 + src/main/java/org/nl/fill/FillTest.java | 223 ++++++++ src/main/java/org/nl/util/TestFileUtil.java | 74 +++ target/classes/org/nl/fill/FillData.class | Bin 0 -> 2397 bytes target/classes/org/nl/fill/FillTest.class | Bin 0 -> 8074 bytes .../classes/org/nl/util/TestFileUtil$1.class | Bin 0 -> 208 bytes .../nl/util/TestFileUtil$TestPathBuild.class | Bin 0 -> 1898 bytes target/classes/org/nl/util/TestFileUtil.class | Bin 0 -> 2103 bytes target/classes/simpleFill1731491705207.xlsx | 0 19 files changed, 1091 insertions(+) create mode 100644 .idea/.gitignore create mode 100644 .idea/compiler.xml create mode 100644 .idea/encodings.xml create mode 100644 .idea/inspectionProfiles/Project_Default.xml create mode 100644 .idea/jarRepositories.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/uiDesigner.xml create mode 100644 .idea/vcs.xml create mode 100644 pom.xml create mode 100644 src/main/java/org/nl/demo/Demo1.java create mode 100644 src/main/java/org/nl/fill/FillData.java create mode 100644 src/main/java/org/nl/fill/FillTest.java create mode 100644 src/main/java/org/nl/util/TestFileUtil.java create mode 100644 target/classes/org/nl/fill/FillData.class create mode 100644 target/classes/org/nl/fill/FillTest.class create mode 100644 target/classes/org/nl/util/TestFileUtil$1.class create mode 100644 target/classes/org/nl/util/TestFileUtil$TestPathBuild.class create mode 100644 target/classes/org/nl/util/TestFileUtil.class create mode 100644 target/classes/simpleFill1731491705207.xlsx diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..73f69e0 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..d535da1 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..aa00ffa --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..6560a98 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,36 @@ + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..29b7f1e --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..132404b --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..e96534f --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..6c0b863 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..b67a82e --- /dev/null +++ b/pom.xml @@ -0,0 +1,540 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.2.10.RELEASE + + + org.nl + test + 1.0-SNAPSHOT + + + UTF-8 + UTF-8 + 1.8 + 1.16 + 1.1.22 + 1.2.0.Final + 1.31.0 + 5.8.22 + 0.11.1 + 8.2.0 + + + 5.9.0 + 1.9 + 1.8 + + + + + org.jetbrains + annotations + 13.0 + + + org.codehaus.groovy + groovy-all + 3.0.13 + pom + + + + + org.dromara.dynamictp + dynamic-tp-spring-boot-starter-adapter-webserver + 1.1.7 + + + + + com.yomahub + tlog-all-spring-boot-starter + 1.5.0 + + + org.apache.lucene + lucene-core + ${lucene.version} + + + org.apache.lucene + lucene-highlighter + ${lucene.version} + + + org.apache.lucene + lucene-analyzers-common + ${lucene.version} + + + com.github.magese + ik-analyzer + ${lucene.version} + + + + + org.apache.lucene + lucene-analyzers-smartcn + ${lucene.version} + + + + org.apache.lucene + lucene-queryparser + ${lucene.version} + + + + + + + + + com.github.oshi + oshi-core + 5.0.1 + + + + + com.internetitem + logback-elasticsearch-appender + 1.6 + + + + + org.fusesource.jansi + jansi + 1.9 + + + + + cn.hutool + hutool-all + ${hutool.version} + + + + + com.github.pagehelper + pagehelper-spring-boot-starter + 1.2.12 + + + org.mybatis + mybatis + + + + + + org.springframework.boot + spring-boot-starter-web + + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + cn.dev33 + sa-token-spring-boot-starter + ${sa-token.version} + + + cn.dev33 + sa-token-sso + ${sa-token.version} + + + + cn.dev33 + sa-token-jwt + ${sa-token.version} + + + + + org.springframework.boot + spring-boot-starter-cache + + + + org.apache.commons + commons-lang3 + + + + + org.bgee.log4jdbc-log4j2 + log4jdbc-log4j2-jdbc4.1 + ${log4jdbc.version} + + + + + mysql + mysql-connector-java + + + + + com.alibaba + druid-spring-boot-starter + ${druid.version} + + + + org.projectlombok + lombok + true + + + cn.dev33 + sa-token-dao-redis + 1.31.0 + + + com.baomidou + mybatis-plus-boot-starter + 3.4.0 + + + org.apache.velocity + velocity-engine-core + 2.3 + + + com.baomidou + mybatis-plus-generator + 3.4.0 + + + xerces + xercesImpl + 2.12.0 + + + + + + org.mapstruct + mapstruct + ${mapstruct.version} + + + org.mapstruct + mapstruct-processor + ${mapstruct.version} + provided + + + javax.inject + javax.inject + 1 + + + + + com.github.whvcse + easy-captcha + 1.6.2 + + + + + nl.basjes.parse.useragent + yauaa + 5.23 + + + + eu.bitwalker + UserAgentUtils + 1.21 + + + + + com.hynnet + jxl + 2.6.12.1 + + + + commons-beanutils + commons-beanutils-core + 1.8.0 + + + + + org.springframework.boot + spring-boot-starter-aop + + + + + org.springframework.boot + spring-boot-starter-freemarker + + + + + commons-configuration + commons-configuration + ${configuration.version} + + + + com.alicp.jetcache + jetcache-starter-redis + 2.5.14 + + + + com.oracle.database.jdbc + ojdbc5 + 11.2.0.4 + + + + + + + + org.springframework.boot + spring-boot-starter-websocket + + + org.redisson + redisson-spring-boot-starter + 3.16.4 + + + + io.jsonwebtoken + jjwt-impl + ${jjwt.version} + + + io.jsonwebtoken + jjwt-jackson + ${jjwt.version} + + + + + org.quartz-scheduler + quartz + + + + + ch.ethz.ganymed + ganymed-ssh2 + build210 + + + com.jcraft + jsch + 0.1.55 + + + + + com.alibaba + easyexcel + 2.2.6 + + + org.json + json + 20131018 + + + + commons-io + commons-io + 2.8.0 + + + org.openscada.jinterop + org.openscada.jinterop.core + 2.1.8 + + + org.bouncycastle + bcprov-jdk15on + + + + + org.openscada.jinterop + org.openscada.jinterop.deps + 1.5.0 + + + org.bouncycastle + bcprov-jdk15on + + + + + org.openscada.utgard + org.openscada.opc.dcom + 1.5.0 + + + org.openscada.utgard + org.openscada.opc.lib + 1.5.0 + + + + org.bouncycastle + bcprov-jdk15on + 1.54 + + + + + org.apache.commons + commons-csv + ${commons-csv.version} + + + + org.apache.poi + poi + 4.1.2 + + + org.apache.poi + poi-ooxml + 4.1.2 + + + org.apache.poi + poi-ooxml-schemas + 4.1.2 + + + org.springframework.retry + spring-retry + 1.2.5.RELEASE + + + io.swagger + swagger-annotations + 1.5.22 + + + junit + junit + 4.11 + test + + + + org.eclipse.milo + sdk-client + 0.6.3 + + + + org.eclipse.milo + sdk-server + 0.6.3 + + + + + org.apache.poi + poi-ooxml + 5.2.5 + + + com.alibaba + easyexcel + 3.1.0 + + + + + ${project.artifactId} + + + org.springframework.boot + spring-boot-maven-plugin + 2.2.10.RELEASE + + org.nl.AppRun + true + + + + + + repackage + + + + + + org.apache.maven.plugins + maven-war-plugin + 3.2.2 + + false + ${project.artifactId} + + + + + + + + ${basedir}/src/main/java + + **/*.* + + + **/*.java + + + + ${basedir}/src/main/resources + + **/*.* + + + + + + + + + + diff --git a/src/main/java/org/nl/demo/Demo1.java b/src/main/java/org/nl/demo/Demo1.java new file mode 100644 index 0000000..ddcf246 --- /dev/null +++ b/src/main/java/org/nl/demo/Demo1.java @@ -0,0 +1,5 @@ +package org.nl.demo; + +public class Demo1 { + +} diff --git a/src/main/java/org/nl/fill/FillData.java b/src/main/java/org/nl/fill/FillData.java new file mode 100644 index 0000000..c63ae19 --- /dev/null +++ b/src/main/java/org/nl/fill/FillData.java @@ -0,0 +1,14 @@ +package org.nl.fill; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.Date; + +@Data +@EqualsAndHashCode +public class FillData { + private String name; + private double number; + private Date date; +} diff --git a/src/main/java/org/nl/fill/FillTest.java b/src/main/java/org/nl/fill/FillTest.java new file mode 100644 index 0000000..6077691 --- /dev/null +++ b/src/main/java/org/nl/fill/FillTest.java @@ -0,0 +1,223 @@ +package org.nl.fill; + +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelWriter; +import com.alibaba.excel.enums.WriteDirectionEnum; +import com.alibaba.excel.util.ListUtils; +import com.alibaba.excel.util.MapUtils; +import com.alibaba.excel.write.metadata.WriteSheet; +import com.alibaba.excel.write.metadata.fill.FillConfig; +import com.alibaba.excel.write.metadata.fill.FillWrapper; +import org.junit.jupiter.api.Test; +import org.nl.util.TestFileUtil; + +import java.io.File; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class FillTest { + /** + * 最简单的填充 + * + * @since 2.1.1 + */ + @Test + public void simpleFill() { + // 模板注意 用{} 来表示你要用的变量 如果本来就有"{","}" 特殊字符 用"\{","\}"代替 + String templateFileName = + TestFileUtil.getPath() + "demo" + File.separator + "fill" + File.separator + "simple.xlsx"; + + // 方案1 根据对象填充 + String fileName = TestFileUtil.getPath() + "simpleFill" + System.currentTimeMillis() + ".xlsx"; + // 这里 会填充到第一个sheet, 然后文件流会自动关闭 + FillData fillData = new FillData(); + fillData.setName("张三"); + fillData.setNumber(5.2); + EasyExcel.write(fileName).withTemplate(templateFileName).sheet().doFill(fillData); + + // 方案2 根据Map填充 + fileName = TestFileUtil.getPath() + "simpleFill" + System.currentTimeMillis() + ".xlsx"; + // 这里 会填充到第一个sheet, 然后文件流会自动关闭 + Map map = MapUtils.newHashMap(); + map.put("name", "张三"); + map.put("number", 5.2); + EasyExcel.write(fileName).withTemplate(templateFileName).sheet().doFill(map); + } + + /** + * 填充列表 + * + * @since 2.1.1 + */ + @Test + public void listFill() { + // 模板注意 用{} 来表示你要用的变量 如果本来就有"{","}" 特殊字符 用"\{","\}"代替 + // 填充list 的时候还要注意 模板中{.} 多了个点 表示list + // 如果填充list的对象是map,必须包涵所有list的key,哪怕数据为null,必须使用map.put(key,null) + String templateFileName = + TestFileUtil.getPath() + "demo" + File.separator + "fill" + File.separator + "list.xlsx"; + + // 方案1 一下子全部放到内存里面 并填充 + String fileName = TestFileUtil.getPath() + "listFill" + System.currentTimeMillis() + ".xlsx"; + // 这里 会填充到第一个sheet, 然后文件流会自动关闭 + EasyExcel.write(fileName).withTemplate(templateFileName).sheet().doFill(data()); + + // 方案2 分多次 填充 会使用文件缓存(省内存) + fileName = TestFileUtil.getPath() + "listFill" + System.currentTimeMillis() + ".xlsx"; + try (ExcelWriter excelWriter = EasyExcel.write(fileName).withTemplate(templateFileName).build()) { + WriteSheet writeSheet = EasyExcel.writerSheet().build(); + excelWriter.fill(data(), writeSheet); + excelWriter.fill(data(), writeSheet); + } + } + + /** + * 复杂的填充 + * + * @since 2.1.1 + */ + @Test + public void complexFill() { + // 模板注意 用{} 来表示你要用的变量 如果本来就有"{","}" 特殊字符 用"\{","\}"代替 + // {} 代表普通变量 {.} 代表是list的变量 + String templateFileName = + TestFileUtil.getPath() + "demo" + File.separator + "fill" + File.separator + "complex.xlsx"; + + String fileName = TestFileUtil.getPath() + "complexFill" + System.currentTimeMillis() + ".xlsx"; + // 方案1 + try (ExcelWriter excelWriter = EasyExcel.write(fileName).withTemplate(templateFileName).build()) { + WriteSheet writeSheet = EasyExcel.writerSheet().build(); + // 这里注意 入参用了forceNewRow 代表在写入list的时候不管list下面有没有空行 都会创建一行,然后下面的数据往后移动。默认 是false,会直接使用下一行,如果没有则创建。 + // forceNewRow 如果设置了true,有个缺点 就是他会把所有的数据都放到内存了,所以慎用 + // 简单的说 如果你的模板有list,且list不是最后一行,下面还有数据需要填充 就必须设置 forceNewRow=true 但是这个就会把所有数据放到内存 会很耗内存 + // 如果数据量大 list不是最后一行 参照下一个 + FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build(); + excelWriter.fill(data(), fillConfig, writeSheet); + excelWriter.fill(data(), fillConfig, writeSheet); + Map map = MapUtils.newHashMap(); + map.put("date", "2019年10月9日13:28:28"); + map.put("total", 1000); + excelWriter.fill(map, writeSheet); + } + } + + /** + * 数据量大的复杂填充 + *

+ * 这里的解决方案是 确保模板list为最后一行,然后再拼接table.还有03版没救,只能刚正面加内存。 + * + * @since 2.1.1 + */ + @Test + public void complexFillWithTable() { + // 模板注意 用{} 来表示你要用的变量 如果本来就有"{","}" 特殊字符 用"\{","\}"代替 + // {} 代表普通变量 {.} 代表是list的变量 + // 这里模板 删除了list以后的数据,也就是统计的这一行 + String templateFileName = + TestFileUtil.getPath() + "demo" + File.separator + "fill" + File.separator + "complexFillWithTable.xlsx"; + + String fileName = TestFileUtil.getPath() + "complexFillWithTable" + System.currentTimeMillis() + ".xlsx"; + + // 方案1 + try (ExcelWriter excelWriter = EasyExcel.write(fileName).withTemplate(templateFileName).build()) { + WriteSheet writeSheet = EasyExcel.writerSheet().build(); + // 直接写入数据 + excelWriter.fill(data(), writeSheet); + excelWriter.fill(data(), writeSheet); + + // 写入list之前的数据 + Map map = new HashMap(); + map.put("date", "2019年10月9日13:28:28"); + excelWriter.fill(map, writeSheet); + + // list 后面还有个统计 想办法手动写入 + // 这里偷懒直接用list 也可以用对象 + List> totalListList = ListUtils.newArrayList(); + List totalList = ListUtils.newArrayList(); + totalListList.add(totalList); + totalList.add(null); + totalList.add(null); + totalList.add(null); + // 第四列 + totalList.add("统计:1000"); + // 这里是write 别和fill 搞错了 + excelWriter.write(totalListList, writeSheet); + // 总体上写法比较复杂 但是也没有想到好的版本 异步的去写入excel 不支持行的删除和移动,也不支持备注这种的写入,所以也排除了可以 + // 新建一个 然后一点点复制过来的方案,最后导致list需要新增行的时候,后面的列的数据没法后移,后续会继续想想解决方案 + } + } + + /** + * 横向的填充 + * + * @since 2.1.1 + */ + @Test + public void horizontalFill() { + // 模板注意 用{} 来表示你要用的变量 如果本来就有"{","}" 特殊字符 用"\{","\}"代替 + // {} 代表普通变量 {.} 代表是list的变量 + String templateFileName = + TestFileUtil.getPath() + "demo" + File.separator + "fill" + File.separator + "horizontal.xlsx"; + + String fileName = TestFileUtil.getPath() + "horizontalFill" + System.currentTimeMillis() + ".xlsx"; + // 方案1 + try (ExcelWriter excelWriter = EasyExcel.write(fileName).withTemplate(templateFileName).build()) { + WriteSheet writeSheet = EasyExcel.writerSheet().build(); + FillConfig fillConfig = FillConfig.builder().direction(WriteDirectionEnum.HORIZONTAL).build(); + excelWriter.fill(data(), fillConfig, writeSheet); + excelWriter.fill(data(), fillConfig, writeSheet); + + Map map = new HashMap<>(); + map.put("date", "2019年10月9日13:28:28"); + excelWriter.fill(map, writeSheet); + } + } + + /** + * 多列表组合填充填充 + * + * @since 2.2.0-beta1 + */ + @Test + public void compositeFill() { + // 模板注意 用{} 来表示你要用的变量 如果本来就有"{","}" 特殊字符 用"\{","\}"代替 + // {} 代表普通变量 {.} 代表是list的变量 {前缀.} 前缀可以区分不同的list + String templateFileName = + TestFileUtil.getPath() + "demo" + File.separator + "fill" + File.separator + "composite.xlsx"; + + String fileName = TestFileUtil.getPath() + "compositeFill" + System.currentTimeMillis() + ".xlsx"; + + // 方案1 + try (ExcelWriter excelWriter = EasyExcel.write(fileName).withTemplate(templateFileName).build()) { + WriteSheet writeSheet = EasyExcel.writerSheet().build(); + FillConfig fillConfig = FillConfig.builder().direction(WriteDirectionEnum.HORIZONTAL).build(); + // 如果有多个list 模板上必须有{前缀.} 这里的前缀就是 data1,然后多个list必须用 FillWrapper包裹 + excelWriter.fill(new FillWrapper("data1", data()), fillConfig, writeSheet); + excelWriter.fill(new FillWrapper("data1", data()), fillConfig, writeSheet); + excelWriter.fill(new FillWrapper("data2", data()), writeSheet); + excelWriter.fill(new FillWrapper("data2", data()), writeSheet); + excelWriter.fill(new FillWrapper("data3", data()), writeSheet); + excelWriter.fill(new FillWrapper("data3", data()), writeSheet); + + Map map = new HashMap(); + //map.put("date", "2019年10月9日13:28:28"); + map.put("date", new Date()); + + excelWriter.fill(map, writeSheet); + } + } + + private List data() { + List list = ListUtils.newArrayList(); + for (int i = 0; i < 10; i++) { + FillData fillData = new FillData(); + list.add(fillData); + fillData.setName("张三"); + fillData.setNumber(5.2); + fillData.setDate(new Date()); + } + return list; + } +} diff --git a/src/main/java/org/nl/util/TestFileUtil.java b/src/main/java/org/nl/util/TestFileUtil.java new file mode 100644 index 0000000..67e2b91 --- /dev/null +++ b/src/main/java/org/nl/util/TestFileUtil.java @@ -0,0 +1,74 @@ +package org.nl.util; + +import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; + +import java.io.File; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +public class TestFileUtil { + public static InputStream getResourcesFileInputStream(String fileName) { + return Thread.currentThread().getContextClassLoader().getResourceAsStream("" + fileName); + } + + public static String getPath() { + return TestFileUtil.class.getResource("/").getPath(); + } + + public static TestPathBuild pathBuild() { + return new TestPathBuild(); + } + + public static File createNewFile(String pathName) { + File file = new File(getPath() + pathName); + if (file.exists()) { + file.delete(); + } else { + if (!file.getParentFile().exists()) { + file.getParentFile().mkdirs(); + } + } + return file; + } + + public static File readFile(String pathName) { + return new File(getPath() + pathName); + } + + public static File readUserHomeFile(String pathName) { + return new File(System.getProperty("user.home") + File.separator + pathName); + } + + /** + * build to test file path + **/ + public static class TestPathBuild { + private TestPathBuild() { + subPath = new ArrayList<>(); + } + + private final List subPath; + + public TestPathBuild sub(String dirOrFile) { + subPath.add(dirOrFile); + return this; + } + + public String getPath() { + if (CollectionUtils.isEmpty(subPath)) { + return TestFileUtil.class.getResource("/").getPath(); + } + if (subPath.size() == 1) { + return TestFileUtil.class.getResource("/").getPath() + subPath.get(0); + } + StringBuilder path = new StringBuilder(TestFileUtil.class.getResource("/").getPath()); + path.append(subPath.get(0)); + for (int i = 1; i < subPath.size(); i++) { + path.append(File.separator).append(subPath.get(i)); + } + return path.toString(); + } + + } +} diff --git a/target/classes/org/nl/fill/FillData.class b/target/classes/org/nl/fill/FillData.class new file mode 100644 index 0000000000000000000000000000000000000000..4c1b0d94d8602441f43bbf81ce26f01fed9ff3e9 GIT binary patch literal 2397 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