فهرست منبع

优化数据字典

zhou-hao 5 سال پیش
والد
کامیت
35133c824f
28فایلهای تغییر یافته به همراه705 افزوده شده و 46 حذف شده
  1. 1 0
      hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/access/DefaultDataAccessType.java
  2. 0 6
      hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/TokenState.java
  3. 1 1
      hsweb-authorization/hsweb-authorization-api/src/test/java/org/hswebframework/web/authorization/UserTokenManagerTests.java
  4. 9 7
      hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/ReactiveTreeSortEntityService.java
  5. 1 1
      hsweb-core/src/main/java/org/hswebframework/web/dict/DictDefine.java
  6. 4 3
      hsweb-core/src/main/java/org/hswebframework/web/dict/DictDefineRepository.java
  7. 0 4
      hsweb-core/src/main/java/org/hswebframework/web/dict/EnumDict.java
  8. 0 1
      hsweb-core/src/main/java/org/hswebframework/web/dict/ItemDefine.java
  9. 1 1
      hsweb-core/src/main/java/org/hswebframework/web/dict/defaults/DefaultClassDictDefine.java
  10. 1 2
      hsweb-core/src/main/java/org/hswebframework/web/dict/defaults/DefaultDictDefine.java
  11. 38 13
      hsweb-core/src/main/java/org/hswebframework/web/dict/defaults/DefaultDictDefineRepository.java
  12. 0 1
      hsweb-core/src/main/java/org/hswebframework/web/dict/defaults/DefaultItemDefine.java
  13. 0 5
      hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultDimensionService.java
  14. 1 1
      hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/PermissionSynchronization.java
  15. 22 0
      hsweb-system/hsweb-system-dictionary/pom.xml
  16. 57 0
      hsweb-system/hsweb-system-dictionary/src/main/java/org/hswebframework/web/dictionary/configuration/DictionaryAutoConfiguration.java
  17. 49 0
      hsweb-system/hsweb-system-dictionary/src/main/java/org/hswebframework/web/dictionary/configuration/DictionaryProperties.java
  18. 74 0
      hsweb-system/hsweb-system-dictionary/src/main/java/org/hswebframework/web/dictionary/entity/DictionaryEntity.java
  19. 95 0
      hsweb-system/hsweb-system-dictionary/src/main/java/org/hswebframework/web/dictionary/entity/DictionaryItemEntity.java
  20. 15 0
      hsweb-system/hsweb-system-dictionary/src/main/java/org/hswebframework/web/dictionary/event/ClearDictionaryCacheEvent.java
  21. 66 0
      hsweb-system/hsweb-system-dictionary/src/main/java/org/hswebframework/web/dictionary/service/CompositeDictDefineRepository.java
  22. 76 0
      hsweb-system/hsweb-system-dictionary/src/main/java/org/hswebframework/web/dictionary/service/DefaultDictionaryItemService.java
  23. 111 0
      hsweb-system/hsweb-system-dictionary/src/main/java/org/hswebframework/web/dictionary/service/DefaultDictionaryService.java
  24. 48 0
      hsweb-system/hsweb-system-dictionary/src/main/java/org/hswebframework/web/dictionary/webflux/WebfluxDictionaryController.java
  25. 26 0
      hsweb-system/hsweb-system-dictionary/src/main/java/org/hswebframework/web/dictionary/webflux/WebfluxDictionaryItemController.java
  26. 3 0
      hsweb-system/hsweb-system-dictionary/src/main/resources/META-INF/spring.factories
  27. 1 0
      hsweb-system/pom.xml
  28. 5 0
      pom.xml

+ 1 - 0
hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/access/DefaultDataAccessType.java

@@ -2,6 +2,7 @@ package org.hswebframework.web.authorization.access;
 
 import lombok.AllArgsConstructor;
 import lombok.Getter;
+import org.hswebframework.web.dict.Dict;
 import org.hswebframework.web.dict.EnumDict;
 
 @Getter

+ 0 - 6
hsweb-authorization/hsweb-authorization-api/src/main/java/org/hswebframework/web/authorization/token/TokenState.java

