From 259fc4af0a91f3aeb7bf0563f53ade765cc8871b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=86=B7=E5=86=B7?= <2270033969@qq.com> Date: Fri, 30 Aug 2024 16:04:32 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E5=AD=97=E5=85=B8):=20=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E5=AD=97=E5=85=B8=E8=BD=AC=E6=8D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes 41 --- README.md | 43 ++++++ pom.xml | 2 +- .../excel/ResponseExcelAutoConfiguration.java | 102 +++++++------- .../excel/annotation/DictTypeProperty.java | 30 +++++ .../aop/RequestExcelArgumentResolver.java | 1 + .../excel/converters/DictTypeConvert.java | 125 ++++++++++++++++++ .../handler/AbstractSheetWriteHandler.java | 1 + .../handler/DefaultDictDataProvider.java | 9 ++ .../excel/handler/DictDataProvider.java | 86 ++++++++++++ .../plugin/excel/kit/SpringContextKit.java | 125 ++++++++++++++++++ .../pig4cloud/plugin/excel/vo/DictEnum.java | 62 +++++++++ .../plugin/excel/enums/DemoController.java | 56 ++++++++ .../excel/enums/DemoControllerTest.java | 125 ++++++++++++++++++ .../plugin/excel/enums/IndexOrNameData2.java | 24 ++++ .../plugin/excel/enums/IndexOrNameData3.java | 23 ++++ .../pig4cloud/plugin/excel/enums/SexEnum.java | 23 ++++ src/test/resources/tmp/enums.xlsx | Bin 0 -> 3619 bytes 17 files changed, 790 insertions(+), 47 deletions(-) create mode 100644 src/main/java/com/pig4cloud/plugin/excel/annotation/DictTypeProperty.java create mode 100644 src/main/java/com/pig4cloud/plugin/excel/converters/DictTypeConvert.java create mode 100644 src/main/java/com/pig4cloud/plugin/excel/handler/DefaultDictDataProvider.java create mode 100644 src/main/java/com/pig4cloud/plugin/excel/handler/DictDataProvider.java create mode 100644 src/main/java/com/pig4cloud/plugin/excel/kit/SpringContextKit.java create mode 100644 src/main/java/com/pig4cloud/plugin/excel/vo/DictEnum.java create mode 100644 src/test/java/com/pig4cloud/plugin/excel/enums/DemoController.java create mode 100644 src/test/java/com/pig4cloud/plugin/excel/enums/DemoControllerTest.java create mode 100644 src/test/java/com/pig4cloud/plugin/excel/enums/IndexOrNameData2.java create mode 100644 src/test/java/com/pig4cloud/plugin/excel/enums/IndexOrNameData3.java create mode 100644 src/test/java/com/pig4cloud/plugin/excel/enums/SexEnum.java create mode 100644 src/test/resources/tmp/enums.xlsx diff --git a/README.md b/README.md index 723772b..059b740 100644 --- a/README.md +++ b/README.md @@ -149,6 +149,49 @@ public List export(String param) { return list; } ``` +### 字典转换 + +- 方式一: 固定枚举 + +```java + @ExcelProperty(value = "列1") + // 指定对应的枚举类 (字符串) + @DictTypeProperty(enums = SexEnum.class) + private String sex; +``` + +```java +@Getter +@RequiredArgsConstructor +// 必须继承 DictEnum +public enum SexEnum implements DictEnum { + MALE("0", "男"), + FEMALE("1", "女"); + // 必须有的字段 + private final String value; + // 必须有的字段 + private final String label; +} +``` + +- 方式二: 读取系统字典 + +```java +@Autowired +private DictDataProvider dictDataProvider; + +// 在系统启动完毕后,添加字典数据 +dictDataProvider.addDict("sex_type", "0", "男"); +dictDataProvider.addDict("sex_type", "1", "女"); +``` + +```java +@ExcelProperty(value = "列1") +// 指定对应的字典类型 +@DictTypeProperty("sex_type") +private String sex; +``` + ### 导出并加密 diff --git a/pom.xml b/pom.xml index 4879619..c4e491d 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.pig4cloud.excel excel-spring-boot-starter - 3.3.0 + 3.3.1-SNAPSHOT excel-spring-boot-starter easy and high performance excel https://pig4cloud.com diff --git a/src/main/java/com/pig4cloud/plugin/excel/ResponseExcelAutoConfiguration.java b/src/main/java/com/pig4cloud/plugin/excel/ResponseExcelAutoConfiguration.java index d3a977b..1295d50 100644 --- a/src/main/java/com/pig4cloud/plugin/excel/ResponseExcelAutoConfiguration.java +++ b/src/main/java/com/pig4cloud/plugin/excel/ResponseExcelAutoConfiguration.java @@ -4,6 +4,9 @@ import com.pig4cloud.plugin.excel.aop.RequestExcelArgumentResolver; import com.pig4cloud.plugin.excel.aop.ResponseExcelReturnValueHandler; import com.pig4cloud.plugin.excel.config.ExcelConfigProperties; +import com.pig4cloud.plugin.excel.handler.DefaultDictDataProvider; +import com.pig4cloud.plugin.excel.handler.DictDataProvider; +import com.pig4cloud.plugin.excel.kit.SpringContextKit; import com.pig4cloud.plugin.excel.processor.NameProcessor; import com.pig4cloud.plugin.excel.processor.NameSpelExpressionProcessor; import jakarta.annotation.PostConstruct; @@ -28,60 +31,67 @@ */ @AutoConfiguration @RequiredArgsConstructor -@Import(ExcelHandlerConfiguration.class) +@Import({ExcelHandlerConfiguration.class, SpringContextKit.class}) @EnableConfigurationProperties(ExcelConfigProperties.class) public class ResponseExcelAutoConfiguration { - private final RequestMappingHandlerAdapter requestMappingHandlerAdapter; + private final RequestMappingHandlerAdapter requestMappingHandlerAdapter; - private final ResponseExcelReturnValueHandler responseExcelReturnValueHandler; + private final ResponseExcelReturnValueHandler responseExcelReturnValueHandler; - /** - * SPEL 解析处理器 - * @return NameProcessor excel名称解析器 - */ - @Bean - @ConditionalOnMissingBean - public NameProcessor nameProcessor() { - return new NameSpelExpressionProcessor(); - } + /** + * SPEL 解析处理器 + * + * @return NameProcessor excel名称解析器 + */ + @Bean + @ConditionalOnMissingBean + public NameProcessor nameProcessor() { + return new NameSpelExpressionProcessor(); + } - /** - * Excel名称解析处理切面 - * @param nameProcessor SPEL 解析处理器 - * @return DynamicNameAspect - */ - @Bean - @ConditionalOnMissingBean - public DynamicNameAspect dynamicNameAspect(NameProcessor nameProcessor) { - return new DynamicNameAspect(nameProcessor); - } + /** + * Excel名称解析处理切面 + * + * @param nameProcessor SPEL 解析处理器 + * @return DynamicNameAspect + */ + @Bean + @ConditionalOnMissingBean + public DynamicNameAspect dynamicNameAspect(NameProcessor nameProcessor) { + return new DynamicNameAspect(nameProcessor); + } - /** - * 追加 Excel返回值处理器 到 springmvc 中 - */ - @PostConstruct - public void setReturnValueHandlers() { - List returnValueHandlers = requestMappingHandlerAdapter - .getReturnValueHandlers(); + /** + * 追加 Excel返回值处理器 到 springmvc 中 + */ + @PostConstruct + public void setReturnValueHandlers() { + List returnValueHandlers = requestMappingHandlerAdapter + .getReturnValueHandlers(); - List newHandlers = new ArrayList<>(); - newHandlers.add(responseExcelReturnValueHandler); - assert returnValueHandlers != null; - newHandlers.addAll(returnValueHandlers); - requestMappingHandlerAdapter.setReturnValueHandlers(newHandlers); - } + List newHandlers = new ArrayList<>(); + newHandlers.add(responseExcelReturnValueHandler); + assert returnValueHandlers != null; + newHandlers.addAll(returnValueHandlers); + requestMappingHandlerAdapter.setReturnValueHandlers(newHandlers); + } - /** - * 追加 Excel 请求处理器 到 springmvc 中 - */ - @PostConstruct - public void setRequestExcelArgumentResolver() { - List argumentResolvers = requestMappingHandlerAdapter.getArgumentResolvers(); - List resolverList = new ArrayList<>(); - resolverList.add(new RequestExcelArgumentResolver()); - resolverList.addAll(argumentResolvers); - requestMappingHandlerAdapter.setArgumentResolvers(resolverList); - } + /** + * 追加 Excel 请求处理器 到 springmvc 中 + */ + @PostConstruct + public void setRequestExcelArgumentResolver() { + List argumentResolvers = requestMappingHandlerAdapter.getArgumentResolvers(); + List resolverList = new ArrayList<>(); + resolverList.add(new RequestExcelArgumentResolver()); + resolverList.addAll(argumentResolvers); + requestMappingHandlerAdapter.setArgumentResolvers(resolverList); + } + @Bean + @ConditionalOnMissingBean + public DictDataProvider dictDataProvider() { + return new DefaultDictDataProvider(); + } } diff --git a/src/main/java/com/pig4cloud/plugin/excel/annotation/DictTypeProperty.java b/src/main/java/com/pig4cloud/plugin/excel/annotation/DictTypeProperty.java new file mode 100644 index 0000000..ce2df1a --- /dev/null +++ b/src/main/java/com/pig4cloud/plugin/excel/annotation/DictTypeProperty.java @@ -0,0 +1,30 @@ +package com.pig4cloud.plugin.excel.annotation; + +import com.pig4cloud.plugin.excel.vo.DictEnum; + +import java.lang.annotation.*; + +/** + * Excel dict type 属性 + * + * @author lengleng + * @date 2024/08/30 + */ +@Documented +@Target({ ElementType.FIELD }) +@Retention(RetentionPolicy.RUNTIME) +public @interface DictTypeProperty { + + /** + * 字典类型字段 + * @return {@link String } + */ + String value() default ""; + + /** + * [有限]直接从系统字典枚举解析,不走缓存 + * @return 与当前字典有关的系统字典枚举列表 + */ + Class[] enums() default {}; + +} diff --git a/src/main/java/com/pig4cloud/plugin/excel/aop/RequestExcelArgumentResolver.java b/src/main/java/com/pig4cloud/plugin/excel/aop/RequestExcelArgumentResolver.java index 7b799ff..2dcd752 100644 --- a/src/main/java/com/pig4cloud/plugin/excel/aop/RequestExcelArgumentResolver.java +++ b/src/main/java/com/pig4cloud/plugin/excel/aop/RequestExcelArgumentResolver.java @@ -76,6 +76,7 @@ public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer m .registerConverter(LocalTimeStringConverter.INSTANCE) .registerConverter(LongStringConverter.INSTANCE) .registerConverter(StringArrayConverter.INSTANCE) + .registerConverter(DictTypeConvert.INSTANCE) .ignoreEmptyRow(requestExcel.ignoreEmptyRow()) .sheet() .headRowNumber(requestExcel.headRowNumber()) diff --git a/src/main/java/com/pig4cloud/plugin/excel/converters/DictTypeConvert.java b/src/main/java/com/pig4cloud/plugin/excel/converters/DictTypeConvert.java new file mode 100644 index 0000000..e6e8021 --- /dev/null +++ b/src/main/java/com/pig4cloud/plugin/excel/converters/DictTypeConvert.java @@ -0,0 +1,125 @@ +package com.pig4cloud.plugin.excel.converters; + +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.data.ReadCellData; +import com.alibaba.excel.metadata.data.WriteCellData; +import com.alibaba.excel.metadata.property.ExcelContentProperty; +import com.pig4cloud.plugin.excel.annotation.DictTypeProperty; +import com.pig4cloud.plugin.excel.handler.DictDataProvider; +import com.pig4cloud.plugin.excel.kit.SpringContextKit; +import com.pig4cloud.plugin.excel.vo.DictEnum; +import lombok.extern.slf4j.Slf4j; + +import java.lang.reflect.Field; +import java.util.Objects; + +/** + * dict 转换器 + * + * @author lengleng + * @date 2024/08/30 + */ +@Slf4j +public enum DictTypeConvert implements Converter { + + /** + * 实例 + */ + INSTANCE; + + /** + * 支持 Java Type Key + * + * @return {@link Class } + */ + @Override + public Class supportJavaTypeKey() { + return String.class; + } + + /** + * 支持 Excel 键入键 + * + * @return {@link CellDataTypeEnum } + */ + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.STRING; + } + + /** + * 转换为 Java 数据 + * + * @param cellData 单元格数据 + * @param contentProperty content 属性 + * @param globalConfiguration 全局配置 + * @return {@link String } + * @throws Exception 异常 + */ + @Override + public String convertToJavaData(ReadCellData cellData, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) throws Exception { + if (contentProperty == null || contentProperty.getDateTimeFormatProperty() == null) { + return cellData.getStringValue(); + } + Field field = contentProperty.getField(); + + DictTypeProperty declaredAnnotation = field.getDeclaredAnnotation(DictTypeProperty.class); + if (Objects.isNull(declaredAnnotation)) { + return cellData.getStringValue(); + } + + if (declaredAnnotation.enums().length != 0) { + + DictEnum[] enums = declaredAnnotation.enums()[0].getEnumConstants(); + return DictEnum.getValueByLabel(enums, cellData.getStringValue()); + } + + DictDataProvider dictDataProvider = SpringContextKit.getBean(DictDataProvider.class); + DictEnum[] dictEnums = dictDataProvider.getDict(declaredAnnotation.value()); + if (dictEnums == null) { + return cellData.getStringValue(); + } + return DictEnum.getValueByLabel(dictEnums, cellData.getStringValue()); + } + + /** + * 转换为 Excel 数据 + * + * @param value 价值 + * @param contentProperty content 属性 + * @param globalConfiguration 全局配置 + * @return {@link WriteCellData }<{@link String }> + */ + @Override + public WriteCellData convertToExcelData(String value, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) throws Exception { + Field field = contentProperty.getField(); + + DictTypeProperty declaredAnnotation = field.getDeclaredAnnotation(DictTypeProperty.class); + if (Objects.isNull(declaredAnnotation)) { + return new WriteCellData<>(value); + } + + if (declaredAnnotation.enums().length != 0) { + DictEnum[] enums = declaredAnnotation.enums()[0].getEnumConstants(); + return new WriteCellData<>(DictEnum.getLabelByValue(enums, value)); + } + + DictDataProvider dictDataProvider = SpringContextKit.getBean(DictDataProvider.class); + DictEnum[] dictEnums = dictDataProvider.getDict(declaredAnnotation.value()); + + if (dictEnums == null) { + return new WriteCellData<>(value); + } + + String labelByValue = DictEnum.getLabelByValue(dictEnums, value); + if (labelByValue != null) { + return new WriteCellData<>(labelByValue); + } + return new WriteCellData<>(value); + } + +} diff --git a/src/main/java/com/pig4cloud/plugin/excel/handler/AbstractSheetWriteHandler.java b/src/main/java/com/pig4cloud/plugin/excel/handler/AbstractSheetWriteHandler.java index d6adf0d..3e99b84 100644 --- a/src/main/java/com/pig4cloud/plugin/excel/handler/AbstractSheetWriteHandler.java +++ b/src/main/java/com/pig4cloud/plugin/excel/handler/AbstractSheetWriteHandler.java @@ -112,6 +112,7 @@ public ExcelWriter getExcelWriter(HttpServletResponse response, ResponseExcel re .registerConverter(LocalTimeStringConverter.INSTANCE) .registerConverter(LongStringConverter.INSTANCE) .registerConverter(StringArrayConverter.INSTANCE) + .registerConverter(DictTypeConvert.INSTANCE) .autoCloseStream(true) .excelType(responseExcel.suffix()) .inMemory(responseExcel.inMemory()); diff --git a/src/main/java/com/pig4cloud/plugin/excel/handler/DefaultDictDataProvider.java b/src/main/java/com/pig4cloud/plugin/excel/handler/DefaultDictDataProvider.java new file mode 100644 index 0000000..41d1745 --- /dev/null +++ b/src/main/java/com/pig4cloud/plugin/excel/handler/DefaultDictDataProvider.java @@ -0,0 +1,9 @@ +package com.pig4cloud.plugin.excel.handler; + +/** + * @author lengleng + * @date 2024/8/30 + */ +public class DefaultDictDataProvider implements DictDataProvider { + +} diff --git a/src/main/java/com/pig4cloud/plugin/excel/handler/DictDataProvider.java b/src/main/java/com/pig4cloud/plugin/excel/handler/DictDataProvider.java new file mode 100644 index 0000000..d950c3d --- /dev/null +++ b/src/main/java/com/pig4cloud/plugin/excel/handler/DictDataProvider.java @@ -0,0 +1,86 @@ +package com.pig4cloud.plugin.excel.handler; + +import com.pig4cloud.plugin.excel.vo.DictEnum; +import org.apache.commons.lang3.ArrayUtils; + +import java.util.HashMap; +import java.util.Map; + +/** + * dict 数据提供程序 + * + * @author lengleng + * @date 2024/08/30 + */ +public interface DictDataProvider { + + static Map cache = new HashMap<>(); + + /** + * 获取缓存 + * + * @return {@link Map }<{@link String }, {@link DictEnum[] }> + */ + default Map getCache() { + return cache; + } + + /** + * 获取 dict + * + * @param type 类型 + * @return {@link DictEnum[] } + */ + default DictEnum[] getDict(String type) { + return cache.get(type); + } + + /** + * 添加 dict + * + * @param type 类型 + * @param key key + * @param value value + */ + default void addDict(String type, String key, String value) { + // 1. 获取当前已有的 DictEnum 数组 + DictEnum[] existingEnums = cache.get(type); + + // 2. 创建新的 DictEnum 对象 + DictEnum newEnum = new DictEnum() { + @Override + public String getValue() { + return key; + } + + @Override + public String getLabel() { + return value; + } + }; + + // 3. 使用 ArrayUtils.add 将新元素添加到数组中 + DictEnum[] newEnums = ArrayUtils.add(existingEnums, newEnum); + + // 4. 将新数组放入 cache 中 + cache.put(type, newEnums); + } + + + /** + * 删除 dict + * + * @param type 类型 + */ + default void delDict(String type) { + cache.remove(type); + } + + /** + * 重新加载 dict + */ + default void clear() { + cache.clear(); + } + +} diff --git a/src/main/java/com/pig4cloud/plugin/excel/kit/SpringContextKit.java b/src/main/java/com/pig4cloud/plugin/excel/kit/SpringContextKit.java new file mode 100644 index 0000000..c7ea8b3 --- /dev/null +++ b/src/main/java/com/pig4cloud/plugin/excel/kit/SpringContextKit.java @@ -0,0 +1,125 @@ +/* + * + * Copyright (c) 2018-2025, lengleng All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the pig4cloud.com developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: lengleng (wangiegie@gmail.com) + * + */ + +package com.pig4cloud.plugin.excel.kit; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.ListableBeanFactory; +import org.springframework.beans.factory.config.BeanFactoryPostProcessor; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.context.ApplicationEvent; +import org.springframework.context.annotation.Lazy; + +import java.util.Map; + +/** + * @author lengleng + * @date 2018/6/27 Spring 工具类 + */ +@Slf4j +@Lazy(false) +public class SpringContextKit implements BeanFactoryPostProcessor, ApplicationContextAware, DisposableBean { + + private static ConfigurableListableBeanFactory beanFactory; + + private static ApplicationContext applicationContext = null; + + /** + * 取得存储在静态变量中的ApplicationContext. + */ + public static ApplicationContext getApplicationContext() { + return applicationContext; + } + + /** + * BeanFactoryPostProcessor, 注入Context到静态变量中. + */ + @Override + public void postProcessBeanFactory(ConfigurableListableBeanFactory factory) throws BeansException { + SpringContextKit.beanFactory = factory; + } + + /** + * 实现ApplicationContextAware接口, 注入Context到静态变量中. + */ + @Override + public void setApplicationContext(ApplicationContext applicationContext) { + SpringContextKit.applicationContext = applicationContext; + } + + public static ListableBeanFactory getBeanFactory() { + return null == beanFactory ? applicationContext : beanFactory; + } + + /** + * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型. + */ + @SuppressWarnings("unchecked") + public static T getBean(String name) { + return (T) getBeanFactory().getBean(name); + } + + /** + * 从静态变量applicationContext中取得Bean, Map + */ + public static Map getBeansOfType(Class type) { + return getBeanFactory().getBeansOfType(type); + } + + /** + * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型. + */ + public static T getBean(Class requiredType) { + return getBeanFactory().getBean(requiredType); + } + + /** + * 清除SpringContextKit中的ApplicationContext为Null. + */ + public static void clearHolder() { + if (log.isDebugEnabled()) { + log.debug("清除SpringContextKit中的ApplicationContext:" + applicationContext); + } + applicationContext = null; + } + + /** + * 发布事件 + * @param event + */ + public static void publishEvent(ApplicationEvent event) { + if (applicationContext == null) { + return; + } + applicationContext.publishEvent(event); + } + + /** + * 实现DisposableBean接口, 在Context关闭时清理静态变量. + */ + @Override + public void destroy() { + SpringContextKit.clearHolder(); + } + +} diff --git a/src/main/java/com/pig4cloud/plugin/excel/vo/DictEnum.java b/src/main/java/com/pig4cloud/plugin/excel/vo/DictEnum.java new file mode 100644 index 0000000..8424f46 --- /dev/null +++ b/src/main/java/com/pig4cloud/plugin/excel/vo/DictEnum.java @@ -0,0 +1,62 @@ +package com.pig4cloud.plugin.excel.vo; + +import java.util.Arrays; +import java.util.Objects; + +/** + * 数据字典枚举接口。系统字典枚举接口 + * + * @author HouKunLin + */ +public interface DictEnum { + + /** + * 字典值 + * @return 字典值 + */ + String getValue(); + + /** + * 字典文本 + * @return 字典文本 + */ + String getLabel(); + + /** + * 判断字典值是否相等 + * @param o 传入的值,可为当前的枚举对象 + * @return 判断是否相等 + */ + default boolean eq(Object o) { + return this == o || Objects.equals(o, getValue()); + } + + /** + * 根据字典值获取字典文本 + * @param enums 枚举类的所有枚举值 + * @param value 字典值 + * @return 对应的字典文本 + */ + static String getLabelByValue(E[] enums, String value) { + return Arrays.stream(enums) + .filter(e -> Objects.equals(e.getValue(), value)) + .map(DictEnum::getLabel) + .findFirst() + .orElse(null); + } + + /** + * 根据字典文本获取字典值 + * @param enums 枚举类的所有枚举值 + * @param label 字典文本 + * @return 对应的字典值 + */ + static String getValueByLabel(E[] enums, String label) { + return Arrays.stream(enums) + .filter(e -> Objects.equals(e.getLabel(), label)) + .map(DictEnum::getValue) + .findFirst() + .orElse(null); + } + +} diff --git a/src/test/java/com/pig4cloud/plugin/excel/enums/DemoController.java b/src/test/java/com/pig4cloud/plugin/excel/enums/DemoController.java new file mode 100644 index 0000000..73e9147 --- /dev/null +++ b/src/test/java/com/pig4cloud/plugin/excel/enums/DemoController.java @@ -0,0 +1,56 @@ +package com.pig4cloud.plugin.excel.enums; + +import com.pig4cloud.plugin.excel.annotation.RequestExcel; +import com.pig4cloud.plugin.excel.annotation.ResponseExcel; +import com.pig4cloud.plugin.excel.vo.ErrorMessage; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author lengleng + * @date 2024/8/30 + */ +@RestController +@RequestMapping("/demo") +public class DemoController { + + @ResponseExcel + @RequestMapping("/test") + public List test() { + List list = new ArrayList<>(); + IndexOrNameData2 indexOrNameData2 = new IndexOrNameData2(); + indexOrNameData2.setSex("0"); + + IndexOrNameData2 indexOrNameData3 = new IndexOrNameData2(); + indexOrNameData3.setSex("1"); + list.add(indexOrNameData2); + list.add(indexOrNameData3); + return list; + } + + @ResponseExcel + @RequestMapping("/test2") + public List test2() { + List list2 = new ArrayList<>(); + IndexOrNameData3 indexOrNameData2 = new IndexOrNameData3(); + indexOrNameData2.setSex("0"); + + IndexOrNameData3 indexOrNameData3 = new IndexOrNameData3(); + indexOrNameData3.setSex("1"); + list2.add(indexOrNameData2); + list2.add(indexOrNameData3); + return list2; + } + + @PostMapping("/upload") + public void upload(@RequestExcel List dataList, BindingResult bindingResult) { + // JSR 303 校验通用校验获取失败的数据 + List errorMessageList = (List) bindingResult.getTarget(); + } + +} diff --git a/src/test/java/com/pig4cloud/plugin/excel/enums/DemoControllerTest.java b/src/test/java/com/pig4cloud/plugin/excel/enums/DemoControllerTest.java new file mode 100644 index 0000000..3dfc5a8 --- /dev/null +++ b/src/test/java/com/pig4cloud/plugin/excel/enums/DemoControllerTest.java @@ -0,0 +1,125 @@ +package com.pig4cloud.plugin.excel.enums; + +import com.pig4cloud.plugin.excel.handler.DictDataProvider; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.core.io.ClassPathResource; +import org.springframework.http.MediaType; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.mock.web.MockMultipartFile; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.multipart; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@SpringBootApplication(scanBasePackages = "com.pig4cloud.plugin.excel") +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +public class DemoControllerTest { + + @Autowired + private WebApplicationContext webApplicationContext; + + private MockMvc mockMvc; + + @BeforeEach + public void setUp() { + mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build(); + } + + /** + * 单元测试,写出excel 字段固定枚举 enum + * @throws Exception + */ + @Test + void testFileDownloadAndSave() throws Exception { + MvcResult result = mockMvc.perform(get("/demo/test")).andExpect(status().isOk()).andReturn(); + + MockHttpServletResponse response = result.getResponse(); + byte[] fileContent = response.getContentAsByteArray(); + + // 验证响应不为空 + assertThat(fileContent).isNotEmpty(); + + // 保存文件到 resources 目录 + saveFileToResources("downloaded-example.xlsx", fileContent); + } + + @Autowired + private DictDataProvider dictDataProvider; + + /** + * 单元测试,写出excel 字段指定枚举 type + * @throws Exception + */ + @Test + void test2FileDownloadAndSave() throws Exception { + dictDataProvider.addDict("sex_type", "0", "男"); + dictDataProvider.addDict("sex_type", "1", "女"); + + MvcResult result = mockMvc.perform(get("/demo/test2")).andExpect(status().isOk()).andReturn(); + + MockHttpServletResponse response = result.getResponse(); + byte[] fileContent = response.getContentAsByteArray(); + + // 验证响应不为空 + assertThat(fileContent).isNotEmpty(); + + // 保存文件到 resources 目录 + saveFileToResources("downloaded-example.xlsx", fileContent); + } + + private void saveFileToResources(String filename, byte[] content) throws IOException { + // 获取 resources 目录路径 + File resourceDirectory = new File("src/test/resources"); + if (!resourceDirectory.exists()) { + resourceDirectory.mkdirs(); + } + + // 创建目标文件 + File outputFile = new File(resourceDirectory, filename); + try (FileOutputStream fos = new FileOutputStream(outputFile)) { + fos.write(content); + } + + // 验证文件是否成功写入 + assertThat(outputFile.exists()).isTrue(); + assertThat(outputFile.length()).isEqualTo(content.length); + } + + @Test + void testFileUpload() throws Exception { + + ClassPathResource classPathResource = new ClassPathResource("tmp/enums.xlsx"); + + // 创建一个模拟的 Excel 文件 + MockMultipartFile mockFile = new MockMultipartFile("file", // 参数名称,应该与 Controller + // 中接收的文件参数名称一致 + "enums.xlsx", // 上传的文件名 + MediaType.MULTIPART_FORM_DATA_VALUE, // 文件类型 + classPathResource.getContentAsByteArray() // 文件内容,可以根据需要替换为实际的Excel内容 + ); + + // 模拟文件上传请求 + MvcResult result = mockMvc.perform(multipart("/demo/upload") // 上传文件的URL + .file(mockFile) // 添加文件 + .contentType(MediaType.MULTIPART_FORM_DATA) // 设置内容类型为 multipart/form-data + ) + .andExpect(status().isOk()) // 验证返回的 HTTP 状态码是 200 OK + .andReturn(); + + // 这里可以进一步验证上传处理后的结果,例如返回的消息、数据库中的数据等 + } + +} diff --git a/src/test/java/com/pig4cloud/plugin/excel/enums/IndexOrNameData2.java b/src/test/java/com/pig4cloud/plugin/excel/enums/IndexOrNameData2.java new file mode 100644 index 0000000..6f29e7f --- /dev/null +++ b/src/test/java/com/pig4cloud/plugin/excel/enums/IndexOrNameData2.java @@ -0,0 +1,24 @@ +package com.pig4cloud.plugin.excel.enums; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.pig4cloud.plugin.excel.annotation.DictTypeProperty; +import lombok.Data; + +/** + * 指定列的下标或者列名测试实体 + * + * @author lengleng + * @date 2021/4/16 + */ +@Data +public class IndexOrNameData2 { + + /** + * 读取第一列 + */ + @ExcelProperty(value = "列1") + // 指定对应的枚举类 (字符串) + @DictTypeProperty(enums = SexEnum.class) + private String sex; + +} diff --git a/src/test/java/com/pig4cloud/plugin/excel/enums/IndexOrNameData3.java b/src/test/java/com/pig4cloud/plugin/excel/enums/IndexOrNameData3.java new file mode 100644 index 0000000..81d8e85 --- /dev/null +++ b/src/test/java/com/pig4cloud/plugin/excel/enums/IndexOrNameData3.java @@ -0,0 +1,23 @@ +package com.pig4cloud.plugin.excel.enums; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.pig4cloud.plugin.excel.annotation.DictTypeProperty; +import lombok.Data; + +/** + * 指定列的下标或者列名测试实体 + * + * @author lengleng + * @date 2021/4/16 + */ +@Data +public class IndexOrNameData3 { + + /** + * 读取第一列 + */ + @ExcelProperty(value = "列1") + @DictTypeProperty("sex_type") + private String sex; + +} diff --git a/src/test/java/com/pig4cloud/plugin/excel/enums/SexEnum.java b/src/test/java/com/pig4cloud/plugin/excel/enums/SexEnum.java new file mode 100644 index 0000000..9571e64 --- /dev/null +++ b/src/test/java/com/pig4cloud/plugin/excel/enums/SexEnum.java @@ -0,0 +1,23 @@ +package com.pig4cloud.plugin.excel.enums; + +import com.pig4cloud.plugin.excel.vo.DictEnum; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +/** + * @author lengleng + * @date 2024/8/30 + */ +@Getter +@RequiredArgsConstructor +// 必须继承 DictEnum +public enum SexEnum implements DictEnum { + + MALE("0", "男"), + FEMALE("1", "女"); + + // 必须有的字段 + private final String value; + // 必须有的字段 + private final String label; +} diff --git a/src/test/resources/tmp/enums.xlsx b/src/test/resources/tmp/enums.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..d5a6b1669a6754dc21f5395699546f2361e4c346 GIT binary patch literal 3619 zcmai12{@E%8@7$Xpurfjwjg9rWvR)|SWXyGl6^g78`-z9)!35VKcvH-Bx?sHp~(^@ zd-i>85Xz85^UoL3@t>}q@4Du_uJ8Ju_xqmvy`THJM_-4UMx26srn@{OyiZmwQ- zu3i>Ke(rYYYZAWKT`Ev-Twh8-w^Ew>M9&cQFR^1(`Cq{w5~Ch`uVvQo=O7Y1QK@ z|KSl1LR1T9k%0_KtZaQ#t9%sliN<@}((TwN6mzMa+i;*lRanL&s@}s&9yP+vBy^aG z6b&Ej74A?j;z@BAF5vRwWn)2|DQ%Ze6RFeI3=3;Us~9B6)-`;Ug0r(`+FicIAA|d%mUbc%3EtE%~d7)|+-{YTv3P zbNx5Tuas)iVpFQj(t*o_v-&z zO)U+LvJh;o!CeQjI1R?o)nI$ToJj*Cr8r$Jjgi_Kd`zW_GJZj{beji-vhRG4Lwa^VU_Z|qWmaDv&u^^O39FviSsB5~W{7Gf^ac$Bh))gKr=CFzD zTGQ;r(C{(@8%RbF2l)Ggr~s5)W$1KfcEF*~rurR9Q1Sz|ZZ`U!ZtiGFD|dH*rh4&s z1~N_6mV?!sYewdk)w+_y=Z2YV-g1>KGK(Pj;%D}>=*qXy5{KV5L-XYY5gDBKzm-krrs9(Kc-r<+B@-b!)L|t%$w9eSrdUi{dacDda}Fz z`tVtPF3ZNv(+;TXdcrlGdMQ{GNxL}+XUl67QK_1YxhGee^cP{h!%u+s>NRJ@)8l}&`j!ShFjFz(p|G7Q@&xJ-BSeMd@28M#fIM z1tZp>`k&HY+<)ZGkvkPZGk}2~y%>RWOG z+JYSSzpm7a=_kIR;L>G`n2Ftb%<`O>#N67V!lzoNKP5M7BaL=Cu3^5k%r`gl_o!}2 zTIj;3!r89yTle%?SA0DmCT34pJ*{9|gwv`o zcCq@NUhzl7o1{Oe7dA}MiF<@Gmt_vf{hIwXyfL)o^cb|!FWNXN8C&i5fc5%^%f`uO z%@UK?KZjQe*Fd>UjB?u)Kn3n~{X)LGG{F9r4otfhc=@^5egE_dqc^TSQm~O#_SDbU zXF&z}i43Al)+5T+3rJViN5N{94{SFfVqXq@3$4SD#s}M+l~f@)xPC;{-0*`eb05Qm z0I5{xl+Kx%FjoCYiK>EAn^sS1p62v@iRpQk8#+Y$f<-_W*V$CHej~9zhq7hyzN_*? zwl;SQ51(FEe=o(!q7%qFh42^?tgTt+xl7=xl(s|_{^U3B!-V`yolYNh=E9t-I5d5i zKDPB{lzk+85L&GL{$A_*lvl7MXpw9BctCwPUy>Qm@#mkEZk0btGIN^33;1KlkaMs4 z+Q;gG=nL^Aq0O;Zxu?Jz)FJR!CG^DD(#y715t?VQ)13vZZBfhJfzLGY|1j0R;vtYov6}Pk%=@T4&zqbSr%gqVrfN zLKxdTOuIZ^eC#7vt>iY7Krr7;@%0B|8X3MTo9K%C^GVl8Nn(To0}@Ywd|4lQ-QJq5 zw{mhrW5pD?(iw4*tMduQo$3qr9Ehm(8g-^QL4%uoKwIn*Pzu$S6ZM0&xk(5~+eyWg9SYBW~*G9G$G&nvmtMeM2YuE6=_a{76XXLb3QuB&7d^eQ%C$#gwT!`)YJld(_nT@foRY})q z6)a>7W_1intSOt9Lan**i4o-(Fs?Yi)d|9}x~40lUIW=qx4{tmb;5-v!Bx{s4NCCT zTB^p1WwDjwYH&rXx4JRJ>U{S??m9Ps&A^PJbl+}kUHh#_aP45TGjV@LXlMG~(Q_ul zq(qAD4D#s0bLP5A+H^Qy2o5bxk&`WpyI=99uB5uYR|%|06o_33I8<&H5*MyuFpHq2 z*1Hs*W0||4>M&kP^7RKbhT$im)Q8h=S=E@jIw^@*^nb=)vZ6UNuHJ>~bvYl`d`TDf zIxo&oO{9I85V3xXm!N*F?tS2!P@eLFKt<&C#I$S0oGhR~rsf)}?-Tj)r#0G(Yo2}A zA%}&W{CB$`$^LfQa_)cxz=L+Qv-3ieMU}ir1564stk$NHhJDzMP8fZQxXhk$_)3C0 zL^*J6AVcvKKEqaP=~=3=^}{0@jty;pazh|>nqbmPoPiIBUw!=U^j-84lC_XG4Wvl5 zklcB6xqL7a6R(%!1^={NGcn0v5d#mymfe&9D`{*GMxN6wG>&xlV7~7qj>6<6_4FGa zQ^wJoTuDHxib6WCKS@&)NtrcB$Y(7-YYXp6IHd3>oR7nxgUBbG{?zUCYVUCy=JWl! zDu1x$@O)6Al%}#Ow^?!d7>;ns8>ke+7{x<|rIVQSuf)U3FCy#2`UJIKJHCy$qA+Rn zs+P-34jmlMqDoM4>Q~pHgvnbHJ-y%2(R6sSEBdb`v-}~t8zg7}fA+#$wZFeb zc6P0q8R@|Q&UyXYyTF=^+N|N;v_mBh7wZ_J{fPGx54#|7A|LvjkNhXGxT<1!PV6)- z-e1jIzGjXQmSEl8n6dq|J5K`@~&`y0wGZd$S#w z>wpc~4-EBB*?XqwVEW!*1%@gx`1hlY48*_LfP*{iX)2(nz~J4F1o9nVhaY43VCtUa z0CEF}?SAxuzo-5zEC-YKS`lbNK#lfemHZEl{N7(^)4_fA$N>-oXxRPWWccwB|JT0y TIv`r$NqX{ift=a){mB0ZJ!f_a literal 0 HcmV?d00001