当前位置:网站首页>An integrated framework for caching, loading, refreshing and mapping data dictionaries
An integrated framework for caching, loading, refreshing and mapping data dictionaries
2022-06-09 07:40:00 【Don't ask me what I dislike】
Preface
In the process of business development , I always deal with dictionaries . for instance : Gender , type , Status, etc , Can be summed up as the scope of the dictionary .
The composition of a dictionary is divided into : Dictionary type 、 Dictionary data .
among Dictionary data Belonging to a class Dictionary type . Can pass Dictionary type obtain Dictionary data . As mentioned at the beginning , Gender is the dictionary type ,1- male ;0- Woman ; Just for dictionary data . among “1” and “0” Is the code value ,“ male ” and “ Woman ” Is the display value . Store code values in the database , Display values on the page .
The purpose of the dictionary :
- Front end drop-down box
- List display , You need to convert code values to display values
- Logical condition judgment ( Both front and rear ends need )
- Data range limits
ad locum , For the time being, I will classify the sources of dictionaries into three categories : enumeration 、 Dictionary table 、 Business data .
- enumeration : Use enumeration , It is convenient to make logical judgment and data range limitation in the code .
- Dictionary table : Use one or more dictionary tables , Unified management of dictionary data in the project .( May repeat with enum )
- Business data : In some cases , We need to use business data as a dictionary .( data source , Data sheets, etc )
Text
According to the purpose in the preface , The dictionary framework requires the following functions :
- Cache dictionary types and dictionary data
- Easy to load real-time business dictionary data
- According to the dictionary type and dictionary data code value , Mapping to display values
So the dictionary framework is also designed according to the above three points :
- cache ( Application startup cache )
- load ( The application starts loading )
- Reload ( Dynamic dictionary changes , Modify cache data )
- serialize ( mapping )
Engineering structure drawing
One 、 Load and cache
To find a dictionary quickly , Or used for mapping . The easiest way , Cache data . Cache data into memory , Or in other middleware , Improve efficiency .
Design
The external operations of cached data are uniformly placed in DictDataCache Class .
In my design , Because there are three sources of data in the dictionary , So the cache is also placed in three different locations . It uses Hutool Caching tools in tools , And I have implemented a custom cache class NoClearCache
Custom persistent cache NoClearCache
package com.cah.project.core.dict.cache;
import cn.hutool.cache.impl.AbstractCache;
import java.util.HashMap;
/** * Function description : No clean cache <br/> */
public class NoClearCache<K, V> extends AbstractCache<K, V> {
private static final long serialVersionUID = 1L;
public NoClearCache() {
cacheMap = new HashMap<>();
}
@Override
protected int pruneCache() {
return 0;
}
}
Copy code By three handler Deposit . And use Enumerate factories To manage DictLoadEnum. If you are interested, you can check your own “ Strategy enumeration ” special column .
Dictionary load enumeration DictLoadEnum
package com.cah.project.core.dict.enums;
import cn.hutool.extra.spring.SpringUtil;
import com.cah.project.core.dict.annotation.DictType;
import com.cah.project.core.dict.handler.BusinessDictHandler;
import com.cah.project.core.dict.handler.DictDataHandler;
import com.cah.project.core.dict.handler.DictEnumHandler;
import com.cah.project.core.dict.handler.IDictHandler;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.stream.Stream;
/** * Function description : Dictionary load enumeration <br/> */
@Getter
@AllArgsConstructor
@DictType(typeCode= "LOAD_TYPE", typeName = " Dictionary load type ")
public enum DictLoadEnum implements IDictEnum {
/** enumeration ( Permanent cache ) */
ENUM("1", " enumeration ", DictEnumHandler.class),
/** Dictionary table ( fifo )[ If it conflicts with enumeration , The enumeration will be overwritten ] */
DICT_TABLE("2", " Dictionary table ", DictDataHandler.class),
/** Business data ( Frequency of use ) */
BUSINESS_DATA("3", " Business data ", BusinessDictHandler.class),
;
private final String type;
private final String msg;
private final Class<? extends IDictHandler> handler;
public static DictLoadEnum indexOf(String type) {
return Stream.of(values()).filter(d -> d.getType().equals(type)).findFirst().orElse(ENUM);
}
public IDictHandler getDictHandler() {
return SpringUtil.getBean(getHandler());
}
@Override
public String getCode() {
return getType();
}
/** * Function description : Start loading <br/> */
public static void start() {
for(DictLoadEnum dle : DictLoadEnum.values()) {
dle.getDictHandler().loadDictCache();
}
}
}
Copy code Three handler A unified interface is implemented IDictHandler, And inherited the abstract class AbstractDictHandler, stay AbstractDictHandler in , Defines the cache properties .
protected Cache<String, List<DictDataOptions>> cacheData;
Copy code Every implementation , Create different cache objects by yourself , Different caching strategies can be implemented . Such as :
- Enumeration cache , Itself is code , So you can set the permanent cache
NoClearCache, No size ; - Dictionary table cache , have access to “ FIFO cache ”
FIFOCache, And set the size to 10000 individual ; - Business data caching , have access to “ At least use caching ”
LFUCache, And set the size to 10000 individual ;
Interface IDictHandler
loadDictCache() Method to load the cache .
reloadDictCache() Reload cache . Must cooperate with Event Events use
getDictDataOptions() Get dictionary data .
package com.cah.project.core.dict.handler;
import com.cah.project.core.dict.domain.vo.DictDataOptions;
import com.cah.project.core.dict.event.DictEvent;
import org.springframework.context.ApplicationListener;
import java.util.List;
/*** * Function description : Dictionary loading interface <br/> */
public interface IDictHandler extends ApplicationListener<DictEvent> {
/** * Function description : Load cache <br/> */
void loadDictCache();
/** * Function description : Reload cache <br/> */
void reloadDictCache(String typeCode);
/** * Function description : By dictionary type , Get dictionary data <br/> * * @param typeCode Dictionary type * @return "java.util.List<com.cah.project.module.standard.domain.vo.out.DictDataOptions>" */
List<DictDataOptions> getDictDataOptions(String typeCode);
}
Copy code abstract class AbstractDictHandler
package com.cah.project.core.dict.handler;
import cn.hutool.cache.Cache;
import cn.hutool.core.collection.ListUtil;
import com.cah.project.core.dict.cache.DictDataCache;
import com.cah.project.core.dict.domain.vo.DictDataOptions;
import com.cah.project.core.dict.event.DictEvent;
import java.util.List;
/** * Function description : Dictionary processing , abstract class <br/> */
public abstract class AbstractDictHandler implements IDictHandler {
/*** * Function description : Cache object <br/> */
protected Cache<String, List<DictDataOptions>> cacheData;
public AbstractDictHandler() {}
@Override
public void onApplicationEvent(DictEvent event) {
reloadDictCache(event.getTypeCode());
}
/** * Function description : Add dictionary type <br/> * * @param typeCode Dictionary type * @param typeName Dictionary type name */
protected void addDictType(String typeCode, String typeName) {
DictDataCache.addType(typeCode, typeName);
}
/*** * Function description : Batch add dictionary data cache <br/> * * @param typeCode Dictionary type * @param dataList Dictionary data list */
protected void put(String typeCode, List<DictDataOptions> dataList) {
if(cacheData.get(typeCode) == null) {
cacheData.put(typeCode, ListUtil.list(false));
}
cacheData.get(typeCode).addAll(dataList);
}
/** * Function description : Add dictionary data cache for a single entry <br/> * * @param typeCode Dictionary type * @param dataValue The dictionary is worth * @param dataLabel Dictionary labels */
protected void put(String typeCode, String dataValue, String dataLabel) {
if(cacheData.get(typeCode) == null) {
cacheData.put(typeCode, ListUtil.list(false));
}
cacheData.get(typeCode).add(DictDataOptions.builder().typeCode(typeCode).dataValue(dataValue).dataLabel(dataLabel).build());
}
/** * Function description : Remove the cache <br/> * * @param typeCode Dictionary type */
protected void remove(String typeCode) {
cacheData.remove(typeCode);
}
}
Copy code 1、 enumeration
In the code , How to automatically and easily add enumerations to the cache ? I defined an annotation DictType , There's also an interface IDictEnum. Through these two classes , You can use reflection , Add the enumeration class to the enumeration cache . For specific use, please refer to the above DictLoadEnum class .
Enumerate dictionary annotations DictType
package com.cah.project.core.dict.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** * Function description : Dictionary type annotation <br/> */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface DictType {
/** Dictionary type */
String typeCode();
/** Dictionary name */
String typeName();
}
Copy code Enumeration Dictionary interface IDictEnum
package com.cah.project.core.dict.enums;
/** * Function description : Dictionary enumeration interface <br/> */
public interface IDictEnum {
/** * Function description : Code value <br/> */
String getCode();
/** * Function description : Display value <br/> */
String getMsg();
}
Copy code The implementation is as follows : Scan through packages and interfaces , Cycle to judge whether it meets the requirements . In the pass condition , get data , Add to cache .
Enumerate dictionary handlers DictEnumHandler
package com.cah.project.core.dict.handler;
import cn.hutool.core.util.ClassUtil;
import com.cah.project.core.dict.annotation.DictType;
import com.cah.project.core.dict.cache.NoClearCache;
import com.cah.project.core.dict.domain.vo.DictDataOptions;
import com.cah.project.core.dict.enums.IDictEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Set;
@Slf4j
@Component
public class DictEnumHandler extends AbstractDictHandler {
// By configuring , Implement package scanning
@Value("${dict.enum.package:com.cah.project}")
private String packageStr;
public DictEnumHandler() {
cacheData = new NoClearCache<>();
}
@Override
public List<DictDataOptions> getDictDataOptions(String typeCode) {
return cacheData.get(typeCode);
}
@Override
public void loadDictCache() {
try {
// If there is no data , To register
Set<Class<?>> classes = ClassUtil.scanPackageBySuper(packageStr, IDictEnum.class);
for (Class<?> aClass : classes) {
if (ClassUtil.isEnum(aClass)) {
DictType dictType = aClass.getAnnotation(DictType.class);
if (dictType == null) {
throw new RuntimeException(" enumeration :" + aClass.getName() + " Does not add @DictType annotation .");
}
Method codeMethod = ClassUtil.getDeclaredMethod(aClass, "getCode");
Method msgMethod = ClassUtil.getDeclaredMethod(aClass, "getMsg");
if (codeMethod == null || msgMethod == null) {
continue;
}
// obtain enum All instances of
Object[] objList = aClass.getEnumConstants();
for (Object obj : objList) {
put(dictType.typeCode(), (String) codeMethod.invoke(obj), (String) msgMethod.invoke(obj));
}
// Add dictionary type
addDictType(dictType.typeCode(), dictType.typeName());
}
}
} catch (IllegalAccessException | InvocationTargetException e) {
log.error(" Enumerate cache load exceptions :{}", e.getMessage());
}
}
@Override
public void reloadDictCache(String typeCode) {
// Due to the memory , No need to reload
}
}
Copy code 2、 Dictionary table
The dictionary table needs to be distributed for loading , So the dictionary table processing interface is redefined IDictDataHandler, And use abstract classes AbstractDictDataHandler The general method , And the default implementation class DefaultDictDataHandler. This ensures the integrity of the framework , Not strongly dependent on the business .
Dictionary table processor DictDataHandler
package com.cah.project.core.dict.handler;
import cn.hutool.cache.CacheUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import com.cah.project.core.dict.cache.DictDataCache;
import com.cah.project.core.dict.domain.vo.DictDataOptions;
import com.cah.project.core.dict.handler.dictData.IDictDataHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
/** * Function description : Dictionary table loading <br/> */
@Component
public class DictDataHandler extends AbstractDictHandler {
@Autowired
private DictHandlerAware dictHandlerAware;
public DictDataHandler() {
cacheData = CacheUtil.newFIFOCache(10000);
}
@Override
public void loadDictCache() {
// Load Dictionary Cache
getDictDataHandler().loadDictCache(DictDataCache.getTypeList(), cacheData);
}
@Override
public void reloadDictCache(String typeCode) {
remove(typeCode);
List<DictDataOptions> dictDataList = getDictDataHandler().getDictDataOptions(typeCode);
if(CollUtil.isNotEmpty(dictDataList)) {
put(typeCode, dictDataList);
}
}
@Override
public List<DictDataOptions> getDictDataOptions(String typeCode) {
List<DictDataOptions> dictDataOptions = cacheData.get(typeCode);
// If it doesn't exist in the cache , It may be invalid , Query again from the database
if(CollUtil.isEmpty(dictDataOptions)) {
List<DictDataOptions> dictDataList = getDictDataHandler().getDictDataOptions(typeCode);
if(CollUtil.isEmpty(dictDataList)) {
put(typeCode, dictDataList);
} else {
return ListUtil.empty();
}
}
return cacheData.get(typeCode);
}
private IDictDataHandler getDictDataHandler() {
return dictHandlerAware.getDictHandler();
}
}
Copy code Dictionary table interface IDictDataHandler
package com.cah.project.core.dict.handler.dictData;
import cn.hutool.cache.Cache;
import com.cah.project.core.dict.domain.vo.DictDataOptions;
import com.cah.project.core.dict.domain.vo.DictTypeOptions;
import java.util.Collection;
import java.util.List;
import java.util.Set;
public interface IDictDataHandler {
/** * Function description : Get all dictionary types <br/> * * @return "java.util.List<com.cah.project.module.standard.domain.entity.DictTypeEntity>" */
Set<DictTypeOptions> getDictTypeList();
/** * Function description : By dictionary type , Get dictionary data <br/> * * @param typeCode Dictionary type * @return "java.util.List<com.cah.project.module.standard.domain.vo.out.DictDataOptions>" */
List<DictDataOptions> getDictDataOptions(String typeCode);
/** * Function description : By batch dictionary type , Query dictionary data <br/> * * @param typeCodeList Dictionary type collection * @return "java.util.List<com.cah.project.module.standard.domain.vo.out.DictDataOptions>" */
List<DictDataOptions> getDictDataOptions(Collection<String> typeCodeList);
/** * Function description : Load cache <br/> * * @param dictTypeList List of dictionary types * @param cacheData Dictionary cache data */
void loadDictCache(Collection<DictTypeOptions> dictTypeList, Cache<String, List<DictDataOptions>> cacheData);
}
Copy code Dictionary table Abstract implementation AbstractDictDataHandler
package com.cah.project.core.dict.handler.dictData;
import cn.hutool.cache.Cache;
import cn.hutool.core.collection.ListUtil;
import com.cah.project.core.dict.domain.vo.DictDataOptions;
import com.cah.project.core.dict.domain.vo.DictTypeOptions;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/** * Function description : Dictionary table loading <br/> */
public abstract class AbstractDictDataHandler implements IDictDataHandler {
/** Define page size per page */
protected static final int PAGE_SIZE = 50;
@Override
public void loadDictCache(Collection<DictTypeOptions> dictTypeList, Cache<String, List<DictDataOptions>> cacheData) {
Set<DictTypeOptions> dictTypeOptionsSet = getDictTypeList();
dictTypeList.addAll(dictTypeOptionsSet);
List<String> typeCodeList = dictTypeOptionsSet.stream().map(DictTypeOptions::getTypeCode).collect(Collectors.toList());
int total = typeCodeList.size() / PAGE_SIZE + 1;
// Page loading dictionary data
for(int i = 0; i < total; i++) {
List<DictDataOptions> dictDataList = getDictDataOptions(ListUtil.page(i, PAGE_SIZE, typeCodeList));
for(DictDataOptions ddp : dictDataList) {
if(cacheData.get(ddp.getTypeCode()) == null) {
cacheData.put(ddp.getTypeCode(), ListUtil.list(false));
}
cacheData.get(ddp.getTypeCode()).add(ddp);
}
}
}
}
Copy code The dictionary table is implemented by default DefaultDictDataHandler
package com.cah.project.core.dict.handler.dictData;
import com.cah.project.core.dict.domain.vo.DictDataOptions;
import com.cah.project.core.dict.domain.vo.DictTypeOptions;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
/** * Function description : Default implementation <br/> */
public class DefaultDictDataHandler extends AbstractDictDataHandler {
public DefaultDictDataHandler() {
super();
}
@Override
public Set<DictTypeOptions> getDictTypeList() {
return Collections.emptySet();
}
@Override
public List<DictDataOptions> getDictDataOptions(String typeCode) {
return Collections.emptyList();
}
@Override
public List<DictDataOptions> getDictDataOptions(Collection<String> typeCodeList) {
return Collections.emptyList();
}
}
Copy code Specific business implementation StandardAbstractDictDataHandler
The implementation is placed in a specific business service , Here is an example to show .
package com.cah.project.module.standard.service.handler;
import com.cah.project.core.dict.domain.vo.DictDataOptions;
import com.cah.project.core.dict.domain.vo.DictTypeOptions;
import com.cah.project.core.dict.handler.dictData.AbstractDictDataHandler;
import com.cah.project.module.standard.service.IDictDataService;
import com.cah.project.module.standard.service.IDictTypeService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
@Slf4j
@Component
public class StandardAbstractDictDataHandler extends AbstractDictDataHandler {
@Autowired
private IDictTypeService dictTypeService;
@Autowired
private IDictDataService dictDataService;
@Override
public Set<DictTypeOptions> getDictTypeList() {
return dictTypeService.selectAll().stream()
.map(e -> DictTypeOptions.builder().typeCode(e.getTypeCode()).typeName(e.getTypeName()).build())
.collect(Collectors.toSet());
}
@Override
public List<DictDataOptions> getDictDataOptions(String typeCode) {
return dictDataService.selectListByCode(typeCode).stream()
.map(e -> DictDataOptions.builder().typeCode(e.getTypeCode()).dataLabel(e.getDataLabel()).dataValue(e.getDataValue()).build())
.collect(Collectors.toList());
}
@Override
public List<DictDataOptions> getDictDataOptions(Collection<String> typeCodeList) {
return dictDataService.selectListByCodes(typeCodeList).stream()
.map(e -> DictDataOptions.builder().typeCode(e.getTypeCode()).dataLabel(e.getDataLabel()).dataValue(e.getDataValue()).build())
.collect(Collectors.toList());
}
}
Copy code 3、 Business data
Dictionary of business data types , Similar to a dictionary table . But it's not exactly the same . Basically a business table , Is a dictionary type and dictionary data . So the design method is different from the dictionary table .
Business Dictionary processing interface IBusinessDictHandler
typeCode() Set the business dictionary type
typeName() Set the business dictionary type description ( It's better to have )
getDictDataList() Get business dictionary data
package com.cah.project.core.dict.handler.business;
import com.cah.project.core.dict.domain.vo.DictDataOptions;
import java.util.List;
/** * Function description : Business Dictionary processing interface <br/> */
public interface IBusinessDictHandler {
/** * Function description : Get dictionary type <br/> */
String typeCode();
/** * Function description : Dictionary description <br/> */
String typeName();
/** * Function description : Get dictionary data <br/> */
List<DictDataOptions> getDictDataList();
}
Copy code Business Dictionary processing abstract implementation AbstractBusinessDictHandler
There's nothing to write about , Just let it go
package com.cah.project.core.dict.handler.business;
/** * Function description : Business Dictionary processing , Abstract implementation <br/> */
public abstract class AbstractBusinessDictHandler implements IBusinessDictHandler {
}
Copy code Specific business implementation DataSourceDictHandler
package com.cah.project.module.meta.service.handler;
import com.cah.project.core.dict.domain.vo.DictDataOptions;
import com.cah.project.core.dict.handler.business.AbstractBusinessDictHandler;
import com.cah.project.module.meta.domain.entity.DataSourceEntity;
import com.cah.project.module.meta.service.IDataSourceService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.stream.Collectors;
/** * Function description : Data source dictionary processing <br/> */
@Component
public class DataSourceDictHandler extends AbstractBusinessDictHandler {
@Autowired
private IDataSourceService dataSourceService;
@Override
public String typeCode() {
return "DATA_SOURCE";
}
@Override
public String typeName() {
return " data source ";
}
@Override
public List<DictDataOptions> getDictDataList() {
List<DataSourceEntity> dataSourceList = dataSourceService.selectAll();
return dataSourceList.stream()
.map(e -> DictDataOptions.builder().typeCode(typeCode()).dataLabel(e.getName()).dataValue(e.getId()).build())
.collect(Collectors.toList());
}
}
Copy code Two 、 Scan and start
1、 Implement class scanning
The dictionary table is also a business data dictionary , Generally, they belong to different business systems . So in this project , Only a default null implementation . As long as the concrete implementation , You can replace the default implementation . The function consists of DictHandlerAware Realization ApplicationContextAware Interface to achieve this .
scanning DictHandlerAware
package com.cah.project.core.dict.handler;
import cn.hutool.core.map.MapUtil;
import com.cah.project.core.dict.handler.business.IBusinessDictHandler;
import com.cah.project.core.dict.handler.dictData.AbstractDictDataHandler;
import com.cah.project.core.dict.handler.dictData.DefaultDictDataHandler;
import com.cah.project.core.dict.handler.dictData.IDictDataHandler;
import lombok.Getter;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/** * Function description : adopt spring, Register the business dictionary implementation class to map in , Easy to use <br/> */
@Getter
@Component
public class DictHandlerAware implements ApplicationContextAware {
// The business data dictionary implements a collection (key: Business Dictionary type ,value: Business Dictionary implementation )
private final Map<String, IBusinessDictHandler> handlerMap = new HashMap<>();
// Set the default implementation
private IDictDataHandler dictHandler = new DefaultDictDataHandler();
/** * Function description : Get the application context and get the corresponding interface implementation class <br/> * * @param applicationContext Context */
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
// Return all corresponding data according to the interface type bean
Map<String, IBusinessDictHandler> map = applicationContext.getBeansOfType(IBusinessDictHandler.class);
Set<Map.Entry<String, IBusinessDictHandler>> entries = map.entrySet();
for(Map.Entry<String, IBusinessDictHandler> entry : entries) {
this.handlerMap.put(entry.getValue().typeCode(), entry.getValue());
}
// According to the abstract class , Return to the dictionary implementation
Map<String, AbstractDictDataHandler> dictMap = applicationContext.getBeansOfType(AbstractDictDataHandler.class);
if(MapUtil.isNotEmpty(dictMap)) {
dictHandler = dictMap.entrySet().iterator().next().getValue();
}
}
}
Copy code 2、 Start loading
By implementing ApplicationRunner Interface , Implement the cache function of loading dictionary .
Start class DictStartRunner
package com.cah.project.core.dict;
import com.cah.project.core.dict.enums.DictLoadEnum;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
/** * Function description : The dictionary starts loading <br/> */
@Component
@Order(value = 2)
public class DictStartRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) {
try {
DictLoadEnum.start();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Copy code 3、 ... and 、 Refresh
As long as the data in the database , There are changes ( newly added 、 modify 、 Delete ). At this time , You need to modify the corresponding cache .
It's used here ApplicationEvent To process . By customizing DictEvent Pass on Dictionary type typeCode. Then from IDictHandler Inherit ApplicationListener<DictEvent> Listening interface . Abstract processor AbstractDictHandler Default implementation onApplicationEvent(DictEvent event) Method . And redefine abstract methods abstract void reloadDictCache(String typeCode) The logic is written by each concrete implementation class .
Custom events DictEvent
package com.cah.project.core.dict.event;
import lombok.Getter;
import org.springframework.context.ApplicationEvent;
/** * Function description : Dictionary reload event <br/> */
@Getter
public class DictEvent extends ApplicationEvent {
private final String typeCode;
/** * Create a new {@code ApplicationEvent}. * * @param source the object on which the event initially occurred or with * which the event is associated (never {@code null}) */
public DictEvent(Object source, String typeCode) {
super(source);
this.typeCode = typeCode;
}
}
Copy code Send event class DictReloadPublishEvent
package com.cah.project.core.dict.event;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/** * Function description : Dictionary reload event operation <br/> */
@Component
public class DictReloadPublishEvent {
@Resource
private ApplicationContext applicationContext;
public void publishEvent(String typeCode) {
DictEvent de = new DictEvent(this, typeCode);
applicationContext.publishEvent(de);
}
}
Copy code Refresh events using
@Autowired
private DictReloadPublishEvent dictReloadPublishEvent;
public void test() {
dictReloadPublishEvent.publishEvent("SEX_TYPE");
}
Copy code Four 、 mapping ( serialize )
Please refer to [Jackson Serialize dictionary field properties ] and [Jackson Serialize dictionary field properties ( upgrade )] The content of . One of the classes has been adjusted . Moved to the project . Not affecting use .
5、 ... and 、 test
1、 Dictionaries Controller
package com.cah.project.module.standard.controller;
import com.cah.project.core.dict.domain.vo.DictDataOptions;
import com.cah.project.core.dict.domain.vo.DictTypeOptions;
import com.cah.project.core.domain.out.CommonResult;
import com.cah.project.module.standard.service.IDictDataService;
import com.cah.project.module.standard.service.IDictTypeService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
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 java.util.Collection;
import java.util.List;
/** * Function description : Dictionaries <br/> */
@RestController
@RequestMapping("/dict")
@Api(tags = {" Dictionaries "})
public class DictController {
@Autowired
private IDictTypeService dictTypeService;
@Autowired
private IDictDataService dictDataService;
@GetMapping("type/options")
@ApiOperation(value = " Get the dictionary type drop-down options ")
public CommonResult<Collection<DictTypeOptions>> selectOptions() {
return CommonResult.data(dictTypeService.selectOptions());
}
@GetMapping("data/options/{typeCode}")
@ApiOperation(value = " Get dictionary data drop-down options ")
public CommonResult<List<DictDataOptions>> selectDataOptions(@PathVariable String typeCode) {
return CommonResult.data(dictDataService.selectDataOptionsByCode(typeCode));
}
@GetMapping("data/options/{loadType}/{typeCode}")
@ApiOperation(value = " Get dictionary data drop-down options , According to the loading parameters , Look for different data ")
public CommonResult<List<DictDataOptions>> selectDataOptionsByLoadType(@PathVariable String loadType, @PathVariable String typeCode) {
return CommonResult.data(dictDataService.selectDataOptionsByLoadType(loadType, typeCode));
}
}
Copy code 2、 Dictionaries Service
package com.cah.project.module.standard.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cah.project.core.enums.YesOrNoEnum;
import com.cah.project.module.standard.domain.entity.DictTypeEntity;
import com.cah.project.core.dict.domain.vo.DictTypeOptions;
import com.cah.project.module.standard.mapper.DictTypeMapper;
import com.cah.project.module.standard.service.IDictTypeService;
import com.cah.project.core.dict.cache.DictDataCache;
import org.springframework.stereotype.Service;
import java.util.Collection;
import java.util.List;
/** * Function description : Dictionary type Service implementation <br/> */
@Service
public class DictTypeServiceImpl extends ServiceImpl<DictTypeMapper, DictTypeEntity> implements IDictTypeService {
@Override
public Collection<DictTypeOptions> selectOptions() {
// From the cache
return DictDataCache.getTypeList();
}
@Override
public List<DictTypeEntity> selectAll() {
return lambdaQuery().eq(DictTypeEntity::getEnable, YesOrNoEnum.YES.getCode()).list();
}
}
Copy code package com.cah.project.module.standard.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cah.project.core.dict.cache.DictDataCache;
import com.cah.project.core.dict.domain.vo.DictDataOptions;
import com.cah.project.core.enums.YesOrNoEnum;
import com.cah.project.module.standard.domain.entity.DictDataEntity;
import com.cah.project.module.standard.mapper.DictDataMapper;
import com.cah.project.module.standard.service.IDictDataService;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import java.util.Collection;
import java.util.List;
/** * Function description : Dictionary data Service implementation <br/> */
@Service
@RequiredArgsConstructor(onConstructor_ = {@Autowired, @Lazy})
public class DictDataServiceImpl extends ServiceImpl<DictDataMapper, DictDataEntity> implements IDictDataService {
@Override
public List<DictDataOptions> selectDataOptionsByCode(String dictType) {
return DictDataCache.get(dictType);
}
@Override
public List<DictDataOptions> selectDataOptionsByLoadType(String loadType, String dictType) {
return DictDataCache.get(loadType, dictType);
}
@Override
public List<DictDataEntity> selectListByCode(String dictType) {
return lambdaQuery().eq(DictDataEntity::getTypeCode, dictType)
.eq(DictDataEntity::getEnable, YesOrNoEnum.YES.getCode()).list();
}
@Override
public List<DictDataEntity> selectListByCodes(Collection<String> dictTypeList) {
return lambdaQuery().in(DictDataEntity::getTypeCode, dictTypeList)
.eq(DictDataEntity::getEnable, YesOrNoEnum.YES.getCode()).list();
}
}
Copy code 3、 The interface test
Get a list of dictionary types
Get dictionary data list - enumeration
Get dictionary data list - Dictionary table
Get dictionary data list - Business data
6、 ... and 、 Code address
summary
The description is not good , Will improve more . Welcome to discuss . Subsequent optimization contents : Multilevel ( Such as provincial and urban areas , National geographic , Industry category, medium category, small category, etc ) How to implement and cache dictionaries ? By splitting into single layers , Or add multi-level content to be considered .
边栏推荐
- 【无标题】
- Squid proxy application
- Some pitfalls encountered in using Renren open source project
- Compiling opencv4.5.5 with CUDA (4.2.0+cuda11.1+cudnn8.0.5 failed)
- Related methods of thread class
- Web performance testing strategy
- In the afternoon of July 2, 2022, Jinan IT technology gathering, interested friends scanned the code to sign up for group exchange
- The sandbox and ikonia have reached a cooperation to restore the murals of the football legend Pirlo in the metauniverse
- 2022年塔式起重机司机(建筑特殊工种)考试题模拟考试题库及模拟考试
- 多线程-程序进程线程的概念
猜你喜欢

Interpretation of the functions of the navigation system in the government hall

Selenium: Introduction

Simulated question bank and answers for the 2022 National latest fire facility operator (intermediate fire facility operator) examination

Oracle: time type

Compiling opencv4.5.5 with CUDA (4.2.0+cuda11.1+cudnn8.0.5 failed)

Sql Or NoSql,看完这一篇你就懂了

2022广东省安全员C证第三批(专职安全生产管理人员)考题及模拟考试

2022年最新山西建筑安全员模拟题库及答案

2022制冷与空调设备安装修理特种作业证考试题库及答案

How idea views the path to save code
随机推荐
Simulated question bank and answers for the 2022 National latest fire facility operator (intermediate fire facility operator) examination
New occupation: digital management abbess is in hot demand. As long as she comes for an interview, the enterprise will make an offer
How idea views the path to save code
Use of qflags flag class
MySQL: subquery
Related methods of thread class
On the readable and writable conditions of socket
Summary on the usage of distributed transaction Seata
Some pitfalls encountered in using Renren open source project
2022年7月2日下午,济南IT技术聚会,感兴趣的朋友扫码报名并入群交流
Installing MySQL using docker
2022年中式烹调师(初级)考试题库及在线模拟考试
ftp服务
MySQL: grouping query
Selenium: Introduction
(十三)valgrind在ARM上交叉编译和内存泄漏检测
知行之桥EDI系统Shopify端口的使用
PostgreSQL数据库复制——后台一等公民进程WalReceiver 提取信息
2022 tower crane driver (construction special type of work) examination question simulation examination question bank and simulation examination
Recruitment | go to work, kill werewolves after work, and recruit people every day. I'm afraid it's going to happen!