来源:https://www.cnblogs.com/CoderGuokai/p/7884746.html
需求:
1.项目开发中会有一些平凡使用的数据需要加载到内存中;以减少数据库交互次数.降低服务器和数据库压力.
思路:
1.在系统启动时,将监听web容器创建完成事件;
2.创建一个用于存储相关数据的Dic类;
3.在监听到容器创建完成后,将为Dic类中的静态变量赋值;
4.这样就可以在应用中随意使用Dic类中的数据;
优劣势:
1.减少web服务与数据库的交互次数,减轻双方压力;
2.web服务启动时间将会被延长;
环境:
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
过程:
1.创建一个类实现接口
ApplicationListener<ContextRefreshedEvent>,并将这个类用@component标签扫描入Spring的对象管理池;
@Component
public class AppSpringEventListener implements ApplicationListener<ContextRefreshedEvent>{
@Override
public void onApplicationEvent(ContextRefreshedEvent arg0) {
//spring会调用两次这个方法,因为启动时会创建了两个容器(root application context 和projectName-servlet context),
//我们只在root上下文创建成功后执行这个方法,初始化参数
if(arg0.getApplicationContext().getParent()==null){
//初始化数据字典
DictionariesHelper.getInstance().init();
//初始化省市县字典
RegionHelper.getInstance().init();
}
}
}
2.在DictionariesHelper类中定义静态变量用于存储字典信息,在RegionHelper中定义静态变量用于存储省市县信息;
@Component
public class DictionariesHelper {
private static final Logger log = LoggerFactory.getLogger(DictionariesHelper.class);
//按层级存储字典信息
private static Map<Object,Object> dataDictionaries = new LinkedHashMap<Object,Object>();
//存储所有字典信息
private static Map<String, String> dataAllMap = new LinkedHashMap<String, String>();
private static DictionariesHelper dictionariesHelper;
//service组件
private static DataDictionariesServise dataDictionariesServise;
//私有化构造函数
private DictionariesHelper(){}
public static DictionariesHelper getInstance(){
if(DictionariesHelper.dictionariesHelper==null){
DictionariesHelper.dictionariesHelper = new DictionariesHelper();
}
return DictionariesHelper.dictionariesHelper;
}
/**
* 初始化数据字典
*/
public void init(){
if(DictionariesHelper.dataDictionaries.size()==0){
initDataDictionaries();
}
}
/**
* 重载数据字典
*/
public void reLoad() {
// TODO Auto-generated method stub
DictionariesHelper.dataDictionaries.clear();
DictionariesHelper.dataAllMap.clear();
init();
}
/**
* 初始化数据字典
*/
private void initDataDictionaries(){
log.info("--------------数据字典初始化开始---------------");
//获取系统当前时间
Long startTime = System.currentTimeMillis();
List<Map<String, Object>> typeList = dataDictionariesServise.queryDataType();
for(Map<String, Object> typeMap:typeList){
LinkedHashMap<Object, Object> paraMap = new LinkedHashMap<Object,Object>();
paraMap.put("OBJTYPE", typeMap.get("OBJTYPE"));
paraMap.put("OBJNAME", typeMap.get("OBJNAME"));
paraMap.put("OBJTYPECODE", typeMap.get("CONTYPEID"));
List<Map<String, Object>> dataList = dataDictionariesServise.queryDataByType(typeMap);
for(Map<String, Object> dataMap:dataList){
//加载所有数据至dataAllMap
DictionariesHelper.dataAllMap.put((String)dataMap.get("CONCODE"),(String)dataMap.get("CONNAME"));
}
DictionariesHelper.dataDictionaries.put(typeMap.get("OBJTYPE"), dataList);
}
log.info("--------------数据字典完成初始化,共用时"+(System.currentTimeMillis()-startTime)+"ms---------------");
}
/**
* 获取所有字典数据
*/
public static Map<Object,Object> getDataDictionaries(){
return DictionariesHelper.dataDictionaries;
}
/**
* 根据类型获取下设的字典数据
* @param type 类型编码(T_COMMON_TYPE表中的OBJTYPE字段)
* @return map:key为code,value为name
*/
public static List getDicListByType(String type){
return (List)DictionariesHelper.dataDictionaries.get(type);
}
/**
* 根据key获取value
* @param code 编码(T_COMMON_INFO中的CONCODE)
* @return 值(T_COMMON_INFO中的CONNAME)
*/
public static String getDicValueByCode(String code){
return DictionariesHelper.dataAllMap.get(code);
}
@Autowired(required = true)
public void setDataDictionariesServise(DataDictionariesServise dataDictionariesServise){
DictionariesHelper.dataDictionariesServise = dataDictionariesServise;
}
}
public class RegionHelper {
private static final Logger log = LoggerFactory.getLogger(RegionHelper.class);
private static Map<Object,Object> regionDictionaries = new LinkedHashMap<Object, Object>();
private static RegionHelper regionHelper;
//service组件
private static DataDictionariesServise dataDictionariesServise;
private static List<Map<String, Object>> zTreeDatalist = new ArrayList<Map<String, Object>>();
//省市县级别
public static Integer province = 1;
public static Integer city = 2;
public static Integer town = 3;
public static RegionHelper getInstance(){
if(RegionHelper.regionHelper==null){
RegionHelper.regionHelper = new RegionHelper();
}
return RegionHelper.regionHelper;
}
/**
* 初始化省市县字典
*/
public void init(){
if(RegionHelper.regionDictionaries.size()==0){
initRegionDictionaries();
}
}
/**
* 重载省市县字典
*/
public void reLoad(){
RegionHelper.regionDictionaries.clear();
init();
}
/**
* 初始化省市县字典
*/
private void initRegionDictionaries() {
log.info("--------------省市县字典初始化开始---------------");
//获取系统当前时间
Long startTime = System.currentTimeMillis();
List<Map<String, Object>> list= dataDictionariesServise.queryRegion();
for(Map<String, Object> map:list){
//根据map构造字典
loadRegionData(map);
}
log.info("--------------省市县字典完成初始化,共用时"+(System.currentTimeMillis()-startTime)+"ms---------------");
}
/**
* 根据编码获取这个区划的Map,其中AREALIST是下设区县
* @param regionCode 需要的省市县
* @return 区划Map
*/
public static Map<Object,Object> getRegionMapByRegionCode(String regionCode){
Integer level = RegionHelper.getRegionLevelByCode(regionCode);
if(level==RegionHelper.province){
return (Map<Object,Object>)RegionHelper.regionDictionaries.get(regionCode);
}else if(level==RegionHelper.city){
return (Map<Object,Object>)((Map<Object,Object>)(((Map<Object,Object>)RegionHelper.regionDictionaries.get(regionCode.substring(0,2)+"0000")).get("AREALIST"))).get(regionCode);
}else if(level==RegionHelper.town){
return (Map<Object,Object>)((Map<Object,Object>)((Map<Object,Object>)((Map<Object,Object>)(((Map<Object,Object>)RegionHelper.regionDictionaries.get(regionCode.substring(0,2)+"0000")).get("AREALIST"))).get(regionCode.substring(0,4)+"00")).get("AREALIST")).get(regionCode);
}else{
return null;
}
}
/**
* 根据编码获取这个区划的下设区域,数据符合zTree简单数据格式
* @param regionCode 需要的省市县编码
* @return 符合zTree简单数据格式的json字符串
*/
public static String getRegionZTreeDataByRegionCode(String regionCode){
RegionHelper.zTreeDatalist.clear();
return JSONArray.toJSONString(RegionHelper.getRegionZTreeListByMap(RegionHelper.getRegionMapByRegionCode(regionCode)));
}
private static List<Map<String, Object>> getRegionZTreeListByMap(Map<Object, Object> map) {
Map<String,Object> resultMap = new LinkedHashMap<String, Object>();
resultMap.put("id", map.get("CODE"));
resultMap.put("name", map.get("NAME"));
resultMap.put("pId", map.get("SUPERIOR"));
boolean isAdd = true;
if((Map<Object,Object>)map.get("AREALIST")!=null&&((Map<Object,Object>)map.get("AREALIST")).size()>0){
resultMap.put("isParent",true);
RegionHelper.zTreeDatalist.add(resultMap);
isAdd = false;
Iterator iter = ((Map<Object,Object>)map.get("AREALIST")).keySet().iterator();
while(iter.hasNext()){
RegionHelper.getRegionZTreeListByMap((Map<Object,Object>)((Map<Object,Object>)map.get("AREALIST")).get(iter.next()));
}
}else{
resultMap.put("isParent",false);
}
if(isAdd){
RegionHelper.zTreeDatalist.add(resultMap);
}
//数组反转
//Collections.reverse(RegionHelper.zTreeDatalist);
return RegionHelper.zTreeDatalist;
}
/**
* @param regionCode 地区编码
* @return 省市县级别:1代表省;2代表市3代表县
*/
public static Integer getRegionLevelByCode(String regionCode){
Integer i = Integer.parseInt(regionCode);
if(i%100==0){
if(i%10000==0){
return RegionHelper.province;
}else {
return RegionHelper.city;
}
}else{
return RegionHelper.town;
}
}
private Boolean loadRegionData(Map<String, Object> map) {
//加载省
if(RegionHelper.regionDictionaries.get(map.get("PROCODE"))==null){
Map<Object,Object> dataMap = new LinkedHashMap<Object,Object>();
dataMap.put("CODE", map.get("PROCODE"));
dataMap.put("NAME", map.get("PRONAME"));
dataMap.put("AREALIST",new LinkedHashMap<Object,Object>());
RegionHelper.regionDictionaries.put(map.get("PROCODE"), dataMap);
}
if(map.get("PROCODE")==null){
return true;
}
//加载市
Map<Object,Object> obj = (Map<Object,Object>)(((Map<Object,Object>)RegionHelper.regionDictionaries.get(map.get("PROCODE"))).get("AREALIST"));
if(obj.get(map.get("CITYCODE"))==null&&map.get("CITYCODE")!=null){
Map<Object,Object> dataMap = new LinkedHashMap<Object,Object>();
dataMap.put("CODE", map.get("CITYCODE"));
dataMap.put("NAME", map.get("CITYNAME"));
dataMap.put("SUPERIOR", map.get("PROCODE"));
dataMap.put("AREALIST",new LinkedHashMap<Object,Object>());
obj.put(map.get("CITYCODE"), dataMap);
}
if(map.get("CITYCODE")==null){
return true;
}
//加载县
obj = (Map<Object,Object>)((Map<Object,Object>)((Map<Object,Object>)(((Map<Object,Object>)RegionHelper.regionDictionaries.get(map.get("PROCODE"))).get("AREALIST"))).get(map.get("CITYCODE"))).get("AREALIST");
if(obj.get("TOWNCODE")==null&&map.get("TOWNCODE")!=null){
Map<Object,Object> dataMap = new LinkedHashMap<Object,Object>();
dataMap.put("CODE", map.get("TOWNCODE"));
dataMap.put("NAME", map.get("TOWNNAME"));
dataMap.put("SUPERIOR", map.get("CITYCODE"));
obj.put(map.get("TOWNCODE"), dataMap);
}
return true;
}
@Autowired(required = true)
public void setDataDictionariesServise(DataDictionariesServise dataDictionariesServise){
RegionHelper.dataDictionariesServise = dataDictionariesServise;
}
}
String ztreeData = RegionHelper.getRegionZTreeDataByRegionCode("XXX");
//调用字典内存数据
List dicList = DictionariesHelper.getDicListByType("xxx");
原理:
1.Spring会在web容器创建完成时调用SpringApplicationListener接口中的onApplicationEvent方法,所以我们自定义类实现
SpringApplicationListener接口,重写onApplicationEvent方法.以便spring在容器完成创建事件后调用我的实现类,运行自定义方法.
总结:
1.使用@Component标注两个工具类是为了可以使用@Autowired标签帮助我将service对象注入对象中;
2.不能在在声明service对象的属性名上直接使用@Autowired标签,那样的话值注不进去还spring报错(不清楚为什么).所以我写了set方法用于注入service;
3.在两个Helper类中,我用于存储数据的都是LinkedHashMap,而不是HashMap,因为,字典和省市县在读取数据时很多时候都会排序的寻求.而HashMap是无序的.这样就算我在SQL中将数据排序.当放入Map中时又变成无序的了.而LinkedHashMap会记录数据进入的循序.这样的话就可以满足我排序的要求;
4.在
SpringApplicationListener中的onApplicationEvent方法中我做了一个if判断,是因为Spring在启动中会在两个容器创建时(root application context和projectName-servlet context).其中projectName-servlet context是root application context的子容器.所以,我们判断当当前容器的父容器是空时(也就是root application context),才执行我们的初始化方法.