diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/PageResult.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/PageResult.java index 9791425df..a89a755ea 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/PageResult.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/PageResult.java @@ -5,7 +5,7 @@ import lombok.NoArgsConstructor; import java.io.Serial; import java.io.Serializable; -import java.util.List; +import java.util.Collection; /** * 表格分页数据对象 @@ -27,12 +27,23 @@ public class PageResult implements Serializable { /** * 列表数据 */ - private List rows; + private Collection rows; + + /** + * 分页 + * + * @param list 列表数据 + * @param total 总记录数 + */ + public PageResult(Collection list, long total) { + this.rows = list; + this.total = total; + } /** * 根据分页对象构建表格分页数据对象 */ - public static PageResult build(List list, long total) { + public static PageResult build(Collection list, long total) { PageResult rspData = new PageResult<>(); rspData.setRows(list); rspData.setTotal(total); @@ -42,7 +53,7 @@ public class PageResult implements Serializable { /** * 根据数据列表构建表格分页数据对象 */ - public static PageResult build(List list) { + public static PageResult build(Collection list) { PageResult rspData = new PageResult<>(); rspData.setRows(list); rspData.setTotal(list.size()); diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/TaskAssigneeDTO.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/TaskAssigneeDTO.java index d3b4dac55..8444a8ef2 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/TaskAssigneeDTO.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/TaskAssigneeDTO.java @@ -6,6 +6,7 @@ import lombok.NoArgsConstructor; import java.io.Serial; import java.io.Serializable; +import java.util.Collection; import java.util.Date; import java.util.List; import java.util.function.Function; @@ -42,7 +43,7 @@ public class TaskAssigneeDTO implements Serializable { * 将源列表转换为 TaskHandler 列表 * * @param 通用类型 - * @param sourceList 待转换的源列表 + * @param sourceCollection 待转换的源列表 * @param storageId 提取 storageId 的函数 * @param handlerCode 提取 handlerCode 的函数 * @param handlerName 提取 handlerName 的函数 @@ -51,13 +52,13 @@ public class TaskAssigneeDTO implements Serializable { * @return 转换后的 TaskHandler 列表 */ public static List convertToHandlerList( - List sourceList, + Collection sourceCollection, Function storageId, Function handlerCode, Function handlerName, Function groupName, Function createTimeMapper) { - return sourceList.stream() + return sourceCollection.stream() .map(item -> new TaskHandler( storageId.apply(item), handlerCode.apply(item), diff --git a/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/collection/TranslationCollection.java b/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/collection/TranslationCollection.java new file mode 100644 index 000000000..d4bc63d5d --- /dev/null +++ b/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/collection/TranslationCollection.java @@ -0,0 +1,26 @@ +package org.dromara.common.translation.collection; + +import java.lang.annotation.*; + +/** + * 集合翻译(声明到需要翻译的实体上) + * + * @author 秋辞未寒 + */ +@Inherited +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE}) +@Documented +public @interface TranslationCollection { + + /** + * 类型 + */ + String type(); + + /** + * 其他条件 例如: 字典type(sys_user_gender) + */ + String other() default ""; + +} diff --git a/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/collection/TranslationCollectionBinding.java b/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/collection/TranslationCollectionBinding.java new file mode 100644 index 000000000..9ba23156c --- /dev/null +++ b/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/collection/TranslationCollectionBinding.java @@ -0,0 +1,20 @@ +package org.dromara.common.translation.collection; + +import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; +import tools.jackson.databind.annotation.JsonSerialize; + +import java.lang.annotation.*; + +/** + * 序列化器绑定注解 + * + * @author 秋辞未寒 + */ +@Inherited +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE}) +@Documented +@JacksonAnnotationsInside +@JsonSerialize(using = TranslationCollectionSerializer.class) +public @interface TranslationCollectionBinding { +} diff --git a/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/collection/TranslationCollectionProcessor.java b/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/collection/TranslationCollectionProcessor.java new file mode 100644 index 000000000..11fc4f8ef --- /dev/null +++ b/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/collection/TranslationCollectionProcessor.java @@ -0,0 +1,17 @@ +package org.dromara.common.translation.collection; + +import java.util.Collection; + +/** + * 翻译集合处理器 + * @param 输入类型 + * @param 目标类型 + * + * @author 秋辞未寒 + */ +public interface TranslationCollectionProcessor { + + + Collection process(Collection value,String other) throws Exception; + +} diff --git a/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/collection/TranslationCollectionSerializer.java b/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/collection/TranslationCollectionSerializer.java new file mode 100644 index 000000000..5b45b0e1e --- /dev/null +++ b/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/collection/TranslationCollectionSerializer.java @@ -0,0 +1,62 @@ +package org.dromara.common.translation.collection; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ClassUtil; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.utils.reflect.AnnotationUtils; +import tools.jackson.core.JacksonException; +import tools.jackson.core.JsonGenerator; +import tools.jackson.databind.SerializationContext; +import tools.jackson.databind.ValueSerializer; + +import java.util.Collection; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * 集合翻译序列化器 + * + * @author 秋辞未寒 + */ +@Slf4j +public class TranslationCollectionSerializer extends ValueSerializer> { + + /** + * 全局翻译实现类映射器 + */ + public static final Map> TRANSLATION_MAPPER = new ConcurrentHashMap<>(); + + @Override + public void serialize(TranslationCollectionWrapper value, JsonGenerator gen, SerializationContext provider) throws JacksonException { + if (CollUtil.isEmpty(value)) { + return; + } + Class elementType = value.getElementType(); + if (elementType == null) { + elementType = ClassUtil.getClass(CollUtil.getFirst(value)); + } + // 获取包装原内容(很重要!!!!!!如果原样使用的话,会无限递归!) + Collection collection = value.getCollection(); + TranslationCollection annotation = AnnotationUtils.getAnnotation(elementType, TranslationCollection.class); + if (annotation != null ) { + String type = annotation.type(); + String other = annotation.other(); + TranslationCollectionProcessor processor = TRANSLATION_MAPPER.get(type); + if (processor != null) { + try { + collection = processor.process(collection,other); + } catch (Exception e) { + log.error("翻译处理异常,type: {}, value: {}", type, value, e); + // 出现异常时输出原始值而不是中断序列化 + collection = value.getCollection(); + } + } + } + gen.writeStartArray(); + for (Object o : collection) { + gen.writePOJO(o); + } + gen.writeEndArray(); + } + +} diff --git a/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/collection/TranslationCollectionType.java b/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/collection/TranslationCollectionType.java new file mode 100644 index 000000000..76ee7a08d --- /dev/null +++ b/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/collection/TranslationCollectionType.java @@ -0,0 +1,22 @@ +package org.dromara.common.translation.collection; + +import java.lang.annotation.*; + + +/** + * 集合翻译类型 + * + * @author 秋辞未寒 + */ +@Inherited +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE}) +@Documented +public @interface TranslationCollectionType { + + /** + * 类型 + */ + String type(); + +} diff --git a/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/collection/TranslationCollectionWrapper.java b/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/collection/TranslationCollectionWrapper.java new file mode 100644 index 000000000..7f17c1707 --- /dev/null +++ b/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/collection/TranslationCollectionWrapper.java @@ -0,0 +1,126 @@ +package org.dromara.common.translation.collection; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ClassUtil; +import lombok.Getter; + +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.Objects; + +/** + * 翻译集合包装器 + * + * @param 元素类型 + * + * @author 秋辞未寒 + */ +@Getter +@TranslationCollectionBinding +public class TranslationCollectionWrapper implements Collection { + + private final Collection collection; + private final Class elementType; + + /** + * 不建议直接使用构造函数去构建包装器 + */ + private TranslationCollectionWrapper(Collection collection, Class elementType) { + this.collection = collection; + this.elementType = elementType; + } + + /** + * 包装集合成翻译集合 + * @param collection 待包装的集合 + * @return 包装后的集合类型 + * @param 元素类型 + */ + public static TranslationCollectionWrapper form(Collection collection) { + return form(collection,null); + } + + /** + * 包装集合成翻译集合 (推荐使用该函数,可以减少不必要的迭代器取值~) + * @param collection 待包装的集合 + * @param elementType 元素Class实例 + * @return 包装后的集合类型 + * @param 元素类型 + */ + public static TranslationCollectionWrapper form(Collection collection, Class elementType) { + if (Objects.isNull(collection)) { + collection = Collections.emptyList(); + } + if (Objects.isNull(elementType)) { + elementType = ClassUtil.getClass(CollUtil.getFirst(collection)); + } + return new TranslationCollectionWrapper<>(collection,elementType); + } + + + @Override + public int size() { + return collection.size(); + } + + @Override + public boolean isEmpty() { + return collection.isEmpty(); + } + + @Override + public boolean contains(Object o) { + return collection.contains(o); + } + + @Override + public Iterator iterator() { + return collection.iterator(); + } + + @Override + public Object[] toArray() { + return collection.toArray(); + } + + @Override + public T[] toArray(T[] a) { + return collection.toArray(a); + } + + @Override + public boolean add(E e) { + return collection.add(e); + } + + @Override + public boolean remove(Object o) { + return collection.remove(o); + } + + @Override + public boolean containsAll(Collection c) { + return collection.containsAll(c); + } + + @Override + public boolean addAll(Collection c) { + return collection.addAll(c); + } + + @Override + public boolean removeAll(Collection c) { + return collection.removeAll(c); + } + + @Override + public boolean retainAll(Collection c) { + return collection.retainAll(c); + } + + @Override + public void clear() { + collection.clear(); + } +} diff --git a/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/config/TranslationConfig.java b/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/config/TranslationConfig.java index d1b52fdf6..efad0300b 100644 --- a/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/config/TranslationConfig.java +++ b/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/config/TranslationConfig.java @@ -3,6 +3,9 @@ package org.dromara.common.translation.config; import jakarta.annotation.PostConstruct; import lombok.extern.slf4j.Slf4j; import org.dromara.common.translation.annotation.TranslationType; +import org.dromara.common.translation.collection.TranslationCollectionProcessor; +import org.dromara.common.translation.collection.TranslationCollectionSerializer; +import org.dromara.common.translation.collection.TranslationCollectionType; import org.dromara.common.translation.core.TranslationInterface; import org.dromara.common.translation.core.handler.TranslationBeanSerializerModifier; import org.dromara.common.translation.core.handler.TranslationHandler; @@ -26,12 +29,15 @@ import java.util.Map; public class TranslationConfig { @Autowired - private List> list; + private List> translationInterfaces; + + @Autowired + private List> translationCollectionHandlers; @PostConstruct public void init() { - Map> map = new HashMap<>(list.size()); - for (TranslationInterface trans : list) { + Map> map = new HashMap<>(translationInterfaces.size()); + for (TranslationInterface trans : translationInterfaces) { if (trans.getClass().isAnnotationPresent(TranslationType.class)) { TranslationType annotation = trans.getClass().getAnnotation(TranslationType.class); map.put(annotation.type(), trans); @@ -40,6 +46,17 @@ public class TranslationConfig { } } TranslationHandler.TRANSLATION_MAPPER.putAll(map); + + Map> handlerMaps = new HashMap<>(translationCollectionHandlers.size()); + for (TranslationCollectionProcessor trans : translationCollectionHandlers) { + if (trans.getClass().isAnnotationPresent(TranslationCollectionType.class)) { + TranslationCollectionType annotation = trans.getClass().getAnnotation(TranslationCollectionType.class); + handlerMaps.put(annotation.type(), (TranslationCollectionProcessor) trans); + } else { + log.warn(trans.getClass().getName() + " 翻译实现类未标注 TranslationCollectionType 注解!"); + } + } + TranslationCollectionSerializer.TRANSLATION_MAPPER.putAll(handlerMaps); } @Bean diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/vo/TestDemoVo.java b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/vo/TestDemoVo.java index 0f760c8a3..d76980fec 100644 --- a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/vo/TestDemoVo.java +++ b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/vo/TestDemoVo.java @@ -1,15 +1,16 @@ package org.dromara.demo.domain.vo; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated; import org.apache.fesod.sheet.annotation.ExcelProperty; import org.apache.fesod.sheet.annotation.format.DateTimeFormat; import org.dromara.common.excel.annotation.ExcelNotation; import org.dromara.common.excel.annotation.ExcelRequired; import org.dromara.common.translation.annotation.Translation; +import org.dromara.common.translation.collection.TranslationCollection; import org.dromara.common.translation.constant.TransConstant; import org.dromara.demo.domain.TestDemo; -import io.github.linpeilie.annotations.AutoMapper; -import lombok.Data; import java.io.Serial; import java.io.Serializable; @@ -22,6 +23,7 @@ import java.util.Date; * @author Lion Li * @date 2021-07-26 */ +@TranslationCollection(type = "test") @Data @ExcelIgnoreUnannotated @AutoMapper(target = TestDemo.class) diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/TestDemoServiceImpl.java b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/TestDemoServiceImpl.java index 014b7e81d..1caa39756 100644 --- a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/TestDemoServiceImpl.java +++ b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/TestDemoServiceImpl.java @@ -9,6 +9,7 @@ import org.dromara.common.core.exception.ServiceException; import org.dromara.common.core.utils.MapstructUtils; import org.dromara.common.core.utils.StringUtils; import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.translation.collection.TranslationCollectionWrapper; import org.dromara.demo.domain.TestDemo; import org.dromara.demo.domain.bo.TestDemoBo; import org.dromara.demo.domain.vo.TestDemoVo; @@ -53,7 +54,7 @@ public class TestDemoServiceImpl implements ITestDemoService { public PageResult queryPageList(TestDemoBo bo, PageQuery pageQuery) { LambdaQueryWrapper lqw = buildQueryWrapper(bo); Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); - return PageResult.build(result.getRecords(), result.getTotal()); + return PageResult.build(TranslationCollectionWrapper.form(result.getRecords()), result.getTotal()); } /** diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/translation/TestDemoVoTranslationCollectionCollectionHandler.java b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/translation/TestDemoVoTranslationCollectionCollectionHandler.java new file mode 100644 index 000000000..3e2b7a557 --- /dev/null +++ b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/translation/TestDemoVoTranslationCollectionCollectionHandler.java @@ -0,0 +1,27 @@ +package org.dromara.demo.translation; + +import cn.hutool.core.util.IdUtil; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.json.utils.JsonUtils; +import org.dromara.common.translation.collection.TranslationCollectionType; +import org.dromara.common.translation.collection.TranslationCollectionProcessor; +import org.dromara.demo.domain.vo.TestDemoVo; + +import java.util.ArrayList; +import java.util.Collection; + +@Slf4j +@TranslationCollectionType(type = "test") +public class TestDemoVoTranslationCollectionCollectionHandler implements TranslationCollectionProcessor { + + @Override + public Collection process(Collection value, String other) throws Exception { + log.info("翻译前的数据:{}", JsonUtils.toJsonString(value)); + ArrayList vos = new ArrayList<>(value); + for (TestDemoVo vo : vos) { + vo.setValue("啊啦啦啦啦啦啦啦啦啦:"+ IdUtil.fastSimpleUUID()); + } + log.info("翻译后的数据:{}", JsonUtils.toJsonString(vos)); + return vos; + } +} diff --git a/ruoyi-modules/ruoyi-demo/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-modules/ruoyi-demo/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 000000000..429c221b1 --- /dev/null +++ b/ruoyi-modules/ruoyi-demo/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +org.dromara.demo.translation.TestDemoVoTranslationCollectionCollectionHandler