alibaba.excel库使用
目录
依赖
实体类
Controller
Service
所用到的接口及工具类
ExcelUtil
ExcelListener
DefaultExcelListener
DefaultExcelResult
ExcelResult
JsonUtils
SpringUtils
StreamUtils
ValidatorUtils
SpringUtils
使用alibab中的excel库来实现excel的导入、导出
依赖
<dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>5.2.3</version></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>5.2.3</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.2.1</version><exclusions><exclusion><groupId>org.apache.poi</groupId><artifactId>poi-ooxml-schemas</artifactId></exclusion></exclusions></dependency>
实体类
@ExcelProperty、@ExcelIgnoreUnannotated注解
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import com.ict.lux.core.domain.BaseEntity;
import lombok.Data;
import lombok.NoArgsConstructor;import javax.validation.constraints.NotBlank;@Data
@NoArgsConstructor
@ExcelIgnoreUnannotated
public class BaseProductStackImportVo extends BaseEntity {private static final long serialVersionUID = 4732391370534949564L;/*** 编码*/@NotBlank(message = "编码不能为空")@ExcelProperty(value = "编码")private String stackNo;/*** 名称*/@NotBlank(message = "名称不能为空")@ExcelProperty(value = "名称")private String stackName;}===================================================================================import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;import java.time.LocalDateTime;@Data
@ExcelIgnoreUnannotated
public class BaseProductStackVo {/*** id*/private int id;/*** 编码*/@ExcelProperty(value = "编码")private String stackNo;/*** 名称*/@ExcelProperty(value = "名称")private String stackName;/*** 创建时间*/@ExcelProperty(value = "创建时间")private LocalDateTime createTime;/*** 创建人姓名*/@ExcelProperty(value = "创建人")private String createName;/*** 更新时间*/@ExcelProperty(value = "更新时间")private LocalDateTime updateTime;/*** 更新人姓名*/@ExcelProperty(value = "更新人")private String updateName;}
Controller
/*** 导入数据** @param file 导入文件*/@PostMapping(value = "/importData", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)public R<Void> importData(@RequestPart("file") MultipartFile file) throws Exception {ExcelResult<BaseProductStackImportVo> excelResult = ExcelUtil.importExcel(file.getInputStream(), BaseProductStackImportVo.class, true);List<BaseProductStackImportVo> volist = excelResult.getList();List<BaseProductStackEntity> list = BeanUtil.copyToList(volist, BaseProductStackEntity.class);baseProductStackService.importBatch(list);return R.ok(excelResult.getAnalysis());}/*** 导出*/@PostMapping("/export")public void export(@Validated(QueryGroup.class) BaseProductStackBo baseBo, HttpServletResponse response) {List<BaseProductStackVo> list = baseProductStackService.queryAll(baseBo);ExcelUtil.exportExcel(list, "123信息", BaseProductStackVo.class, response);}/*** 下载导入模版*/@PostMapping("/template")public void template(HttpServletResponse response) {List<BaseProductStackImportVo> list = new ArrayList<>();ExcelUtil.exportExcel(list, "123信息导入模板", BaseProductStackImportVo.class, response);}
Service
/*** 批量导入*/void importBatch(List<BaseProductStackEntity> importData);/*** 查询全部信息*/List<BaseProductStackVo> queryAll(BaseProductStackBo baseBo);/*** 批量导入*/@Override@Transactional(rollbackFor = Exception.class)public void importBatch(List<BaseProductStackEntity> importData) {List<BaseProductStackEntity> saveOrUpdateList = new ArrayList<>();//验证是否有重复List<String> duplicates = new ArrayList<>();importData.forEach(data -> {String duplicate = String.join(PlmConstants.Underline, data.getStackNo());if (duplicates.contains(duplicate)) {throw new QMSException("导入的123信息重复,请检查:" + data.getStackNo());}duplicates.add(duplicate);BaseProductStackEntity baseProductStackEntity = this.findOne(data.getStackNo());if (ObjectUtil.isNotNull(baseProductStackEntity)) {BeanUtil.copyProperties(data, baseProductStackEntity, CopyOptions.create().setIgnoreNullValue(true));saveOrUpdateList.add(baseProductStackEntity);} else {saveOrUpdateList.add(data);}});baseMapper.insertOrUpdateBatch(saveOrUpdateList);saveOrUpdateList.forEach(entity -> {RedisUtils.setCacheObject(buildRedisKey(entity.getStackNo()), entity);});}/*** 导出*/@Overridepublic List<BaseProductStackVo> queryAll(BaseProductStackBo baseBo) {//select * from xxxreturn baseMapper.customQueryList(baseBo);}
所用到的接口及工具类
ExcelUtil
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class ExcelUtil {/*** 同步导入(适用于小数据量)** @param is 输入流* @return 转换后集合*/public static <T> List<T> importExcel(InputStream is, Class<T> clazz) {return EasyExcel.read(is).head(clazz).autoCloseStream(false).sheet().doReadSync();}/*** 使用校验监听器 异步导入 同步返回** @param is 输入流* @param clazz 对象类型* @param isValidate 是否 Validator 检验 默认为是* @return 转换后集合*/public static <T> ExcelResult<T> importExcel(InputStream is, Class<T> clazz, boolean isValidate) {DefaultExcelListener<T> listener = new DefaultExcelListener<>(isValidate);EasyExcel.read(is, clazz, listener).sheet().doRead();return listener.getExcelResult();}/*** 使用自定义监听器 异步导入 自定义返回** @param is 输入流* @param clazz 对象类型* @param listener 自定义监听器* @return 转换后集合*/public static <T> ExcelResult<T> importExcel(InputStream is, Class<T> clazz, ExcelListener<T> listener) {EasyExcel.read(is, clazz, listener).sheet().doRead();return listener.getExcelResult();}/*** 导出excel** @param list 导出数据集合* @param sheetName 工作表的名称* @param clazz 实体类* @param response 响应体*/public static <T> void exportExcel(List<T> list, String sheetName, Class<T> clazz, HttpServletResponse response) {try {resetResponse(sheetName, response);ServletOutputStream os = response.getOutputStream();exportExcel(list, sheetName, clazz, false, os);} catch (IOException e) {throw new RuntimeException("导出Excel异常");}}/*** 导出excel** @param list 导出数据集合* @param sheetName 工作表的名称* @param clazz 实体类* @param merge 是否合并单元格* @param response 响应体*/public static <T> void exportExcel(List<T> list, String sheetName, Class<T> clazz, boolean merge, HttpServletResponse response) {try {resetResponse(sheetName, response);ServletOutputStream os = response.getOutputStream();exportExcel(list, sheetName, clazz, merge, os);} catch (IOException e) {throw new RuntimeException("导出Excel异常");}}/*** 导出excel** @param list 导出数据集合* @param sheetName 工作表的名称* @param clazz 实体类* @param os 输出流*/public static <T> void exportExcel(List<T> list, String sheetName, Class<T> clazz, OutputStream os) {exportExcel(list, sheetName, clazz, false, os);}/*** 导出excel** @param list 导出数据集合* @param sheetName 工作表的名称* @param clazz 实体类* @param merge 是否合并单元格* @param os 输出流*/public static <T> void exportExcel(List<T> list, String sheetName, Class<T> clazz, boolean merge, OutputStream os) {ExcelWriterSheetBuilder builder = EasyExcel.write(os, clazz).autoCloseStream(false)// 自动适配.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())// 大数值自动转换 防止失真.registerConverter(new ExcelBigNumberConvert()).sheet(sheetName);if (merge) {// 合并处理器builder.registerWriteHandler(new CellMergeStrategy(list, true));}builder.doWrite(list);}/*** 单表多数据模板导出 模板格式为 {.属性}** @param filename 文件名* @param templatePath 模板路径 resource 目录下的路径包括模板文件名* 例如: excel/temp.xlsx* 重点: 模板文件必须放置到启动类对应的 resource 目录下* @param data 模板需要的数据* @param response 响应体*/public static void exportTemplate(List<Object> data, String filename, String templatePath, HttpServletResponse response) {try {resetResponse(filename, response);ServletOutputStream os = response.getOutputStream();exportTemplate(data, templatePath, os);} catch (IOException e) {throw new RuntimeException("导出Excel异常");}}/*** 单表多数据模板导出 模板格式为 {.属性}** @param templatePath 模板路径 resource 目录下的路径包括模板文件名* 例如: excel/temp.xlsx* 重点: 模板文件必须放置到启动类对应的 resource 目录下* @param data 模板需要的数据* @param os 输出流*/public static void exportTemplate(List<Object> data, String templatePath, OutputStream os) {ClassPathResource templateResource = new ClassPathResource(templatePath);ExcelWriter excelWriter = EasyExcel.write(os).withTemplate(templateResource.getStream()).autoCloseStream(false)// 大数值自动转换 防止失真.registerConverter(new ExcelBigNumberConvert()).build();WriteSheet writeSheet = EasyExcel.writerSheet().build();if (CollUtil.isEmpty(data)) {throw new IllegalArgumentException("数据为空");}// 单表多数据导出 模板格式为 {.属性}for (Object d : data) {excelWriter.fill(d, writeSheet);}excelWriter.finish();}/*** 多表多数据模板导出 模板格式为 {key.属性}** @param filename 文件名* @param templatePath 模板路径 resource 目录下的路径包括模板文件名* 例如: excel/temp.xlsx* 重点: 模板文件必须放置到启动类对应的 resource 目录下* @param data 模板需要的数据* @param response 响应体*/public static void exportTemplateMultiList(Map<String, Object> data, String filename, String templatePath, HttpServletResponse response) {try {resetResponse(filename, response);ServletOutputStream os = response.getOutputStream();exportTemplateMultiList(data, templatePath, os);} catch (IOException e) {throw new RuntimeException("导出Excel异常");}}/*** 多表多数据模板导出 模板格式为 {key.属性}** @param templatePath 模板路径 resource 目录下的路径包括模板文件名* 例如: excel/temp.xlsx* 重点: 模板文件必须放置到启动类对应的 resource 目录下* @param data 模板需要的数据* @param os 输出流*/public static void exportTemplateMultiList(Map<String, Object> data, String templatePath, OutputStream os) {ClassPathResource templateResource = new ClassPathResource(templatePath);ExcelWriter excelWriter = EasyExcel.write(os).withTemplate(templateResource.getStream()).autoCloseStream(false)// 大数值自动转换 防止失真.registerConverter(new ExcelBigNumberConvert()).build();WriteSheet writeSheet = EasyExcel.writerSheet().build();if (CollUtil.isEmpty(data)) {throw new IllegalArgumentException("数据为空");}for (Map.Entry<String, Object> map : data.entrySet()) {// 设置列表后续还有数据FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();if (map.getValue() instanceof Collection) {// 多表导出必须使用 FillWrapperexcelWriter.fill(new FillWrapper(map.getKey(), (Collection<?>) map.getValue()), fillConfig, writeSheet);} else {excelWriter.fill(map.getValue(), writeSheet);}}excelWriter.finish();}/*** 重置响应体*/private static void resetResponse(String sheetName, HttpServletResponse response) throws UnsupportedEncodingException {String filename = encodingFilename(sheetName);FileUtils.setAttachmentResponseHeader(response, filename);response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8");}/*** 解析导出值 0=男,1=女,2=未知** @param propertyValue 参数值* @param converterExp 翻译注解* @param separator 分隔符* @return 解析后值*/public static String convertByExp(String propertyValue, String converterExp, String separator) {StringBuilder propertyString = new StringBuilder();String[] convertSource = converterExp.split(StringUtils.SEPARATOR);for (String item : convertSource) {String[] itemArray = item.split("=");if (StringUtils.containsAny(propertyValue, separator)) {for (String value : propertyValue.split(separator)) {if (itemArray[0].equals(value)) {propertyString.append(itemArray[1] + separator);break;}}} else {if (itemArray[0].equals(propertyValue)) {return itemArray[1];}}}return StringUtils.stripEnd(propertyString.toString(), separator);}/*** 反向解析值 男=0,女=1,未知=2** @param propertyValue 参数值* @param converterExp 翻译注解* @param separator 分隔符* @return 解析后值*/public static String reverseByExp(String propertyValue, String converterExp, String separator) {StringBuilder propertyString = new StringBuilder();String[] convertSource = converterExp.split(StringUtils.SEPARATOR);for (String item : convertSource) {String[] itemArray = item.split("=");if (StringUtils.containsAny(propertyValue, separator)) {for (String value : propertyValue.split(separator)) {if (itemArray[1].equals(value)) {propertyString.append(itemArray[0] + separator);break;}}} else {if (itemArray[1].equals(propertyValue)) {return itemArray[0];}}}return StringUtils.stripEnd(propertyString.toString(), separator);}/*** 编码文件名*/public static String encodingFilename(String filename) {return IdUtil.fastSimpleUUID() + "_" + filename + ".xlsx";}}
ExcelListener<T>
import com.alibaba.excel.read.listener.ReadListener;/*** Excel 导入监听** @author chensir*/
public interface ExcelListener<T> extends ReadListener<T> {ExcelResult<T> getExcelResult();}
DefaultExcelListener<T>
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.exception.ExcelAnalysisException;
import com.alibaba.excel.exception.ExcelDataConvertException;
import com.ict.lux.utils.JsonUtils;
import com.ict.lux.utils.StreamUtils;
import com.ict.lux.utils.ValidatorUtils;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.Map;
import java.util.Set;/*** Excel 导入监听** @author chensir*/
@Slf4j
@NoArgsConstructor
public class DefaultExcelListener<T> extends AnalysisEventListener<T> implements ExcelListener<T> {/*** 是否Validator检验,默认为是*/private Boolean isValidate = Boolean.TRUE;/*** excel 表头数据*/private Map<Integer, String> headMap;/*** 导入回执*/private ExcelResult<T> excelResult;public DefaultExcelListener(boolean isValidate) {this.excelResult = new DefaultExcelResult<>();this.isValidate = isValidate;}/*** 处理异常** @param exception ExcelDataConvertException* @param context Excel 上下文*/@Overridepublic void onException(Exception exception, AnalysisContext context) throws Exception {String errMsg = null;if (exception instanceof ExcelDataConvertException) {// 如果是某一个单元格的转换异常 能获取到具体行号ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException) exception;Integer rowIndex = excelDataConvertException.getRowIndex();Integer columnIndex = excelDataConvertException.getColumnIndex();errMsg = StrUtil.format("第{}行-第{}列-表头{}: 解析异常<br/>",rowIndex + 1, columnIndex + 1, headMap.get(columnIndex));if (log.isDebugEnabled()) {log.error(errMsg);}}if (exception instanceof ConstraintViolationException) {ConstraintViolationException constraintViolationException = (ConstraintViolationException) exception;Set<ConstraintViolation<?>> constraintViolations = constraintViolationException.getConstraintViolations();String constraintViolationsMsg = StreamUtils.join(constraintViolations, ConstraintViolation::getMessage, ", ");errMsg = StrUtil.format("第{}行数据校验异常: {}", context.readRowHolder().getRowIndex() + 1, constraintViolationsMsg);if (log.isDebugEnabled()) {log.error(errMsg);}}excelResult.getErrorList().add(errMsg);throw new ExcelAnalysisException(errMsg);}@Overridepublic void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {this.headMap = headMap;log.debug("解析到一条表头数据: {}", JsonUtils.toJsonString(headMap));}@Overridepublic void invoke(T data, AnalysisContext context) {if (isValidate) {ValidatorUtils.validate(data);}excelResult.getList().add(data);}@Overridepublic void doAfterAllAnalysed(AnalysisContext context) {log.debug("所有数据解析完成!");}@Overridepublic ExcelResult<T> getExcelResult() {return excelResult;}}
DefaultExcelResult<T>
import cn.hutool.core.util.StrUtil;
import lombok.Setter;import java.util.ArrayList;
import java.util.List;/*** 默认excel返回对象** @author chensir*/
public class DefaultExcelResult<T> implements ExcelResult<T> {/*** 数据对象list*/@Setterprivate List<T> list;/*** 错误信息列表*/@Setterprivate List<String> errorList;public DefaultExcelResult() {this.list = new ArrayList<>();this.errorList = new ArrayList<>();}public DefaultExcelResult(List<T> list, List<String> errorList) {this.list = list;this.errorList = errorList;}public DefaultExcelResult(ExcelResult<T> excelResult) {this.list = excelResult.getList();this.errorList = excelResult.getErrorList();}@Overridepublic List<T> getList() {return list;}@Overridepublic List<String> getErrorList() {return errorList;}/*** 获取导入回执** @return 导入回执*/@Overridepublic String getAnalysis() {int successCount = list.size();int errorCount = errorList.size();if (successCount == 0) {return "读取失败,未解析到数据";} else {if (errorCount == 0) {return StrUtil.format("恭喜您,全部读取成功!共{}条", successCount);} else {return "";}}}
}
ExcelResult<T>
/*** excel返回对象** @author chensir*/
public interface ExcelResult<T> {/*** 对象列表*/List<T> getList();/*** 错误列表*/List<String> getErrorList();/*** 导入回执*/String getAnalysis();
}
JsonUtils
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.exc.MismatchedInputException;
import com.ict.lux.utils.spring.SpringUtils;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;import java.io.IOException;
import java.util.ArrayList;
import java.util.List;/*** JSON 工具类** @author chensir*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class JsonUtils {private static final ObjectMapper OBJECT_MAPPER = SpringUtils.getBean(ObjectMapper.class);public static ObjectMapper getObjectMapper() {return OBJECT_MAPPER;}public static String toJsonString(Object object) {if (ObjectUtil.isNull(object)) {return null;}try {return OBJECT_MAPPER.writeValueAsString(object);} catch (JsonProcessingException e) {throw new RuntimeException(e);}}public static <T> T parseObject(String text, Class<T> clazz) {if (StringUtils.isEmpty(text)) {return null;}try {return OBJECT_MAPPER.readValue(text, clazz);} catch (IOException e) {throw new RuntimeException(e);}}public static <T> T parseObject(byte[] bytes, Class<T> clazz) {if (ArrayUtil.isEmpty(bytes)) {return null;}try {return OBJECT_MAPPER.readValue(bytes, clazz);} catch (IOException e) {throw new RuntimeException(e);}}public static <T> T parseObject(String text, TypeReference<T> typeReference) {if (StringUtils.isBlank(text)) {return null;}try {return OBJECT_MAPPER.readValue(text, typeReference);} catch (IOException e) {throw new RuntimeException(e);}}public static Dict parseMap(String text) {if (StringUtils.isBlank(text)) {return null;}try {return OBJECT_MAPPER.readValue(text, OBJECT_MAPPER.getTypeFactory().constructType(Dict.class));} catch (MismatchedInputException e) {// 类型不匹配说明不是jsonreturn null;} catch (IOException e) {throw new RuntimeException(e);}}public static List<Dict> parseArrayMap(String text) {if (StringUtils.isBlank(text)) {return null;}try {return OBJECT_MAPPER.readValue(text, OBJECT_MAPPER.getTypeFactory().constructCollectionType(List.class, Dict.class));} catch (IOException e) {throw new RuntimeException(e);}}public static <T> List<T> parseArray(String text, Class<T> clazz) {if (StringUtils.isEmpty(text)) {return new ArrayList<>();}try {return OBJECT_MAPPER.readValue(text, OBJECT_MAPPER.getTypeFactory().constructCollectionType(List.class, clazz));} catch (IOException e) {throw new RuntimeException(e);}}}
SpringUtils
package com.ict.lux.utils.spring;import cn.hutool.extra.spring.SpringUtil;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;/*** spring工具类** @author chensir*/
@Component
public final class SpringUtils extends SpringUtil {/*** 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true** @param name* @return boolean*/public static boolean containsBean(String name) {return getBeanFactory().containsBean(name);}/*** 判断以给定名字注册的bean定义是一个singleton还是一个prototype。* 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException)** @param name* @return boolean*/public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException {return getBeanFactory().isSingleton(name);}/*** @param name* @return Class 注册对象的类型*/public static Class<?> getType(String name) throws NoSuchBeanDefinitionException {return getBeanFactory().getType(name);}/*** 如果给定的bean名字在bean定义中有别名,则返回这些别名** @param name*/public static String[] getAliases(String name) throws NoSuchBeanDefinitionException {return getBeanFactory().getAliases(name);}/*** 获取aop代理对象** @param invoker* @return*/@SuppressWarnings("unchecked")public static <T> T getAopProxy(T invoker) {return (T) AopContext.currentProxy();}/*** 获取spring上下文*/public static ApplicationContext context() {return getApplicationContext();}}
StreamUtils
package com.ict.lux.utils;import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;/*** stream 流工具类** @author chensir*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class StreamUtils {/*** 将collection过滤** @param collection 需要转化的集合* @param function 过滤方法* @return 过滤后的list*/public static <E> List<E> filter(Collection<E> collection, Predicate<E> function) {if (CollUtil.isEmpty(collection)) {return CollUtil.newArrayList();}return collection.stream().filter(function).collect(Collectors.toList());}/*** 将collection拼接** @param collection 需要转化的集合* @param function 拼接方法* @return 拼接后的list*/public static <E> String join(Collection<E> collection, Function<E, String> function) {return join(collection, function, StringUtils.SEPARATOR);}/*** 将collection拼接** @param collection 需要转化的集合* @param function 拼接方法* @param delimiter 拼接符* @return 拼接后的list*/public static <E> String join(Collection<E> collection, Function<E, String> function, CharSequence delimiter) {if (CollUtil.isEmpty(collection)) {return StringUtils.EMPTY;}return collection.stream().map(function).filter(Objects::nonNull).collect(Collectors.joining(delimiter));}/*** 将collection排序** @param collection 需要转化的集合* @param comparing 排序方法* @return 排序后的list*/public static <E> List<E> sorted(Collection<E> collection, Comparator<E> comparing) {if (CollUtil.isEmpty(collection)) {return CollUtil.newArrayList();}return collection.stream().sorted(comparing).collect(Collectors.toList());}/*** 将collection转化为类型不变的map<br>* <B>{@code Collection<V> ----> Map<K,V>}</B>** @param collection 需要转化的集合* @param key V类型转化为K类型的lambda方法* @param <V> collection中的泛型* @param <K> map中的key类型* @return 转化后的map*/public static <V, K> Map<K, V> toIdentityMap(Collection<V> collection, Function<V, K> key) {if (CollUtil.isEmpty(collection)) {return MapUtil.newHashMap();}return collection.stream().collect(Collectors.toMap(key, Function.identity(), (l, r) -> l));}/*** 将Collection转化为map(value类型与collection的泛型不同)<br>* <B>{@code Collection<E> -----> Map<K,V> }</B>** @param collection 需要转化的集合* @param key E类型转化为K类型的lambda方法* @param value E类型转化为V类型的lambda方法* @param <E> collection中的泛型* @param <K> map中的key类型* @param <V> map中的value类型* @return 转化后的map*/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 collection.stream().collect(Collectors.toMap(key, value, (l, r) -> l));}/*** 将collection按照规则(比如有相同的班级id)分类成map<br>* <B>{@code Collection<E> -------> Map<K,List<E>> } </B>** @param collection 需要分类的集合* @param key 分类的规则* @param <E> collection中的泛型* @param <K> map中的key类型* @return 分类后的map*/public static <E, K> Map<K, List<E>> groupByKey(Collection<E> collection, Function<E, K> key) {if (CollUtil.isEmpty(collection)) {return MapUtil.newHashMap();}return collection.stream().collect(Collectors.groupingBy(key, LinkedHashMap::new, Collectors.toList()));}/*** 将collection按照两个规则(比如有相同的年级id,班级id)分类成双层map<br>* <B>{@code Collection<E> ---> Map<T,Map<U,List<E>>> } </B>** @param collection 需要分类的集合* @param key1 第一个分类的规则* @param key2 第二个分类的规则* @param <E> 集合元素类型* @param <K> 第一个map中的key类型* @param <U> 第二个map中的key类型* @return 分类后的map*/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 collection.stream().collect(Collectors.groupingBy(key1, LinkedHashMap::new, Collectors.groupingBy(key2, LinkedHashMap::new, Collectors.toList())));}/*** 将collection按照两个规则(比如有相同的年级id,班级id)分类成双层map<br>* <B>{@code Collection<E> ---> Map<T,Map<U,E>> } </B>** @param collection 需要分类的集合* @param key1 第一个分类的规则* @param key2 第二个分类的规则* @param <T> 第一个map中的key类型* @param <U> 第二个map中的key类型* @param <E> collection中的泛型* @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();}return collection.stream().collect(Collectors.groupingBy(key1, LinkedHashMap::new, Collectors.toMap(key2, Function.identity(), (l, r) -> l)));}/*** 将collection转化为List集合,但是两者的泛型不同<br>* <B>{@code Collection<E> ------> List<T> } </B>** @param collection 需要转化的集合* @param function collection中的泛型转化为list泛型的lambda表达式* @param <E> collection中的泛型* @param <T> List中的泛型* @return 转化后的list*/public static <E, T> List<T> toList(Collection<E> collection, Function<E, T> function) {if (CollUtil.isEmpty(collection)) {return CollUtil.newArrayList();}return collection.stream().map(function).filter(Objects::nonNull).collect(Collectors.toList());}/*** 将collection转化为Set集合,但是两者的泛型不同<br>* <B>{@code Collection<E> ------> Set<T> } </B>** @param collection 需要转化的集合* @param function collection中的泛型转化为set泛型的lambda表达式* @param <E> collection中的泛型* @param <T> Set中的泛型* @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();}return collection.stream().map(function).filter(Objects::nonNull).collect(Collectors.toSet());}/*** 合并两个相同key类型的map** @param map1 第一个需要合并的 map* @param map2 第二个需要合并的 map* @param merge 合并的lambda,将key value1 value2合并成最终的类型,注意value可能为空的情况* @param <K> map中的key类型* @param <X> 第一个 map的value类型* @param <Y> 第二个 map的value类型* @param <V> 最终map的value类型* @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();}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;}}
ValidatorUtils
package com.ict.lux.utils;import com.ict.lux.utils.spring.SpringUtils;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Validator;
import java.util.Set;/*** Validator 校验框架工具** @author chensir*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class ValidatorUtils {private static final Validator VALID = SpringUtils.getBean(Validator.class);public static <T> void validate(T object, Class<?>... groups) {Set<ConstraintViolation<T>> validate = VALID.validate(object, groups);if (!validate.isEmpty()) {throw new ConstraintViolationException("参数校验异常", validate);}}}
SpringUtils
package com.ict.lux.utils.spring;import cn.hutool.extra.spring.SpringUtil;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;/*** spring工具类** @author chensir*/
@Component
public final class SpringUtils extends SpringUtil {/*** 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true** @param name* @return boolean*/public static boolean containsBean(String name) {return getBeanFactory().containsBean(name);}/*** 判断以给定名字注册的bean定义是一个singleton还是一个prototype。* 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException)** @param name* @return boolean*/public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException {return getBeanFactory().isSingleton(name);}/*** @param name* @return Class 注册对象的类型*/public static Class<?> getType(String name) throws NoSuchBeanDefinitionException {return getBeanFactory().getType(name);}/*** 如果给定的bean名字在bean定义中有别名,则返回这些别名** @param name*/public static String[] getAliases(String name) throws NoSuchBeanDefinitionException {return getBeanFactory().getAliases(name);}/*** 获取aop代理对象** @param invoker* @return*/@SuppressWarnings("unchecked")public static <T> T getAopProxy(T invoker) {return (T) AopContext.currentProxy();}/*** 获取spring上下文*/public static ApplicationContext context() {return getApplicationContext();}}
。。。。