Browse Source

优化字典注册。增加数组,使用位运算进行多选查询

zhou-hao 7 years ago
parent
commit
3ac037528c

+ 45 - 0
hsweb-commons/hsweb-commons-dao/hsweb-commons-dao-mybatis/src/main/java/org/hswebframework/web/dao/mybatis/EnumDictHandlerRegister.java

@@ -20,10 +20,12 @@ import org.springframework.core.type.classreading.MetadataReaderFactory;
 import org.springframework.util.ClassUtils;
 
 import java.io.IOException;
+import java.lang.reflect.Array;
 import java.sql.CallableStatement;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
+import java.util.List;
 
 import static org.springframework.util.StringUtils.tokenizeToStringArray;
 
@@ -42,6 +44,7 @@ public class EnumDictHandlerRegister {
                 ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
     }
 
+    @SuppressWarnings("all")
     public static void register(String[] packages) {
         if (typeHandlerRegistry == null) {
             log.error("请在spring容器初始化后再调用此方法!");
@@ -59,7 +62,11 @@ public class EnumDictHandlerRegister {
                         if (enumType.isEnum() && EnumDict.class.isAssignableFrom(enumType)) {
                             log.debug("register enum dict:{}", enumType);
                             DefaultDictDefineRepository.registerDefine(DefaultDictDefineRepository.parseEnumDict(enumType));
+                            //注册枚举类型
                             typeHandlerRegistry.register(enumType, new EnumDictHandler(enumType));
+
+                            //注册枚举数组类型
+                            typeHandlerRegistry.register(Array.newInstance(enumType, 0).getClass(), new EnumDictArrayHandler(enumType));
                         }
                     } catch (Exception ignore) {
 
@@ -71,6 +78,44 @@ public class EnumDictHandlerRegister {
         }
     }
 
+    @Getter
+    @Setter
+    @AllArgsConstructor
+    @MappedJdbcTypes({JdbcType.NUMERIC, JdbcType.TINYINT, JdbcType.INTEGER, JdbcType.BIGINT})
+    static class EnumDictArrayHandler<T extends Enum & EnumDict> implements TypeHandler<Object[]> {
+
+        private Class<T> type;
+
+        @Override
+        public void setParameter(PreparedStatement ps, int i, Object[] parameter, JdbcType jdbcType) throws SQLException {
+            T[] ts = ((T[]) parameter);
+            ps.setLong(i, EnumDict.toBit(type, ts));
+        }
+
+        @Override
+        public Object[] getResult(ResultSet rs, String columnName) throws SQLException {
+            return toArray(rs.getLong(columnName));
+        }
+
+        @Override
+        public Object[] getResult(ResultSet rs, int columnIndex) throws SQLException {
+            return toArray(rs.getLong(columnIndex));
+        }
+
+        @Override
+        public Object[] getResult(CallableStatement cs, int columnIndex) throws SQLException {
+            return toArray(cs.getLong(columnIndex));
+        }
+
+        private Object[] toArray(Long value) {
+            if (null == value) {
+                return null;
+            }
+            List<T> ts = EnumDict.getByBit(getType(), value);
+            return ts.toArray((Object[]) Array.newInstance(type, ts.size()));
+        }
+    }
+
     @Getter
     @Setter
     @AllArgsConstructor

+ 37 - 2
hsweb-core/src/main/java/org/hswebframework/web/dict/EnumDict.java

@@ -1,10 +1,13 @@
 package org.hswebframework.web.dict;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Optional;
 import java.util.function.Predicate;
 
 /**
- * 枚举字典,使用枚举来实现数据字典,可通过集成此接口来实现一些有趣的功能
+ * 枚举字典,使用枚举来实现数据字典,可通过集成此接口来实现一些有趣的功能.
+ * ⚠️:如果使用了位运算来判断枚举,枚举数量不要超过64个,且顺序不要随意变动!
  *
  * @author zhouhao
  * @see 3.0
@@ -26,6 +29,17 @@ public interface EnumDict<V> {
      */
     String getText();
 
+    /**
+     * {@link Enum#ordinal}
+     *
+     * @return 枚举序号, 如果枚举顺序改变, 此值将被变动
+     */
+    int ordinal();
+
+    default long getBit() {
+        return 1L << (long) ordinal();
+    }
+
     /**
      * 对比是否和value相等,对比地址,值,value转为string忽略大小写对比,text忽略大小写对比
      *
@@ -39,6 +53,9 @@ public interface EnumDict<V> {
                 || getText().equalsIgnoreCase(String.valueOf(v));
     }
 
+    default boolean in(long bit) {
+        return (bit & getBit()) != 0;
+    }
 
     /**
      * 枚举选项的描述,对一个选项进行详细的描述有时候是必要的.默认值为{@link this#getText()}
@@ -92,6 +109,24 @@ public interface EnumDict<V> {
      * @see this#find(Class, Predicate)
      */
     static <T extends Enum & EnumDict> Optional<T> find(Class<T> type, Object target) {
-        return find(type, v->v.eq(target));
+        return find(type, v -> v.eq(target));
+    }
+
+    static <T extends Enum & EnumDict> long toBit(Class<T> type, T... t) {
+        long value = 0;
+        for (T t1 : t) {
+            value |= t1.getBit();
+        }
+        return value;
+    }
+
+    static <T extends Enum & EnumDict> List<T> getByBit(Class<T> tClass, long mask) {
+        List<T> arr = new ArrayList<>();
+        for (T t : tClass.getEnumConstants()) {
+            if (t.in(mask)) {
+                arr.add(t);
+            }
+        }
+        return arr;
     }
 }

+ 16 - 12
hsweb-core/src/test/java/org/hswebframework/web/dict/DictDefineTest.java

@@ -1,22 +1,15 @@
 package org.hswebframework.web.dict;
 
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.parser.DefaultJSONParser;
-import com.alibaba.fastjson.parser.ParserConfig;
-import com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer;
-import com.alibaba.fastjson.parser.deserializer.ObjectDeserializer;
-import com.alibaba.fastjson.serializer.SerializerFeature;
 import org.hswebframework.web.dict.defaults.DefaultClassDictDefine;
 import org.hswebframework.web.dict.defaults.DefaultDictDefineRepository;
 import org.hswebframework.web.dict.defaults.DefaultDictSupportApi;
 import org.junit.Assert;
 import org.junit.Test;
 
-import java.lang.reflect.Modifier;
-import java.lang.reflect.Type;
 import java.util.HashMap;
 import java.util.List;
 
+import static org.hswebframework.web.dict.EnumDict.*;
 import static org.junit.Assert.*;
 
 /**
@@ -32,16 +25,27 @@ public class DictDefineTest {
     @Test
     public void testEnumDict() {
 
-        Assert.assertEquals(UserCode.SIMPLE, EnumDict.findByValue(UserCode.class, UserCode.SIMPLE.getValue()).orElse(null));
+        Assert.assertEquals(UserCode.SIMPLE, findByValue(UserCode.class, UserCode.SIMPLE.getValue()).orElse(null));
 
-        Assert.assertEquals(UserCode.SIMPLE, EnumDict.findByText(UserCode.class, UserCode.SIMPLE.getText()).orElse(null));
+        Assert.assertEquals(UserCode.SIMPLE, findByText(UserCode.class, UserCode.SIMPLE.getText()).orElse(null));
+
+        Assert.assertEquals(UserCode.SIMPLE, find(UserCode.class, UserCode.SIMPLE.getText()).orElse(null));
+
+        long bit = toBit(UserCode.class, UserCode.values());
+
+        System.out.println(bit);
+
+        for (UserCode userCode : UserCode.values()) {
+            Assert.assertTrue(userCode.in(bit));
+        }
+
+        List<UserCode> codes = getByBit(UserCode.class, bit);
 
-        Assert.assertEquals(UserCode.SIMPLE, EnumDict.find(UserCode.class, UserCode.SIMPLE.getText()).orElse(null));
     }
 
     @Test
     public void testParse() {
-
+//        JSON.toJSONString("",SerializerFeature.PrettyFormat)
         DefaultClassDictDefine define = DefaultClassDictDefine.builder()
                 .id("test-code")
                 .field("code")

+ 63 - 1
hsweb-core/src/test/java/org/hswebframework/web/dict/UserCode.java

@@ -10,7 +10,69 @@ import lombok.Getter;
 public enum UserCode implements EnumDict {
 
     SIMPLE("SIMPLE", "TEXT", "测试"),
-    TEST("TEST", "TEST", "测试");
+    TEST("TEST", "TEST", "测试"),
+    CODE0("TEST0","TEST0","TEST0"),
+    CODE1("TEST1","TEST1","TEST1"),
+    CODE2("TEST2","TEST2","TEST2"),
+    CODE3("TEST3","TEST3","TEST3"),
+    CODE4("TEST4","TEST4","TEST4"),
+    CODE5("TEST5","TEST5","TEST5"),
+    CODE6("TEST6","TEST6","TEST6"),
+    CODE7("TEST7","TEST7","TEST7"),
+    CODE8("TEST8","TEST8","TEST8"),
+    CODE9("TEST9","TEST9","TEST9"),
+    CODE10("TEST10","TEST10","TEST10"),
+    CODE11("TEST11","TEST11","TEST11"),
+    CODE12("TEST12","TEST12","TEST12"),
+    CODE13("TEST13","TEST13","TEST13"),
+    CODE14("TEST14","TEST14","TEST14"),
+    CODE15("TEST15","TEST15","TEST15"),
+    CODE16("TEST16","TEST16","TEST16"),
+    CODE17("TEST17","TEST17","TEST17"),
+    CODE18("TEST18","TEST18","TEST18"),
+    CODE19("TEST19","TEST19","TEST19"),
+    CODE20("TEST20","TEST20","TEST20"),
+    CODE21("TEST21","TEST21","TEST21"),
+    CODE22("TEST22","TEST22","TEST22"),
+    CODE23("TEST23","TEST23","TEST23"),
+    CODE24("TEST24","TEST24","TEST24"),
+    CODE25("TEST25","TEST25","TEST25"),
+    CODE26("TEST26","TEST26","TEST26"),
+    CODE27("TEST27","TEST27","TEST27"),
+    CODE28("TEST28","TEST28","TEST28"),
+    CODE29("TEST29","TEST29","TEST29"),
+    CODE30("TEST30","TEST30","TEST30"),
+    CODE31("TEST31","TEST31","TEST31"),
+    CODE32("TEST32","TEST32","TEST32"),
+    CODE33("TEST33","TEST33","TEST33"),
+    CODE34("TEST34","TEST34","TEST34"),
+    CODE35("TEST35","TEST35","TEST35"),
+    CODE36("TEST36","TEST36","TEST36"),
+    CODE37("TEST37","TEST37","TEST37"),
+    CODE38("TEST38","TEST38","TEST38"),
+    CODE39("TEST39","TEST39","TEST39"),
+    CODE40("TEST40","TEST40","TEST40"),
+    CODE41("TEST41","TEST41","TEST41"),
+    CODE42("TEST42","TEST42","TEST42"),
+    CODE43("TEST43","TEST43","TEST43"),
+    CODE44("TEST44","TEST44","TEST44"),
+    CODE45("TEST45","TEST45","TEST45"),
+    CODE46("TEST46","TEST46","TEST46"),
+    CODE47("TEST47","TEST47","TEST47"),
+    CODE48("TEST48","TEST48","TEST48"),
+    CODE49("TEST49","TEST49","TEST49"),
+    CODE50("TEST50","TEST50","TEST50"),
+    CODE51("TEST51","TEST51","TEST51"),
+    CODE52("TEST52","TEST52","TEST52"),
+    CODE53("TEST53","TEST53","TEST53"),
+    CODE54("TEST54","TEST54","TEST54"),
+    CODE55("TEST55","TEST55","TEST55"),
+    CODE56("TEST56","TEST56","TEST56"),
+    CODE57("TEST57","TEST57","TEST57"),
+    CODE58("TEST58","TEST58","TEST58"),
+    CODE59("TEST59","TEST59","TEST59"),
+    CODE60("TEST60","TEST60","TEST60"),
+    ;
 
 
     private String value;