Java code to modify the properties of the yml configuration file

Reference blog

Problem background

The development agent needs to accept the agent information and the heartbeat return cycle from the
server. The client cannot install the database. Consider storing it in the yml configuration file and dynamically modify the parameters through the code.

Dependencies that need to be imported

<dependency>
	<groupId>org.yaml</groupId>
    <artifactId>snakeyaml</artifactId>
</dependency>

Modify the tool class of yml

package agent.utils;

import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;

import java.io.*;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

/**
 * @author [email protected]
 * 修改YmL文件的工具类
 * @version 1.0
 * @date 2020/11/14 17:01
 */
public class YmlUtil {
    
    
    private final static DumperOptions OPTIONS = new DumperOptions();

    private static File file;

    private static InputStream ymlInputSteam;

    private static Object CONFIG_MAP;

    private static Yaml yaml;

    static {
    
    
        //将默认读取的方式设置为块状读取
        OPTIONS.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
    }

    /**
     * 使用其他方法之前必须调用一次 设置yml的输出文件,当没有设置输入流时可以不设置输入流,默认以此文件读入
     *
     * @param file 输出的文件
     */
    public static void setYmlFile(File file) throws FileNotFoundException {
    
    
        YmlUtil.file = file;
        if (ymlInputSteam == null) {
    
    
            setYmlInputSteam(new FileInputStream(file));
        }
    }


    /**
     * 使用其他方法之前必须调用一次 设置yml的输入流
     *
     * @param inputSteam 输入流
     */
    public static void setYmlInputSteam(InputStream inputSteam) {
    
    
        ymlInputSteam = inputSteam;
        yaml = new Yaml(OPTIONS);
        CONFIG_MAP = yaml.load(ymlInputSteam);
    }

    /**
     * 根据键获取值
     *
     * @param key 键
     * @return 查询到的值
     */
    @SuppressWarnings("unchecked")
    public static Object getByKey(String key) {
    
    
        if (ymlInputSteam == null) {
    
    
            return null;
        }
        String[] keys = key.split("\\.");
        Object configMap = CONFIG_MAP;
        for (String s : keys) {
    
    
            if (configMap instanceof Map) {
    
    
                configMap = ((Map<String, Object>) configMap).get(s);
            } else {
    
    
                break;
            }
        }
        return configMap == null ? "" : configMap;
    }

    public static void saveOrUpdateByKey(String key, Object value) throws IOException {
    
    
        KeyAndMap keyAndMap = new KeyAndMap(key).invoke();
        key = keyAndMap.getKey();
        Map<String, Object> map = keyAndMap.getMap();
        map.put(key, value);
        //将数据重新写回文件
        yaml.dump(CONFIG_MAP, new FileWriter(file));
    }

    public static void removeByKey(String key) throws Exception {
    
    
        KeyAndMap keyAndMap = new KeyAndMap(key).invoke();
        key = keyAndMap.getKey();
        Map<String, Object> map = keyAndMap.getMap();
        Map<String, Object> fatherMap = keyAndMap.getFatherMap();
        map.remove(key);
        if (map.size() == 0) {
    
    
            Set<Map.Entry<String, Object>> entries = fatherMap.entrySet();
            for (Map.Entry<String, Object> entry : entries) {
    
    
                if (entry.getValue() == map) {
    
    
                    fatherMap.remove(entry.getKey());
                }
            }
        }
        yaml.dump(CONFIG_MAP, new FileWriter(file));
    }

    private static class KeyAndMap {
    
    
        private String key;
        private Map<String, Object> map;
        private Map<String, Object> fatherMap;

        public KeyAndMap(String key) {
    
    
            this.key = key;
        }

        public String getKey() {
    
    
            return key;
        }

        public Map<String, Object> getMap() {
    
    
            return map;
        }

        public Map<String, Object> getFatherMap() {
    
    
            return fatherMap;
        }

        @SuppressWarnings("unchecked")
        public KeyAndMap invoke() {
    
    
            if (file == null) {
    
    
                System.err.println("请设置文件路径");
            }
            if (null == CONFIG_MAP) {
    
    
                CONFIG_MAP = new LinkedHashMap<>();
            }
            String[] keys = key.split("\\.");
            key = keys[keys.length - 1];
            map = (Map<String, Object>) CONFIG_MAP;
            for (int i = 0; i < keys.length - 1; i++) {
    
    
                String s = keys[i];
                if (map.get(s) == null || !(map.get(s) instanceof Map)) {
    
    
                    map.put(s, new HashMap<>(4));
                }
                fatherMap = map;
                map = (Map<String, Object>) map.get(s);
            }
            return this;
        }
    }
}

Test class

import java.io.File;
import java.util.Objects;
/**
 * @author [email protected]
 * yml编辑工具测试类
 * @version 1.0
 * @date 2020/11/14 17:11
 */
public class test {
    
    
    public static void main(String[] args) throws Exception {
    
    
        /**
         * 这里修改的是target目录编译后的路径,所以运行调试时。src目录下不会变
         */
        File yml = new File(Objects.requireNonNull(test.class.getClassLoader().getResource("application.yml")).toURI());
        //不管执行什么操作一定要先执行这个
        YmlUtil.setYmlFile(yml);
        System.out.println(YmlUtil.getByKey("修改前"+"heart.agentId"));
        System.out.println("aaaaaa");
        YmlUtil.saveOrUpdateByKey("heart.agentId", "哈哈哈哈");
        //YmlUtil.removeByKey("heart.agentId");
    }
}

There is a problem to pay attention to here, the modification is the configuration file in the target, not the src/resources

Existing follow-up problems

The project is run as a jar package, java.lang.IllegalArgumentException: URI is not hierarchicaland errors will be encountered during the operation .
What the code uses is to File f = new File(this.getClass().getResource("路径/目录").toURI());read all the files under this path. It was normal to run in the code environment, but after packaging, an URI is not hierarchicalerror occurred during the operation .
After DEBUG, it was discovered that when reading the file locally, the URI path was: file:/E:/idea-workspace/project/module(the module where the jar package is located) /target/classes/package/路径或者目录, but after packaging, all files under the path are also read, but the URI becomes: jar:file:/E:/idea-workspace/project/module(war packaging Module) is /target/war包名called /WEB-INF/lib/ the package name that needs to be read. Jar!/ is the path or directory, and the file read from the module where the jar is located becomes read from the packaged jar under the lib in the war class file, error is reported URI is not hierarchical.

The solution is to move the yml configuration file to the outside of the jar package

Just write the file name when reading

File yml = new File("application.yml");

It needs to be refreshed every time when getting the parameters, and the file is read instead of get after injection.

YmlUtil.setYmlFile(yml);
YmlUtil.getByKey();

Modify the parameters at runtime

java -jar demo.jar --spring.config.location=路径(application.yml)

Modify yml configuration at startup

java -jar iscas-agent-1.0-SNAPSHOT.jar --spring.config.location=application.yml --heart.agentLocation=北京

Guess you like

Origin blog.csdn.net/wenyichuan/article/details/109700894