@@ -10,12 +10,6 @@ import org.hswebframework.web.dict.EnumDict;
 @Getter
 @AllArgsConstructor
 public enum TokenState implements EnumDict<String> {
-    /**
-     * 正常,有效
-     */
-    @Deprecated
-    effective("effective", "正常"),
-
     /**
      * 正常,有效
      */

+ 1 - 1
hsweb-authorization/hsweb-authorization-api/src/test/java/org/hswebframework/web/authorization/UserTokenManagerTests.java

@@ -43,7 +43,7 @@ public class UserTokenManagerTests {
 
         Assert.assertEquals(userToken.getState(), TokenState.deny);
 
-        userTokenManager.changeUserState("admin", TokenState.effective).subscribe();
+        userTokenManager.changeUserState("admin", TokenState.normal).subscribe();
 
         Thread.sleep(1200);
 

+ 9 - 7
hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/service/ReactiveTreeSortEntityService.java

@@ -32,9 +32,9 @@ public interface ReactiveTreeSortEntityService<E extends TreeSortSupportEntity<K
     default Mono<Integer> insertBatch(Publisher<? extends Collection<E>> entityPublisher) {
         return this.getRepository()
                 .insertBatch(Flux.from(entityPublisher)
-                .flatMap(Flux::fromIterable)
-                .flatMap(e -> Flux.fromIterable(TreeSupportEntity.expandTree2List(e, getIDGenerator())))
-                .collectList());
+                        .flatMap(Flux::fromIterable)
+                        .flatMap(e -> Flux.fromIterable(TreeSupportEntity.expandTree2List(e, getIDGenerator())))
+                        .collectList());
     }
 
     @Override
@@ -68,9 +68,11 @@ public interface ReactiveTreeSortEntityService<E extends TreeSortSupportEntity<K
 
     void setChildren(E entity, List<E> children);
 
-    List<E> getChildren(E entity);
+    default List<E> getChildren(E entity) {
+        return entity.getChildren();
+    }
 
-   default boolean isRootNode(E entity){
-       return StringUtils.isEmpty(entity.getParentId()) || "-1".equals(String.valueOf(entity.getParentId()));
-   }
+    default boolean isRootNode(E entity) {
+        return StringUtils.isEmpty(entity.getParentId()) || "-1".equals(String.valueOf(entity.getParentId()));
+    }
 }

+ 1 - 1
hsweb-core/src/main/java/org/hswebframework/web/dict/DictDefine.java

@@ -14,6 +14,6 @@ public interface DictDefine extends Serializable {
 
     String getComments();
 
-    List<EnumDict<Object>> getItems();
+    List<? extends EnumDict<?>> getItems();
 
 }

+ 4 - 3
hsweb-core/src/main/java/org/hswebframework/web/dict/DictDefineRepository.java

@@ -1,15 +1,16 @@
 package org.hswebframework.web.dict;
 
-import java.util.List;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
 
 /**
  * @author zhouhao
  * @since 1.0
  */
 public interface DictDefineRepository {
-    DictDefine getDefine(String id);
+    Mono<DictDefine> getDefine(String id);
 
-    List<DictDefine> getAllDefine();
+    Flux<DictDefine> getAllDefine();
 
     void addDefine(DictDefine dictDefine);
 }

+ 0 - 4
hsweb-core/src/main/java/org/hswebframework/web/dict/EnumDict.java

@@ -1,7 +1,6 @@
 package org.hswebframework.web.dict;
 
 import com.alibaba.fastjson.JSONException;
-import com.alibaba.fastjson.JSONObject;
 import com.alibaba.fastjson.annotation.JSONType;
 import com.alibaba.fastjson.parser.DefaultJSONParser;
 import com.alibaba.fastjson.parser.JSONLexer;
@@ -17,9 +16,6 @@ import com.fasterxml.jackson.databind.DeserializationContext;
 import com.fasterxml.jackson.databind.JsonDeserializer;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
-import com.fasterxml.jackson.databind.deser.std.EnumDeserializer;
-import com.fasterxml.jackson.databind.node.ObjectNode;
-import com.fasterxml.jackson.databind.util.EnumResolver;
 import lombok.SneakyThrows;
 import lombok.extern.slf4j.Slf4j;
 import org.hswebframework.web.exception.ValidationException;

+ 0 - 1
hsweb-core/src/main/java/org/hswebframework/web/dict/ItemDefine.java

@@ -20,6 +20,5 @@ public interface ItemDefine extends EnumDict<String> {
         return getOrdinal();
     }
 
-    List<ItemDefine> getChildren();
 
 }

+ 1 - 1
hsweb-core/src/main/java/org/hswebframework/web/dict/defaults/DefaultClassDictDefine.java

@@ -24,5 +24,5 @@ public class DefaultClassDictDefine implements ClassDictDefine {
     private String                 id;
     private String                 alias;
     private String                 comments;
-    private List<EnumDict<Object>> items;
+    private List<? extends EnumDict<?>> items;
 }

+ 1 - 2
hsweb-core/src/main/java/org/hswebframework/web/dict/defaults/DefaultDictDefine.java

@@ -22,6 +22,5 @@ public class DefaultDictDefine implements DictDefine {
     private String           id;
     private String           alias;
     private String           comments;
-    private String           parserId;
-    private List<EnumDict<Object>> items;
+    private List<? extends EnumDict<?>> items;
 }

+ 38 - 13
hsweb-core/src/main/java/org/hswebframework/web/dict/defaults/DefaultDictDefineRepository.java

