详解Spring Boot使用系统参数表提升系统的灵活性
一、使用系统参数表的好处
以数据库表形式存储的系统参数表比配置文件(.properties文件或.yaml文件)要更灵活,因为无需重启系统就可以动态更新。
系统参数表可用于存储下列数据:
表字段枚举值,如下列字段:
`question_type` tinyint(4) not null default 0 comment '题型,1-单选题,2-多选题,3-问答题',
这个字段现在有3种取值,但是难保将来有扩展的可能,如:是非题、计算题、应用题等。
因此将取值的枚举值用系统参数表来配置,可以提高系统扩展灵活性。
另一方面,对于前端而言,就可以通过查询系统参数表数据,用于ui呈现,而不必硬编码。如前端需要用下拉框来显示所有可能的”题型“,这个列表就可以查询系统参数表来获取。
因此可以将所有字段枚举值纳入系统参数表管理。
参数设置,如邮件参数,对接的第三方系统的url等。
二、系统参数表的表结构
系统参数表的表结构如下:
drop table if exists `sys_parameters`; create table `sys_parameters` ( `class_id` int(11) not null default 0 comment '参数大类id', `class_key` varchar(60) not null default '' comment '参数大类key', `class_name` varchar(60) not null default '' comment '参数大类名称', `item_id` int(11) not null default 0 comment '参数大类下子项id', `item_key` varchar(200) not null default '' comment '子项key', `item_value` varchar(200) not null default '' comment '子项值', `item_desc` varchar(512) not null default '' comment '子项描述', -- 记录操作信息 `login_name` varchar(80) not null default '' comment '操作人账号', `delete_flag` tinyint(4) not null default 0 comment '记录删除标记,1-已删除', `create_time` datetime not null default now() comment '创建时间', `update_time` datetime default null on update now() comment '更新时间', primary key (`class_id`, `item_id`) ) engine = innodb default charset = utf8 comment '系统参数表';
说明:
class_id字段只要确保一个参数大类(如一个枚举字段名)使用唯一值。使用class_key和item_key自动,便于提高记录数据和代码的可读性。class_key一般可以取字段名,但如果发生同名时,需要修改,确保不同表的同名字段,使用不同的class_key。对于枚举值类型,item_key可以取item_id相同的值,只是数据类型不同,此item_key转换成整型数,就是对应字段的值。
这个表的数据一般可以由开发人员提供,包括初始或变动的sql脚本,由dba执行,项目无需为此开发界面来维护。
下面是初始脚本示例:
insert into sys_parameters(class_id, class_key, class_name, item_id, item_key, item_value, item_desc) values (11, 'receive_flag', '短信接收标志', 0, '0', '未接收', ''); insert into sys_parameters(class_id, class_key, class_name, item_id, item_key, item_value, item_desc) values (11, 'receive_flag', '短信接收标志', 1, '1', '已接收', ''); insert into sys_parameters(class_id, class_key, class_name, item_id, item_key, item_value, item_desc) values (11, 'receive_flag', '短信接收标志', 2, '2', '发送失败', ''); 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', '问答题', ''); insert into sys_parameters(class_id, class_key, class_name, item_id, item_key, item_value, item_desc) values (101, 'url_param', 'url参数', 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参数', 1, 'url_action', '/questinvest/show', '请求接口方法');
三、系统参数表在项目中的使用
在spring boot项目中,系统参数表一般只需在应用启动时加载一次,并提供更新接口允许管理员来更新数据。下面详细说明使用方法。
3.1、entity类
先定义系统参数表的实体类,实体类为sysparameter,代码如下:
package com.abc.questinvest.entity; import javax.persistence.column; import lombok.data; /** * @classname : sysparameter * @description : 系统参数信息对象类 * */ @data public class sysparameter { //参数大类id @column(name = "class_id") private integer classid; //参数大类key @column(name = "class_key") private string classkey; //参数大类名称 @column(name = "class_name") private string classname; //子项id @column(name = "item_id") private integer itemid; //子项key @column(name = "item_key") private string itemkey; //子项值 @column(name = "item_value") private string itemvalue; //子项描述 @column(name = "item_desc") private string itemdesc; //========记录操作信息================ // 操作人姓名 @column(name = "login_name") private string loginname; // 记录删除标记,保留 @column(name = "delete_flag") private byte deleteflag; // 创建时间 @column(name = "create_time") private date createtime; // 更新时间 @column(name = "update_time") private date updatetime; }
3.2、dao类
数据访问类为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表数据访问类 * */ @mapper public interface sysparameterdao { //查询所有系统参数,按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类,使用mybatis,只需提供查询接口就行了,因为修改在数据库后台执行了。当然如果项目方认为有必要提供界面来维护该表,则可增加相应crud的接口。
3.3、service类
服务接口类为sysparameterservice,代码如下:
package com.abc.questinvest.service; import java.util.list; import com.abc.questinvest.entity.sysparameter; /** * @classname : sysparameterservice * @description : 系统参数数据服务 * */ public interface sysparameterservice { /** * * @methodname : loaddata * @description : 加载数据库中数据,允许重复调用 * @return : 成功返回true,否则返回false。 * */ public boolean loaddata(); /** * * @methodname : getparameterclass * @description : 获取指定classkey的参数类别的子项列表 * @param classkey : 参数类别key * @return : 指定classkey的参数类别的子项列表 * */ public list<sysparameter> getparameterclass(string classkey); /** * * @methodname : getparameteritembykey * @description : 根据classkey和itemkey获取参数子项 * @param classkey : 参数类别key * @param itemkey : 子项key * @return : sysparameter对象 * */ public sysparameter getparameteritembykey(string classkey,string itemkey); /** * * @methodname : getparameteritembyvalue * @description : 根据classkey和itemvalue获取参数子项 * @param classkey : 参数类别key * @param itemvalue : 子项值 * @return : sysparameter对象 * */ public sysparameter getparameteritembyvalue(string classkey,string itemvalue); }
sysparameterservice类定义了下列接口方法:
- loaddata方法,用于初始加载数据和更新数据。
- getparameterclass方法,获取指定classkey的类别的所有子项列表。此方法调用会非常频繁。
- getparameteritembykey方法,根据classkey和itemkey获取参数子项,用于根据枚举值显示物理含义。此方法调用会非常频繁。
- getparameteritembyvalue方法,根据classkey和itemvalue获取参数子项,用于根据物理含义取得枚举值。此方法调用会非常频繁。
3.4、serviceimpl类
服务实现类为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实现类 * @summary : 实现对系统参数的管理 * */ @slf4j @service public class sysparameterserviceimpl implements sysparameterservice{ //sys_parameters表数据访问对象 @autowired private sysparameterdao sysparameterdao; //管理全部的sysparameter表记录 private map<string,map<string,sysparameter>> sysparametermap = new hashmap<string,map<string,sysparameter>>(); /** * * @methodname : loaddata * @description : 加载数据库中数据 * @return : 成功返回true,否则返回false。 * */ @override public boolean loaddata() { try { //查询sys_parameters表,获取全部数据 list<sysparameter> sysparameterlist = sysparameterdao.selectall(); synchronized(sysparametermap) { //先清空map,便于刷新调用 sysparametermap.clear(); //将查询结果放入map对象中,按每个类别组织 for(sysparameter item : sysparameterlist) { string classkey = item.getclasskey(); string itemkey = item.getitemkey(); map<string,sysparameter> sysparameterclassmap = null; if (sysparametermap.containskey(classkey)) { //如果存在该类别,则获取对象 sysparameterclassmap = sysparametermap.get(classkey); }else { //如果不存在该类别,则创建 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的参数类别的子项列表 * @param classkey : 参数类别key * @return : 指定classkey的参数类别的子项列表 * */ @override public list<sysparameter> getparameterclass(string classkey){ list<sysparameter> sysparameterlist = new arraylist<sysparameter>(); //获取classkey对应的子map,将所有子项加入列表中 if (sysparametermap.containskey(classkey)) { map<string,sysparameter> sysparameterclassmap = sysparametermap.get(classkey); for(sysparameter item : sysparameterclassmap.values()) { sysparameterlist.add(item); } } return sysparameterlist; } /** * * @methodname : getparameteritembykey * @description : 根据classkey和itemkey获取参数子项 * @param classkey : 参数类别key * @param itemkey : 子项key * @return : sysparameter对象 * */ @override public 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 : 根据classkey和itemvalue获取参数子项 * @param classkey : 参数类别key * @param itemvalue : 子项值 * @return : sysparameter对象 * */ @override public 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类使用了map<string,map<string,sysparameter>>类型的属性变量sysparametermap来管理全部的系统参数,外层map管理classkey到map<string,sysparameter>的映射关系,每一项为一个参数类别,而里层map<string,sysparameter>,用于管理itemkey与sysparameter之间的映射关系,每一项为该类别下的一个子项。使用sysparametermap属性的目的,是将所有系统参数都加载到内存中,从而无需频繁访问数据库。
loaddata方法,用于初始加载数据和更新时刷新数据,为了防止更新时脏读数据,加了同步锁。这个方法调用不频繁。
3.5、全局配置服务类
全局配置服务类用于管理全局配置参数,包括系统参数、权限树等。如果只有一种参数,可以不必有此类,因为这样加了一层壳。
服务接口类为globalconfigservice,代码如下:
package com.abc.questinvest.service; /** * @classname : globalconfigservice * @description : 全局变量管理类 * */ public interface globalconfigservice { /** * * @methodname : loaddata * @description : 加载数据 * @return : 成功返回true,否则返回false * */ public boolean loaddata(); //获取sysparameterservice对象 public sysparameterservice getsysparameterservice(); //获取其它配置数据服务对象 //public functiontreeservice getfunctiontreeservice(); }
globalconfigservice提供了下列接口方法:
- loaddata方法,加载配置对象数据,确定多个配置对象的加载次序。
- getsysparameterservice方法,获取系统参数服务类对象。
- 获取其它可能的配置服务对象的方法。
服务实现类为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实现类 * */ @service public class globalconfigserviceimpl implements globalconfigservice{ //系统参数表数据服务对象 @autowired private sysparameterservice sysparameterservice; //其它配置数据服务对象 /** * * @methodname : loaddata * @description : 加载数据 * @return : 成功返回true,否则返回false * */ @override public boolean loaddata() { boolean bret = false; //加载sys_parameters表记录 bret = sysparameterservice.loaddata(); if (!bret) { return bret; } //加载其它配置数据 return bret; } //获取sysparameterservice对象 @override public sysparameterservice getsysparameterservice() { return sysparameterservice; } //获取其它配置数据服务对象方法 }
3.6、启动时加载
全局配置服务类在应用启动时加载到spring容器中,这样可实现共享,减少对数据库的访问压力。
实现一个applicationlistener类,代码如下:
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 : 应用侦听器 * */ @component public class applicationstartup implements applicationlistener<contextrefreshedevent>{ //全局变量管理对象,此处不能自动注入 private globalconfigservice globalconfigservice = null; @override public void onapplicationevent(contextrefreshedevent contextrefreshedevent) { try { if(contextrefreshedevent.getapplicationcontext().getparent() == null){ //root application context 没有parent. system.out.println("========定义全局变量=================="); // 将 applicationcontext 转化为 webapplicationcontext webapplicationcontext webapplicationcontext = (webapplicationcontext)contextrefreshedevent.getapplicationcontext(); // 从 webapplicationcontext 中获取 servletcontext servletcontext servletcontext = webapplicationcontext.getservletcontext(); //加载全局变量管理对象 globalconfigservice = (globalconfigservice)webapplicationcontext.getbean(globalconfigservice.class); //加载数据 boolean bret = globalconfigservice.loaddata(); if (false == bret) { system.out.println("加载全局变量失败"); return; } //====================================================================== // servletcontext设置值 servletcontext.setattribute("global_config_service", globalconfigservice); } } catch (exception e) { e.printstacktrace(); } } }
注意,globalconfigservice不能自动注入,否则得到空指针。通过下列代码来加载bean。
//加载全局变量管理对象 globalconfigservice = (globalconfigservice)webapplicationcontext.getbean(globalconfigservice.class);
代码中,将globalconfigservice对象作为全局变量加入servletcontext中,就可以实现共享了。
在启动类中,加入该应用侦听器applicationstartup。
public static void main(string[] args) { springapplication springapplication = new springapplication(questinvestapplication.class); springapplication.addlisteners(new applicationstartup()); springapplication.run(args); }
3.7、在服务实现类中访问系统参数
httpservletrequest类型对象request在控制器方法中可以获取,可作为参数传入服务实现类的方法中。下面是服务实现类访问系统参数的示例代码:
//获取servletcontext对象 servletcontext servletcontext = request.getservletcontext(); //获取全部数据服务对象 globalconfigservice globalconfigservice = (globalconfigservice)servletcontext.getattribute("global_config_service"); //获取系统参数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使用系统参数表提升系统的灵活性的详细内容,更多关于spring boot使用系统参数表提升系统的灵活性的资料请关注其它相关文章!
上一篇: 富士施乐4000打印机怎么使用?