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();}}
。。。。
相关文章:
alibaba.excel库使用
目录 依赖 实体类 Controller Service 所用到的接口及工具类 ExcelUtil ExcelListener DefaultExcelListener DefaultExcelResult ExcelResult JsonUtils SpringUtils StreamUtils ValidatorUtils SpringUtils 使用alibab中的excel库来实现excel的导入、导出 依赖 <de…...
机器学习模型选择评估和超参数调优
如何选择模型?如何评估模型?如何调整模型的超参数?模型评估要在测试集上进行,不能在训练集上进行,否则评估的准确率总是100%。所以,一般我们准备好数据集后,要将其分为训练集和测试集࿰…...

深入浅出 Typescript
TypeScript 是 JavaScript 的一个超集,支持 ECMAScript 6 标准(ES6 教程)。 TypeScript 由微软开发的自由和开源的编程语言。 TypeScript 设计目标是开发大型应用,它可以编译成纯 JavaScript,编译出来的 JavaScript …...

Vue3和TypeScript项目-移动端兼容
1 全局安装typescript 2 检测安装成功 3 写的是ts代码,但是最后一定要变成js代码,才能在浏览器使用 这样就会多一个js文件 3 ts语法 数组语法 对象语法 安装vue3项目 成功后进入app。安装依赖。因为我们用的是脚手架,要引入东西的时候不需要…...

基于STM32CubeMX和keil采用通用定时器中断实现固定PWM可调PWM波输出分别实现LED闪烁与呼吸灯
文章目录 前言1. PWM波阐述2. 通用定时器2.1 为什么用TIM142.2 TIM14功能介绍2.3 一些配置参数解释2.4 PWM实现流程&中断2.4.1 非中断PWM输出(LED闪烁)2.4.2 中断PWM输出(LED呼吸灯) 3. STM32CubeMX配置3.1 GPIO配置3.2 时钟配置3.3 定时器相关参数配置3.4 Debug配置3.5 中…...

