diff --git a/flyfish-data/src/main/java/com/flyfish/framework/context/ViewModelContext.java b/flyfish-data/src/main/java/com/flyfish/framework/context/ViewModelContext.java new file mode 100644 index 0000000..39c244e --- /dev/null +++ b/flyfish-data/src/main/java/com/flyfish/framework/context/ViewModelContext.java @@ -0,0 +1,53 @@ +package com.flyfish.framework.context; + +import com.flyfish.framework.context.interceptor.ViewModelInterceptor; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.stereotype.Component; +import reactor.core.publisher.Mono; + +import java.util.List; + +/** + * 全局上下文 + * + * @author wangyu + * 支持插件式增加处理器 + */ +@Component +public class ViewModelContext { + + // 唯一实例 + private static ViewModelContext INSTANCE; + + // 拦截器们 + private final List interceptors; + + /** + * 通过构造器注入 + */ + public ViewModelContext(List interceptors) { + this.interceptors = interceptors; + INSTANCE = this; + } + + /** + * 全局对象拦截器 + * + * @param value 对象值 + * @param 泛型 + * @return 结果 + */ + public static Mono intercept(T value) { + if (null != INSTANCE) { + List interceptors = INSTANCE.interceptors; + if (CollectionUtils.isNotEmpty(interceptors)) { + for (ViewModelInterceptor interceptor : interceptors) { + if (interceptor.supports(value)) { + return interceptor.intercept(value); + } + } + } + } + return Mono.just(value); + } +} diff --git a/flyfish-data/src/main/java/com/flyfish/framework/context/interceptor/ViewModelInterceptor.java b/flyfish-data/src/main/java/com/flyfish/framework/context/interceptor/ViewModelInterceptor.java new file mode 100644 index 0000000..2a05490 --- /dev/null +++ b/flyfish-data/src/main/java/com/flyfish/framework/context/interceptor/ViewModelInterceptor.java @@ -0,0 +1,28 @@ +package com.flyfish.framework.context.interceptor; + +import reactor.core.publisher.Mono; + +/** + * 视图模型拦截器 + * + * @author wangyu + */ +public interface ViewModelInterceptor { + + /** + * 是否支持 + * + * @param data 数据 + * @return 结果 + */ + boolean supports(Object data); + + /** + * 拦截并返回 + * + * @param data 数据 + * @param 泛型 + * @return 结果 + */ + Mono intercept(T data); +} diff --git a/flyfish-data/src/main/java/com/flyfish/framework/domain/base/Vo.java b/flyfish-data/src/main/java/com/flyfish/framework/domain/base/Vo.java index 9121c5d..9a2ee52 100644 --- a/flyfish-data/src/main/java/com/flyfish/framework/domain/base/Vo.java +++ b/flyfish-data/src/main/java/com/flyfish/framework/domain/base/Vo.java @@ -1,5 +1,6 @@ package com.flyfish.framework.domain.base; +import com.flyfish.framework.context.ViewModelContext; import reactor.core.publisher.Mono; /** @@ -32,4 +33,14 @@ public interface Vo { default Mono> retrieve(T po) { return Mono.just(from(po)); } + + /** + * 最终的wrap方法,用于全局拦截 + * + * @param po 数据库实体 + * @return 结果 + */ + default Mono> wrap(T po) { + return retrieve(po).flatMap(ViewModelContext::intercept); + } } diff --git a/flyfish-dict/src/main/java/com/flyfish/framework/dict/config/DictionaryConfig.java b/flyfish-dict/src/main/java/com/flyfish/framework/dict/config/DictionaryConfig.java index 5dfd80c..7e156e3 100644 --- a/flyfish-dict/src/main/java/com/flyfish/framework/dict/config/DictionaryConfig.java +++ b/flyfish-dict/src/main/java/com/flyfish/framework/dict/config/DictionaryConfig.java @@ -40,4 +40,5 @@ public class DictionaryConfig implements ImportBeanDefinitionRegistrar { Map attrs = metadata.getAnnotationAttributes(EnableDictProcess.class.getCanonicalName(), true); this.basePackages = (String[]) MapUtils.getObject(attrs, "basePackages"); } + } diff --git a/flyfish-dict/src/main/java/com/flyfish/framework/dict/handler/DictAnnotationInterceptor.java b/flyfish-dict/src/main/java/com/flyfish/framework/dict/handler/DictAnnotationInterceptor.java new file mode 100644 index 0000000..152a75b --- /dev/null +++ b/flyfish-dict/src/main/java/com/flyfish/framework/dict/handler/DictAnnotationInterceptor.java @@ -0,0 +1,76 @@ +package com.flyfish.framework.dict.handler; + +import com.flyfish.framework.annotations.DictValue; +import com.flyfish.framework.context.interceptor.ViewModelInterceptor; +import com.flyfish.framework.dict.domain.DictionaryValue; +import com.flyfish.framework.dict.service.DictionaryService; +import com.flyfish.framework.utils.ReflectionUtils; +import lombok.RequiredArgsConstructor; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.reflect.FieldUtils; +import org.springframework.stereotype.Component; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.util.function.Tuples; + +import java.lang.reflect.Field; +import java.util.List; +import java.util.Objects; + +import static org.apache.commons.lang3.ObjectUtils.defaultIfNull; + +/** + * 保证首当其冲被检测到,设置order 0 + * 用于处理字典值,无侵入注入 + * + * @author wangyu + */ +@Component +@RequiredArgsConstructor +public class DictAnnotationInterceptor implements ViewModelInterceptor { + + // 字典服务 + private final DictionaryService dictionaryService; + + /** + * 当前对象包含@DictValue的属性时支持 + * + * @param data 返回值 + * @return 结果 + */ + @Override + public boolean supports(Object data) { + List fields = FieldUtils.getFieldsListWithAnnotation(data.getClass(), DictValue.class); + return CollectionUtils.isNotEmpty(fields); + } + + /** + * 处理对象中的字典注解 + * + * @param data 数据 + * @return 处理后结果 + */ + @Override + public Mono intercept(T data) { + List fields = FieldUtils.getFieldsListWithAnnotation(data.getClass(), DictValue.class); + return Flux.fromIterable(fields) + .flatMap(field -> { + DictValue dictValue = field.getAnnotation(DictValue.class); + String code = dictValue.value(); + String fieldName = field.getName(); + Object value = ReflectionUtils.getFieldValue(data, fieldName); + return dictionaryService.getByCode(code).map(dict -> dict.getValues() + .stream() + .filter(item -> item.getValue().equals(value)) + .findFirst() + .map(DictionaryValue::getText) + .orElse(defaultIfNull((String) value, "")) + ).map(mapped -> Tuples.of(fieldName, mapped)); + }) + .filter(Objects::nonNull) + .reduce(data, (result, tuple) -> { + ReflectionUtils.setFieldValue(result, tuple.getT1(), tuple.getT2()); + return result; + }); + } +} diff --git a/flyfish-web/src/main/resources/templates/ReactiveViewController.tpl b/flyfish-web/src/main/resources/templates/ReactiveViewController.tpl index b10ce8d..ff55280 100644 --- a/flyfish-web/src/main/resources/templates/ReactiveViewController.tpl +++ b/flyfish-web/src/main/resources/templates/ReactiveViewController.tpl @@ -28,10 +28,10 @@ public class #{className} { return service.getPageList(qo) .map(Result::accept) .flatMap(result -> result.flatMap(list -> Flux.fromIterable(list) - .flatMap(item -> new #{listViewClassName}().retrieve(item)) + .flatMap(item -> new #{listViewClassName}().wrap(item)) .collectList())); } - return service.getList(qo).flatMap(item -> new #{listViewClassName}().retrieve(item)) + return service.getList(qo).flatMap(item -> new #{listViewClassName}().wrap(item)) .collectList() .map(Result::accept); }