我理解的yml文件
在我們學習過springboot項目的同學對這個文件肯定是特別熟悉,通常我們都是用它來修改保存我們的項目配置,最簡單的就是數據庫的配置,然后就是資源讀取配置,redies配置,緩存配置,以及jwt的配置等等,因為yml文件主要用於我們的項目配置,所以一個特點就是易於人們閱讀,修改;即使一個剛接觸yml文件的人加上簡單的注釋,肯定也能夠看懂打部分內容的;
我總結的特點就是:
- 直觀,易於閱讀,修改
- 可以把對象的層次結構展現得很直觀
- 用key:value的方式屬性
- 用空格數量表示層級關系
我工作中遇到的問題
大家估計在spring中主要都是讀取yml文件,所以對於寫yml文件的過程經歷不太多,我的項目系統是自己的java框架,然后要集成另外的一個spring項目,當我的項目修改數據庫信息的時候同時也要修改這個springboot項目的數據庫配置信息,那么就存在一個對yml的讀和寫的過程,我經過百度后加上自己的代碼,就得到了自己想要的效果;主要用到了ymal這個開源工具類;
maven依賴
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.25</version>
</dependency>
讀取
關鍵代碼,ymal工具自動將yml文件轉換為map結構的對象
//解析yml文件的關鍵類
Yaml yml =null;
try (FileInputStream in = new FileInputStream(file)){
yml = new Yaml();
obj = (Map)yml.load(in);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Map<String,Object> springMap =(Map)obj.get("spring");
寫入
關鍵代碼,
try (FileWriter writer = new FileWriter(file)) {
//writer.write(yml.dump(obj));
writer.write(yml.dumpAsMap(obj));
//writer.write(yml.dumpAs(obj, Tag.MAP, DumperOptions.FlowStyle.BLOCK));
//可以自定義寫入格式
//writer.write(yml.dumpAs(obj, Tag.MAP, DumperOptions.FlowStyle.FLOW));
} catch (IOException e) {
e.printStackTrace();
}
我用的是dumpAsMap方法,這個方法能夠自動把map結構的對象轉為yml文件的key:value的結構,map層級用兩個空格表示,但是我的這個項目用了4個空格,所以后面我還得重新特殊處理一下;
完整代碼,
因為我的主要目的是修改數據庫配置信息,由於項目系統支持了很多類型的數據庫,所以我要適配各種數據庫;
@SpringBootTest
public class DemoTest {
@Test
public void readYmlTest() {
//要讀的文件路徑
String filePath ="C:"+File.separator+"Users"+File.separator+"17247"+File.separator+"Desktop"+File.separator+"application-exclusive.yml";
Map<String,Object> obj =null;
File file = new File(filePath);
//解析yml文件的關鍵類
Yaml yml =null;
try (FileInputStream in = new FileInputStream(file)){
yml = new Yaml();
obj = (Map)yml.load(in);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Map<String,Object> springMap =(Map)obj.get("spring");
String url = "jdbc:oracle:thin:@127.0.0.1:1521/orcl";
//String url = "jdbc:dm://127.0.0.1:5236/DMSERVER?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8";
String usesrname = "poc";
String pwd = "ENC(w2PXuzg+U60Zs2MA/FouyQ==)";
AEDatasourceFactory AeDatasourceFactory = new AEDatasourceFactory(url,usesrname,pwd);
//根據不同數據庫更新模板
AeDatasourceFactory.updateDatasourceTemplet(springMap);
try (FileWriter writer = new FileWriter(file)) {
//writer.write(yml.dump(obj));
//writer.write(yml.dumpAsMap(obj));
writer.write(yml.dumpAs(obj, Tag.MAP, DumperOptions.FlowStyle.BLOCK));
//writer.write(yml.dumpAs(obj, Tag.MAP, DumperOptions.FlowStyle.BLOCK));
} catch (IOException e) {
e.printStackTrace();
}
//重新讀取文件調整空格
StringBuffer buffer = new StringBuffer();
String newLine =System.lineSeparator();
try (BufferedReader input = new BufferedReader(
new InputStreamReader(new FileInputStream(file), "utf-8"));) {
String line;
while ((line = input.readLine()) != null) {
String lineTrim = line.trim();
String pre ="";
if(line.startsWith(" ")){
int length = line.length()-lineTrim.length();
pre = this.getSpaceByNum(length*2);
}
if(lineTrim.startsWith("- ")){
//有橫杠的需要再加4個空格
pre = pre+this.getSpaceByNum(4);
}
buffer.append(pre+lineTrim);
buffer.append(newLine);
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
try (BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(new FileOutputStream(filePath, false), "utf-8"))) {
writer.write(buffer.toString());
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
//獲取指定數量的空格
private String getSpaceByNum(int num){
StringBuffer buffer = new StringBuffer();
for(int i=0;i<num;i++){
buffer.append(" ");
}
return buffer.toString();
}
private String getAEEncryptPassword(String input) {
return input ;
}
}
適配數據庫工廠類
import java.util.LinkedHashMap;
import java.util.Map;
/**
* AE數據源模板工廠類
*/
public class AEDatasourceFactory {
//oracle數據庫
private final String ORACLE_TYPE="jdbc:oracle";
//sqlserver數據庫類型
private final String SQLSERVER_TYPE="jdbc:oracle";
//db2數據庫
private final String DB2_TYPE="jdbc:db2";
//達夢數據庫
private final String DM_TYPE="jdbc:dm";
//pg數據庫
private final String PG_TYPE="dbc:postgresql";
//高斯數據庫
private final String GAUSS_TYPE="jdbc:zenith";
String url;
String username;
String password;
public AEDatasourceFactory(String url, String username, String password) {
this.url=url;
this.username=username;
this.password=password;
}
/**
* 獲取更新數據源模板
* @param springMap
*/
public void updateDatasourceTemplet(Map<String,Object> springMap){
Map<String,Object> dataSource = (Map<String,Object>)springMap.get("datasource");
Map<String,Object> jpaMap = (Map<String,Object>)dataSource.get("jpa");
if(jpaMap==null){
//應該是jpa和datasource同級的,
// 但是他們提供的可能是不同級的
jpaMap = springMap.get("jpa")!=null?(Map<String,Object>)springMap.get("jpa"):new LinkedHashMap<>();
}
dataSource.clear();
Map<String,Object> hikari = new LinkedHashMap<>();
hikari.put("auto-commit",false);
if(url.startsWith(ORACLE_TYPE) || url.startsWith(SQLSERVER_TYPE)){
dataSource.put("type","com.zaxxer.hikari.HikariDataSource");
dataSource.put("url",url);
dataSource.put("username",username);
dataSource.put("password",getAEEncryptPassword(password));
dataSource.put("hikari",hikari);
}else if(url.startsWith(DM_TYPE)){
dataSource.put("url",url);
dataSource.put("username",username);
dataSource.put("password",getAEEncryptPassword(password));
dataSource.put("driver-class-name","dm.jdbc.driver.DmDriver");
}else if(url.startsWith(DB2_TYPE)){
dataSource.put("type","com.zaxxer.hikari.HikariDataSource");
dataSource.put("driver-class-name","com.ibm.db2.jcc.DB2Driver");
dataSource.put("hikari",hikari);
}else if(url.startsWith(GAUSS_TYPE)){
dataSource.put("url",url);
dataSource.put("username",username);
dataSource.put("password",getAEEncryptPassword(password));
dataSource.put("driver-class-name","com.huawei.gauss.jdbc.ZenithDriver");
}else if(url.startsWith(PG_TYPE)){
dataSource.put("type","com.zaxxer.hikari.HikariDataSource");
dataSource.put("url",url);
dataSource.put("username",username);
dataSource.put("password",getAEEncryptPassword(password));
dataSource.put("hikari",hikari);
//pg沒有jpa
jpaMap=null;
}
if(jpaMap!=null){
getJpaTemplet(jpaMap);
springMap.put("jpa",jpaMap);
}
}
private void getJpaTemplet(Map<String,Object> jpaMap){
if(jpaMap==null){
return;
}
jpaMap.clear();
Map<String,Object> properties = new LinkedHashMap<>();
if(url.startsWith(ORACLE_TYPE) || url.startsWith(SQLSERVER_TYPE)){
jpaMap.put("database-platform","org.hibernate.dialect.Oracle12cDialect");
jpaMap.put("database","ORACLE");
jpaMap.put("show-sql",false);
properties.put("hibernate.id.new_generator_mappings",true);
properties.put("hibernate.connection.provider_disables_autocommit",true);
properties.put("hibernate.cache.use_second_level_cache",false);
properties.put("hibernate.cache.use_query_cache",false);
properties.put("hibernate.generate_statistics",false);
jpaMap.put("properties",properties);
}else if(url.startsWith(GAUSS_TYPE)){
//不知道為啥要用oracle的
properties.put("hibernate.dialect","org.hibernate.dialect.Oracle12cDialect");
jpaMap.put("properties",properties);
}else if(url.startsWith(DM_TYPE)){
properties.put("hibernate.dialect","org.hibernate.dialect.DmDialect");
jpaMap.put("properties",properties);
}else if(url.startsWith(PG_TYPE)){
}else if(url.startsWith(DB2_TYPE)){
properties.put("hibernate.dialect","com.diwork.intelliv.workbench.auth.dialect.CustomDB2Dialect");
properties.put("hibernate.auto_quote_keyword",true);
jpaMap.put("properties",properties);
jpaMap.put("show-sql",true);
Map<String,Object> hibernate = new LinkedHashMap<>();
Map<String,Object> naming = new LinkedHashMap<>();
naming.put("physical-strategy","org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl");
hibernate.put("naming",naming);
jpaMap.put("hibernate",hibernate);
}
}
//密碼加密方法
private String getAEEncryptPassword(String input) {
return input ;
}
}
這樣修改了指定的內容,而且還保證了文件的原格式,但有個問題是文件的注釋會丟失;
