详解Spring Boot使用系统参数表提升系统的灵活性

2022-07-22,,,,

目录
    • 3.1、entity类
    • 3.2、dao类
    • 3.3、service类
    • 3.4、serviceimpl类

一、使用系统参数表的好处

​​以数据库表形式存储的系统参数表比配置文件(.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使用系统参数表提升系统的灵活性的资料请关注其它相关文章!

《详解Spring Boot使用系统参数表提升系统的灵活性.doc》

下载本文的Word格式文档,以方便收藏与打印。