詳解Spring Boot使用系統(tǒng)參數(shù)表提升系統(tǒng)的靈活性
以數(shù)據(jù)庫(kù)表形式存儲(chǔ)的系統(tǒng)參數(shù)表比配置文件(.properties文件或.yaml文件)要更靈活,因?yàn)闊o(wú)需重啟系統(tǒng)就可以動(dòng)態(tài)更新。
系統(tǒng)參數(shù)表可用于存儲(chǔ)下列數(shù)據(jù):
表字段枚舉值,如下列字段:
`question_type` TINYINT(4) NOT NULL DEFAULT 0 COMMENT ’題型,1-單選題,2-多選題,3-問(wèn)答題’,
這個(gè)字段現(xiàn)在有3種取值,但是難保將來(lái)有擴(kuò)展的可能,如:是非題、計(jì)算題、應(yīng)用題等。
因此將取值的枚舉值用系統(tǒng)參數(shù)表來(lái)配置,可以提高系統(tǒng)擴(kuò)展靈活性。
另一方面,對(duì)于前端而言,就可以通過(guò)查詢(xún)系統(tǒng)參數(shù)表數(shù)據(jù),用于UI呈現(xiàn),而不必硬編碼。如前端需要用下拉框來(lái)顯示所有可能的”題型“,這個(gè)列表就可以查詢(xún)系統(tǒng)參數(shù)表來(lái)獲取。
因此可以將所有字段枚舉值納入系統(tǒng)參數(shù)表管理。
參數(shù)設(shè)置,如郵件參數(shù),對(duì)接的第三方系統(tǒng)的URL等。
二、系統(tǒng)參數(shù)表的表結(jié)構(gòu)系統(tǒng)參數(shù)表的表結(jié)構(gòu)如下:
DROP TABLE IF EXISTS `sys_parameters`;CREATE TABLE `sys_parameters`( `class_id` INT(11) NOT NULL DEFAULT 0 COMMENT ’參數(shù)大類(lèi)id’, `class_key` VARCHAR(60) NOT NULL DEFAULT ’’ COMMENT ’參數(shù)大類(lèi)key’, `class_name` VARCHAR(60) NOT NULL DEFAULT ’’ COMMENT ’參數(shù)大類(lèi)名稱(chēng)’, `item_id` INT(11) NOT NULL DEFAULT 0 COMMENT ’參數(shù)大類(lèi)下子項(xiàng)id’, `item_key` VARCHAR(200) NOT NULL DEFAULT ’’ COMMENT ’子項(xiàng)key’, `item_value` VARCHAR(200) NOT NULL DEFAULT ’’ COMMENT ’子項(xiàng)值’, `item_desc` VARCHAR(512) NOT NULL DEFAULT ’’ COMMENT ’子項(xiàng)描述’, -- 記錄操作信息 `login_name` VARCHAR(80) NOT NULL DEFAULT ’’ COMMENT ’操作人賬號(hào)’, `delete_flag` TINYINT(4) NOT NULL DEFAULT 0 COMMENT ’記錄刪除標(biāo)記,1-已刪除’, `create_time` DATETIME NOT NULL DEFAULT NOW() COMMENT ’創(chuàng)建時(shí)間’, `update_time` DATETIME DEFAULT NULL ON UPDATE NOW() COMMENT ’更新時(shí)間’, PRIMARY KEY (`class_id`, `item_id`)) ENGINE = InnoDB DEFAULT CHARSET = utf8 COMMENT ’系統(tǒng)參數(shù)表’;
說(shuō)明:
class_id字段只要確保一個(gè)參數(shù)大類(lèi)(如一個(gè)枚舉字段名)使用唯一值。使用class_key和item_key自動(dòng),便于提高記錄數(shù)據(jù)和代碼的可讀性。class_key一般可以取字段名,但如果發(fā)生同名時(shí),需要修改,確保不同表的同名字段,使用不同的class_key。對(duì)于枚舉值類(lèi)型,item_key可以取item_id相同的值,只是數(shù)據(jù)類(lèi)型不同,此item_key轉(zhuǎn)換成整型數(shù),就是對(duì)應(yīng)字段的值。
這個(gè)表的數(shù)據(jù)一般可以由開(kāi)發(fā)人員提供,包括初始或變動(dòng)的SQL腳本,由DBA執(zhí)行,項(xiàng)目無(wú)需為此開(kāi)發(fā)界面來(lái)維護(hù)。
下面是初始腳本示例:
INSERT INTO sys_parameters(class_id, class_key, class_name, item_id, item_key, item_value, item_desc)VALUES (11, ’receive_flag’, ’短信接收標(biāo)志’, 0, ’0’, ’未接收’, ’’);INSERT INTO sys_parameters(class_id, class_key, class_name, item_id, item_key, item_value, item_desc)VALUES (11, ’receive_flag’, ’短信接收標(biāo)志’, 1, ’1’, ’已接收’, ’’);INSERT INTO sys_parameters(class_id, class_key, class_name, item_id, item_key, item_value, item_desc)VALUES (11, ’receive_flag’, ’短信接收標(biāo)志’, 2, ’2’, ’發(fā)送失敗’, ’’);INSERT INTO sys_parameters(class_id, class_key, class_name, item_id, item_key, item_value, item_desc)VALUES (12, ’question_type’, ’題型’, 1, ’1’, ’單選題’, ’’);INSERT INTO sys_parameters(class_id, class_key, class_name, item_id, item_key, item_value, item_desc)VALUES (12, ’question_type’, ’題型’, 2, ’2’, ’多選題’, ’’);INSERT INTO sys_parameters(class_id, class_key, class_name, item_id, item_key, item_value, item_desc)VALUES (12, ’question_type’, ’題型’, 3, ’3’, ’問(wèn)答題’, ’’);INSERT INTO sys_parameters(class_id, class_key, class_name, item_id, item_key, item_value, item_desc)VALUES (101, ’url_param’, ’URL參數(shù)’, 0, ’url_prefix’, ’http://questinvest.abc.com:8880’, ’url前綴部分’);INSERT INTO sys_parameters(class_id, class_key, class_name, item_id, item_key, item_value, item_desc)VALUES (101, ’url_param’, ’URL參數(shù)’, 1, ’url_action’, ’/questInvest/show’, ’請(qǐng)求接口方法’);三、系統(tǒng)參數(shù)表在項(xiàng)目中的使用
在Spring Boot項(xiàng)目中,系統(tǒng)參數(shù)表一般只需在應(yīng)用啟動(dòng)時(shí)加載一次,并提供更新接口允許管理員來(lái)更新數(shù)據(jù)。下面詳細(xì)說(shuō)明使用方法。
3.1、Entity類(lèi)先定義系統(tǒng)參數(shù)表的實(shí)體類(lèi),實(shí)體類(lèi)為SysParameter,代碼如下:
package com.abc.questInvest.entity;import javax.persistence.Column;import lombok.Data;/** * @className: SysParameter * @description: 系統(tǒng)參數(shù)信息對(duì)象類(lèi) * */@Datapublic class SysParameter {//參數(shù)大類(lèi)id@Column(name = 'class_id')private Integer classId;//參數(shù)大類(lèi)key@Column(name = 'class_key')private String classKey;//參數(shù)大類(lèi)名稱(chēng)@Column(name = 'class_name')private String className;//子項(xiàng)id@Column(name = 'item_id')private Integer itemId;//子項(xiàng)key@Column(name = 'item_key')private String itemKey;//子項(xiàng)值@Column(name = 'item_value')private String itemValue;//子項(xiàng)描述@Column(name = 'item_desc')private String itemDesc;//========記錄操作信息================ // 操作人姓名 @Column(name = 'login_name') private String loginName; // 記錄刪除標(biāo)記,保留 @Column(name = 'delete_flag') private Byte deleteFlag;// 創(chuàng)建時(shí)間 @Column(name = 'create_time') private Date createTime; // 更新時(shí)間 @Column(name = 'update_time') private Date updateTime;}3.2、Dao類(lèi)
數(shù)據(jù)訪(fǎng)問(wèn)類(lèi)為SysParameterDao,代碼如下:
package com.abc.questInvest.dao;import java.util.List;import org.apache.ibatis.annotations.Mapper;import org.apache.ibatis.annotations.Select;import com.abc.questInvest.entity.SysParameter;/** * @className: SysParameterDao * @description: sys_parameters表數(shù)據(jù)訪(fǎng)問(wèn)類(lèi) * */@Mapperpublic interface SysParameterDao {//查詢(xún)所有系統(tǒng)參數(shù),按class_id,item_id排序@Select('SELECT class_id,class_key,class_name,item_id,item_key,item_value,item_desc'+ ' FROM sys_parameters WHERE delete_flag = 0' + ' ORDER BY class_id,item_id') List<SysParameter> selectAll();}
SysParameterDao類(lèi),使用Mybatis,只需提供查詢(xún)接口就行了,因?yàn)樾薷脑跀?shù)據(jù)庫(kù)后臺(tái)執(zhí)行了。當(dāng)然如果項(xiàng)目方認(rèn)為有必要提供界面來(lái)維護(hù)該表,則可增加相應(yīng)CRUD的接口。
3.3、Service類(lèi)服務(wù)接口類(lèi)為SysParameterService,代碼如下:
package com.abc.questInvest.service;import java.util.List;import com.abc.questInvest.entity.SysParameter;/** * @className: SysParameterService * @description: 系統(tǒng)參數(shù)數(shù)據(jù)服務(wù) * */public interface SysParameterService {/** * * @methodName: loadData * @description: 加載數(shù)據(jù)庫(kù)中數(shù)據(jù),允許重復(fù)調(diào)用 * @return: 成功返回true,否則返回false。 * */public boolean loadData();/** * * @methodName: getParameterClass * @description: 獲取指定classKey的參數(shù)類(lèi)別的子項(xiàng)列表 * @param classKey: 參數(shù)類(lèi)別key * @return: 指定classKey的參數(shù)類(lèi)別的子項(xiàng)列表 * */public List<SysParameter> getParameterClass(String classKey);/** * * @methodName: getParameterItemByKey * @description: 根據(jù)classKey和itemKey獲取參數(shù)子項(xiàng) * @param classKey: 參數(shù)類(lèi)別key * @param itemKey: 子項(xiàng)key * @return: SysParameter對(duì)象 * */public SysParameter getParameterItemByKey(String classKey,String itemKey);/** * * @methodName: getParameterItemByValue * @description: 根據(jù)classKey和itemValue獲取參數(shù)子項(xiàng) * @param classKey: 參數(shù)類(lèi)別key * @param itemValue: 子項(xiàng)值 * @return: SysParameter對(duì)象 * */public SysParameter getParameterItemByValue(String classKey,String itemValue);}
SysParameterService類(lèi)定義了下列接口方法:
loadData方法,用于初始加載數(shù)據(jù)和更新數(shù)據(jù)。 getParameterClass方法,獲取指定classKey的類(lèi)別的所有子項(xiàng)列表。此方法調(diào)用會(huì)非常頻繁。 getParameterItemByKey方法,根據(jù)classKey和itemKey獲取參數(shù)子項(xiàng),用于根據(jù)枚舉值顯示物理含義。此方法調(diào)用會(huì)非常頻繁。 getParameterItemByValue方法,根據(jù)classKey和itemValue獲取參數(shù)子項(xiàng),用于根據(jù)物理含義取得枚舉值。此方法調(diào)用會(huì)非常頻繁。3.4、ServiceImpl類(lèi)服務(wù)實(shí)現(xiàn)類(lèi)為SysParameterServiceImpl,代碼如下:
package com.abc.questInvest.service.impl;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import com.abc.questInvest.dao.SysParameterDao;import com.abc.questInvest.entity.SysParameter;import com.abc.questInvest.service.SysParameterService;import lombok.extern.slf4j.Slf4j;/** * @className: SysParameterServiceImpl * @description: SysParameterService實(shí)現(xiàn)類(lèi) * @summary: 實(shí)現(xiàn)對(duì)系統(tǒng)參數(shù)的管理 * */@Slf4j@Servicepublic class SysParameterServiceImpl implements SysParameterService{//sys_parameters表數(shù)據(jù)訪(fǎng)問(wèn)對(duì)象@Autowiredprivate SysParameterDao sysParameterDao;//管理全部的SysParameter表記錄private Map<String,Map<String,SysParameter>> sysParameterMap = new HashMap<String,Map<String,SysParameter>>();/** * * @methodName: loadData * @description: 加載數(shù)據(jù)庫(kù)中數(shù)據(jù) * @return: 成功返回true,否則返回false。 * */@Overridepublic boolean loadData() {try{//查詢(xún)sys_parameters表,獲取全部數(shù)據(jù)List<SysParameter> sysParameterList = sysParameterDao.selectAll();synchronized(sysParameterMap) {//先清空map,便于刷新調(diào)用sysParameterMap.clear();//將查詢(xún)結(jié)果放入map對(duì)象中,按每個(gè)類(lèi)別組織for(SysParameter item : sysParameterList) {String classKey = item.getClassKey();String itemKey = item.getItemKey();Map<String,SysParameter> sysParameterClassMap = null;if (sysParameterMap.containsKey(classKey)) {//如果存在該類(lèi)別,則獲取對(duì)象sysParameterClassMap = sysParameterMap.get(classKey);}else {//如果不存在該類(lèi)別,則創(chuàng)建sysParameterClassMap = new HashMap<String,SysParameter>();//加入map中sysParameterMap.put(classKey, sysParameterClassMap);}sysParameterClassMap.put(itemKey,item);}}}catch(Exception e) {log.error(e.getMessage());e.printStackTrace();return false;}return true;}/** * * @methodName: getParameterClass * @description: 獲取指定classKey的參數(shù)類(lèi)別的子項(xiàng)列表 * @param classKey: 參數(shù)類(lèi)別key * @return: 指定classKey的參數(shù)類(lèi)別的子項(xiàng)列表 * */@Overridepublic List<SysParameter> getParameterClass(String classKey){List<SysParameter> sysParameterList = new ArrayList<SysParameter>();//獲取classKey對(duì)應(yīng)的子map,將所有子項(xiàng)加入列表中if (sysParameterMap.containsKey(classKey)) {Map<String,SysParameter> sysParameterClassMap = sysParameterMap.get(classKey);for(SysParameter item : sysParameterClassMap.values()) {sysParameterList.add(item);}}return sysParameterList;}/** * * @methodName: getParameterItemByKey * @description: 根據(jù)classKey和itemKey獲取參數(shù)子項(xiàng) * @param classKey: 參數(shù)類(lèi)別key * @param itemKey: 子項(xiàng)key * @return: SysParameter對(duì)象 * */@Overridepublic SysParameter getParameterItemByKey(String classKey,String itemKey) {SysParameter sysParameter = null;if (sysParameterMap.containsKey(classKey)) {//如果classKey存在Map<String,SysParameter> sysParameterClassMap = sysParameterMap.get(classKey);if (sysParameterClassMap.containsKey(itemKey)) {//如果itemKey存在sysParameter = sysParameterClassMap.get(itemKey);}}return sysParameter;}/** * * @methodName: getParameterItemByValue * @description: 根據(jù)classKey和itemValue獲取參數(shù)子項(xiàng) * @param classKey: 參數(shù)類(lèi)別key * @param itemValue: 子項(xiàng)值 * @return: SysParameter對(duì)象 * */@Overridepublic SysParameter getParameterItemByValue(String classKey,String itemValue) {SysParameter sysParameter = null;if (sysParameterMap.containsKey(classKey)) {//如果classKey存在Map<String,SysParameter> sysParameterClassMap = sysParameterMap.get(classKey);//遍歷for (Map.Entry<String,SysParameter> item : sysParameterClassMap.entrySet()) {if(item.getValue().getItemValue().equals(itemValue)) {//如果匹配值sysParameter = item.getValue();break;}}}return sysParameter;}}
SysParameterServiceImpl類(lèi)使用了Map<String,Map<String,SysParameter>>類(lèi)型的屬性變量sysParameterMap來(lái)管理全部的系統(tǒng)參數(shù),外層Map管理classKey到Map<String,SysParameter>的映射關(guān)系,每一項(xiàng)為一個(gè)參數(shù)類(lèi)別,而里層Map<String,SysParameter>,用于管理itemKey與SysParameter之間的映射關(guān)系,每一項(xiàng)為該類(lèi)別下的一個(gè)子項(xiàng)。使用sysParameterMap屬性的目的,是將所有系統(tǒng)參數(shù)都加載到內(nèi)存中,從而無(wú)需頻繁訪(fǎng)問(wèn)數(shù)據(jù)庫(kù)。
loadData方法,用于初始加載數(shù)據(jù)和更新時(shí)刷新數(shù)據(jù),為了防止更新時(shí)臟讀數(shù)據(jù),加了同步鎖。這個(gè)方法調(diào)用不頻繁。
3.5、全局配置服務(wù)類(lèi)全局配置服務(wù)類(lèi)用于管理全局配置參數(shù),包括系統(tǒng)參數(shù)、權(quán)限樹(shù)等。如果只有一種參數(shù),可以不必有此類(lèi),因?yàn)檫@樣加了一層殼。
服務(wù)接口類(lèi)為GlobalConfigService,代碼如下:
package com.abc.questInvest.service;/** * @className: GlobalConfigService * @description: 全局變量管理類(lèi) * */public interface GlobalConfigService {/** * * @methodName: loadData * @description: 加載數(shù)據(jù) * @return: 成功返回true,否則返回false * */public boolean loadData();//獲取SysParameterService對(duì)象public SysParameterService getSysParameterService();//獲取其它配置數(shù)據(jù)服務(wù)對(duì)象//public FunctionTreeService getFunctionTreeService();}
GlobalConfigService提供了下列接口方法:
loadData方法,加載配置對(duì)象數(shù)據(jù),確定多個(gè)配置對(duì)象的加載次序。 getSysParameterService方法,獲取系統(tǒng)參數(shù)服務(wù)類(lèi)對(duì)象。 獲取其它可能的配置服務(wù)對(duì)象的方法。服務(wù)實(shí)現(xiàn)類(lèi)為GlobalConfigServiceImpl,代碼如下:
package com.abc.questInvest.service.impl;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import com.abc.questInvest.service.FunctionTreeService;import com.abc.questInvest.service.GlobalConfigService;import com.abc.questInvest.service.RoleFuncRightsService;import com.abc.questInvest.service.SysParameterService;import com.abc.questInvest.service.TableCodeConfigService;/** * @className: GlobalConfigServiceImpl * @description: GlobalConfigService實(shí)現(xiàn)類(lèi) * */@Servicepublic class GlobalConfigServiceImpl implements GlobalConfigService{//系統(tǒng)參數(shù)表數(shù)據(jù)服務(wù)對(duì)象@Autowiredprivate SysParameterService sysParameterService;//其它配置數(shù)據(jù)服務(wù)對(duì)象/** * * @methodName: loadData * @description: 加載數(shù)據(jù) * @return: 成功返回true,否則返回false * */@Overridepublic boolean loadData() {boolean bRet = false;//加載sys_parameters表記錄bRet = sysParameterService.loadData();if (!bRet) {return bRet;}//加載其它配置數(shù)據(jù)return bRet;}//獲取SysParameterService對(duì)象@Overridepublic SysParameterService getSysParameterService() {return sysParameterService;}//獲取其它配置數(shù)據(jù)服務(wù)對(duì)象方法}3.6、啟動(dòng)時(shí)加載
全局配置服務(wù)類(lèi)在應(yīng)用啟動(dòng)時(shí)加載到Spring容器中,這樣可實(shí)現(xiàn)共享,減少對(duì)數(shù)據(jù)庫(kù)的訪(fǎng)問(wèn)壓力。
實(shí)現(xiàn)一個(gè)ApplicationListener類(lèi),代碼如下:
package com.abc.questInvest;import javax.servlet.ServletContext;import org.springframework.context.ApplicationListener;import org.springframework.context.event.ContextRefreshedEvent;import org.springframework.stereotype.Component;import org.springframework.web.context.WebApplicationContext;import com.abc.questInvest.service.GlobalConfigService;/** * @className: ApplicationStartup * @description: 應(yīng)用偵聽(tīng)器 * */@Componentpublic class ApplicationStartup implements ApplicationListener<ContextRefreshedEvent>{ //全局變量管理對(duì)象,此處不能自動(dòng)注入 private GlobalConfigService globalConfigService = null;@Override public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {try {if(contextRefreshedEvent.getApplicationContext().getParent() == null){ //root application context 沒(méi)有parent.System.out.println('========定義全局變量==================');// 將 ApplicationContext 轉(zhuǎn)化為 WebApplicationContext WebApplicationContext webApplicationContext = (WebApplicationContext)contextRefreshedEvent.getApplicationContext(); // 從 webApplicationContext 中獲取 servletContext ServletContext servletContext = webApplicationContext.getServletContext();//加載全局變量管理對(duì)象 globalConfigService = (GlobalConfigService)webApplicationContext.getBean(GlobalConfigService.class); //加載數(shù)據(jù) boolean bRet = globalConfigService.loadData(); if (false == bRet) { System.out.println('加載全局變量失敗'); return; } //====================================================================== // servletContext設(shè)置值 servletContext.setAttribute('GLOBAL_CONFIG_SERVICE', globalConfigService); } } catch (Exception e) {e.printStackTrace(); } }}
注意,globalConfigService不能自動(dòng)注入,否則得到空指針。通過(guò)下列代碼來(lái)加載bean。
//加載全局變量管理對(duì)象globalConfigService = (GlobalConfigService)webApplicationContext.getBean(GlobalConfigService.class);
代碼中,將globalConfigService對(duì)象作為全局變量加入ServletContext中,就可以實(shí)現(xiàn)共享了。
在啟動(dòng)類(lèi)中,加入該應(yīng)用偵聽(tīng)器ApplicationStartup。
public static void main(String[] args) { SpringApplication springApplication = new SpringApplication(QuestInvestApplication.class); springApplication.addListeners(new ApplicationStartup()); springApplication.run(args); }3.7、在服務(wù)實(shí)現(xiàn)類(lèi)中訪(fǎng)問(wèn)系統(tǒng)參數(shù)
HttpServletRequest類(lèi)型對(duì)象request在控制器方法中可以獲取,可作為參數(shù)傳入服務(wù)實(shí)現(xiàn)類(lèi)的方法中。下面是服務(wù)實(shí)現(xiàn)類(lèi)訪(fǎng)問(wèn)系統(tǒng)參數(shù)的示例代碼:
//獲取ServletContext對(duì)象ServletContext servletContext = request.getServletContext();//獲取全部數(shù)據(jù)服務(wù)對(duì)象GlobalConfigService globalConfigService = (GlobalConfigService)servletContext.getAttribute('GLOBAL_CONFIG_SERVICE');//獲取系統(tǒng)參數(shù)url_prefix的值String url_prefix = '';SysParameter sysParameter = null;sysParameter = globalConfigService.getSysParameterService().getParameterItemByKey('url_param', 'url_prefix');if (sysParameter != null) { url_prefix = sysParameter.getItemValue();}
以上就是詳解Spring Boot使用系統(tǒng)參數(shù)表提升系統(tǒng)的靈活性的詳細(xì)內(nèi)容,更多關(guān)于Spring Boot使用系統(tǒng)參數(shù)表提升系統(tǒng)的靈活性的資料請(qǐng)關(guān)注好吧啦網(wǎng)其它相關(guān)文章!
相關(guān)文章:
1. IntelliJ IDEA導(dǎo)入jar包的方法2. Python requests庫(kù)參數(shù)提交的注意事項(xiàng)總結(jié)3. vue-electron中修改表格內(nèi)容并修改樣式4. python ansible自動(dòng)化運(yùn)維工具執(zhí)行流程5. 匹配模式 - XSL教程 - 46. python操作mysql、excel、pdf的示例7. JavaScript中l(wèi)ayim之整合右鍵菜單的示例代碼8. SpringBoot參數(shù)校驗(yàn)與國(guó)際化使用教程9. 通過(guò)Python pyecharts輸出保存圖片代碼實(shí)例10. 詳談ajax返回?cái)?shù)據(jù)成功 卻進(jìn)入error的方法
