需求:
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),才執行我們的初始化方法.