Controller 方法返回對象,配置 MappingJackson2JsonView 後,JSON 輸出被包裹一層鍵名(通常是模型屬性名或類名簡寫):
// 期望
{"code":200,"data":{"id":1}}
// 實際
{"commonAjaxResponse":{"code":200,"data":{"id":1}}}
Spring MVC 的 ModelAndView 模型是 Map 結構,MappingJackson2JsonView 默認將整個模型 Map 序列化。當模型中只有一個條目時,若開啟 extractValueFromSingleKeyModel,會直接序列化該值而非整個 Map。
<bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView">
<property name="extractValueFromSingleKeyModel" value="true"/>
</bean>
<!-- 内容協商視圖解析器 -->
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="order" value="1"/>
<property name="contentNegotiationManager">
<bean class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="favorPathExtension" value="true"/>
<property name="favorParameter" value="false"/>
<property name="defaultContentType" value="application/json"/>
</bean>
</property>
<property name="defaultViews">
<list>
<!-- 關鍵:開啟單鍵模型值提取 -->
<bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView">
<property name="extractValueFromSingleKeyModel" value="true"/>
<!-- 可選:禁用 FAIL_ON_EMPTY_BEANS 避免無屬性類報錯 -->
<property name="objectMapper">
<bean class="com.fasterxml.jackson.databind.ObjectMapper">
<property name="serializationInclusion" value="NON_NULL"/>
</bean>
</property>
</bean>
</list>
</property>
</bean>
@Configuration
@EnableWebMvc
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.favorPathExtension(true).defaultContentType(MediaType.APPLICATION_JSON);
}
@Bean
public View jsonView() {
MappingJackson2JsonView view = new MappingJackson2JsonView();
view.setExtractValueFromSingleKeyModel(true); // 核心
view.setObjectMapper(objectMapper()); // 可選自定義 ObjectMapper
return view;
}
@Bean
public ObjectMapper objectMapper() {
ObjectMapper om = new ObjectMapper();
om.setSerializationInclusion(JsonInclude.Include.NON_NULL);
om.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
return om;
}
}
Spring Boot 默認使用 HttpMessageConverter(MappingJackson2HttpMessageConverter)而非 MappingJackson2JsonView,**不會產生根節點包裹問題**。若遷移老項目發現該問題,說明仍在使用 ViewResolver 鏈,按上述 XML/Java Config 修正即可。
| 方案 | 適用場景 | 是否需額外依賴 |
|---|---|---|
extractValueFromSingleKeyModel=true | 傳統 XML/ViewResolver 架構 | 無 |
改用 @RestController + HttpMessageConverter | 現代 Spring Boot 項目 | 無 |
手動返回 ResponseEntity<T> | 需精確控制狀態碼、Header | 無 |
String 視圖名而非對象,不走此 View,無效。FAIL_ON_EMPTY_BEANS,空 Bean 會拋異常,建議配置 objectMapper.configure(FAIL_ON_EMPTY_BEANS, false)。一行 extractValueFromSingleKeyModel=true 即可徹底解決老項目 JSON 多層包裝痛點,建議在統一視圖配置類中集中管理。