mysql大表的深度分页慢sql案例(跳页分页)
1 背景 有一张表,内容是 redis缓存中的key信息,数据量约1000万级, expiry列上有一个普通B树索引。 -- test.top definitionCREATE TABLE top (database int(11) DEFAULT NULL,type varchar(50) DEFAULT NULL,key varchar(500) DEFAULT NUL…...

集中/本地转发、AC、AP
1.ADSL ADSL MODEM(ADSL 强制解调器)俗称ADSL猫 ADSL是一种异步传输模式(ATM)。ADSL是指使用电话线上网,需要专用的猫(Modem),在上网的时候高频和低频分离,所以上网电话两不耽误,速…...

Spring集成Seata
Seata的集成方式有: 1. Seata-All 2. Seata-Spring-Boot-Starter 3. Spring-Cloud-Starter-Seata 本案例使用Seata-All演示: 第一步:下载Seata 第二步:为了更好看到效果,我们将Seata的数据存储改为db 将seata\sc…...

三种方式创建对象的几种方式及new实例化时做了什么?
创建对象的几种方式 利用对象字面量创建对象 const obj {}2.利用 new Object创建对象 const obj new Object()3.使用 构造函数实例化对象 function Fn(name) {this.name name} const obj new Fn(张三) console.log(obj.name); //张三为什么要用构造函数的形式࿱…...

vue2-vue实例挂载的过程
1、思考 new Vue()这个过程中究竟做了什么?过程中是如何完成数据的绑定,又是如何将数据渲染到视图的等等。 2、分析 首先找到vue的构造函数。 源码位置:/src/core/instance/index.js options是用户传递过来的配置项,如data、meth…...
C++ 右值引用案例
C 右值引用案例 右值引用(Rvalue reference)是 C11 引入的新特性,它的主要意义是实现移动语义(Move semantics)和完美转发(Perfect forwarding)。这两者都可以提高代码的性能和灵活性。 一、移…...

2.文件的逻辑结构
第四章 文件管理 2.文件的逻辑结构 顺序文件采用顺序存储则意味着各个逻辑上相邻的记录在物理上也是相邻的存储的。所以如果第0号记录的逻辑地址为0的话,则i号记录的逻辑为i *L。 特别的如果这个定长记录的顺序文件采用串结构,也就是这些记录的顺序和他…...

20天学rust(一)和rust say hi
关注我,学习Rust不迷路 工欲善其事,必先利其器。第一节我们先来配置rust需要的环境和安装趁手的工具,然后写一个简单的小程序。 安装 Rust环境 Rust 官方有提供一个叫做 rustup 的工具,专门用于 rust 版本的管理,网…...

牢记这16个SpringBoot 扩展接口,写出更加漂亮的代码
1、背景 Spring的核心思想就是容器,当容器refresh的时候,外部看上去风平浪静,其实内部则是一片惊涛骇浪,汪洋一片。Springboot更是封装了Spring,遵循约定大于配置,加上自动装配的机制。很多时候我们只要引…...
c++两种设计模式 单例和工厂模式
c两种设计模式 单例和工厂模式 一.单例 1.单例的概念 1.当前的类最多只能创建一个实例 2.当前这个唯一的实例,必须由当前类创建(自主创建),而不是调用者创建 3.必须向整个系统提供全局的访问点,来获取唯一的实例 …...

2023-08-05——JVM 栈
栈 stack 栈:数据结构 程序数据结构算法 栈:先进后出,后进先出 好比一个:桶 队列:先进先出(FIFO :First Input First Out) 好比一个:管道 栈:喝多了吐。队列…...

Camera之PhysicalCameraSettingsList/SurfaceMap/CameraMetadata/RequestList的关系(三十二)
简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药. 更多原创,欢迎关注:Android…...

【ONE·Linux || 基础IO(二)】
总言 文件系统与动静态库相关介绍。 文章目录 总言2、文件系统2.1、背景知识2.2、磁盘管理2.2.1、磁盘文件系统图2.2.2、inode与文件名 2.3、软硬链接 3、动静态库3.1、站在编写库的人的角度:如何写一个库?3.1.1、静态库制作3.1.3、动态库制作 3.2、站在…...
【LeetCode 算法】Power of Heroes 英雄的力量
文章目录 Power of Heroes 英雄的力量问题描述:分析代码Math Tag Power of Heroes 英雄的力量 问题描述: 给你一个下标从 0 开始的整数数组 nums ,它表示英雄的能力值。如果我们选出一部分英雄,这组英雄的 力量 定义为ÿ…...
合宙Air724UG LuatOS-Air script lib API--ntp
ntp Table of Contents ntp ntp.timeSync(period, fnc, fun) ntp 模块功能:网络授时. 重要提醒!!!!!! 本功能模块采用多个免费公共的NTP服务器来同步时间 并不能保证任何时间任何地点都能百分…...
Java 语言特性(面试系列2)
一、SQL 基础 1. 复杂查询 (1)连接查询(JOIN) 内连接(INNER JOIN):返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...

【项目实战】通过多模态+LangGraph实现PPT生成助手
PPT自动生成系统 基于LangGraph的PPT自动生成系统,可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析:自动解析Markdown文档结构PPT模板分析:分析PPT模板的布局和风格智能布局决策:匹配内容与合适的PPT布局自动…...
[Java恶补day16] 238.除自身以外数组的乘积
给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O(n) 时间复杂度…...
使用Matplotlib创建炫酷的3D散点图:数据可视化的新维度
文章目录 基础实现代码代码解析进阶技巧1. 自定义点的大小和颜色2. 添加图例和样式美化3. 真实数据应用示例实用技巧与注意事项完整示例(带样式)应用场景在数据科学和可视化领域,三维图形能为我们提供更丰富的数据洞察。本文将手把手教你如何使用Python的Matplotlib库创建引…...
React---day11
14.4 react-redux第三方库 提供connect、thunk之类的函数 以获取一个banner数据为例子 store: 我们在使用异步的时候理应是要使用中间件的,但是configureStore 已经自动集成了 redux-thunk,注意action里面要返回函数 import { configureS…...

深入浅出深度学习基础:从感知机到全连接神经网络的核心原理与应用
文章目录 前言一、感知机 (Perceptron)1.1 基础介绍1.1.1 感知机是什么?1.1.2 感知机的工作原理 1.2 感知机的简单应用:基本逻辑门1.2.1 逻辑与 (Logic AND)1.2.2 逻辑或 (Logic OR)1.2.3 逻辑与非 (Logic NAND) 1.3 感知机的实现1.3.1 简单实现 (基于阈…...

Kafka入门-生产者
生产者 生产者发送流程: 延迟时间为0ms时,也就意味着每当有数据就会直接发送 异步发送API 异步发送和同步发送的不同在于:异步发送不需要等待结果,同步发送必须等待结果才能进行下一步发送。 普通异步发送 首先导入所需的k…...

免费数学几何作图web平台
光锐软件免费数学工具,maths,数学制图,数学作图,几何作图,几何,AR开发,AR教育,增强现实,软件公司,XR,MR,VR,虚拟仿真,虚拟现实,混合现实,教育科技产品,职业模拟培训,高保真VR场景,结构互动课件,元宇宙http://xaglare.c…...

yaml读取写入常见错误 (‘cannot represent an object‘, 117)
错误一:yaml.representer.RepresenterError: (‘cannot represent an object’, 117) 出现这个问题一直没找到原因,后面把yaml.safe_dump直接替换成yaml.dump,确实能保存,但出现乱码: 放弃yaml.dump,又切…...
GB/T 43887-2024 核级柔性石墨板材检测
核级柔性石墨板材是指以可膨胀石墨为原料、未经改性和增强、用于核工业的核级柔性石墨板材。 GB/T 43887-2024核级柔性石墨板材检测检测指标: 测试项目 测试标准 外观 GB/T 43887 尺寸偏差 GB/T 43887 化学成分 GB/T 43887 密度偏差 GB/T 43887 拉伸强度…...