readListener = new ExcelBeanReadListener<>();
+ if (excelFile instanceof File) {
+ EasyExcel.read((File) excelFile, contentType, readListener).doReadAll();
+ } else if (excelFile instanceof InputStream) {
+ EasyExcel.read((InputStream) excelFile, contentType, readListener).doReadAll();
+ } else {
+ throw new ExcelException("Unsupported excel file");
+ }
+ return readListener.getReadResult();
+ }
+
+}
\ No newline at end of file
diff --git a/commons/common-util/src/main/java/com/schbrain/common/util/IdWorker.java b/commons/common-util/src/main/java/com/schbrain/common/util/IdWorker.java
new file mode 100644
index 0000000..67959a9
--- /dev/null
+++ b/commons/common-util/src/main/java/com/schbrain/common/util/IdWorker.java
@@ -0,0 +1,125 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ * http://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.
+ */
+
+package com.schbrain.common.util;
+
+import java.security.SecureRandom;
+import java.util.Random;
+
+/***
+ * @author adyliu (imxylz@gmail.com)
+ * @since 1.0
+ */
+public class IdWorker {
+
+ /**
+ * 生成的自增id的大小减少到18位
+ */
+ private static final long ID_EPOCH = 1420041600000L;
+ private static final long workerIdBits = 5L;
+ private static final long datacenterIdBits = 5L;
+ private static final long maxWorkerId = ~(-1L << workerIdBits);
+ private static final long maxDatacenterId = ~(-1L << datacenterIdBits);
+ private static final long sequenceBits = 12L;
+ private static final long workerIdShift = sequenceBits;
+ private static final long datacenterIdShift = sequenceBits + workerIdBits;
+ private static final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
+ private static final long sequenceMask = ~(-1L << sequenceBits);
+ private static final Random r = new SecureRandom();
+ // 需要等 r 初始化
+ private static final IdWorker INSTANCE = new IdWorker(ID_EPOCH);
+ private final long workerId;
+ private final long datacenterId;
+ private final long idEpoch;
+ private long lastTimestamp = -1L;
+ private long sequence;
+
+ public IdWorker(long idEpoch) {
+ this(r.nextInt((int) maxWorkerId), r.nextInt((int) maxDatacenterId), 0, idEpoch);
+ }
+
+ public IdWorker(long workerId, long datacenterId, long sequence) {
+ this(workerId, datacenterId, sequence, 1420041600000L);
+ }
+
+ public IdWorker(long workerId, long datacenterId, long sequence, long idEpoch) {
+ this.workerId = workerId;
+ this.datacenterId = datacenterId;
+ this.sequence = sequence;
+ this.idEpoch = idEpoch;
+ if (workerId < 0 || workerId > maxWorkerId) {
+ throw new IllegalArgumentException("workerId is illegal: " + workerId);
+ }
+ if (datacenterId < 0 || datacenterId > maxDatacenterId) {
+ throw new IllegalArgumentException("datacenterId is illegal: " + workerId);
+ }
+ if (idEpoch >= System.currentTimeMillis()) {
+ throw new IllegalArgumentException("idEpoch is illegal: " + idEpoch);
+ }
+ }
+
+ public static long getId() {
+ return INSTANCE.nextId();
+ }
+
+ public static String getIdStr() {
+ return String.valueOf(INSTANCE.nextId());
+ }
+
+ /**
+ * get the timestamp (millis second) of id
+ *
+ * @param id the nextId
+ * @return the timestamp of id
+ */
+ public long getIdTimestamp(long id) {
+ return idEpoch + (id >> timestampLeftShift);
+ }
+
+ private synchronized long nextId() {
+ long timestamp = timeGen();
+ if (timestamp < lastTimestamp) {
+ throw new IllegalStateException("Clock moved backwards.");
+ }
+ if (lastTimestamp == timestamp) {
+ sequence = (sequence + 1) & sequenceMask;
+ if (sequence == 0) {
+ timestamp = tilNextMillis(lastTimestamp);
+ }
+ } else {
+ sequence = 0;
+ }
+ lastTimestamp = timestamp;
+ return ((timestamp - idEpoch) << timestampLeftShift)//
+ | (datacenterId << datacenterIdShift)//
+ | (workerId << workerIdShift)//
+ | sequence;
+ }
+
+ private long tilNextMillis(long lastTimestamp) {
+ long timestamp = timeGen();
+ while (timestamp <= lastTimestamp) {
+ timestamp = timeGen();
+ }
+ return timestamp;
+ }
+
+ private long timeGen() {
+ return System.currentTimeMillis();
+ }
+
+}
\ No newline at end of file
diff --git a/commons/common-util/src/main/java/com/schbrain/common/util/InetUtils.java b/commons/common-util/src/main/java/com/schbrain/common/util/InetUtils.java
new file mode 100644
index 0000000..0d2727c
--- /dev/null
+++ b/commons/common-util/src/main/java/com/schbrain/common/util/InetUtils.java
@@ -0,0 +1,105 @@
+package com.schbrain.common.util;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.IOException;
+import java.net.*;
+import java.nio.ByteBuffer;
+import java.util.Enumeration;
+
+/**
+ * Copy from SpringCloud
+ *
+ * @author liaozan
+ * @since 2021/11/19
+ */
+@Slf4j
+public class InetUtils {
+
+ public static HostInfo findFirstNonLoopBackHostInfo() {
+ InetAddress address = findFirstNonLoopBackAddress();
+ if (address != null) {
+ return convertAddress(address);
+ }
+ HostInfo hostInfo = new HostInfo();
+ hostInfo.setHostname("localhost");
+ hostInfo.setIpAddress("127.0.0.1");
+ return hostInfo;
+ }
+
+ private static InetAddress findFirstNonLoopBackAddress() {
+ InetAddress result = null;
+ try {
+ int lowest = Integer.MAX_VALUE;
+ Enumeration interfaces = NetworkInterface.getNetworkInterfaces();
+ while (interfaces.hasMoreElements()) {
+ NetworkInterface networkInterface = interfaces.nextElement();
+ if (networkInterface.isUp()) {
+ if (networkInterface.getIndex() < lowest || result == null) {
+ lowest = networkInterface.getIndex();
+ } else {
+ continue;
+ }
+
+ Enumeration inetAddresses = networkInterface.getInetAddresses();
+ while (inetAddresses.hasMoreElements()) {
+ InetAddress address = inetAddresses.nextElement();
+ if (address instanceof Inet4Address && !address.isLoopbackAddress()) {
+ result = address;
+ }
+ }
+ }
+ }
+ } catch (IOException ex) {
+ log.error("Cannot get first non-loopBack address", ex);
+ }
+
+ if (result != null) {
+ return result;
+ }
+
+ try {
+ return InetAddress.getLocalHost();
+ } catch (UnknownHostException e) {
+ log.warn("Unable to retrieve localhost");
+ }
+
+ return null;
+ }
+
+ private static HostInfo convertAddress(final InetAddress address) {
+ HostInfo hostInfo = new HostInfo();
+ String hostname = address.getHostName();
+ hostInfo.setHostname(hostname);
+ hostInfo.setIpAddress(address.getHostAddress());
+ return hostInfo;
+ }
+
+ @Data
+ public static class HostInfo {
+
+ public static final String NAME = "machineHostInfo";
+
+ private String ipAddress;
+ private String hostname;
+
+ @JsonIgnore
+ public int getIpAddressAsInt() {
+ InetAddress inetAddress;
+ String host = this.ipAddress;
+ if (host == null) {
+ host = this.hostname;
+ }
+ try {
+ inetAddress = InetAddress.getByName(host);
+ } catch (final UnknownHostException e) {
+ throw new IllegalArgumentException(e);
+ }
+ return ByteBuffer.wrap(inetAddress.getAddress()).getInt();
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/commons/common-util/src/main/java/com/schbrain/common/util/JacksonUtils.java b/commons/common-util/src/main/java/com/schbrain/common/util/JacksonUtils.java
new file mode 100644
index 0000000..3654c24
--- /dev/null
+++ b/commons/common-util/src/main/java/com/schbrain/common/util/JacksonUtils.java
@@ -0,0 +1,243 @@
+package com.schbrain.common.util;
+
+import cn.hutool.extra.spring.SpringUtil;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.*;
+import com.fasterxml.jackson.databind.node.NullNode;
+import com.schbrain.common.constants.ResponseActionConstants;
+import com.schbrain.common.constants.ResponseCodeConstants;
+import com.schbrain.common.exception.BaseException;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.reflect.TypeUtils;
+
+import java.lang.reflect.ParameterizedType;
+import java.util.*;
+
+import static com.fasterxml.jackson.databind.SerializationFeature.INDENT_OUTPUT;
+
+/**
+ * @author liaozan
+ * @since 2021/10/12
+ */
+@Slf4j
+public class JacksonUtils {
+
+ private static ObjectMapper OBJECT_MAPPER;
+ private static ObjectMapper PRETTY_OBJECT_MAPPER;
+
+ public static ObjectMapper getObjectMapper() {
+ if (OBJECT_MAPPER == null) {
+ // Delay to get ObjectMapper from spring container to keep the same behavior with application
+ try {
+ OBJECT_MAPPER = SpringUtil.getBean(ObjectMapper.class).copy();
+ } catch (Exception e) {
+ log.warn("Could not get ObjectMapper from Spring Container, return new instance for use");
+ OBJECT_MAPPER = new ObjectMapper();
+ }
+ OBJECT_MAPPER.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
+ }
+ return OBJECT_MAPPER;
+ }
+
+ public static ObjectMapper getPrettyObjectMapper() {
+ if (PRETTY_OBJECT_MAPPER == null) {
+ PRETTY_OBJECT_MAPPER = getObjectMapper().copy().enable(INDENT_OUTPUT);
+ }
+ return PRETTY_OBJECT_MAPPER;
+ }
+
+ public static String toJsonString(Object data) {
+ return toJsonString(data, false);
+ }
+
+ public static String toPrettyJsonString(Object data) {
+ return toJsonString(data, true);
+ }
+
+ public static String toJsonString(Object data, boolean pretty) {
+ try {
+ if (pretty) {
+ return getPrettyObjectMapper().writeValueAsString(data);
+ }
+ return getObjectMapper().writeValueAsString(data);
+ } catch (Exception e) {
+ throw new JSONException("Object 转 JSON 出错", e);
+ }
+ }
+
+ public static JsonNode getJsonNode(String json) {
+ try {
+ if (StringUtils.isBlank(json)) {
+ return NullNode.getInstance();
+ }
+ return getObjectMapper().readTree(json);
+ } catch (Exception e) {
+ throw new JSONException("JSON 转 JsonNode 出错", e);
+ }
+ }
+
+ public static T getObjectFromBytes(byte[] bytes, Class type) {
+ if (ArrayUtils.isEmpty(bytes)) {
+ return null;
+ }
+ try {
+ return getObjectMapper().readValue(bytes, type);
+ } catch (Exception e) {
+ throw new JSONException("Byte 转 Object 出错", e);
+ }
+ }
+
+ public static T getObjectFromBytes(byte[] bytes, ParameterizedType type) {
+ if (ArrayUtils.isEmpty(bytes)) {
+ return null;
+ }
+ try {
+ JavaType valueType = getObjectMapper().getTypeFactory().constructType(type);
+ return getObjectMapper().readValue(bytes, valueType);
+ } catch (Exception e) {
+ throw new JSONException("Byte 转 Object 出错", e);
+ }
+ }
+
+ public static T getObjectFromBytes(byte[] bytes, TypeReference typeReference) {
+ if (ArrayUtils.isEmpty(bytes)) {
+ return null;
+ }
+ try {
+ return getObjectMapper().readValue(bytes, typeReference);
+ } catch (Exception e) {
+ throw new JSONException("Byte 转 Object 出错", e);
+ }
+ }
+
+ public static T getObjectFromBytesWithTypeConstruct(byte[] bytes, Class genericsType, Class>... innerTypes) {
+ if (ArrayUtils.isEmpty(bytes)) {
+ return null;
+ }
+ try {
+ JavaType valueType = constructType(genericsType, innerTypes);
+ return getObjectMapper().readValue(bytes, valueType);
+ } catch (Exception e) {
+ throw new JSONException("Byte 转 Object 出错", e);
+ }
+ }
+
+ public static T getObjectFromJson(String json, Class type) {
+ if (StringUtils.isBlank(json)) {
+ return null;
+ }
+ try {
+ return getObjectMapper().readValue(json, type);
+ } catch (Exception e) {
+ throw new JSONException("JSON 转 Object 出错", e);
+ }
+ }
+
+ public static T getObjectFromJson(String json, ParameterizedType type) {
+ if (StringUtils.isBlank(json)) {
+ return null;
+ }
+ try {
+ JavaType valueType = getObjectMapper().getTypeFactory().constructType(type);
+ return getObjectMapper().readValue(json, valueType);
+ } catch (Exception e) {
+ throw new JSONException("JSON 转 Object 出错", e);
+ }
+ }
+
+ public static T getObjectFromJson(String json, TypeReference typeReference) {
+ if (StringUtils.isBlank(json)) {
+ return null;
+ }
+ try {
+ return getObjectMapper().readValue(json, typeReference);
+ } catch (Exception e) {
+ throw new JSONException("JSON 转 Object 出错", e);
+ }
+ }
+
+ public static T getObjectFromJsonWithTypeConstruct(String json, Class genericsType, Class>... innerTypes) {
+ if (StringUtils.isBlank(json)) {
+ return null;
+ }
+ try {
+ JavaType valueType = constructType(genericsType, innerTypes);
+ return getObjectMapper().readValue(json, valueType);
+ } catch (Exception e) {
+ throw new JSONException("JSON 转 Object 出错", e);
+ }
+ }
+
+ public static Map getMapFromJson(String json) {
+ return getMapFromJson(json, Object.class);
+ }
+
+ public static Map getMapFromJson(String json, Class valueType) {
+ return getMapFromJson(json, String.class, valueType);
+ }
+
+ public static Map getMapFromJson(String json, Class keyType, Class valueType) {
+ if (StringUtils.isBlank(json)) {
+ return new LinkedHashMap<>();
+ }
+ try {
+ JavaType mapType = getObjectMapper().getTypeFactory().constructMapType(LinkedHashMap.class, keyType, valueType);
+ return getObjectMapper().readValue(json, mapType);
+ } catch (Exception e) {
+ throw new JSONException("JSON 转 Map 出错", e);
+ }
+ }
+
+ public static List getListFromJson(String json, Class itemType) {
+ if (StringUtils.isBlank(json)) {
+ return new ArrayList<>();
+ }
+ try {
+ JavaType listType = getObjectMapper().getTypeFactory().constructCollectionType(ArrayList.class, itemType);
+ return getObjectMapper().readValue(json, listType);
+ } catch (Exception e) {
+ throw new JSONException("JSON 转 List 出错", e);
+ }
+ }
+
+ public static byte[] writeObjectAsBytes(Object data) {
+ try {
+ return getObjectMapper().writeValueAsBytes(data);
+ } catch (Exception e) {
+ throw new JSONException("Object 转 Byte 出错", e);
+ }
+ }
+
+ public static JavaType constructType(Class> genericsType, Class>... innerTypes) {
+ return getObjectMapper().getTypeFactory().constructType(TypeUtils.parameterize(genericsType, innerTypes));
+ }
+
+ public static T convertValue(Object fromValue, Class toValueType) {
+ try {
+ return getObjectMapper().convertValue(fromValue, toValueType);
+ } catch (Exception e) {
+ throw new JSONException("JSON 转换出错", e);
+ }
+ }
+
+ public static T convertValue(Object fromValue, JavaType toValueType) {
+ try {
+ return getObjectMapper().convertValue(fromValue, toValueType);
+ } catch (Exception e) {
+ throw new JSONException("JSON 转换出错", e);
+ }
+ }
+
+ public static class JSONException extends BaseException {
+
+ private static final long serialVersionUID = 1656914307906296812L;
+
+ public JSONException(String message, Throwable cause) {
+ super(message, cause, ResponseCodeConstants.SERVER_ERROR, ResponseActionConstants.ALERT);
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/commons/common-util/src/main/java/com/schbrain/common/util/PageUtils.java b/commons/common-util/src/main/java/com/schbrain/common/util/PageUtils.java
new file mode 100644
index 0000000..005cbd3
--- /dev/null
+++ b/commons/common-util/src/main/java/com/schbrain/common/util/PageUtils.java
@@ -0,0 +1,73 @@
+package com.schbrain.common.util;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.schbrain.common.entity.PageParam;
+import com.schbrain.common.entity.PaginationInfo;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.function.Function;
+
+import static com.schbrain.common.constants.PageConstants.*;
+
+/**
+ * @author liaozan
+ * @since 2022/1/7
+ */
+public class PageUtils {
+
+ public static IPage fromParam(PageParam pageParam) {
+ return fromParam(pageParam.getPageIndex(), pageParam.getPageSize(), pageParam.isSearchCount());
+ }
+
+ public static IPage fromParam(long pageIndex, long pageSize) {
+ return fromParam(pageIndex, pageSize, DEFAULT_SEARCH_COUNT);
+ }
+
+ public static IPage fromParam(long pageIndex, long pageSize, boolean searchCount) {
+ return Page.of(pageIndex, pageSize, searchCount);
+ }
+
+ public static PaginationInfo fromResult(IPage page) {
+ return fromResult(page, page.getRecords());
+ }
+
+ public static PaginationInfo fromResult(IPage page, Function mapper) {
+ return fromResult(page.convert(mapper));
+ }
+
+ public static PaginationInfo fromResult(IPage page, List dataList) {
+ return new PaginationInfo<>(page.getCurrent(), page.getSize(), page.getTotal(), dataList);
+ }
+
+ public static PaginationInfo fromResult(PaginationInfo info, Function mapper) {
+ List dataList = StreamUtils.toList(info.getDataList(), mapper);
+ return fromResult(info, dataList);
+ }
+
+ public static PaginationInfo fromResult(PaginationInfo info, List dataList) {
+ return new PaginationInfo<>(info.getPageIndex(), info.getPageSize(), info.getTotalCount(), dataList);
+ }
+
+ public static PaginationInfo emptyResult(IPage page) {
+ return new PaginationInfo<>(page.getCurrent(), page.getSize(), DEFAULT_TOTAL_COUNT, Collections.emptyList());
+ }
+
+ public static PaginationInfo emptyResult(PageParam pageParam) {
+ return new PaginationInfo<>(pageParam.getPageIndex(), pageParam.getPageSize(), DEFAULT_TOTAL_COUNT, Collections.emptyList());
+ }
+
+ public static PaginationInfo emptyResult(PaginationInfo> page) {
+ return new PaginationInfo<>(page.getPageIndex(), page.getPageSize(), DEFAULT_TOTAL_COUNT, Collections.emptyList());
+ }
+
+ public static PageParam toParam(IPage> page) {
+ PageParam pageParam = new PageParam();
+ pageParam.setPageIndex(Math.toIntExact(page.getCurrent()));
+ pageParam.setPageSize(Math.toIntExact(page.getSize()));
+ pageParam.setSearchCount(page.searchCount());
+ return pageParam;
+ }
+
+}
\ No newline at end of file
diff --git a/commons/common-util/src/main/java/com/schbrain/common/util/ParameterDiscoverUtils.java b/commons/common-util/src/main/java/com/schbrain/common/util/ParameterDiscoverUtils.java
new file mode 100644
index 0000000..bc00849
--- /dev/null
+++ b/commons/common-util/src/main/java/com/schbrain/common/util/ParameterDiscoverUtils.java
@@ -0,0 +1,33 @@
+package com.schbrain.common.util;
+
+import cn.hutool.core.util.ArrayUtil;
+import com.google.common.collect.Maps;
+import org.springframework.core.DefaultParameterNameDiscoverer;
+import org.springframework.core.ParameterNameDiscoverer;
+
+import java.lang.reflect.Method;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * @author liaozan
+ * @since 2022/5/18
+ */
+public class ParameterDiscoverUtils {
+
+ private static final ParameterNameDiscoverer DISCOVERER = new DefaultParameterNameDiscoverer();
+
+ public static Map getMethodArgsMap(Method method, Object[] args) {
+ String[] parameterNames = DISCOVERER.getParameterNames(method);
+ if (ArrayUtil.isEmpty(parameterNames)) {
+ // Return a new instance to avoid external modification causing errors
+ return new LinkedHashMap<>();
+ }
+ Map argsMap = Maps.newLinkedHashMapWithExpectedSize(parameterNames.length);
+ for (int i = 0; i < parameterNames.length; i++) {
+ argsMap.put(parameterNames[i], args[i]);
+ }
+ return argsMap;
+ }
+
+}
\ No newline at end of file
diff --git a/commons/common-util/src/main/java/com/schbrain/common/util/PortUtils.java b/commons/common-util/src/main/java/com/schbrain/common/util/PortUtils.java
new file mode 100644
index 0000000..e22ec12
--- /dev/null
+++ b/commons/common-util/src/main/java/com/schbrain/common/util/PortUtils.java
@@ -0,0 +1,49 @@
+package com.schbrain.common.util;
+
+import com.schbrain.common.exception.BaseException;
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.IOException;
+import java.net.ServerSocket;
+
+/**
+ * net util
+ *
+ * @author xuxueli 2017-11-29 17:00:25
+ */
+@Slf4j
+public class PortUtils {
+
+ public static int findAvailablePort(int defaultPort) {
+ int portTmp = defaultPort;
+ while (portTmp < 65535) {
+ if (!isPortUsed(portTmp)) {
+ return portTmp;
+ } else {
+ portTmp++;
+ }
+ }
+ throw new BaseException("no available port.");
+ }
+
+ public static boolean isPortUsed(int port) {
+ boolean used = false;
+ ServerSocket serverSocket = null;
+ try {
+ serverSocket = new ServerSocket(port);
+ } catch (IOException e) {
+ log.warn("current port[{}] is in use", port);
+ used = true;
+ } finally {
+ if (serverSocket != null) {
+ try {
+ serverSocket.close();
+ } catch (IOException e) {
+ log.info(e.getMessage(), e);
+ }
+ }
+ }
+ return used;
+ }
+
+}
diff --git a/commons/common-util/src/main/java/com/schbrain/common/util/SpelUtils.java b/commons/common-util/src/main/java/com/schbrain/common/util/SpelUtils.java
new file mode 100644
index 0000000..406294f
--- /dev/null
+++ b/commons/common-util/src/main/java/com/schbrain/common/util/SpelUtils.java
@@ -0,0 +1,39 @@
+package com.schbrain.common.util;
+
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.expression.*;
+import org.springframework.expression.spel.standard.SpelExpressionParser;
+import org.springframework.expression.spel.support.StandardEvaluationContext;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+public class SpelUtils {
+
+ private static final ExpressionParser spELParser = new SpelExpressionParser();
+
+ private static final ConcurrentHashMap expressionCache = new ConcurrentHashMap<>();
+
+ public static T parse(String express, Map variables, Class valueType) {
+ StandardEvaluationContext ctx = new StandardEvaluationContext();
+ ctx.setVariables(variables);
+ return parse(express, ctx, valueType);
+ }
+
+ public static T parse(String express, EvaluationContext context, Class valueType) {
+ if (StringUtils.isBlank(express)) {
+ return null;
+ }
+ return getExpression(express).getValue(context, valueType);
+ }
+
+ private static Expression getExpression(String exp) {
+ Expression expression = expressionCache.get(exp);
+ if (null == expression) {
+ expression = spELParser.parseExpression(exp);
+ expressionCache.put(exp, expression);
+ }
+ return expression;
+ }
+
+}
\ No newline at end of file
diff --git a/commons/common-util/src/main/java/com/schbrain/common/util/StreamUtils.java b/commons/common-util/src/main/java/com/schbrain/common/util/StreamUtils.java
new file mode 100644
index 0000000..05f9cc0
--- /dev/null
+++ b/commons/common-util/src/main/java/com/schbrain/common/util/StreamUtils.java
@@ -0,0 +1,160 @@
+package com.schbrain.common.util;
+
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.*;
+import java.util.function.*;
+import java.util.stream.*;
+
+import static java.util.Collections.emptyList;
+import static java.util.stream.Collectors.*;
+
+/**
+ * @author liaozan
+ * @since 2022/8/21
+ */
+@Slf4j
+public class StreamUtils {
+
+ public static List filterToList(Collection data, Predicate predicate) {
+ return filter(data, predicate, Collectors.toList());
+ }
+
+ public static Set filterToSet(Collection data, Predicate predicate) {
+ return filter(data, predicate, Collectors.toSet());
+ }
+
+ public static > C filter(Collection data, Predicate predicate, Collector collector) {
+ return Optional.ofNullable(data).orElse(emptyList()).stream().filter(predicate).collect(collector);
+ }
+
+ public static List toList(Collection data, Function mapper) {
+ return toList(data, mapper, false);
+ }
+
+ public static List toList(Collection data, Function mapper, boolean distinct) {
+ return toList(data, mapper, distinct, false);
+ }
+
+ public static List toList(Collection data, Function mapper, boolean distinct, boolean ignoreNull) {
+ return extract(data, mapper, distinct, ignoreNull, Collectors.toList());
+ }
+
+ public static Set toSet(Collection data, Function mapper) {
+ return toSet(data, mapper, false);
+ }
+
+ public static Set toSet(Collection data, Function mapper, boolean ignoreNull) {
+ return extract(data, mapper, ignoreNull, false, Collectors.toSet());
+ }
+
+ public static Map toMap(Collection data, Function keyMapper) {
+ return toMap(data, keyMapper, false);
+ }
+
+ public static Map toMap(Collection data, Function keyMapper, boolean ordered) {
+ return toMap(data, keyMapper, Function.identity(), ordered);
+ }
+
+ public static Map toMap(Collection data, Function keyMapper, Function valueMapper) {
+ return toMap(data, keyMapper, valueMapper, false);
+ }
+
+ public static Map toMap(Collection data, Function keyMapper, Function valueMapper, boolean ordered) {
+ Supplier