如何用Java在YAML文件中生成字符串格式的多端口配置
解决方案
问题根源
你遇到的YAML格式断裂问题,核心是手动拼接links部分的字符串并直接写入文件,这会干扰SnakeYAML的正常序列化输出,导致后续内容格式错乱。另外之前尝试的Representer配置没有正确应用到YAML实例中,导致端口字符串无法被强制引号包裹。
修正步骤及代码
- 移除手动拼接links的逻辑,改用SnakeYAML自动序列化
links列表,保证YAML结构一致性。 - 配置自定义Representer,强制所有字符串类型的标量使用双引号(或单引号)包裹。
- 将ports数组改为List,和Bean中的类型保持一致,避免序列化时的类型转换问题。
修正后的完整代码:
import org.springframework.stereotype.Service; import org.yaml.snakeyaml.DumperOptions; import org.yaml.snakeyaml.Yaml; import org.yaml.snakeyaml.nodes.Node; import org.yaml.snakeyaml.nodes.Tag; import org.yaml.snakeyaml.representer.Representer; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.time.LocalDateTime; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @Service public class GenerateYamlFileImpl implements GenerateYamlFile { private static final Logger logger = LogManager.getLogger(GenerateYamlFileImpl.class); public void writeYamlfile(Container container, File file) { try (FileWriter writer = new FileWriter(file.getPath() + LocalDateTime.now() + FXMLPageConstants.FILE_TYPE)) { DumperOptions options = new DumperOptions(); options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); options.setPrettyFlow(true); // 配置自定义Representer,强制字符串用双引号包裹 Representer representer = new Representer(options) { @Override protected Node representScalar(Tag tag, String value) { // 对所有字符串标量使用双引号 return super.representScalar(tag, value, DumperOptions.ScalarStyle.DOUBLE_QUOTED); } }; // 使用自定义Representer创建YAML实例 Yaml yaml = new Yaml(representer, options); Map<String, Object> data = new LinkedHashMap<>(); data.put("name", container.getName()); Map<String, Object> topology = new LinkedHashMap<>(); Map<String, Object> nodes = new LinkedHashMap<>(); for (Map.Entry<String, NodesProperties> entry : container.getTopology().getNodes().entrySet()) { Map<String, Object> nodeDetails = new LinkedHashMap<>(); NodesProperties nodeProps = entry.getValue(); nodeDetails.put("kind", nodeProps.getKind()); nodeDetails.put("image", nodeProps.getImage()); if (nodeProps.getGroup() != null && !nodeProps.getGroup().isBlank()) { nodeDetails.put("group", nodeProps.getGroup()); } if (nodeProps.getStartupConfig() != null && !nodeProps.getStartupConfig().isBlank()) { nodeDetails.put("startup-config", nodeProps.getStartupConfig()); } if (nodeProps.getPorts() != null && !nodeProps.getPorts().isEmpty()) { // 将ports转为带":22"后缀的List<String>,保持类型一致 List<String> ports = nodeProps.getPorts().stream() .map(port -> port + ":" + "22") .collect(Collectors.toList()); nodeDetails.put("ports", ports); } nodes.put(entry.getKey(), nodeDetails); } topology.put("nodes", nodes); // 处理links,转为SnakeYAML可序列化的结构,不再手动拼接 List<Map<String, Object>> linksList = container.getTopology().getLinks().stream() .map(link -> { Map<String, Object> linkMap = new LinkedHashMap<>(); linkMap.put("endpoints", link.getEndpoints()); return linkMap; }) .collect(Collectors.toList()); topology.put("links", linksList); data.put("topology", topology); // 一次性序列化所有数据到文件,避免手动写入破坏格式 yaml.dump(data, writer); logger.info("YAML file generated successfully: " + file.getPath()); } catch (IOException e) { logger.error("Error while writing YAML file", e); } } }
关键修改说明
- 自定义Representer:通过重写
representScalar方法,强制所有字符串标量使用双引号包裹,确保端口字符串(如2000:22)被正确识别为字符串类型。 - 移除手动links拼接:将links转为
List<Map>结构,让SnakeYAML自动序列化,保证整个YAML文件的结构完整性,不会出现格式断裂。 - ports改用List:和Bean中的
List<String>类型保持一致,避免数组序列化时可能出现的异常,同时让SnakeYAML能正确应用Representer的规则。
生成效果
修改后生成的YAML会符合预期格式:
name: "example-container" topology: nodes: node1: kind: "server" image: "ubuntu:latest" ports: - "2000:22" - "3000:80" links: - endpoints: ["node1", "node2"]
内容的提问来源于stack exchange,提问作者BEdits
相关产品推荐
相关产品推荐