@@ -1,6 +1,7 @@
 package org.hswebframework.web.dict.defaults;
 
 import lombok.extern.slf4j.Slf4j;
+import org.hswebframework.utils.StringUtils;
 import org.hswebframework.web.dict.*;
 import org.springframework.core.io.Resource;
 import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
@@ -8,6 +9,8 @@ import org.springframework.core.io.support.ResourcePatternResolver;
 import org.springframework.core.type.classreading.MetadataReader;
 import org.springframework.core.type.classreading.SimpleMetadataReaderFactory;
 import org.springframework.util.ReflectionUtils;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
 
 import java.lang.reflect.Field;
 import java.util.*;
@@ -22,40 +25,62 @@ public class DefaultDictDefineRepository implements DictDefineRepository {
     protected static final Map<String, DictDefine> parsedDict = new HashMap<>();
 
     public static void registerDefine(DictDefine define) {
+        if (define == null) {
+            return;
+        }
         parsedDict.put(define.getId(), define);
     }
 
     @SuppressWarnings("all")
-    public static <T extends Enum & EnumDict> ClassDictDefine parseEnumDict(Class<T> type) {
-        log.debug("parse enum dict :{}", type);
+    public static DictDefine parseEnumDict(Class<?> type) {
 
         Dict dict = type.getAnnotation(Dict.class);
+        if (!type.isEnum()) {
+            throw new UnsupportedOperationException("unsupported type " + type);
+        }
+        List<EnumDict<?>> items = new ArrayList<>();
+        for (Object enumConstant : type.getEnumConstants()) {
+            if (enumConstant instanceof EnumDict) {
+                items.add((EnumDict) enumConstant);
+            } else {
+                Enum e = ((Enum) enumConstant);
+                items.add(DefaultItemDefine.builder()
+                        .value(e.name())
+                        .text(e.name())
+                        .ordinal(e.ordinal())
+                        .build());
+            }
+        }
 
-        DefaultClassDictDefine define = new DefaultClassDictDefine();
-        define.setField("");
+        DefaultDictDefine define = new DefaultDictDefine();
         if (dict != null) {
             define.setId(dict.value());
             define.setComments(dict.comments());
             define.setAlias(dict.alias());
         } else {
-            define.setId(type.getSimpleName());
-            define.setAlias(type.getName());
-            define.setComments(type.getSimpleName());
-        }
-       // define.setItems(new ArrayList<>(Arrays.<T>asList(type.getEnumConstants())));
 
+            String id = StringUtils.camelCase2UnderScoreCase(type.getSimpleName()).replace("_", "-");
+            if (id.startsWith("-")) {
+                id = id.substring(1);
+            }
+            define.setId(id);
+            define.setAlias(type.getSimpleName());
+//            define.setComments();
+        }
+        define.setItems(items);
+        log.debug("parse enum dict : {} as : {}", type, define.getId());
         return define;
 
     }
 
     @Override
-    public DictDefine getDefine(String id) {
-        return parsedDict.get(id);
+    public Mono<DictDefine> getDefine(String id) {
+        return Mono.justOrEmpty(parsedDict.get(id));
     }
 
     @Override
-    public List<DictDefine> getAllDefine() {
-        return new ArrayList<>(parsedDict.values());
+    public Flux<DictDefine> getAllDefine() {
+        return Flux.fromIterable(parsedDict.values());
     }
 
     @Override

+ 0 - 1
hsweb-core/src/main/java/org/hswebframework/web/dict/defaults/DefaultItemDefine.java

@@ -21,5 +21,4 @@ public class DefaultItemDefine implements ItemDefine {
     private String value;
     private String comments;
     private int ordinal;
-    private List<ItemDefine> children;
 }

+ 0 - 5
hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/DefaultDimensionService.java

@@ -39,11 +39,6 @@ public class DefaultDimensionService
         entity.setChildren(children);
     }
 
-    @Override
-    public List<DimensionEntity> getChildren(DimensionEntity entity) {
-        return entity.getChildren();
-    }
-
     @Override
     public Flux<DimensionType> getAllType() {
         return dimensionTypeRepository

+ 1 - 1
hsweb-system/hsweb-system-authorization/hsweb-system-authorization-default/src/main/java/org/hswebframework/web/system/authorization/defaults/service/PermissionSynchronization.java

@@ -34,7 +34,7 @@ public class PermissionSynchronization implements CommandLineRunner {
                 .describe(definition.getDescription())
                 .status((byte) 1)
                 .build());
-
+        entity.setId(definition.getId());
 
         Map<String, ActionEntity> oldAction = new HashMap<>();
         if (entity.getActions() != null) {

+ 22 - 0
hsweb-system/hsweb-system-dictionary/pom.xml

@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>hsweb-system</artifactId>
+        <groupId>org.hswebframework.web</groupId>
+        <version>4.0.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>hsweb-system-dictionary</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.hswebframework.web</groupId>
+            <artifactId>hsweb-commons-crud</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+    </dependencies>
+
+</project>

+ 57 - 0
hsweb-system/hsweb-system-dictionary/src/main/java/org/hswebframework/web/dictionary/configuration/DictionaryAutoConfiguration.java

@@ -0,0 +1,57 @@
+package org.hswebframework.web.dictionary.configuration;
+
+import org.hswebframework.web.dictionary.service.CompositeDictDefineRepository;
+import org.hswebframework.web.dictionary.service.DefaultDictionaryItemService;
+import org.hswebframework.web.dictionary.service.DefaultDictionaryService;
+import org.hswebframework.web.dictionary.webflux.WebfluxDictionaryController;
+import org.hswebframework.web.dictionary.webflux.WebfluxDictionaryItemController;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@EnableConfigurationProperties(DictionaryProperties.class)
+public class DictionaryAutoConfiguration {
+
+
+    @Configuration(proxyBeanMethods = false)
+    static class DictionaryServiceConfiguration {
+
+        @Bean
+        public DefaultDictionaryItemService defaultDictionaryItemService() {
+            return new DefaultDictionaryItemService();
+        }
+
+        @Bean
+        public DefaultDictionaryService defaultDictionaryService() {
+            return new DefaultDictionaryService();
+        }
+
+        @Bean
+        public CompositeDictDefineRepository compositeDictDefineRepository(DictionaryProperties properties) {
+            CompositeDictDefineRepository repository = new CompositeDictDefineRepository();
+            properties.doScanEnum()
+                    .stream()
+                    .map(CompositeDictDefineRepository::parseEnumDict)
+                    .forEach(repository::addDefine);
+            return repository;
+        }
+    }
+
+
+    @Configuration
+    @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
+    static class DictionaryWebFluxConfiguration {
+
+        @Bean
+        public WebfluxDictionaryController webfluxDictionaryController(){
+            return new WebfluxDictionaryController();
+        }
+
+        @Bean
+        public WebfluxDictionaryItemController webfluxDictionaryItemController(){
+            return new WebfluxDictionaryItemController();
+        }
+    }
+}

+ 49 - 0
hsweb-system/hsweb-system-dictionary/src/main/java/org/hswebframework/web/dictionary/configuration/DictionaryProperties.java

@@ -0,0 +1,49 @@
+package org.hswebframework.web.dictionary.configuration;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.SneakyThrows;
+import org.hswebframework.web.dict.EnumDict;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
+import org.springframework.core.io.support.ResourcePatternResolver;
+import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
+import org.springframework.core.type.classreading.MetadataReader;
+import org.springframework.core.type.classreading.MetadataReaderFactory;
+import org.springframework.util.ClassUtils;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+@ConfigurationProperties(prefix = "hsweb.dict")
+@Getter
+@Setter
+public class DictionaryProperties {
+
+    private Set<String> enumPackages=new HashSet<>();
+
+    @SneakyThrows
+    public List<Class> doScanEnum(){
+        Set<String> packages = new HashSet<>(enumPackages);
+        packages.add("org.hswebframework.web");
+        CachingMetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory();
+        ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
+        List<Class> classes = new ArrayList<>();
+        for (String enumPackage : packages) {
+            String path = "classpath*:"+ ClassUtils.convertClassNameToResourcePath(enumPackage)+"/**/*.class";
+            Resource[] resources = resourcePatternResolver.getResources(path);
+            for (Resource resource : resources) {
+                MetadataReader reader = metadataReaderFactory.getMetadataReader(resource);
+                Class clazz=Class.forName(reader.getClassMetadata().getClassName());
+                if(clazz.isEnum()&& EnumDict.class.isAssignableFrom(clazz)){
+                    classes.add(clazz);
+                }
+            }
+        }
+        metadataReaderFactory.clearCache();
+        return classes;
+    }
+}

+ 74 - 0
hsweb-system/hsweb-system-dictionary/src/main/java/org/hswebframework/web/dictionary/entity/DictionaryEntity.java

@@ -0,0 +1,74 @@
+/*
+ *  Copyright 2019 http://www.hswebframework.org
+ *  
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *  
+ */
+package org.hswebframework.web.dictionary.entity;
+
+
+import lombok.Getter;
+import lombok.Setter;
+import org.hswebframework.web.api.crud.entity.GenericEntity;
+import org.hswebframework.web.api.crud.entity.RecordCreationEntity;
+import org.hswebframework.web.dict.DictDefine;
+import org.hswebframework.web.dict.defaults.DefaultDictDefine;
+
+import javax.persistence.Column;
+import javax.persistence.Table;
+import javax.validation.constraints.NotBlank;
+import java.util.List;
+
+/**
+ * 数据字典
+ *
+ * @author hsweb-generator-online
+ */
+@Table(name = "s_dictionary")
+@Getter
+@Setter
+public class DictionaryEntity extends GenericEntity<String> implements RecordCreationEntity {
+    //字典名称
+    @Column(nullable = false)
+    @NotBlank(message = "名称不能为空")
+    private String                     name;
+    //分类
+    @Column(length = 32,name = "classified")
+    private String                     classified;
+    //说明
+    @Column(nullable = false)
+    private String                     describe;
+    //创建时间
+    @Column
+    private Long                       createTime;
+    //创建人id
+    @Column(name = "creator_id")
+    private String                     creatorId;
+    //状态
+    @Column(name = "status")
+    private Byte                       status;
+
+    //字段选项
+    private List<DictionaryItemEntity> items;
+
+
+    public DictDefine toDictDefine(){
+       return DefaultDictDefine
+                .builder()
+                .id(this.getId())
+                .alias(this.getName())
+                .comments(this.getDescribe())
+                .items(this.getItems())
+                .build();
+    }
+}

+ 95 - 0
hsweb-system/hsweb-system-dictionary/src/main/java/org/hswebframework/web/dictionary/entity/DictionaryItemEntity.java

@@ -0,0 +1,95 @@
+/*
+ *  Copyright 2019 http://www.hswebframework.org
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.hswebframework.web.dictionary.entity;
+
+import com.alibaba.fastjson.JSONObject;
+import lombok.Getter;
+import lombok.Setter;
+import org.hswebframework.web.api.crud.entity.GenericTreeSortSupportEntity;
+import org.hswebframework.web.dict.EnumDict;
+
+import javax.persistence.Column;
+import javax.persistence.Index;
+import javax.persistence.Table;
+import java.util.List;
+
+/**
+ * 数据字典选项
+ */
+@Getter
+@Setter
+@Table(name = "s_dictionary_item",indexes = {
+        @Index(name = "idx_dic_item_dic_id",columnList = "dic_id"),
+        @Index(name = "idx_dic_item_ordinal",columnList = "ordinal"),
+        @Index(name = "idx_dic_item_path",columnList = "path")
+})
+public class DictionaryItemEntity extends GenericTreeSortSupportEntity<String> implements EnumDict<String> {
+    //字典id
+    @Column(name = "dict_id", length = 32, updatable = false, nullable = false)
+    private String dictId;
+    //名称
+    @Column
+    private String name;
+    //字典值
+    @Column
+    private String value;
+    //字典文本
+    @Column
+    private String text;
+    //字典值类型
+    @Column(name = "value_type")
+    private String valueType;
+    //是否启用
+    @Column
+    private Byte status;
+    //说明
+    @Column
+    private String describe;
+
+    //快速搜索码
+    @Column(name = "search_code")
+    private String searchCode;
+
+    @Column(name = "ordinal", nullable = false, updatable = false)
+    private Integer ordinal;
+
+    @Override
+    public int ordinal() {
+        return ordinal == null ? 0 : ordinal;
+    }
+
+    private List<DictionaryItemEntity> children;
+
+    @Override
+    public Object getWriteJSONObject() {
+        JSONObject jsonObject = new JSONObject();
+        jsonObject.put("id", getId());
+        jsonObject.put("name", getName());
+        jsonObject.put("dictId", getDictId());
+        jsonObject.put("value", getValue());
+        jsonObject.put("text", getText());
+        jsonObject.put("ordinal", getOrdinal());
+        jsonObject.put("sortIndex", getSortIndex());
+        jsonObject.put("parentId", getParentId());
+        jsonObject.put("path", getPath());
+        jsonObject.put("mask", getMask());
+        jsonObject.put("searchCode", getSearchCode());
+        jsonObject.put("status", getStatus());
+        jsonObject.put("describe", getDescribe());
+        return jsonObject;
+    }
+}

+ 15 - 0
hsweb-system/hsweb-system-dictionary/src/main/java/org/hswebframework/web/dictionary/event/ClearDictionaryCacheEvent.java

@@ -0,0 +1,15 @@
+package org.hswebframework.web.dictionary.event;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+/**
+ * @author zhouhao
+ */
+@AllArgsConstructor(staticName = "of")
+@Getter
+@NoArgsConstructor(staticName = "of")
+public class ClearDictionaryCacheEvent {
+    private String dictionaryId;
+}

+ 66 - 0
hsweb-system/hsweb-system-dictionary/src/main/java/org/hswebframework/web/dictionary/service/CompositeDictDefineRepository.java

@@ -0,0 +1,66 @@
+package org.hswebframework.web.dictionary.service;
+
+import lombok.extern.slf4j.Slf4j;
+import org.hswebframework.web.api.crud.entity.QueryParamEntity;
+import org.hswebframework.web.cache.ReactiveCacheManager;
+import org.hswebframework.web.dict.DictDefine;
+import org.hswebframework.web.dict.defaults.DefaultDictDefineRepository;
+import org.hswebframework.web.dictionary.entity.DictionaryEntity;
+import org.hswebframework.web.dictionary.event.ClearDictionaryCacheEvent;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.event.EventListener;
+import org.springframework.util.StringUtils;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+@Slf4j
+public class CompositeDictDefineRepository extends DefaultDictDefineRepository {
+
+    @Autowired
+    private DefaultDictionaryService dictionaryService;
+
+    @Autowired
+    private ReactiveCacheManager cacheManager;
+
+    @EventListener
+    public void handleClearCacheEvent(ClearDictionaryCacheEvent event) {
+        if(StringUtils.isEmpty(event.getDictionaryId())){
+            cacheManager.<DictDefine>getCache("dic-define")
+                    .clear()
+                    .doOnSuccess(r -> log.info("clear all dic cache success"))
+                    .subscribe();
+        }else{
+            cacheManager.<DictDefine>getCache("dic-define")
+                    .evict(event.getDictionaryId())
+                    .doOnSuccess(r -> log.info("clear dict [{}] cache success", event.getDictionaryId()))
+                    .subscribe();
+        }
+
+    }
+
+    @Override
+    public Mono<DictDefine> getDefine(String id) {
+        return super.getDefine(id)
+                .switchIfEmpty(Mono.defer(() -> cacheManager.<DictDefine>getCache("dic-define")
+                        .mono(id)
+                        .onCacheMissResume(getFromDb(id))));
+    }
+
+    @Override
+    public Flux<DictDefine> getAllDefine() {
+        return Flux.concat(super.getAllDefine(), QueryParamEntity
+                .newQuery()
+                .noPaging()
+                .execute(dictionaryService::findAllDetail)
+                .map(DictionaryEntity::toDictDefine));
+    }
+
+    private Mono<DictDefine> getFromDb(String id) {
+        return dictionaryService
+                .findDetailById(id)
+                .filter(e -> Byte.valueOf((byte) 1).equals(e.getStatus()))
+                .map(DictionaryEntity::toDictDefine);
+    }
+
+
+}

+ 76 - 0
hsweb-system/hsweb-system-dictionary/src/main/java/org/hswebframework/web/dictionary/service/DefaultDictionaryItemService.java

@@ -0,0 +1,76 @@
+package org.hswebframework.web.dictionary.service;
+
+import org.hswebframework.ezorm.rdb.mapping.ReactiveDelete;
+import org.hswebframework.ezorm.rdb.mapping.ReactiveUpdate;
+import org.hswebframework.ezorm.rdb.mapping.defaults.SaveResult;
+import org.hswebframework.web.crud.service.GenericReactiveCrudService;
+import org.hswebframework.web.crud.service.ReactiveTreeSortEntityService;
+import org.hswebframework.web.dictionary.entity.DictionaryItemEntity;
+import org.hswebframework.web.dictionary.event.ClearDictionaryCacheEvent;
+import org.hswebframework.web.id.IDGenerator;
+import org.reactivestreams.Publisher;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationEventPublisher;
+import reactor.core.publisher.Mono;
+
+import java.util.Collection;
+import java.util.List;
+
+public class DefaultDictionaryItemService extends GenericReactiveCrudService<DictionaryItemEntity, String>
+        implements ReactiveTreeSortEntityService<DictionaryItemEntity, String> {
+
+    @Autowired
+    public ApplicationEventPublisher eventPublisher;
+
+    @Override
+    public IDGenerator<String> getIDGenerator() {
+        return IDGenerator.SNOW_FLAKE_STRING;
+    }
+
+    @Override
+    public void setChildren(DictionaryItemEntity entity, List<DictionaryItemEntity> children) {
+        entity.setChildren(children);
+    }
+
+    @Override
+    public Mono<Integer> insert(Publisher<DictionaryItemEntity> entityPublisher) {
+        return super.insert(entityPublisher)
+                .doOnSuccess(r->eventPublisher.publishEvent(ClearDictionaryCacheEvent.of()));
+    }
+
+    @Override
+    public Mono<Integer> insertBatch(Publisher<? extends Collection<DictionaryItemEntity>> entityPublisher) {
+        return super.insertBatch(entityPublisher)
+                .doOnSuccess(r->eventPublisher.publishEvent(ClearDictionaryCacheEvent.of()));
+    }
+
+    @Override
+    public Mono<Integer> updateById(String id, Mono<DictionaryItemEntity> entityPublisher) {
+        return super.updateById(id,entityPublisher)
+                .doOnSuccess(r->eventPublisher.publishEvent(ClearDictionaryCacheEvent.of()));
+    }
+
+    @Override
+    public Mono<Integer> deleteById(Publisher<String> idPublisher) {
+        return super.deleteById(idPublisher)
+                .doOnSuccess(r->eventPublisher.publishEvent(ClearDictionaryCacheEvent.of()));
+    }
+
+    @Override
+    public Mono<SaveResult> save(Publisher<DictionaryItemEntity> entityPublisher) {
+        return super.save(entityPublisher)
+                .doOnSuccess(r->eventPublisher.publishEvent(ClearDictionaryCacheEvent.of()));
+    }
+
+    @Override
+    public ReactiveUpdate<DictionaryItemEntity> createUpdate() {
+        return super.createUpdate()
+                .onExecute(r->r.doOnSuccess(l->eventPublisher.publishEvent(ClearDictionaryCacheEvent.of())));
+    }
+
+    @Override
+    public ReactiveDelete createDelete() {
+        return super.createDelete()
+                .onExecute(r->r.doOnSuccess(l->eventPublisher.publishEvent(ClearDictionaryCacheEvent.of())));
+    }
+}

+ 111 - 0
hsweb-system/hsweb-system-dictionary/src/main/java/org/hswebframework/web/dictionary/service/DefaultDictionaryService.java

@@ -0,0 +1,111 @@
+package org.hswebframework.web.dictionary.service;
+
+import org.hswebframework.ezorm.rdb.mapping.ReactiveDelete;
+import org.hswebframework.ezorm.rdb.mapping.ReactiveUpdate;
+import org.hswebframework.ezorm.rdb.mapping.defaults.SaveResult;
+import org.hswebframework.web.api.crud.entity.QueryParamEntity;
+import org.hswebframework.web.api.crud.entity.SortSupportEntity;
+import org.hswebframework.web.crud.service.GenericReactiveCrudService;
+import org.hswebframework.web.dictionary.entity.DictionaryEntity;
+import org.hswebframework.web.dictionary.entity.DictionaryItemEntity;
+import org.hswebframework.web.dictionary.event.ClearDictionaryCacheEvent;
+import org.reactivestreams.Publisher;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationEventPublisher;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+import java.util.Collection;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+public class DefaultDictionaryService extends GenericReactiveCrudService<DictionaryEntity, String> {
+
+    @Autowired
+    private DefaultDictionaryItemService itemService;
+
+    @Autowired
+    private ApplicationEventPublisher eventPublisher;
+
+    @Override
+    public Mono<Integer> insert(Publisher<DictionaryEntity> entityPublisher) {
+        return super.insert(entityPublisher)
+                .doOnSuccess(r->eventPublisher.publishEvent(ClearDictionaryCacheEvent.of()));
+    }
+
+    @Override
+    public Mono<Integer> insertBatch(Publisher<? extends Collection<DictionaryEntity>> entityPublisher) {
+        return super.insertBatch(entityPublisher)
+                .doOnSuccess(r->eventPublisher.publishEvent(ClearDictionaryCacheEvent.of()));
+    }
+
+    @Override
+    public Mono<Integer> updateById(String id, Mono<DictionaryEntity> entityPublisher) {
+        return super.updateById(id,entityPublisher)
+                .doOnSuccess(r->eventPublisher.publishEvent(ClearDictionaryCacheEvent.of()));
+    }
+
+    @Override
+    public Mono<Integer> deleteById(Publisher<String> idPublisher) {
+        return super.deleteById(idPublisher)
+                .doOnSuccess(r->eventPublisher.publishEvent(ClearDictionaryCacheEvent.of()));
+    }
+
+    @Override
+    public Mono<SaveResult> save(Publisher<DictionaryEntity> entityPublisher) {
+        return super.save(entityPublisher)
+                .doOnSuccess(r->eventPublisher.publishEvent(ClearDictionaryCacheEvent.of()));
+    }
+
+    @Override
+    public ReactiveUpdate<DictionaryEntity> createUpdate() {
+        return super.createUpdate()
+                .onExecute(r->r.doOnSuccess(l->eventPublisher.publishEvent(ClearDictionaryCacheEvent.of())));
+    }
+
+    @Override
+    public ReactiveDelete createDelete() {
+        return super.createDelete()
+                .onExecute(r->r.doOnSuccess(l->eventPublisher.publishEvent(ClearDictionaryCacheEvent.of())));
+    }
+
+
+    public Mono<DictionaryEntity> findDetailById(String id) {
+        return findById(Mono.just(id))
+                .zipWith(itemService
+                                .createQuery()
+                                .where(DictionaryItemEntity::getDictId, id)
+                                .fetch()
+                                .collectList(),
+                        (dic, items) -> {
+                            dic.setItems(items);
+                            return dic;
+                        });
+    }
+
+    public Flux<DictionaryEntity> findAllDetail(QueryParamEntity paramEntity) {
+        /*
+            1. 查询出所有字典并以ID为key转为map
+            2. 查询出所有字段选项并按dicId分组
+            3. 根据分组后的key(dictId)获取字段
+            4. 将2的分组结果放到字典里
+         */
+        return createQuery()
+                .setParam(paramEntity)
+                .fetch()
+                .collect(Collectors.toMap(DictionaryEntity::getId, Function.identity())) //.1
+                .flatMapMany(dicMap ->
+                        itemService.createQuery()
+                                .fetch()
+                                .groupBy(DictionaryItemEntity::getDictId)//.2
+                                .flatMap(group -> Mono
+                                        .justOrEmpty(dicMap.get(group.key())) //.3
+                                        .zipWhen(dict -> group.collectList(),
+                                                (dict, items) -> {
+                                                    items.sort(SortSupportEntity::compareTo);
+                                                    dict.setItems(items);  //.4
+                                                    return dict;
+                                                })));
+    }
+
+}

+ 48 - 0
hsweb-system/hsweb-system-dictionary/src/main/java/org/hswebframework/web/dictionary/webflux/WebfluxDictionaryController.java

@@ -0,0 +1,48 @@
+package org.hswebframework.web.dictionary.webflux;
+
+import org.hswebframework.web.authorization.annotation.Authorize;
+import org.hswebframework.web.authorization.annotation.Resource;
+import org.hswebframework.web.crud.service.ReactiveCrudService;
+import org.hswebframework.web.crud.web.reactive.ReactiveServiceCrudController;
+import org.hswebframework.web.dict.DictDefine;
+import org.hswebframework.web.dict.DictDefineRepository;
+import org.hswebframework.web.dict.EnumDict;
+import org.hswebframework.web.dictionary.entity.DictionaryEntity;
+import org.hswebframework.web.dictionary.service.DefaultDictionaryService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import reactor.core.publisher.Flux;
+
+
+@RestController
+@RequestMapping("/dictionary")
+@Resource(id = "dictionary", name = "数据字典")
+public class WebfluxDictionaryController implements ReactiveServiceCrudController<DictionaryEntity, String> {
+
+    @Autowired
+    private DefaultDictionaryService dictionaryService;
+
+    @Autowired
+    private DictDefineRepository repository;
+
+    @Override
+    public ReactiveCrudService<DictionaryEntity, String> getService() {
+        return dictionaryService;
+    }
+
+    @GetMapping("/{id:.+}/items")
+    @Authorize(merge = false)
+    public Flux<EnumDict<?>> getItemDefineById(@PathVariable String id) {
+        return repository.getDefine(id)
+                .flatMapIterable(DictDefine::getItems);
+    }
+
+    @GetMapping("/_all")
+    @Authorize(merge = false)
+    public Flux<DictDefine> getAllDict() {
+        return repository.getAllDefine();
+    }
+}

+ 26 - 0
hsweb-system/hsweb-system-dictionary/src/main/java/org/hswebframework/web/dictionary/webflux/WebfluxDictionaryItemController.java

@@ -0,0 +1,26 @@
+package org.hswebframework.web.dictionary.webflux;
+
+import org.hswebframework.web.authorization.annotation.Resource;
+import org.hswebframework.web.crud.service.ReactiveCrudService;
+import org.hswebframework.web.crud.web.reactive.ReactiveServiceCrudController;
+import org.hswebframework.web.dictionary.entity.DictionaryItemEntity;
+import org.hswebframework.web.dictionary.service.DefaultDictionaryItemService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+
+@RestController
+@RequestMapping("/dictionary-item")
+@Resource(id = "dictionary", name = "数据字典")
+public class WebfluxDictionaryItemController implements ReactiveServiceCrudController<DictionaryItemEntity, String> {
+
+    @Autowired
+    private DefaultDictionaryItemService dictionaryItemService;
+
+    @Override
+    public ReactiveCrudService<DictionaryItemEntity, String> getService() {
+        return dictionaryItemService;
+    }
+
+}

+ 3 - 0
hsweb-system/hsweb-system-dictionary/src/main/resources/META-INF/spring.factories

@@ -0,0 +1,3 @@
+# Auto Configure
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
+org.hswebframework.web.dictionary.configuration.DictionaryAutoConfiguration

+ 1 - 0
hsweb-system/pom.xml

@@ -14,6 +14,7 @@
     <modules>
         <module>hsweb-system-authorization</module>
         <module>hsweb-system-file</module>
+        <module>hsweb-system-dictionary</module>
     </modules>
     <artifactId>hsweb-system</artifactId>
 

+ 5 - 0
pom.xml

@@ -274,6 +274,11 @@
             <artifactId>spring-context-indexer</artifactId>
 <!--            <scope>provided</scope>-->
         </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-configuration-processor</artifactId>
+            <scope>provided</scope>
+        </dependency>
         <dependency>
             <groupId>org.codehaus.groovy</groupId>
             <artifactId>groovy-all</artifactId>