首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Spring MVC 內容協商:ContentNegotiatingViewResolver 實現一資源多表現

     編輯:Java 綜合教學

RESTful 核心模式:同一 URL 根據 Accept/擴展名/參數返回 JSON/XML/HTML

Spring MVC 的 ContentNegotiatingViewResolver 讓單一 Controller 方法根據客戶端需求自動選擇視圖表現形式。本文詳細配置擴展名、Accept Header、請求參數三種協商策略,整合 Jackson JSON、JAXB XML、JSP 三種視圖,並給出 Spring 4/5 與 Boot 2.x 完整配置代碼。

一、三種內容協商策略

策略客戶端請求示例適用場景
路徑擴展名GET /user/1.json /user/1.xml /user/1瀏覽器直訪、API 文檔、緩存友好
Accept HeaderAccept: application/json / application/xml標準 REST 客戶端、Ajax、移動端
請求參數GET /user/1?format=json無法設置 Header 的場景、快速測試

二、XML 配置完整版

<!-- 1. 內容協商視圖解析器:優先級最高 (order=1) -->
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
    <property name="order" value="1"/>
    <!-- 啟用擴展名協商 -->
    <property name="favorPathExtension" value="true"/>
    <!-- 禁用參數協商 -->
    <property name="favorParameter" value="false"/>
    <!-- 忽略 Accept Header(按需開啟) -->
    <property name="ignoreAcceptHeader" value="true"/>
    <!-- 擴展名 → MediaType 映射 -->
    <property name="mediaTypes">
        <map>
            <entry key="json" value="application/json"/>
            <entry key="xml" value="application/xml"/>
            <entry key="html" value="text/html"/>
        </map>
    </property>
    <!-- 預設視圖:JSON (Jackson) + XML (JAXB) -->
    <property name="defaultViews">
        <list>
            <bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"/>
            <bean class="org.springframework.web.servlet.view.xml.MarshallingView">
                <constructor-arg>
                    <bean class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
                        <property name="classesToBeBound">
                            <list><value>com.cn.my.entity.Course</value></list>
                        </property>
                    </bean>
                </constructor-arg>
            </bean>
        </list>
    </property>
</bean>

<!-- 2. JSP 視圖解析器:兜底 (order=2) -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="order" value="2"/>
    <property name="prefix" value="/WEB-INF/jsp/"/>
    <property name="suffix" value=".jsp"/>
    <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
</bean>

三、Controller 實現

@Controller
@RequestMapping("/mul")
public class MultiViewController {
    @RequestMapping("/simple/{courseId}")
    public String simple(@PathVariable String courseId, ModelMap model) {
        Course c = new Course();
        c.setId(courseId);
        c.setName("李四");
        c.setContent("測試內容");
        model.put("course", c);
        return "course"; // 邏輯視圖名
    }
}
  • 返回 String 邏輯視圖名,配合 ModelMap 傳遞數據。
  • 無 @ResponseBody,視圖解析器接管渲染。
  • Course 需加 @XmlRootElement 支持 JAXB 序列化。

四、測試驗證

五、Spring Boot 2.x 簡化配置

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
        configurer.favorPathExtension(true)
                  .favorParameter(false)
                  .ignoreAcceptHeader(true)
                  .mediaType("json", MediaType.APPLICATION_JSON)
                  .mediaType("xml", MediaType.APPLICATION_XML);
    }
    @Bean
    public ViewResolver contentNegotiatingViewResolver(ContentNegotiationManager manager) {
        ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
        resolver.setContentNegotiationManager(manager);
        resolver.setDefaultViews(Arrays.asList(
            new MappingJackson2JsonView(),
            new MarshallingView(jaxb2Marshaller())
        ));
        resolver.setOrder(1);
        return resolver;
    }
    @Bean
    public ViewResolver jspViewResolver() {
        InternalResourceViewResolver r = new InternalResourceViewResolver();
        r.setPrefix("/WEB-INF/jsp/"); r.setSuffix(".jsp"); r.setOrder(2);
        return r;
    }
    @Bean public Jaxb2Marshaller jaxb2Marshaller() {
        Jaxb2Marshaller m = new Jaxb2Marshaller();
        m.setClassesToBeBound(Course.class); return m;
    }
}

六、核心原理解析

  1. ContentNegotiatingViewResolver 實現 ViewResolver,但不直接渲染,而是委派給 defaultViews 或其他 ViewResolver。
  2. 解析流程:
    a. 根據 favorPathExtension/Parameter/AcceptHeader 確定請求的 MediaType。
    b. 遍歷 defaultViews,找到 view.getContentType() 匹配的 View。
    c. 若無匹配,委派給 order 更大的 ViewResolver(如 JSP)。
  3. MappingJackson2JsonView 使用 ObjectMapper 序列化 Model 數據。
  4. MarshallingView 使用 Marshaller (JAXB/XStream) 序列化。

七、最佳實踐建議

  1. 生產環境同時啟用擴展名 + Accept Header,favorPathExtension=true, ignoreAcceptHeader=false。
  2. API 版本控制:/v1/user/1.json 或 Header Accept: application/vnd.myapp.v1+json。
  3. 錯誤處理:配置 DefaultHandlerExceptionResolver 返回統一 JSON 錯誤格式。
  4. 大文件下載:用 AbstractView 子類直接寫 HttpServletResponse,避免內存佔用。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
請求 URL響應 Content-Type響應體
/mul/simple/123.jsonapplication/json{"id":"123","name":"李四","content":"測試內容"}
/mul/simple/123.xmlapplication/xml<course><id>123</id>...</course>
/mul/simple/123text/htmlcourse.jsp 渲染頁面