后端通常需要为了不使用魔法值而去定义枚举类,而枚举类又经常需要被当做数据字典传给前端。次套解决方案就是为了解决枚举值的统一管理的问题,枚举类只要实现
EnumService
接口,就可以集成这套方案。
EnumDictionary - 数据字典对象
import java.io.Serializable;
/**
* 数据字典
*
* @author: Neo
* @date: 2020/12/31 15:59
* @version: 1.0
*/
public class EnumDictionary implements Serializable {
private static final long serialVersionUID = -1113764940965416458L;
private Integer code;
private String name;
private String message;
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
BaseEnum - 枚举接口
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* @author: Neo
* @date: 2020/12/21 11:09
* @version: 1.0
*/
public interface BaseEnum {
String CODE = "code";
String MESSAGE = "message";
String ENUM_CLASS_TAIL = "Enum";
String DEFAULT_SEPARATOR = ",";
/**
* 编码
*
* @return
*/
Integer getCode();
/**
* 详情
*
* @return
*/
String getMessage();
/**
* 是否需要以字典的形式被加载,默认:false
*
* @return
*/
default boolean isLoadDictionary() {
return false;
}
/**
* 字典名称
*
* @return
*/
default String dictionaryName() {
return this.getClass().getSimpleName();
}
/**
* 是否使用默认方式生成字典,默认:false
*
* @return
*/
default boolean isDefaultAssembly() {
return false;
}
/**
* 自定义字典数据
*
* @return
*/
default List<EnumDictionary> dictionaries() {
return Collections.EMPTY_LIST;
}
/**
* 当前对象的 code 是否 和参数中的 code 相等
*
* @param code
* @return
*/
default boolean equalsCode(Integer code) {
return Objects.equals(this.getCode(), code);
}
/**
* 当前对象是否和已知对象不等
*
* @param e
* @return
*/
default boolean notEquals(BaseEnum e) {
return this != e;
}
// =================================【上为接口】=================================
// ============================================================================
// =================================【下为方法】=================================
/**
* 通过 code 获取指定 枚举类型中的 枚举对象
*
* @param clazz
* @param code
* @param <T>
* @return
*/
static <T extends BaseEnum> T getByCode(Class<T> clazz, Integer code) {
if (Objects.isNull(clazz) || Objects.isNull(code)) {
return null;
}
for (T e : clazz.getEnumConstants()) {
if (e.equalsCode(code)) {
return e;
}
}
return null;
}
/**
* 通过 code 获取指定 枚举类型中的 detail
*
* @param enumClass
* @param code
* @param <T>
* @return
*/
static <T extends BaseEnum> String getMessageByCode(Class<T> enumClass, Integer code) {
BaseEnum e = getByCode(enumClass, code);
if (null == e) {
return null;
}
return e.getMessage();
}
/**
* 枚举 转 List
*
* @param enums
* @param <T>
* @return
*/
static <T extends BaseEnum> List<Map<String, String>> toList(T[] enums) {
if (ArrayUtils.isEmpty(enums)) {
return Collections.EMPTY_LIST;
}
List<Map<String, String>> result = new ArrayList<>(enums.length);
Map<String, String> map;
for (T e : enums) {
map = new HashMap<>(2);
map.put(CODE, String.valueOf(e.getCode()));
map.put(MESSAGE, e.getMessage());
result.add(map);
}
return result;
}
/**
* 枚举 转 Map
*
* @param enums
* @param <T>
* @return
*/
static <T extends BaseEnum> Map<Integer, String> toMap(T[] enums) {
if (ArrayUtils.isEmpty(enums)) {
return Collections.EMPTY_MAP;
}
Map<Integer, String> result = new HashMap<>(enums.length);
for (T e : enums) {
result.put(e.getCode(), e.getMessage());
}
return result;
}
/**
* 转枚举 Map
*
* @param enums
* @param <T>
* @return
*/
static <T extends BaseEnum> Map<Integer, T> toEnumMap(T[] enums) {
if (ArrayUtils.isEmpty(enums)) {
return Collections.EMPTY_MAP;
}
Map<Integer, T> result = new HashMap<>(enums.length);
for (T e : enums) {
result.put(e.getCode(), e);
}
return result;
}
/**
* 枚举转字典集合
*
* @param enums
* @param <T>
* @return
*/
static <T extends BaseEnum> List<EnumDictionary> toDictionaries(T[] enums) {
if (ArrayUtils.isEmpty(enums)) {
return Collections.EMPTY_LIST;
}
List<EnumDictionary> result = new ArrayList<>(enums.length);
for (T e : enums) {
result.add(toDictionary(e));
}
return result;
}
/**
* 枚举转字典
*
* @param e
* @param <T>
* @return
*/
static <T extends BaseEnum> EnumDictionary toDictionary(T e) {
if (Objects.isNull(e)) {
return null;
}
EnumDictionary result = new EnumDictionary();
result.setCode(e.getCode());
result.setName(e.toString());
result.setMessage(e.getMessage());
return result;
}
/**
* 清除枚举类尾巴
*
* @param clazz
* @return
*/
static String clearEnumClassTail(Class<?> clazz) {
return Objects.isNull(clazz) ? StringUtils.EMPTY : clearEnumClassTail(clazz.getSimpleName());
}
/**
* 清除枚举类尾巴
*
* @param className
* @return
*/
static String clearEnumClassTail(String className) {
return StringUtils.removeEndIgnoreCase(className, ENUM_CLASS_TAIL);
}
/**
* 通过 code 获取实例
*
* @param map
* @param code
* @param <T>
* @return
*/
static <T extends BaseEnum> T of(Map<Integer, T> map, Integer code) {
if (MapUtils.isEmpty(map) || Objects.isNull(code)) {
return null;
}
return map.get(code);
}
/**
* 通过 code 获取详情
*
* @param map
* @param code
* @param <T>
* @return
*/
static <T extends BaseEnum> String getMessageByCode(Map<Integer, T> map, Integer code) {
T t = of(map, code);
return Objects.nonNull(t) ? t.getMessage() : StringUtils.EMPTY;
}
/**
* 通过 codes 批量获取详情
*
* @param map
* @param codes
* @param <T>
* @return
*/
static <T extends BaseEnum> String getMessagesByCodes(Map<Integer, T> map, String codes) {
return getMessagesByCodes(map, codes, DEFAULT_SEPARATOR);
}
/**
* 通过 codes 批量获取详情
*
* @param map
* @param codes
* @param separator
* @param <T>
* @return
*/
static <T extends BaseEnum> String getMessagesByCodes(Map<Integer, T> map, String codes, String separator) {
if (StringUtils.isBlank(codes) || Objects.isNull(separator)) {
return StringUtils.EMPTY;
}
List<String> codeList = Splitter.on(separator).trimResults().omitEmptyStrings().splitToList(codes);
return getMessagesByCodes(map, codeList);
}
/**
* 通过 codes 批量获取详情
*
* @param map
* @param codes
* @param <T>
* @return
*/
static <T extends BaseEnum> String getMessagesByCodes(Map<Integer, T> map, List<String> codes) {
return Joiner.on(DEFAULT_SEPARATOR).join(getMessageListByCodes(map, codes));
}
/**
* 通过 codes 批量获取详情
*
* @param map
* @param codes
* @param <T>
* @return
*/
static <T extends BaseEnum> List<String> getMessageListByCodes(Map<Integer, T> map, List<String> codes) {
if (CollectionUtils.isEmpty(codes)) {
return Collections.EMPTY_LIST;
}
List<String> result = new ArrayList<>(CollectionUtils.size(codes));
for (String code : codes) {
result.add(getMessageByCode(map, Integer.valueOf(code)));
}
return result;
}
}
枚举类使用示例:YesOrNoEnum
import com.ceair.shoppingservice.base.eunms.BaseEnum;
import java.util.Objects;
/**
* 是否枚举
*
* @author: Neo
* @date: 2021/1/7 14:56
* @version: 1.0
*/
public enum YesOrNoEnum implements BaseEnum {
NO(0, "否"),
YES(1, "是");
private Integer code;
private String message;
YesOrNoEnum(int code, String message) {
this.code = code;
this.message = message;
}
public void setCode(int code) {
this.code = code;
}
public void setMessage(String message) {
this.message = message;
}
@Override
public Integer getCode() {
return this.code;
}
@Override
public String getMessage() {
return this.message;
}
@Override
public boolean isLoadDictionary() {
return true;
}
@Override
public String dictionaryName() {
return BaseEnum.clearEnumClassTail(this.getClass());
}
@Override
public boolean isDefaultAssembly() {
return true;
}
public static boolean isYes(int code) {
return Objects.equals(YES.getCode(), code);
}
public static boolean isNo(int code) {
return Objects.equals(NO.getCode(), code);
}
}
EnumDictionaryManager - 枚举字典管理器
import com.ceair.shoppingservice.base.exception.BaseBusinessException;
import com.ceair.shoppingservice.base.response.ResultCode;
import com.google.common.base.Splitter;
import com.google.common.base.Stopwatch;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.type.filter.AssignableTypeFilter;
import javax.annotation.PostConstruct;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
/**
* 枚举字典管理器
*
* @author: Neo
* @date: 2020/12/31 17:16
* @version: 1.0
*/
@Slf4j
public class EnumDictionaryManager {
public static final Map<String, List<EnumDictionary>> ENUMS = new ConcurrentHashMap<>(16);
/**
* 多个 , 号隔开
*/
@Value("${enum.dictionary.manager.scanner.package:}")
private String scannerPackage;
@PostConstruct
public void postConstruct() {
initDictionary();
}
/**
* 初始化字典
*
* @author: Neo
* @date 2021/1/19 14:43
* @version: 1.0
*/
private void initDictionary() {
log.info("枚举字典管理器【开始】");
Stopwatch stopwatch = Stopwatch.createStarted();
// 初始化枚举字典,默认仅扫描当前包路径下的类,可通过配置实现自定义
if (StringUtils.isBlank(scannerPackage)) {
scannerPackage = this.getClass().getPackage().getName();
}
List<String> scannerPackages = Splitter.on(";").omitEmptyStrings().trimResults().splitToList(scannerPackage);
scannerPackages.forEach(this::initDictionary);
log.info("枚举字典管理器【结束】,初始化耗时:{}/ms", stopwatch.elapsed(TimeUnit.MILLISECONDS));
}
/**
* 初始化字典
*
* @author: Neo
* @date 2021/1/19 14:43
* @version: 1.0
*/
private void initDictionary(String packageName) {
log.info("开始加载 [{}] 包下的枚举", packageName);
ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false);
provider.addIncludeFilter(new AssignableTypeFilter(BaseEnum.class));
Set<BeanDefinition> beans = provider.findCandidateComponents(packageName);
for (BeanDefinition bean : beans) {
try {
Class<? extends BaseEnum> clazz = (Class<? extends BaseEnum>) Class.forName(bean.getBeanClassName());
loadDictionary(clazz);
} catch (ClassNotFoundException e) {
log.error("ClassNotFoundException : [{}]", bean.getBeanClassName());
}
}
}
private <T extends BaseEnum> void loadDictionary(Class<? extends BaseEnum> e) {
BaseEnum[] constants = e.getEnumConstants();
Optional<BaseEnum> optional = Arrays.stream(constants).findFirst();
if (!optional.isPresent()) {
return;
}
BaseEnum baseEnum = optional.get();
// 字典是否需要被加载
if (!baseEnum.isLoadDictionary()) {
return;
}
BaseBusinessException.ifThrow(ENUMS.containsKey(baseEnum.dictionaryName()), ResultCode.ENUM_DICTIONARY_NAME_EXIST);
String dictionaryName = baseEnum.dictionaryName();
// 字典获取策略
ENUMS.put(dictionaryName, baseEnum.isDefaultAssembly() ? defaultAssembly(constants) : baseEnum.dictionaries());
log.info("已加载字典[{}] ---> [{}]", baseEnum.getClass(), dictionaryName);
}
public Map<String, List<EnumDictionary>> ENUMS() {
return ENUMS;
}
/**
* 默认组装字典策略
*
* @param enumItems
* @return
*/
public static List<EnumDictionary> defaultAssembly(BaseEnum[] enumItems) {
return BaseEnum.toDictionaries(enumItems);
}
/**
* 获取字典通过字典名称
*
* @param dictionaryName
* @return
*/
public static List<EnumDictionary> getDictionariesByName(String dictionaryName) {
return getDictionariesByName(dictionaryName, null);
}
/**
* 获取字典通过字典名称
*
* @param dictionaryName
* @param defaultValue
* @return
*/
public static List<EnumDictionary> getDictionariesByName(String dictionaryName, List<EnumDictionary> defaultValue) {
List<EnumDictionary> result = ENUMS.get(dictionaryName);
return Objects.nonNull(result) ? result : defaultValue;
}
/**
* 获取字典通过字典名称
*
* @param clazz
* @return
*/
public static List<EnumDictionary> getDictionariesByClass(Class<? extends BaseEnum> clazz) {
return getDictionariesByClass(clazz, null);
}
/**
* 获取字典通过字典名称
*
* @param clazz
* @param defaultValue
* @return
*/
public static List<EnumDictionary> getDictionariesByClass(Class<? extends BaseEnum> clazz, List<EnumDictionary> defaultValue) {
if (Objects.isNull(clazz)) {
return defaultValue;
}
return getDictionariesByName(clazz.getSimpleName(), defaultValue);
}
/**
* 获取字典通过字典编码
*
* @param dictionaryName
* @param code
* @return
*/
public static EnumDictionary getDictionaryByCode(String dictionaryName, Integer code) {
List<EnumDictionary> dictionaries = getDictionariesByName(dictionaryName);
if (CollectionUtils.isEmpty(dictionaries)) {
return null;
}
Optional<EnumDictionary> optional = dictionaries.stream().filter(e -> Objects.equals(code, e.getCode())).findFirst();
return optional.orElse(null);
}
/**
* 获取字典通过字典编码
*
* @param clazz
* @param code
* @return
*/
public static EnumDictionary getDictionaryByCode(Class<? extends BaseEnum> clazz, Integer code) {
if (Objects.isNull(clazz)) {
return null;
}
return getDictionaryByCode(clazz.getSimpleName(), code);
}
/**
* 判断编码是否存在
*
* @param dictionaryName
* @param code
* @return
*/
public static boolean containsCode(String dictionaryName, Integer code) {
EnumDictionary dictionary = getDictionaryByCode(dictionaryName, code);
return Objects.nonNull(dictionary);
}
/**
* 判断编码是否存在
*
* @param clazz
* @param code
* @return
*/
public static boolean containsCode(Class<? extends BaseEnum> clazz, Integer code) {
if (Objects.isNull(clazz)) {
return false;
}
return containsCode(clazz.getSimpleName(), code);
}
/**
* 判断是否包含字典
*
* @param dictionaryName
* @return
*/
public static boolean containsDictionaries(String dictionaryName) {
return ENUMS.containsKey(dictionaryName);
}
/**
* 判断是否包含字典
*
* @param clazz
* @return
*/
public static boolean containsDictionaries(Class<? extends BaseEnum> clazz) {
if (Objects.isNull(clazz)) {
return false;
}
return containsDictionaries(clazz.getSimpleName());
}
}
使用示例:EnumDictionaryManagerConfig
import com.ceair.shoppingservice.base.eunms.EnumDictionaryManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 枚举字典管理器配置
*
* @author: Neo
* @date: 2021/1/19 11:20
* @version: 1.0
*/
@Configuration
public class EnumDictionaryManagerConfig {
@Bean
public EnumDictionaryManager enumDictionaryManager() {
return new EnumDictionaryManager();
}
}