如何让Spring Config Server返回嵌套结构JSON响应而非解析路径?
Hey there, let's tackle this problem where Spring Config Server is returning flattened key-value pairs in the source section of its response, but you need the nested JSON structure that matches your original YAML. Here's what you can do:
First, Let's Recap the Issue
Your YAML in GitLab looks like this:
holidays: US: - 03/19/2020 - 03/20/2020 - 05/18/2020
But the Config Server response gives you flattened keys like holidays.US[0] instead of the nested holidays.US array. You want the source to mirror the original YAML's structure.
Solution 1: Enable Pretty-Printing (Simplest Fix)
Spring Cloud Config Server has a built-in property that can make it return nested JSON instead of flattened paths. Just add this to your Config Server's application.yml or application.properties:
For YAML:
spring: cloud: config: server: git: pretty-print: true
For properties:
spring.cloud.config.server.git.pretty-print=true
This tells the server to serialize the properties into their natural nested structure rather than flattening them into dot-separated keys. Restart your Config Server, and you should see the nested JSON in the response.
Solution 2: Use the Native Profile (For Local or Cloned Repos)
If you're using a local clone of your GitLab repo (or a native file system source), enabling the native profile can also preserve the nested structure. Here's how to set it up:
- Add the native profile to your Config Server's active profiles:
spring: profiles: active: native cloud: config: server: native: search-locations: file:///path/to/your/gitlab/repo/clone
- Restart the server. This approach uses the native property source handler, which respects the YAML's nested structure by default.
Solution 3: Custom Response Converter (If All Else Fails)
If the above solutions don't work for your setup (e.g., older Spring Cloud versions), you can create a custom HTTP message converter to transform the flattened source into nested JSON. Here's a step-by-step implementation:
- Create a custom converter class that extends
MappingJackson2HttpMessageConverter:
import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.cloud.config.server.environment.Environment; import org.springframework.cloud.config.server.environment.PropertySource; import org.springframework.http.HttpOutputMessage; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class NestedPropertySourceConverter extends MappingJackson2HttpMessageConverter { private final ObjectMapper objectMapper = new ObjectMapper(); @Override protected void writeInternal(Object object, HttpOutputMessage outputMessage) throws IOException { if (object instanceof Environment) { Environment configEnvironment = (Environment) object; // Process each property source to convert flattened keys to nested structure configEnvironment.getPropertySources().forEach(this::convertFlattenedSourceToNested); } super.writeInternal(object, outputMessage); } private void convertFlattenedSourceToNested(PropertySource propertySource) { Map<String, Object> flattenedSource = (Map<String, Object>) propertySource.getSource(); Map<String, Object> nestedSource = new HashMap<>(); for (Map.Entry<String, Object> entry : flattenedSource.entrySet()) { String[] keyParts = entry.getKey().split("\\."); Map<String, Object> currentLevel = nestedSource; for (int i = 0; i < keyParts.length; i++) { String part = keyParts[i]; if (i == keyParts.length - 1) { // Handle array indices like "US[0]" if (part.contains("[")) { String arrayKey = part.substring(0, part.indexOf("[")); int index = Integer.parseInt(part.substring(part.indexOf("[") + 1, part.indexOf("]"))); // Initialize or get the list for the array key List<Object> array = (List<Object>) currentLevel.computeIfAbsent(arrayKey, k -> new ArrayList<>()); // Ensure the list has enough elements to set the index while (array.size() <= index) { array.add(null); } array.set(index, entry.getValue()); } else { currentLevel.put(part, entry.getValue()); } } else { // Move to the next nested level currentLevel = (Map<String, Object>) currentLevel.computeIfAbsent(part, k -> new HashMap<>()); } } } propertySource.setSource(nestedSource); } }
- Register the converter in your Config Server's configuration:
import org.springframework.context.annotation.Configuration; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import java.util.List; @Configuration public class WebConfig implements WebMvcConfigurer { @Override public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { converters.add(new NestedPropertySourceConverter()); } }
This converter intercepts the Config Server's response, transforms the flattened source map into a nested structure, and then sends the modified response back.
Testing the Fix
After applying any of these solutions, hit your Config Server's endpoint (e.g., http://your-config-server:8888/simpleyml/default) and check the source section. It should now show the nested holidays object with the US array, matching your original YAML structure.
内容的提问来源于stack exchange,提问作者VJohn

