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服务器来同步时间 并不能保证任何时间任何地点都能百分…...
为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?
在建筑行业,项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升,传统的管理模式已经难以满足现代工程的需求。过去,许多企业依赖手工记录、口头沟通和分散的信息管理,导致效率低下、成本失控、风险频发。例如&#…...
现代密码学 | 椭圆曲线密码学—附py代码
Elliptic Curve Cryptography 椭圆曲线密码学(ECC)是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础,例如椭圆曲线数字签…...
Java + Spring Boot + Mybatis 实现批量插入
在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法:使用 MyBatis 的 <foreach> 标签和批处理模式(ExecutorType.BATCH)。 方法一:使用 XML 的 <foreach> 标签ÿ…...
视觉slam十四讲实践部分记录——ch2、ch3
ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...
使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...
智能职业发展系统:AI驱动的职业规划平台技术解析
智能职业发展系统:AI驱动的职业规划平台技术解析 引言:数字时代的职业革命 在当今瞬息万变的就业市场中,传统的职业规划方法已无法满足个人和企业的需求。据统计,全球每年有超过2亿人面临职业转型困境,而企业也因此遭…...
[特殊字符] 手撸 Redis 互斥锁那些坑
📖 手撸 Redis 互斥锁那些坑 最近搞业务遇到高并发下同一个 key 的互斥操作,想实现分布式环境下的互斥锁。于是私下顺手手撸了个基于 Redis 的简单互斥锁,也顺便跟 Redisson 的 RLock 机制对比了下,记录一波,别踩我踩过…...
用递归算法解锁「子集」问题 —— LeetCode 78题解析
文章目录 一、题目介绍二、递归思路详解:从决策树开始理解三、解法一:二叉决策树 DFS四、解法二:组合式回溯写法(推荐)五、解法对比 递归算法是编程中一种非常强大且常见的思想,它能够优雅地解决很多复杂的…...
【若依】框架项目部署笔记
参考【SpringBoot】【Vue】项目部署_no main manifest attribute, in springboot-0.0.1-sn-CSDN博客 多一个redis安装 准备工作: 压缩包下载:http://download.redis.io/releases 1. 上传压缩包,并进入压缩包所在目录,解压到目标…...
Python第七周作业
Python第七周作业 文章目录 Python第七周作业 1.使用open以只读模式打开文件data.txt,并逐行打印内容 2.使用pathlib模块获取当前脚本的绝对路径,并创建logs目录(若不存在) 3.递归遍历目录data,输出所有.csv文件的路径…...
