当使用Spring MVC for REST时,你如何让jackson漂亮地打印呈现的JSON?
在使用Spring MVC开发REST服务的同时,我希望在开发中呈现JSON'漂亮的印刷',但在生产中正常(减less空白)。
如果您使用Spring Boot 1.2或更高版本,则简单的解决scheme是添加
spring.jackson.serialization.INDENT_OUTPUT=true
到application.properties
文件。 这假设你正在使用Jackson进行序列化。
如果您使用Spring Boot的早期版本,则可以添加
http.mappers.json-pretty-print=true
这个解决scheme仍然适用于Spring Boot 1.2,但不推荐使用 ,最终将被彻底删除。 在启动时您将在日志中获得弃用警告。
(使用spring-boot-starter-web
进行testing)
当我发布这个问题时,我有一个答案,但我想我会张贴它,以防有更好的替代解决scheme。 这是我的经验:
第一件事是第一件事 MappingJacksonHttpMessageConverter
期望您注入一个Jackson ObjectMapper
实例,并在该实例上执行Jacksonconfiguration(而不是通过Spring类)。
我认为这样做会很简单:
创build一个ObjectMapperFactoryBean
实现,允许我自定义可以注入到MappingJacksonHttpMessageConverter
的ObjectMapper
实例。 例如:
<bean id="jacksonHttpMessageConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"> <property name="objectMapper"> <bean class="com.foo.my.ObjectMapperFactoryBean"> <property name="prettyPrint" value="${json.prettyPrint}"/> </bean> </property> </bean>
然后,在我的ObjectMapperFactoryBean
实现中,我可以做到这一点(在SO上的其他地方已经被logging为解决scheme):
ObjectMapper mapper = new ObjectMapper(); mapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, isPrettyPrint()); return mapper;
但它没有工作。 并试图找出为什么是一场噩梦 。 jackson是一个耐心的重大考验。 看看它的源代码,只会让你更加混淆,因为它使用过时和钝的configurationforms(用于打开/closuresfunction的整数位掩码?你在开玩笑吗?)
我基本上必须从头开始重写Spring的MappingJacksonHttpMessageConverter
,并覆盖它的writeInternal
实现如下:
@Override protected void writeInternal(Object o, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException { JsonEncoding encoding = getEncoding(outputMessage.getHeaders().getContentType()); JsonGenerator jsonGenerator = getObjectMapper().getJsonFactory().createJsonGenerator(outputMessage.getBody(), encoding); try { if (this.prefixJson) { jsonGenerator.writeRaw("{} && "); } if (isPrettyPrint()) { jsonGenerator.useDefaultPrettyPrinter(); } getObjectMapper().writeValue(jsonGenerator, o); } catch (JsonGenerationException ex) { throw new HttpMessageNotWritableException("Could not write JSON: " + ex.getMessage(), ex); } }
我添加到现有的实现的唯一的东西是下面的块:
if (isPrettyPrint()) { jsonGenerator.useDefaultPrettyPrinter(); }
isPrettyPrint()
只是一个JavaBean兼容的getter w /匹配设置器,我添加到我的MappingJacksonHttpMessageConverter
子类。
只有在跳过这些箍环之后,我才能根据我的${json.prettyPrint}
值(根据应用程序的部署方式将其设置为属性)打开或closures漂亮的打印。
我希望这能帮助未来的人!
当你使用Jackson 2.0.0时,你可以用Les想要的方式来做。 我目前使用RC3和configuration似乎按预期工作。
ObjectMapper jacksonMapper = new ObjectMapper(); jacksonMapper.configure(SerializationFeature.INDENT_OUTPUT, true);
转换
{"foo":"foo","bar":{"field1":"field1","field2":"field2"}}
成
{ "foo" : "foo", "bar" : { "field1" : "field1", "field2" : "field2" } }
我如何让jackson打印它生成的JSON内容?
这是一个简单的例子:
原始的JSONinput:
{"one":"AAA","two":["BBB","CCC"],"three":{"four":"DDD","five":["EEE","FFF"]}}
Foo.java:
import java.io.FileReader; import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.map.ObjectWriter; public class Foo { public static void main(String[] args) throws Exception { ObjectMapper mapper = new ObjectMapper(); MyClass myObject = mapper.readValue(new FileReader("input.json"), MyClass.class); // this is Jackson 1.x API only: ObjectWriter writer = mapper.defaultPrettyPrintingWriter(); // ***IMPORTANT!!!*** for Jackson 2.x use the line below instead of the one above: // ObjectWriter writer = mapper.writer().withDefaultPrettyPrinter(); System.out.println(writer.writeValueAsString(myObject)); } } class MyClass { String one; String[] two; MyOtherClass three; public String getOne() {return one;} void setOne(String one) {this.one = one;} public String[] getTwo() {return two;} void setTwo(String[] two) {this.two = two;} public MyOtherClass getThree() {return three;} void setThree(MyOtherClass three) {this.three = three;} } class MyOtherClass { String four; String[] five; public String getFour() {return four;} void setFour(String four) {this.four = four;} public String[] getFive() {return five;} void setFive(String[] five) {this.five = five;} }
输出:
{ "one" : "AAA", "two" : [ "BBB", "CCC" ], "three" : { "four" : "DDD", "five" : [ "EEE", "FFF" ] } }
如果这种方法不完全符合您的需求,那么如果您在API文档v1.8.1中search“漂亮”,则会提供相关的组件。 如果您使用API版本2.x,那么请查看较新的API 2.1.0文档 。
我可能会build议这种方法,它适用于Spring 4.0.x以及更旧的版本。
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import java.util.List; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; @Configuration @EnableWebMvc public class WebMvcConfig extends WebMvcConfigurerAdapter { @Bean public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() { MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter(); mappingJackson2HttpMessageConverter.setObjectMapper(objectMapper()); return mappingJackson2HttpMessageConverter; } @Bean public ObjectMapper objectMapper() { ObjectMapper objMapper = new ObjectMapper(); objMapper.enable(SerializationFeature.INDENT_OUTPUT); return objMapper; } @Override public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { super.configureMessageConverters(converters); converters.add(mappingJackson2HttpMessageConverter()); } }
感谢威利惠勒的解决scheme: 威利惠勒的春季博客
漂亮的打印将通过添加和configurationMappingJackson2HttpMessageConverter转换器启用。 在生产环境中禁用相纸。
消息转换器configuration
<mvc:annotation-driven> <mvc:message-converters> <bean id="jacksonHttpMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> <property name="prettyPrint" value="${json.prettyPrint}" /> </bean> </mvc:message-converters> </mvc:annotation-driven>
我无法让自定义的MappingJacksonHttpMessageConverter按照上面的build议工作,但是我终于能够在configuration后挣扎了。 从代码的angular度来看,我完全是上面提到的,但是我不得不把下面的configuration添加到我的springapp-servlet.xml中来让它工作。
我希望这能帮助那些希望实施相同的人。
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"> <property name="messageConverters"> <list> <ref bean="jsonConverter" /> </list> </property> </bean> <bean id="jsonConverter" class="com.xxx.xxx.xxx.common.PrettyPrintMappingJacksonHttpMessageConverter"> <property name="supportedMediaTypes" value="application/json" /> <property name="prettyPrint" value="true" /> </bean>
Jackson 2有一个更好的API,但是在Spring MVC环境下,Spring MVC使用ObjectMapper#writeValue(JsonGenerator,Object)将对象写成JSON,所以不能解决这个问题。 此writeValue变体不应用Jackson 1.x或2.0中的INDEXECT_OUTPUT等ObjectMapper序列化function。
我认为这有点令人困惑。 由于我们使用ObjectMapper来构buildJsonGenerators,所以我希望返回的生成器可以根据configuration的ObjectMapper设置进行初始化。 我在这里报告这是一个针对jackson2.0的问题: https : //github.com/FasterXML/jackson-databind/issues/12 。
Les基于prettyPrint标志的值调用JsonGenerator#useDefaultPrettyPrinter的build议是我们现在可以做的最好的。 我已经提前创build了一个基于INDENT_OUTPUT SerializationFeature的启用状态的Jackson2 HttpMessageConverter: https ://gist.github.com/2423129。
基于baeldung这可能是一个不错的主意,使用Java 8:
@Override public void extendMessageConverters(List<HttpMessageConverter<?>> converters) { Optional<HttpMessageConverter<?>> converterFound; converterFound = converters.stream().filter(c -> c instanceof AbstractJackson2HttpMessageConverter).findFirst(); if (converterFound.isPresent()) { final AbstractJackson2HttpMessageConverter converter; converter = (AbstractJackson2HttpMessageConverter) converterFound.get(); converter.getObjectMapper().enable(SerializationFeature.INDENT_OUTPUT); converter.getObjectMapper().enable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); } }
我会做这个渲染问题,而不是REST服务的关注。
谁在做渲染? 让该组件格式化JSON。 也许它可以是两个url – 一个用于生产,另一个用于开发。