3 Commits

7 changed files with 365 additions and 62 deletions

View File

@ -1,7 +1,6 @@
package org.dromara.common.core.utils;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
@ -28,10 +27,12 @@ public class StreamUtils {
*/
public static <E> List<E> filter(Collection<E> collection, Predicate<E> function) {
if (CollUtil.isEmpty(collection)) {
return CollUtil.newArrayList();
return Collections.emptyList();
}
return collection.stream()
.filter(function)
// 注意此处不要使用 .toList() 新语法 因为返回的是不可变List 会导致序列化问题
return collection.stream().filter(function).collect(Collectors.toList());
.collect(Collectors.toList());
}
/**
@ -39,13 +40,26 @@ public class StreamUtils {
*
* @param collection 需要查询的集合
* @param function 过滤方法
* @return 找到符合条件的第一个元素,没有则返回null
* @return 找到符合条件的第一个元素,没有则返回 Optional.empty()
*/
public static <E> E findFirst(Collection<E> collection, Predicate<E> function) {
public static <E> Optional<E> findFirst(Collection<E> collection, Predicate<E> function) {
if (CollUtil.isEmpty(collection)) {
return null;
return Optional.empty();
}
return collection.stream().filter(function).findFirst().orElse(null);
return collection.stream()
.filter(function)
.findFirst();
}
/**
* 找到流中满足条件的第一个元素值
*
* @param collection 需要查询的集合
* @param function 过滤方法
* @return 找到符合条件的第一个元素,没有则返回 null
*/
public static <E> E findFirstValue(Collection<E> collection, Predicate<E> function) {
return findFirst(collection,function).orElse(null);
}
/**
@ -53,13 +67,26 @@ public class StreamUtils {
*
* @param collection 需要查询的集合
* @param function 过滤方法
* @return 找到符合条件的任意一个元素,没有则返回null
* @return 找到符合条件的任意一个元素,没有则返回 Optional.empty()
*/
public static <E> Optional<E> findAny(Collection<E> collection, Predicate<E> function) {
if (CollUtil.isEmpty(collection)) {
return Optional.empty();
}
return collection.stream().filter(function).findAny();
return collection.stream()
.filter(function)
.findAny();
}
/**
* 找到流中任意一个满足条件的元素值
*
* @param collection 需要查询的集合
* @param function 过滤方法
* @return 找到符合条件的任意一个元素没有则返回null
*/
public static <E> E findAnyValue(Collection<E> collection, Predicate<E> function) {
return findAny(collection,function).orElse(null);
}
/**
@ -85,7 +112,10 @@ public class StreamUtils {
if (CollUtil.isEmpty(collection)) {
return StringUtils.EMPTY;
}
return collection.stream().map(function).filter(Objects::nonNull).collect(Collectors.joining(delimiter));
return collection.stream()
.map(function)
.filter(Objects::nonNull)
.collect(Collectors.joining(delimiter));
}
/**
@ -97,10 +127,13 @@ public class StreamUtils {
*/
public static <E> List<E> sorted(Collection<E> collection, Comparator<E> comparing) {
if (CollUtil.isEmpty(collection)) {
return CollUtil.newArrayList();
return Collections.emptyList();
}
return collection.stream()
.filter(Objects::nonNull)
.sorted(comparing)
// 注意此处不要使用 .toList() 新语法 因为返回的是不可变List 会导致序列化问题
return collection.stream().filter(Objects::nonNull).sorted(comparing).collect(Collectors.toList());
.collect(Collectors.toList());
}
/**
@ -115,9 +148,11 @@ public class StreamUtils {
*/
public static <V, K> Map<K, V> toIdentityMap(Collection<V> collection, Function<V, K> key) {
if (CollUtil.isEmpty(collection)) {
return MapUtil.newHashMap();
return Collections.emptyMap();
}
return collection.stream().filter(Objects::nonNull).collect(Collectors.toMap(key, Function.identity(), (l, r) -> l));
return collection.stream()
.filter(Objects::nonNull)
.collect(Collectors.toMap(key, Function.identity(), (l, r) -> l));
}
/**
@ -134,9 +169,27 @@ public class StreamUtils {
*/
public static <E, K, V> Map<K, V> toMap(Collection<E> collection, Function<E, K> key, Function<E, V> value) {
if (CollUtil.isEmpty(collection)) {
return MapUtil.newHashMap();
return Collections.emptyMap();
}
return collection.stream().filter(Objects::nonNull).collect(Collectors.toMap(key, value, (l, r) -> l));
return collection.stream()
.filter(Objects::nonNull)
.collect(Collectors.toMap(key, value, (l, r) -> l));
}
/**
* 获取 map 中的数据作为新 Map 的 value key 不变
* @param map 需要处理的map
* @param take 取值函数
* @param <K> map中的key类型
* @param <E> map中的value类型
* @param <V> 新map中的value类型
* @return 新的map
*/
public static <K, E, V> Map<K, V> toMap(Map<K, E> map, BiFunction<K, E, V> take) {
if (CollUtil.isEmpty(map)) {
return Collections.emptyMap();
}
return toMap(map.entrySet(), Map.Entry::getKey, entry -> take.apply(entry.getKey(), entry.getValue()));
}
/**
@ -151,10 +204,10 @@ public class StreamUtils {
*/
public static <E, K> Map<K, List<E>> groupByKey(Collection<E> collection, Function<E, K> key) {
if (CollUtil.isEmpty(collection)) {
return MapUtil.newHashMap();
return Collections.emptyMap();
}
return collection
.stream().filter(Objects::nonNull)
return collection.stream()
.filter(Objects::nonNull)
.collect(Collectors.groupingBy(key, LinkedHashMap::new, Collectors.toList()));
}
@ -172,10 +225,10 @@ public class StreamUtils {
*/
public static <E, K, U> Map<K, Map<U, List<E>>> groupBy2Key(Collection<E> collection, Function<E, K> key1, Function<E, U> key2) {
if (CollUtil.isEmpty(collection)) {
return MapUtil.newHashMap();
return Collections.emptyMap();
}
return collection
.stream().filter(Objects::nonNull)
return collection.stream()
.filter(Objects::nonNull)
.collect(Collectors.groupingBy(key1, LinkedHashMap::new, Collectors.groupingBy(key2, LinkedHashMap::new, Collectors.toList())));
}
@ -192,11 +245,11 @@ public class StreamUtils {
* @return 分类后的map
*/
public static <E, T, U> Map<T, Map<U, E>> group2Map(Collection<E> collection, Function<E, T> key1, Function<E, U> key2) {
if (CollUtil.isEmpty(collection) || key1 == null || key2 == null) {
return MapUtil.newHashMap();
if (CollUtil.isEmpty(collection)) {
return Collections.emptyMap();
}
return collection
.stream().filter(Objects::nonNull)
return collection.stream()
.filter(Objects::nonNull)
.collect(Collectors.groupingBy(key1, LinkedHashMap::new, Collectors.toMap(key2, Function.identity(), (l, r) -> l)));
}
@ -212,10 +265,9 @@ public class StreamUtils {
*/
public static <E, T> List<T> toList(Collection<E> collection, Function<E, T> function) {
if (CollUtil.isEmpty(collection)) {
return CollUtil.newArrayList();
return Collections.emptyList();
}
return collection
.stream()
return collection.stream()
.map(function)
.filter(Objects::nonNull)
// 注意此处不要使用 .toList() 新语法 因为返回的是不可变List 会导致序列化问题
@ -233,11 +285,10 @@ public class StreamUtils {
* @return 转化后的Set
*/
public static <E, T> Set<T> toSet(Collection<E> collection, Function<E, T> function) {
if (CollUtil.isEmpty(collection) || function == null) {
return CollUtil.newHashSet();
if (CollUtil.isEmpty(collection)) {
return Collections.emptySet();
}
return collection
.stream()
return collection.stream()
.map(function)
.filter(Objects::nonNull)
.collect(Collectors.toSet());
@ -257,26 +308,20 @@ public class StreamUtils {
* @return 合并后的map
*/
public static <K, X, Y, V> Map<K, V> merge(Map<K, X> map1, Map<K, Y> map2, BiFunction<X, Y, V> merge) {
if (MapUtil.isEmpty(map1) && MapUtil.isEmpty(map2)) {
return MapUtil.newHashMap();
} else if (MapUtil.isEmpty(map1)) {
map1 = MapUtil.newHashMap();
} else if (MapUtil.isEmpty(map2)) {
map2 = MapUtil.newHashMap();
if (CollUtil.isEmpty(map1) && CollUtil.isEmpty(map2)) {
// 如果两个 map 都为空,则直接返回空的 map
return Collections.emptyMap();
} else if (CollUtil.isEmpty(map1)) {
// 如果 map1 为空,则直接处理返回 map2
return toMap(map2.entrySet(), Map.Entry::getKey, entry -> merge.apply(null, entry.getValue()));
} else if (CollUtil.isEmpty(map2)) {
// 如果 map2 为空,则直接处理返回 map1
return toMap(map1.entrySet(), Map.Entry::getKey, entry -> merge.apply(entry.getValue(), null));
}
Set<K> key = new HashSet<>();
key.addAll(map1.keySet());
key.addAll(map2.keySet());
Map<K, V> map = new HashMap<>();
for (K t : key) {
X x = map1.get(t);
Y y = map2.get(t);
V z = merge.apply(x, y);
if (z != null) {
map.put(t, z);
}
}
return map;
Set<K> keySet = new HashSet<>();
keySet.addAll(map1.keySet());
keySet.addAll(map2.keySet());
return toMap(keySet, key -> key, key -> merge.apply(map1.get(key), map2.get(key)));
}
}

View File

@ -27,6 +27,7 @@ import java.io.UnsupportedEncodingException;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
/**
* Excel相关处理
@ -203,6 +204,45 @@ public class ExcelUtil {
builder.doWrite(list);
}
/**
* 导出excel
*
* @param headType 带Excel注解的类型
* @param os 输出流
* @param options Excel下拉可选项
* @param consumer 导出助手消费函数
*/
public static <T> void exportExcel(Class<T> headType, OutputStream os, List<DropDownOptions> options, Consumer<ExcelWriterHelper> consumer) {
try (ExcelWriter writer = FastExcel.write(os, headType)
.autoCloseStream(false)
// 自动适配
.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
// 大数值自动转换 防止失真
.registerConverter(new ExcelBigNumberConvert())
// 批注必填项处理
.registerWriteHandler(new DataWriteHandler(headType))
// 添加下拉框操作
.registerWriteHandler(new ExcelDownHandler(options))
.build()) {
ExcelWriterHelper helper = ExcelWriterHelper.of(writer);
// 执行消费函数
consumer.accept(helper);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 导出excel
*
* @param headType 带Excel注解的类型
* @param os 输出流
* @param consumer 导出助手消费函数
*/
public static <T> void exportExcel(Class<T> headType, OutputStream os, Consumer<ExcelWriterHelper> consumer) {
exportExcel(headType, os, null, consumer);
}
/**
* 单表多数据模板导出 模板格式为 {.属性}
*

View File

@ -0,0 +1,135 @@
package org.dromara.common.excel.utils;
import cn.idev.excel.ExcelWriter;
import cn.idev.excel.FastExcel;
import cn.idev.excel.context.WriteContext;
import cn.idev.excel.write.builder.ExcelWriterSheetBuilder;
import cn.idev.excel.write.builder.ExcelWriterTableBuilder;
import cn.idev.excel.write.metadata.WriteSheet;
import cn.idev.excel.write.metadata.WriteTable;
import cn.idev.excel.write.metadata.fill.FillConfig;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import java.util.Collection;
import java.util.function.Supplier;
/**
* ExcelWriterHelper Excel写出助手
* <br>
* 提供了一组与 ExcelWriter 一一对应的写出方法,避免直接提供 ExcelWriter 而导致的一些不可控问题比如提前关闭了IO流等
*
*
* @see ExcelWriter
* @author 秋辞未寒
*/
@RequiredArgsConstructor
public class ExcelWriterHelper {
@Getter(AccessLevel.PRIVATE)
private final ExcelWriter excelWriter;
public void write(Collection<?> data, WriteSheet writeSheet) {
excelWriter.write(data, writeSheet);
}
public void write(Supplier<Collection<?>> supplier, WriteSheet writeSheet) {
excelWriter.write(supplier, writeSheet);
}
public void write(Collection<?> data, WriteSheet writeSheet, WriteTable writeTable) {
excelWriter.write(data, writeSheet, writeTable);
}
public void write(Supplier<Collection<?>> supplier, WriteSheet writeSheet, WriteTable writeTable) {
excelWriter.write(supplier.get(), writeSheet, writeTable);
}
public void fill(Object data, WriteSheet writeSheet) {
excelWriter.fill(data, writeSheet);
}
public void fill(Object data, FillConfig fillConfig, WriteSheet writeSheet) {
excelWriter.fill(data, fillConfig, writeSheet);
}
public void fill(Supplier<Object> supplier, WriteSheet writeSheet) {
excelWriter.fill(supplier, writeSheet);
}
public void fill(Supplier<Object> supplier, FillConfig fillConfig, WriteSheet writeSheet) {
excelWriter.fill(supplier, fillConfig, writeSheet);
}
public WriteContext writeContext() {
return excelWriter.writeContext();
}
/**
* 创建一个 ExcelWriterHelper
*
* @param excelWriter ExcelWriter
* @return ExcelWriterHelper
*/
public static ExcelWriterHelper of(ExcelWriter excelWriter) {
return new ExcelWriterHelper(excelWriter);
}
// -------------------------------- sheet start
public static WriteSheet buildSheet(Integer sheetNo, String sheetName) {
return sheetBuilder(sheetNo, sheetName).build();
}
public static WriteSheet buildSheet(Integer sheetNo) {
return sheetBuilder(sheetNo).build();
}
public static WriteSheet buildSheet(String sheetName) {
return sheetBuilder(sheetName).build();
}
public static WriteSheet buildSheet() {
return sheetBuilder().build();
}
public static ExcelWriterSheetBuilder sheetBuilder(Integer sheetNo, String sheetName) {
return FastExcel.writerSheet(sheetNo, sheetName);
}
public static ExcelWriterSheetBuilder sheetBuilder(Integer sheetNo) {
return FastExcel.writerSheet(sheetNo);
}
public static ExcelWriterSheetBuilder sheetBuilder(String sheetName) {
return FastExcel.writerSheet(sheetName);
}
public static ExcelWriterSheetBuilder sheetBuilder() {
return FastExcel.writerSheet();
}
// -------------------------------- sheet end
// -------------------------------- table start
public static WriteTable buildTable(Integer tableNo) {
return tableBuilder(tableNo).build();
}
public static WriteTable buildTable() {
return tableBuilder().build();
}
public static ExcelWriterTableBuilder tableBuilder(Integer tableNo) {
return FastExcel.writerTable(tableNo);
}
public static ExcelWriterTableBuilder tableBuilder() {
return FastExcel.writerTable();
}
// -------------------------------- table end
}

View File

@ -1,5 +1,6 @@
package org.dromara.demo.controller;
import cn.dev33.satoken.annotation.SaIgnore;
import cn.hutool.core.collection.CollUtil;
import jakarta.servlet.http.HttpServletResponse;
import lombok.AllArgsConstructor;
@ -14,6 +15,7 @@ import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@ -94,6 +96,16 @@ public class TestExcelController {
exportExcelService.exportWithOptions(response);
}
/**
* 自定义导出
*
* @param response /
*/
@GetMapping("/customExport")
public void customExport(HttpServletResponse response) throws IOException {
exportExcelService.customExport(response);
}
/**
* 多个sheet导出
*/

View File

@ -2,6 +2,8 @@ package org.dromara.demo.service;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 导出下拉框Excel示例
*
@ -15,4 +17,11 @@ public interface IExportExcelService {
* @param response /
*/
void exportWithOptions(HttpServletResponse response);
/**
* 自定义导出
*
* @param response /
*/
void customExport(HttpServletResponse response) throws IOException;
}

View File

@ -2,17 +2,22 @@ package org.dromara.demo.service.impl;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.idev.excel.write.metadata.WriteSheet;
import jakarta.servlet.http.HttpServletResponse;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.constant.SystemConstants;
import org.dromara.common.core.utils.StreamUtils;
import org.dromara.common.core.utils.file.FileUtils;
import org.dromara.common.excel.core.CellMergeStrategy;
import org.dromara.common.excel.core.DropDownOptions;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.common.excel.utils.ExcelWriterHelper;
import org.dromara.demo.domain.vo.ExportDemoVo;
import org.dromara.demo.service.IExportExcelService;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@ -233,4 +238,61 @@ public class ExportExcelServiceImpl implements IExportExcelService {
this.name = name;
}
}
@Override
public void customExport(HttpServletResponse response) throws IOException {
String filename = ExcelUtil.encodingFilename("自定义导出");
FileUtils.setAttachmentResponseHeader(response, filename);
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8");
ExcelUtil.exportExcel(ExportDemoVo.class, response.getOutputStream(), helper -> {
// 创建表格数据,业务中一般通过数据库查询
List<ExportDemoVo> excelDataList = new ArrayList<>();
for (int i = 0; i < 30; i++) {
// 模拟数据库中的一条数据
ExportDemoVo everyRowData = new ExportDemoVo();
everyRowData.setNickName("用户-" + i);
everyRowData.setUserStatus(SystemConstants.NORMAL);
everyRowData.setGender("1");
everyRowData.setPhoneNumber(String.format("175%08d", i));
everyRowData.setEmail(String.format("175%08d", i) + "@163.com");
everyRowData.setProvinceId(i);
everyRowData.setCityId(i);
everyRowData.setAreaId(i);
excelDataList.add(everyRowData);
}
// 创建表格
WriteSheet sheet = ExcelWriterHelper.sheetBuilder("自定义导出demo")
// 合并单元格
// .registerWriteHandler(new CellMergeStrategy(excelDataList, true))
.build();
helper.write(excelDataList, sheet);
List<ExportDemoVo> excelDataList2 = new ArrayList<>();
for (int i = 0; i < 20; i++) {
int index = 1000 + i;
// 模拟数据库中的一条数据
ExportDemoVo everyRowData = new ExportDemoVo();
everyRowData.setNickName("用户-" + index);
everyRowData.setUserStatus(SystemConstants.NORMAL);
everyRowData.setGender("1");
everyRowData.setPhoneNumber(String.format("175%08d", index));
everyRowData.setEmail(String.format("175%08d", index) + "@163.com");
everyRowData.setProvinceId(index);
everyRowData.setCityId(index);
everyRowData.setAreaId(index);
excelDataList2.add(everyRowData);
}
helper.write(excelDataList2, sheet);
// 或者在同一个excel中创建多个表格
// WriteSheet sheet2 = ExcelWriterHelper.sheetBuilder("自定义导出demo2").build();
// helper.write(excelDataList2, sheet2);
});
}
}

View File

@ -638,14 +638,14 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
//办理人变量替换
ExpressionUtil.evalVariable(buildNextTaskList, FlowParams.build().variable(mergeVariable));
for (FlowNode flowNode : nextFlowNodes) {
Task first = StreamUtils.findFirst(buildNextTaskList, t -> t.getNodeCode().equals(flowNode.getNodeCode()));
if (ObjectUtil.isNotNull(first) && CollUtil.isNotEmpty(first.getPermissionList())) {
List<UserDTO> users = flwTaskAssigneeService.fetchUsersByStorageIds(StringUtils.joinComma(first.getPermissionList()));
if (CollUtil.isNotEmpty(users)) {
StreamUtils.findFirst(buildNextTaskList, t -> t.getNodeCode().equals(flowNode.getNodeCode()))
.ifPresent(first -> {
List<UserDTO> users;
if (CollUtil.isNotEmpty(first.getPermissionList())
&& CollUtil.isNotEmpty(users = flwTaskAssigneeService.fetchUsersByStorageIds(StringUtils.joinComma(first.getPermissionList())))) {
flowNode.setPermissionFlag(StreamUtils.join(users, e -> Convert.toStr(e.getUserId())));
}
}
});
}
}
return nextFlowNodes;