一、工具的制作背景
最近在工作中遇到了这样一个问题:前台的客户端程序需要在后台指定程序更新后清空本地的缓存,后台程序的数量不止一个。这个问题的症结在于客户端程序并不知道后台程序是什么时候更新的,为了解决这个问题,我想了如下的办法:
1、在配置表中设立配置项,保存后台程序的版本号,每次后台程序更新时,将这个版本号也同步更新
2、前台客户端程序也保存一组后台程序的版本号,每次登录程序后读取配置表中的版本号,二者进行比较,如果有一组版本号不匹配,则说明后台程序有变动,前台客户端就需要清空本地的缓存数据了
本次制作的小工具,功能就是在上面的第1步时,根据XML的配置生成若干个SQL语句(merge语句),用于更新配置表中的对应配置项。设计这个工具的目的,一是在修改SQL语句的时候可以避免因马虎等因素造成的语句书写错误,二是同时生成一次语句后可以分享给多个人在多个环境上同时进行升级。
二、工具代码
这个小工具是用Java语言写的,工程如下:
文件version.xml存储了我们准备配置的版本号信息
<?xml version="1.0" encoding="UTF-8"?>
<systems author="Tsybius2014" output="updateVer.sql" remark="none">
<!-- 系统1 -->
<system config_no="110020" name="System1" version="v1.2.0.1" enabled="true" />
<!-- 系统2 -->
<system config_no="110021" name="System2" version="v1.2.3.4" enabled="true" />
<!-- 系统3 -->
<system config_no="110022" name="System3" version="v1.0.0.1" enabled="false" />
</systems>
各配置项说明如下:
1、output为输出的sql文件路径
2、author为作者信息、remark为备注信息,这两个信息会出现在生出的sql脚本的首部,以注释形式出现
3、每个system节点配置了一个系统,config_no为配置项编号,name为配置项说明,version为该系统的版本号,enabled为程序执行时是否生成该系统的MergeInto语句
要将version.xml的内容生成为MergeInto语句,还需要一个模板,我将它放在文件template.txt中,内容如下:
MERGE INTO INTERINS.SYS_CONFIG CONFIG
USING (SELECT #{config_no} AS CONFIG_NO,
'11' AS SUB_SYS_CODE,
#{name} AS CONFIG_NAME,
'0' AS MANAGE_LEVEL,
'0' AS ACCESS_LEVEL,
'2' AS DATA_TYPE,
#{version} AS STR_CONFIG,
'1' AS CONFIG_STATUS,
TO_CHAR(SYSDATE,'yyyy-MM-dd HH:mm:ss') AS DATETIME
FROM DUAL) INPUT
ON (CONFIG.CONFIG_NO = INPUT.CONFIG_NO)
WHEN MATCHED THEN
UPDATE
SET CONFIG.SUB_SYS_CODE = INPUT.SUB_SYS_CODE,
CONFIG.CONFIG_NAME = INPUT.CONFIG_NAME,
CONFIG.DATA_TYPE = INPUT.DATA_TYPE,
CONFIG.STR_CONFIG = INPUT.STR_CONFIG,
CONFIG.CONFIG_STATUS = INPUT.CONFIG_STATUS,
CONFIG.REMARK = 'UPDATE BY GEN_MERGE_INTOS ON ' || INPUT.DATETIME
WHEN NOT MATCHED THEN
INSERT
(CONFIG_NO,
SUB_SYS_CODE,
CONFIG_NAME,
MANAGE_LEVEL,
ACCESS_LEVEL,
DATA_TYPE,
STR_CONFIG,
CONFIG_STATUS,
REMARK)
VALUES
(INPUT.CONFIG_NO,
INPUT.SUB_SYS_CODE,
INPUT.CONFIG_NAME,
INPUT.MANAGE_LEVEL,
INPUT.ACCESS_LEVEL,
INPUT.DATA_TYPE,
INPUT.STR_CONFIG,
INPUT.CONFIG_STATUS,
'INSERT BY GEN_MERGE_INTOS ON ' || INPUT.DATETIME);
其中,用config_no替换#{config_no},用name替换#{name},用version替换#{version},就可以生成对应的MergeInto语句了。
GenMergeIntos.java代码如下:
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedList;
import java.util.Queue;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
/**
* SQL脚本生成工具 - 用于系统版本升级后刷新缓存
*
* @文件名称 GenMergeIntos.java
* @文件作者 Tsybius2014
* @创建时间 2016年2月15日 上午11:01:51
*/
public class GenMergeIntos {
// 输出文件地址(需从配置文件中读取)
static String outputPath = "";
// 输出文件作者(需从配置文件中读取)
static String author = "";
// 备注信息(需从配置文件中读取)
static String remark = "";
// 配置文件地址 - 调试时请修改为 src\\version.xml
static String configPath = "version.xml";
// 模板文件地址 - 调试时请修改为 src\\template.xml
static String templatePath = "template.txt";
// 生成的SQL语句暂存于此
static Queue<String> mergeIntos = null;
public static void main(String[] args) {
//mergeInto语句模板
final String template = getTemplate(templatePath);
//存储mergeInto语句
mergeIntos = new LinkedList<String>();
// 设置句柄
DefaultHandler handler = new DefaultHandler() {
// XML文档开始读取时触发
public void startDocument() {
System.out.println("---------XML文档解析开始---------");
}
// XML文档读取结束时触发
public void endDocument() {
System.out.println("---------XML文档解析结束---------");
}
// 读取到某一元素时触发
public void startElement(String namespaceURI, String lname,
String qname, Attributes attrs) {
if (qname.equals("systems")) {
System.out.println("文件输出路径:" + attrs.getValue("output"));
outputPath = attrs.getValue("output");
System.out.println("作者:" + attrs.getValue("author"));
author = attrs.getValue("author");
System.out.println("备注:" + attrs.getValue("remark"));
remark = attrs.getValue("remark");
} else if (qname.equals("system")) {
if (attrs.getValue("enabled").toLowerCase().equals("true")) {
System.out.print("读取配置:" + attrs.getValue("name") + "; ");
System.out.print("版本号:" + attrs.getValue("version") + "; ");
System.out.println("配置号:" + attrs.getValue("config_no"));
mergeIntos.add(getMergeInto(template,
attrs.getValue("name"), attrs.getValue("version"),
attrs.getValue("config_no")));
}
}
}
};
// 使用SAX解析XML
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setNamespaceAware(false);
try {
File configFile = new File(configPath);
SAXParser saxParser = factory.newSAXParser();
saxParser.parse(configFile, handler);
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
outputMergeIntos();
System.out.println("程序运行结束");
}
/**
* 获取模板
*
* @param templatePath
* @return
*/
public static String getTemplate(String templatePath) {
String template = "";
try {
System.out.println("正在输出到文件" + outputPath);
StringBuilder buffer = new StringBuilder();
InputStream is = new FileInputStream(templatePath);
String line;
BufferedReader reader = new BufferedReader(
new InputStreamReader(is));
line = reader.readLine();
while (line != null) {
buffer.append(line);
buffer.append("\n");
line = reader.readLine();
}
template = buffer.toString();
reader.close();
is.close();
System.out.println("输出完毕" + outputPath);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return template;
}
/**
* 通过模板生成对应SQL语句
*
* @param template
* 模板
* @param name
* 配置名
* @param version
* 版本号
* @param configNo
* 配置号
* @return
*/
public static String getMergeInto(String template, String name,
String version, String configNo) {
String result = template;
result = result.replaceAll("\\#\\{name\\}", "'" + name + "'");
result = result.replaceAll("\\#\\{version\\}", "'" + version + "'");
result = result.replaceAll("\\#\\{config_no\\}", "'" + configNo + "'");
return result;
}
/**
* 将数据输出到文件
*/
public static void outputMergeIntos() {
try {
System.out.println("正在导出到文件:" + outputPath);
File outputFile = new File(outputPath);
BufferedWriter bw = new BufferedWriter(new PrintWriter(outputFile));
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String currDateTime = sdf.format(new Date());
bw.append("-----------------------------------------------------\n");
bw.append("-- 各子系统相关版本号配置项更新\n");
bw.append("-- 创建时间:" + currDateTime + "\n");
bw.append("-- 创建人员:" + author + "\n");
bw.append("-- 备注信息:" + remark + "\n");
bw.append("-----------------------------------------------------\n");
bw.newLine();
for (String mergeInto : mergeIntos) {
bw.append(mergeInto);
bw.newLine();
}
bw.append("-- 完");
bw.close();
System.out.println("导出完毕");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
三、生成jar包并使用
生成jar包并使用的步骤如下:
1、鼠标右键单击项目,在弹出菜单中点击Export
2、向导页第一页,选择Java→JAR file,点击Next
3、选择刚才正在修改的项目,并在下方“JAR file”位置指定输出的Jar包所在的地址,点击Next
4、这一步直接点击Next
5、点击Browse按钮,指定JAR包入口点
6、找到main函数所在的类,点击OK按钮
7、生成的jar包旁边,建立一个bat文件“GenMergeIntos.bat”,代码如下:
@java -jar GenMergeIntos.jar
@pause
8、运行这个bat文件,运行效果如下:
9、生成的sql文件(updateVer.sql)如下
END