我们在运维过程中,经常需要做一些配置,如果有一个工具可以帮你在线修改后台配置文件
读取配置文件内容,同步配置文件到所有机器,是跟我们带来极大的便利性的。
如下为我做这个工具的思路:
配置文件工具单独在一个页签,页面上显示配置文件名称,配置文件功能描述,配置文件内容
1、鼠标悬浮在配置文件内容时以悬浮的提示方式显示文本内容
2、FileData字段带超链接,点击超链接时新开一个窗口,该窗口可以查看和修改文件内容
3、新窗口有两个按钮,保存和取消
4、点击保存时将页面的内容写入到生产机对应的配置文件
5、当文件发生更改时,将文件同步copy到另外两套服务器上
6、写入文件时指定文件格式为UTF-8,读取配置文件内容时也用UTF-8
7、如果当前页面编辑的是xml文件,则需要对特殊字符做转译
8、如果是properties文件,需要对空格的特殊处理
9、读取配置文件写一个热加载的公共类,支持各种类型的文件
我会在系统上线前,运行代码扫描指定目录下我们可查看到的文件类型文件,把所有文件写到files.txt文件
文件内容为:文件名称,功能描述,文件路径
然后工具页面从files.txt读取这些内容,显示到页面上
用户在点击查看文件内容时,我们通过文件路径去获取文件内容单独显示
/* bcwti
*
* Copyright (c) 2010 Parametric Technology Corporation (PTC). All Rights Reserved.
*
* This software is the confidential and proprietary information of PTC
* and is subject to the terms of a software license agreement. You shall
* not disclose such confidential information and shall use it only in accordance
* with the terms of the license agreement.
*
* ecwti
*/
package ext.restlet;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.json.JSONException;
import wt.util.WTProperties;
/**
* This processor initializes and saves Promotion Requests with the attribute
* values entered in the Promotion Request wizard.
*
* <BR>
* <BR>
* <B>Supported API: </B>true <BR>
* <BR>
* <B>Extendable: </B>true
*
*/
public class FileSaveAndCopyTools {
private static List<String> fileFiter = Arrays.asList(".txt", ".properties", ".xls", ".xlsx", ".xml", ".xconf",
".vm");
public static void main(String[] args) throws JSONException, IOException {
String wthome = "D:\\ptc\\Windchill_10.0\\Windchill";
// (String) (WTProperties.getLocalProperties()).getProperty("wt.home", "") + File.separator;
// 测试初始化全量配置文件到files.txt文件
// String filesPath = wthome + File.separator +"codebase"+ File.separator+"ext";
// initFilesTxt(filesPath);
// 测试读取指定路径的文件内容
// String filesPath = wthome + File.separator +"codebase"+ File.separator+"wt.properties";
// System.out.println(readTxt(filesPath));
// 测试从files.txt读取系统中全量的业务配置文件
// List<Map<String, String>> bussnessConfigFile = getPlmBussnessConfigFiles4FileTxt();
// System.out.println(bussnessConfigFile.toString());
// 根据文件路径和页面传递的内容修改文件
// filesPath = "D:\\ptc\\Windchill_10.0\\Windchill\\codebase\\files.txt";
// String fileTxt = "测试写文件";
// boolean updateState = saveBussnessFile(filesPath, fileTxt);
// System.out.println(updateState);
// 页面编辑配置文件的业务描述,点击保存时将数据更新到files.txt文件
// String targetFilePath = "D:\\ptc\\Windchill_10.0\\Windchill\\codebase\\ext\\util\\mail\\footer.txt";
// boolean modifyState = saveFilesTxtContent(targetFilePath, "通用邮件配置文件模板");
// System.out.println("修改某个配置文件的描述,是否成功="+modifyState);
}
/**
*
* 使用文件通道的方式复制文件
* @param s
* 源文件
* @param t
* 复制到的新文件
*/
public static void fileChannelCopy(File sourceFile, File targetFile) {
FileInputStream fi = null;
FileOutputStream fo = null;
FileChannel in = null;
FileChannel out = null;
try {
fi = new FileInputStream(sourceFile);
fo = new FileOutputStream(targetFile);
in = fi.getChannel();// 得到对应的文件通道
out = fo.getChannel();// 得到对应的文件通道
in.transferTo(0, in.size(), out);// 连接两个通道,并且从in通道读取,然后写入out通道
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fi.close();
in.close();
fo.close();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 初始化 wt_home/codebase/files.txt 文件 该文件包含codebase/ext目录下的".txt", ".properties",
* ".xls", ".xlsx", ".xml", ".xconf",".vm" 类型配置文件名称,文件路径
*
* @param rootFilePath
*/
public static void initFilesTxt(String rootFilePath) {
BufferedOutputStream buff = null;
try {
// 配置文件所在目录
File srcFolder = new File(rootFilePath);
// 递归功能获取改目录下所有想要类型的文件
List<Map<String, String>> configNameAndDesc = new ArrayList<Map<String, String>>();
configNameAndDesc = getAllFilesByPath(srcFolder, configNameAndDesc);
System.out.println(configNameAndDesc.size());
// 将文件名,路径,用户写到一个配置文件全清单
String wthome =
"D:\\ptc\\Windchill_10.0\\Windchill";
// (String) (WTProperties.getLocalProperties()).getProperty("wt.home", "");
String fileName = wthome + File.separator + "codebase" + File.separator + "files.txt";
buff = new BufferedOutputStream(new FileOutputStream(new File(fileName)));
for (int i = 0; i < configNameAndDesc.size(); i++) {
Map<String, String> rowInfo = configNameAndDesc.get(i);
buff.write(rowInfo.get("fileName").toString().getBytes());
buff.write(" ".getBytes());
buff.write(rowInfo.get("fileDescription").toString().getBytes());
buff.write(" ".getBytes());
buff.write(rowInfo.get("filePath").toString().getBytes());
buff.write(" ".getBytes());
buff.write("\r\n".getBytes());
buff.write("\r\n".getBytes());
}
buff.flush();
buff.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (buff != null) {
try {
buff.close();
buff = null;
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 根据文件的路径获取文件内容
*
* @param filePath
* @return
*/
public static String readTxt(String filePath) {
StringBuffer textStr = new StringBuffer();
try {
if (StringUtils.isBlank(filePath)) {
return "no data for the file.";
}
String wthome = (String) (WTProperties.getLocalProperties()).getProperty("wt.home", "");
filePath = filePath.replace("wt_home", wthome);
File file = new File(filePath);
if (file.isFile() && file.exists()) {
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file), "utf-8"));
String lineText = null;
while ((lineText = br.readLine()) != null) {
textStr.append(lineText).append("\r\n");
}
br.close();
} else {
System.out.println("文件不存在!");
}
} catch (Exception e) {
System.out.println("文件读取错误!");
}
return textStr.toString();
}
/**
* 根据配置文件路径和前台传递的内容保存文件
*
* @param filePath 文件路径
* @param fileTxt 文件内容
* @return true/false
*/
public static boolean saveBussnessFile(String filePath, String fileTxt) {
if (StringUtils.isBlank(filePath)) {
return false;
}
BufferedOutputStream buff = null;
try {
String wthome = (String) (WTProperties.getLocalProperties()).getProperty("wt.home", "");
filePath = filePath.replace("wt_home", wthome);
File files4Txt = new File(filePath);
if (files4Txt.canRead() && files4Txt.canWrite()) {
buff = new BufferedOutputStream(new FileOutputStream(filePath));
buff.write(fileTxt.getBytes());
}
buff.flush();
buff.close();
/**
* 某个文件通过管理员工具修改后,后台自动将该配置文件同步到生产所有的机器
* 1、获取生产环境的IP集合
* 2、判断当前用户的IP是哪个
* 3、将当前IP已更新的文件与另外两台建立文件通道,copy文件
*/
InetAddress addr = InetAddress.getLocalHost();
String ipAddress = addr.getHostAddress();
//后续改成读取配置文件,避免IP发生变化
String salveIp1 = "10.xx.xx.16";
String salveIp2 = "10.xx.xx.17";
String masterIp = "10.xx.xx.18";
List<String> plmIp = Arrays.asList(salveIp1,salveIp2,masterIp);
//排除需要copy的机器
if(plmIp.contains(ipAddress)) {
plmIp.remove(ipAddress);
}
//这里虽然多写了两个变量,但是从代码可读性上来说是可以接受的
String currentPath = filePath.replaceAll("D:", ipAddress);
for (int i = 0; i < plmIp.size(); i++) {
String targetIp = plmIp.get(i);
String targetFilePath = currentPath.replaceAll(ipAddress, targetIp);
File targetFile = new File(targetFilePath);
File sourceFile = new File(currentPath);
fileChannelCopy(sourceFile, targetFile);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (buff != null) {
try {
buff.close();
buff = null;
} catch (IOException e) {
e.printStackTrace();
}
}
}
return true;
}
/**
* 将某个配置文件中的所有数据封装成List
* @param file
* @return
*/
public static List<String> getAllLineFromFile(File file) {
try {
FileReader fr = new FileReader(file.getPath());
BufferedReader br = new BufferedReader(fr);
List<String> allLineTxt = new ArrayList<String>();
String lineText = "";
while ((lineText = br.readLine()) != null) {
allLineTxt.add(lineText);
}
fr.close();
return allLineTxt;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 配置文件管理员工具功能修改配置文件files.txt的业务功能描述
* @param filePath 文件路径
* @param fileDescription 文件业务功能描述信息
* @return true/false
*/
public static boolean saveFilesTxtContent(String filePath, String fileDescription) {
BufferedOutputStream buff = null;
try {
String wthome =
"D:\\ptc\\Windchill_10.0\\Windchill";
//(String) (WTProperties.getLocalProperties()).getProperty("wt.home", "");
filePath = filePath.replace("wt_home", wthome);
File files4Txt = new File(wthome + File.separator + "codebase" + File.separator + "files.txt");
if (files4Txt.isFile() && files4Txt.exists()) {
//将文件所有行数据封装为总的LIST
List<String> filesTxtContext = getAllLineFromFile(files4Txt);
if(filesTxtContext.size()==0) {
return false;
}
//迭代这个list的每一行数据
for (int i=0; i<filesTxtContext.size(); i++) {
String lineText = filesTxtContext.get(i);
//获取当前行数据的文件名称,文件业务功能描述,文件路径
String[] fileNameAndFilePath = lineText.split(" ");
//如果当前行的数据文件路径和传进来的文件路径一致
if (fileNameAndFilePath.length == 3 && filePath.equals(fileNameAndFilePath[2])) {
//把当前行数据的文件描述部分替换为页面传递进来的文件业务功能描述
String newLineText = lineText.replace(fileNameAndFilePath[1], fileDescription);
//替换掉总list的这条数据
filesTxtContext.remove(i);
filesTxtContext.add(i,newLineText);
break;
}
}
if (files4Txt.canRead() && files4Txt.canWrite()) {
buff = new BufferedOutputStream(new FileOutputStream(files4Txt));
for (String lineText : filesTxtContext) {
//将新的总数据list写入文件
buff.write(lineText.getBytes());
buff.write("\r\n".getBytes());
}
}
buff.flush();
buff.close();
return true;
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (buff != null) {
try {
buff.close();
buff = null;
} catch (IOException e) {
e.printStackTrace();
}
}
}
return false;
}
/**
* 获取指定目录下的所有文件,过滤掉temp/uploaded_file/bak/backup目录 仅收集".txt", ".properties",
* ".xls", ".xlsx", ".xml", ".xconf", ".vm"类型文件
*
* @param srcFolder 目录
* @param configFileInfo List<Map<文件名称,文件路径>>集合
* @return 所有文件的信息List<Map<文件名称,文件路径>>
* @throws JSONException
* @throws IOException
*/
public static List<Map<String, String>> getAllFilesByPath(File srcFolder, List<Map<String, String>> configFileInfo)
throws JSONException, IOException {
// 获取该目录下所有的文件或者文件夹的File数组
File[] fileArray = srcFolder.listFiles();
// 遍历该File数组,得到每一个File对象
if (configFileInfo == null) {
configFileInfo = new ArrayList<Map<String, String>>();
}
if (fileArray.length != 0) {
for (File file : fileArray) {
// 判断该File对象是否是文件夹
if (file.isDirectory()) {
if (isNeedCollectionFiloder(file)) {
getAllFilesByPath(file, configFileInfo);
}
} else {
if (isNeedCollectionFile(file.getName())) {
Map<String, String> lineStr = new HashMap<String, String>();
lineStr.put("fileName", file.getName());
lineStr.put("fileDescription", "TODO:configFile for item/bom/process/iba/partNumber.");
String wthome = (String) (WTProperties.getLocalProperties()).getProperty("wt.home", "");
String filePath = file.getAbsolutePath().replace(wthome, "wt_home");
lineStr.put("filePath", filePath);
configFileInfo.add(lineStr);
}
}
}
}
return configFileInfo;
}
/**
* 读取 wt_home/codebase/files.txt 文件,将系统的业务配置文件显示到管理员工具页面 页面包含文件名称,文件业务描述,文件路径
*
* @return
*/
public static List<Map<String, String>> getPlmBussnessConfigFiles4FileTxt() {
List<Map<String, String>> bussnessConfigFiles = new ArrayList<Map<String, String>>();
BufferedReader br = null;
try {
String wthome = (String) (WTProperties.getLocalProperties()).getProperty("wt.home", "");
File file = new File(wthome + File.separator + "codebase" + File.separator + "files.txt");
if (file.isFile() && file.exists()) {
br = new BufferedReader(new InputStreamReader(new FileInputStream(file), "utf-8"));
String lineText = null;
while ((lineText = br.readLine()) != null) {
Map<String, String> fileInfo4Current = new HashMap<String, String>();
String[] fileNameAndFilePath = lineText.split(" ");
if (fileNameAndFilePath.length == 3) {
fileInfo4Current.put("fileName", fileNameAndFilePath[0]);
fileInfo4Current.put("fileDescription", fileNameAndFilePath[1]);
fileInfo4Current.put("filePath", fileNameAndFilePath[2]);
bussnessConfigFiles.add(fileInfo4Current);
}
}
br.close();
br = null;
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close();
br = null;
} catch (IOException e) {
e.printStackTrace();
}
}
}
return bussnessConfigFiles;
}
/**
* 是否为需要的目录
*
* @param file
* @return
*/
private static boolean isNeedCollectionFiloder(File file) {
if (file.getPath().endsWith("temp")) {
return false;
}
if (file.getPath().endsWith("uploaded_file")) {
return false;
}
if (file.getPath().endsWith("bak")) {
return false;
}
if (file.getPath().endsWith("backup")) {
return false;
}
return true;
}
/**
* 是否为需要的文件类型
*
* @param fileName
* @return
*/
private static boolean isNeedCollectionFile(String fileName) {
if (fileName.contains(".class") || fileName.contains(".jar") || fileName.contains(".bak")
|| fileName.contains("back")) {
return false;
}
if (fileName.endsWith("bak") || fileName.endsWith("back")) {
return false;
}
if (fileName.lastIndexOf(".") == -1) {
return false;
}
String fileType = fileName.substring(fileName.lastIndexOf("."), fileName.length());
if (!fileFiter.contains(fileType)) {
return false;
}
return true;
}
}