最近在工作中碰到一個情況,就是在建置開發環境的過程中,要將一個設定Server位址的properties檔中的IP位址全部改成自己本機的IP位址。
我原本這篇叫做策略模式應用,但我發現我搞錯了,這應該是命令模式才對。
之前都是用手動的方式來修改properties檔中各Server的IP,但因為數量很多可能稍微一忽略就出錯了,所以就寫了一支下面的jar檔來處理。
處理方式主要就是一行一行讀取properties檔的內容,然後用正則表示式(Regular Expression)找到並替換成自己的IP位址,然後輸出成新的properties檔。
比較麻煩的地方是要找到每個要替換的IP位置需要不同的regex規則,且替代的方式也不太一樣。
一開始直覺想到的方式是用陣列儲存每個regex規則然後loop,但問題是這樣的方式並無法得知目前所要搭配的替代方式。也就是說我需要一個集合可裝載key為regex,value為替代的方法實作。
最後想到利用類似策略模式(Strategy Pattern)的方式來解決。而那個裝載的集合就是一個列舉。
Main.java
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class Main {
public static void main(String[] args) {
FileReader fr = null;
FileWriter fw = null;
try {
fr = new FileReader(new File("server.properties")); // 要被替換IP位址的來源properties檔
fw = new FileWriter("new_server.properties"); // 替換IP後的輸出properties檔
BufferedReader br = new BufferedReader(fr);
while(br.ready()) {
String line = br.readLine(); // 一行一行讀取properties檔
line = RegexEnum.findAndReplace(line); // 替換IP位址
fw.write(line + System.lineSeparator()); // 將替換的內容寫出
}
fw.flush();
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
ReplaceStrategy.java
public interface ReplaceStrategy {
public String replace(String s);
}
RegexEnum.java
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public enum RegexEnum implements ReplaceStrategy{
GATEWAY_IP("^gateway_\\nip\\s*=") {
@Override
public String replace(String s) {
return s.substring(0, s.indexOf('=') + 1) + " " + ip;
}
}
GROUP_IP("^group_ip\\s*="){
@Override
public String replace(String s) {
return s.substring(0, s.indexOf('=') + 1) + " group." + ip;
}
},
TCP_HORN_HOST("^tcp_horn_host\\s*=") {
@Override
public String replace(String s) {
return s.substring(0, s.indexOf('=') + 1) + " " + ip;
}
},
DB_URL("^db_\\w*_url\\s*="){
@Override
public String replace(String s) {
return s.replaceFirst("jdbc:mysql://.*/", "jdbc:mysql://"+ ip + "/");
}
},
TOMCAT_HOST_1("^\\w*_tomcat_host1\\s*="){
@Override
public String replace(String s) {
return s.substring(0, s.indexOf('=') + 1) + " " + ip;
}
},
JEDIS_IP("^Jedis_\\w*_IP_Port\\s*="){
@Override
public String replace(String s) {
return s.replaceFirst("redis://.*:", "redis://"+ ip + ":");
}
};
private static String ip = null;
static {
try {
ip = InetAddress.getLocalHost().getHostAddress(); // get local IPv4 addrss
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
private String regex;
private RegexEnum(String regex) {
this.regex = regex;
}
public static String findAndReplace(String line) {
for (RegexEnum e : RegexEnum.values()) {
Pattern p = Pattern.compile(e.getRegex());
Matcher m = p.matcher(line);
if(m.find()) {
return e.replace(line);
}
}
return line;
}
public String getRegex() {
return regex;
}
}
以上的重點在RegexEnum
的實作。RegexEnum
實作RegexStrategy
介面,所以每個RegexEnum
有各自的正則表示式及對應的替代方法,每次從properties檔讀取一行內容都要遍歷每個RegexEnume
規則,符合規則的那一行內容就用對應的替代方法來替代IP位址。
而在Java 8或許可以用Map<String, Function<String, String>>
來裝載正則表示式與其要替代的方法,例如
private static Map<String, Function<String, String>> regexes = new HashMap<>();
private static String ip = null;
static {
...
regexes.put("^gateway_\\nip\\s*=", (s) -> s.substring(0, s.indexOf('=') + 1) + " " + ip);
regexes.put("^group_ip\\s*=", (s) -> s.substring(0, s.indexOf('=') + 1) + " group." + ip);
...
}
然後再用forEach()
之類的方式來loop每一行讀取的內容來替換。
但我對Java 8的lambda還不熟,所以就先寫到這了。
參考:
沒有留言:
張貼留言