1、按照spring boot的约定,配置文件名称默认是classpath根路径下的application.properties,并按其约定加载多个配置文件
2、按指定配置文件的路径及名称读取配置,一般是兼容旧工程没有按spring boot约定命名的配置文件 <br>
3、新增读取yml配置文件的功能,默认先读取properties文件,如果不存在再读取yml文件
public final class ConfigUtil {
private static Logger log = LoggerFactory.getLogger(DataBaseUtil.class);
/**
* spring boot默认的配置文件名称
*/
private static final String CONFIG_FILENAME = "application";
private static final String DEFAULT_SUFFIX = ".properties";
private static final String YML_SUFFIX = ".yml";
/**
* spring boot通过application.properties配置文件中的spring.profiles.active配置项值指定生效的配置文件名称<br>
* 如spring.profiles.active=business,表示application-business.properties配置文件生效
*/
private static final String SPRING_PROFILES_ACTIVE = "spring.profiles.active";
/**
* spring boot约定命名格式"application-{profile}.properties"来定义多个配置文件,其中{profile}是可变部分
*/
private static final String SPRING_BOOT_PROFILE_TEMPLATE = "application-{profile}";
/**
* 属性对象集合,注意这里是线程安全的
*/
private static Map<String, Properties> props = new ConcurrentHashMap<>();
/** 私有的构造函数 */
private ConfigUtil() {
}
/**
* 加载指定配置文件中的配置
*
* @param fileName
* @return
*/
private static Properties loadPropFromFile(String fileName) {
Properties prop = new Properties();
try {
prop.load(ConfigUtil.class.getClassLoader().getResourceAsStream(fileName));
} catch (IOException e) {
e.printStackTrace();
String error = "配置文件工具类加载配置文件" + fileName + "出现异常!";
log.error(e.getMessage()+":===:"+error);
throw new RuntimeException(error);
}
return prop;
}
/**
* 将yml格式文件加载到Properties中
*
* @param fileName 文件名
* @return
*/
private static Properties loadYmlFromFile(String fileName) {
Properties prop = new Properties();
LoaderOptions options = new LoaderOptions();
// 是否允许读取重复key值,默认为true
options.setAllowDuplicateKeys(false);
Yaml yaml = new Yaml(options);
// 加载yml文件流
InputStream inStream = ConfigUtil.class.getClassLoader().getResourceAsStream(fileName);
// 按照文件编码读取流
Reader reader = new UnicodeReader(inStream);
Iterable<Object> it = yaml.loadAll(reader);
Map<String, Object> result = new LinkedHashMap<>();
for (Object object : it) {
// 构建map类型数据
buildFlattenedMap(result, asMap(object), null);
}
prop.putAll(result);
return prop;
}
/**
* 递归转换map源数据,将递归的key值用"."拼接成最终目标map的key值,最终的value为目标map的value值
*
* @param result
* @param source
* @param path
*/
@SuppressWarnings("unchecked")
private static void buildFlattenedMap(Map<String, Object> result, Map<String, Object> source, String path) {
source.forEach((key, value) -> {
if (hasText(path)) {
if (key.startsWith("[")) {
key = path + key;
} else {
// 分层读取key值,使用"."拼接
key = path + '.' + key;
}
}
if (value instanceof String) {
result.put(key, value);
} else if (value instanceof Map) {
// Need a compound key
Map<String, Object> map = (Map<String, Object>) value;
// 递归构造map
buildFlattenedMap(result, map, key);
} else if (value instanceof Collection) {
// Need a compound key
Collection<Object> collection = (Collection<Object>) value;
if (collection.isEmpty()) {
result.put(key, "");
} else {
int count = 0;
for (Object object : collection) {
buildFlattenedMap(result, Collections.singletonMap("[" + (count++) + "]", object), key);
}
}
} else {
result.put(key, (value != null ? value : ""));
}
});
}
/**
* 将object数据转换为Map
*
* @param object
* @return
*/
@SuppressWarnings("unchecked")
private static Map<String, Object> asMap(Object object) {
// YAML can have numbers as keys
Map<String, Object> result = new LinkedHashMap<>();
if (!(object instanceof Map)) {
// A document can be a text literal
result.put("document", object);
return result;
}
Map<Object, Object> map = (Map<Object, Object>) object;
map.forEach((key, value) -> {
if (value instanceof Map) {
value = asMap(value);
}
if (key instanceof CharSequence) {
result.put(key.toString(), value);
} else {
// It has to be a map key in this case
result.put("[" + key.toString() + "]", value);
}
});
return result;
}
// 判断字符串是否有值(不为空、不为null、必须包含字符串)
private static boolean hasText(@Nullable String str) {
return (str != null && !str.isEmpty() && containsText(str));
}
// 是否包含字符
private static boolean containsText(CharSequence str) {
int strLen = str.length();
for (int i = 0; i < strLen; i++) {
if (!Character.isWhitespace(str.charAt(i))) {
return true;
}
}
return false;
}
/**
* 根据属性key得到对应的属性值<br>
* 配置文件按spring boot的约定的配置文件命名规则进行加载<br>
* <font color=red>注意: 暂不支持yml文件属性读取</font>
*
* @param key 键名称
* @return
*/
public static String getPropsValueByKey(String key) {
// TODO 暂时不支持读取yml格式文件,yml文件支持map和list格式数据,需要另写方法支持
if (!props.containsKey(CONFIG_FILENAME)) {
Properties prop = new Properties();
prop = getPropertiesByFileName(CONFIG_FILENAME);
if (prop.get(SPRING_PROFILES_ACTIVE) != null) {
// 依次读取指定的配置文件
for (String partName : prop.get(SPRING_PROFILES_ACTIVE).toString().split(",")) {
prop.putAll(getPropertiesByFileName(SPRING_BOOT_PROFILE_TEMPLATE.replace("{profile}", partName)));
}
}
props.put(CONFIG_FILENAME, prop);
}
Object obj = props.get(CONFIG_FILENAME).get(key);
if (obj == null) {
return null;
} else {
return obj.toString();
}
}
/**
* 根据配置文件名称和属性key得到对应的属性值.<br>
* 一般用于非spring boot约定的配置文件名称,比如集成其它系统的功能时,有固定名称的配置文件,或兼容旧系统<br>
* <font color=red>注意: 暂不支持yml文件属性读取</font>
*
* @param configFileName 配置文件名称
* @param key 属性key值
* @return
*
*/
public static String getPropsValueByKey(String configFileName, String key) {
// TODO 暂时不支持读取yml格式文件,yml文件支持map和list格式数据,需要另写方法支持
if (!props.containsKey(configFileName)) {
props.put(configFileName, loadPropFromFile(configFileName));
}
return props.get(configFileName).getProperty(key);
}
/**
* 根据文件名称获取Properties
*
* @param fileName 文件名
* @return
*/
private static Properties getPropertiesByFileName(String fileName) {
String fileFullName = fileName + DEFAULT_SUFFIX;
InputStream inputStream = ConfigUtil.class.getClassLoader().getResourceAsStream(fileFullName);
if (inputStream == null) {
fileFullName = fileName + YML_SUFFIX;
// 读取yml配置文件
inputStream = ConfigUtil.class.getClassLoader().getResourceAsStream(fileFullName);
return loadYmlFromFile(fileFullName);
} else {
// 读取properties文件
return loadPropFromFile(fileFullName);
}
}
public static String getBody(String bodyName,JSONObject jsonObject) {
String body = (String) jsonObject.get(bodyName);
String reqBody = body;
String pattern = "\\$\\{.*?\\}";
Pattern r = Pattern.compile(pattern);
Matcher matcher = r.matcher(body);
while (matcher.find()) {
String substring = body.substring(matcher.start(), matcher.end());
String s = getPropsValueByKey(substring.substring(2, substring.length() - 1));
reqBody = reqBody.replace(substring, s);
}
return reqBody;
}
}