目录
Java提取${}占位符并组装对应值
实现了一个${}装配工~
零、起因
最近写个JavaWeb项目,数据库相关的配置想放到properties文件中,用的H2,想直接内嵌,但是数据库文件位置想随程序移动,因为这个项目准备是放到U盘里随插随用的程序。然后配置URL时一开始用的是./data
,它是在Tomcat bin目录下生成的,后面了解到有个私有的工作目录:${catalina.base}
,想我的数据库初始化程序也支持这个,直接加到H2的URL中jdbc:h2:${catalina.base}/data;
报错,H2不支持。现在了解到可以通过System.getProperty("catalina.base")
的方式获取到这个路径,那如何把URL中的${catalina.base}
替换成System.getProperty("catalina.base")
的值呢?
壹、想法
百度没得啥资料,我感觉可以通过正则匹配${},然后一个一个替换掉。
贰、实现
首先写了个正则表达式
\$\{[^}]+}
在菜鸟在线工具上测试通过
输入:
jdbc:h2:${catalina.base}/${catalina.base}work/data;MODE=MySQL;DATABASE_TO_LOWER=TRUE;CIPHER=AES;
输出:
共找到 2 处匹配:
${catalina.base}
${catalina.base}
然后在Java中实现了这个正则表达式的匹配
String str = "jdbc:h2:${catalina.base}/${catalina.base}work/data;MODE=MySQL;DATABASE_TO_LOWER=TRUE;CIPHER=AES;";
String pattern = "\\$\\{[^}]+}";
Pattern r = Pattern.compile(pattern);
Matcher m = r.matcher(str);
if(m.find()) {
System.out.println(m.group());
str = m.replaceFirst("第一个位置");
System.out.println(str);
}
输出
${catalina.base}
jdbc:h2:第一个位置/${catalina.base}work/data;MODE=MySQL;DATABASE_TO_LOWER=TRUE;CIPHER=AES;
很好,加了个循环,依次替换掉后面的值
String str = "jdbc:h2:${catalina.base}/${catalina.base}work/data;MODE=MySQL;DATABASE_TO_LOWER=TRUE;CIPHER=AES;";
String pattern = "\\$\\{[^}]+}";
Pattern r = Pattern.compile(pattern);
int index = 0;
while (true) {
Matcher m = r.matcher(str);
if(m.find()){
index++;
System.out.println(m.group());
str = m.replaceFirst("第" + index + "个位置");
System.out.println(str);
}else {
break;
}
}
输出
${catalina.base}
jdbc:h2:第1个位置/${catalina.base}work/data;MODE=MySQL;DATABASE_TO_LOWER=TRUE;CIPHER=AES;
${catalina.base}
jdbc:h2:第1个位置/第2个位置work/data;MODE=MySQL;DATABASE_TO_LOWER=TRUE;CIPHER=AES;
好,真不戳,然后封装一下,替换的值由接口来决定,到时候重写这个接口就好了
package minuhy.ymz.WorkManage.Util;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @Auther: Minuhy
* @Date: 2022/10/2 13:02
* @Decsription: 装配 ${} 表达式的值
*/
public class StringAssembler {
public interface Assemble {
/**
* 装配过程中需要通过${}里面的表达式找到对应的值
* @param key ${}里面的表达式
* @return ${}里面的表达式对应的值
*/
String getStringByKey(String key);
}
/**
* 装配 ${} 格式的字符串
* @param str 原始字符串
* @param assemble 装配过程中获取值的接口
* @return 装配好之后的字符串
*/
public static String assemble(String str, Assemble assemble) {
String pattern = "\\$\\{[^}]+}";
Pattern r = Pattern.compile(pattern);
while (true) {
Matcher m = r.matcher(str);
if (m.find()) {
String key = getKey(m.group());
str = m.replaceFirst(assemble.getStringByKey(key));
} else {
break;
}
}
return str;
}
/**
* 获取 ${} 里面的值
* @param g ${} 表达式
* @return ${} 里面的值
*/
public static String getKey(String g) {
return g.substring(2, g.length() - 1);
}
}
测试:
@Test
public void Test$Exp() {
String str = "jdbc:h2:${key1}/${key2}work/data;";
str = StringAssembler.assemble(str, key ->{
System.out.println(key);
if (key.equals("key1")) {
return "第一个键";
} else if (key.equals("key2")) {
return "第二个键";
}
return "";
});
System.out.println(str);
}
输出:
"C:\Program Files\Java\jdk1.8.0_301\bin\java.exe" -ea -......
key1
key2
jdbc:h2:第一个键/第二个键work/data;
Process finished with exit code 0
成功!
叁、总结
这个方式实现比较简单,但是复杂度应该是挺高的,后面可以尝试优化一下。
肆、参考文档
菜鸟正则表达式工具
问题:Java正则表达式匹配不到结果的解决