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

Spring MVC 自定義視圖與視圖解析器開發實戰:多格式響應統一處理架構

     編輯:Java 相關知識

Spring MVC 視圖解析機制回顧

請求處理流程六階段:

  1. DispatcherServlet 攔截請求。
  2. 根據配置/註解查找 Controller。
  3. Controller 處理業務,返回 ModelAndView(模型數據 + 視圖名)。
  4. 容器按順序調用註冊的 ViewResolver 解析視圖名為 View 對象。
  5. 渲染視圖輸出響應。

Spring MVC 處理流程

常用視圖解析器對照表

常用視圖解析器列表

注意:InternalResourceViewResolver 即使找不到文件也會返回 View(非 null),導致後續解析器不被調用,**必須設置最低優先級(order 最大)**。

場景:支持 JSP、SWF、自定義 .config 三種視圖

需求:統一入口,根據副檔名分派不同解析器,避免 Controller 耦合視圖技術。

一、開發通用視圖類:GenericFileView

繼承 AbstractUrlBasedView,直接將文件內容寫入 Response,設置 Content-Type。

public class GenericFileView extends AbstractUrlBasedView {
    private static final String DEFAULT_CONTENT_TYPE = "text/plain";
    private String responseContent;

    public GenericFileView() { setContentType(DEFAULT_CONTENT_TYPE); }

    @Override
    protected void renderMergedOutputModel(Map<String, Object> model,
            HttpServletRequest request, HttpServletResponse response) throws Exception {
        response.setContentType(getContentType());
        response.getWriter().write(responseContent);
        response.getWriter().close();
    }
    public void setResponseContent(String content) { this.responseContent = content; }
}

適用於瀏覽器可直接渲染的靜態資源(文本、SWF、圖片等),**不支持 JSP 等需編譯的動態視圖**。

二、開發視圖解析器:GenericFileViewResolver

繼承 AbstractCachingViewResolver,實現 Ordered 接口控制優先級。

public class GenericFileViewResolver extends AbstractCachingViewResolver implements Ordered {
    private String location; // 文件根目錄,如 /WEB-INF/swf/
    private String viewName; // Spring 容器中 GenericFileView Bean 名稱
    private int order = 0;

    @Override
    protected View loadView(String viewName, Locale locale) throws Exception {
        if (location == null) throw new Exception("No location specified");
        String requestedPath = location + viewName;
        Resource resource = getApplicationContext().getResource(requestedPath);
        if (!resource.exists()) return null; // 關鍵:找不到返回 null,讓後續解析器處理

        GenericFileView view = getApplicationContext().getBean(this.viewName, GenericFileView.class);
        view.setUrl(requestedPath);
        view.setResponseContent(inputStreamToString(resource.getInputStream(), "ISO-8859-1"));
        return view;
    }
    // getter/setter/order 實現...
}

三、復合視圖解析器:MultipleViewResolver

根據副檔名路由到對應解析器,類似 ContentNegotiatingViewResolver 但更輕量:命中即返回,不遍歷所有解析器。

Spring XML 配置

<bean id="viewResolver" class="com.sample.web.viewresolver.MultipleViewResolver" p:order="0">
  <property name="resolvers">
    <map>
      <entry key="config">
        <bean class="com.sample.web.viewresolver.GenericFileViewResolver"
              p:location="/WEB-INF/config/" p:cache="false">
          <property name="viewName" value="configFileView"/>
        </bean>
      </entry>
      <entry key="swf">
        <bean class="com.sample.web.viewresolver.GenericFileViewResolver"
              p:location="/WEB-INF/swf/" p:cache="false">
          <property name="viewName" value="swfFileView"/>
        </bean>
      </entry>
    </map>
  </property>
</bean>

核心邏輯

@Override
protected View loadView(String viewName, Locale locale) throws Exception {
    String ext = StringUtils.getFilenameExtension(viewName);
    if (ext == null) return null; // 無副檔名交給下一個
    ViewResolver resolver = resolvers.get(ext);
    return (resolver == null) ? null : resolver.resolveViewName(viewName, locale);
}

四、Controller 與視圖 Bean 配置

@Controller
public class SampleController {
    @RequestMapping("/jsp/sample") public String getSampleJsp() { return "SampleJsp"; }
    @RequestMapping("/config/sample.config") public String getSampleConfig() { return "SampleConfig.config"; }
    @RequestMapping("/swf/sample.swf") public String getSampleSwf() { return "SampleSwf.swf"; }
}
<!-- JSP 解析器,order=1 低於復合解析器 -->
<bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver" p:order="1">
  <property name="prefix" value="/WEB-INF/jsp/"/>
  <property name="suffix" value=".jsp"/>
</bean>

<!-- 視圖 Bean 原型作用域,每次請求新實例 -->
<bean id="configFileView" class="com.sample.web.view.GenericFileView"
      p:contentType="text/plain" p:url="" scope="prototype"/>
<bean id="swfFileView" class="com.sample.web.view.GenericFileView"
      p:contentType="application/x-shockwave-flash" p:url="" scope="prototype"/>

五、運行效果驗證

請求 URL處理鏈路響應效果
/swf/sample.swfMultipleViewResolver → swf 解析器 → swfFileView瀏覽器播放 Flash SWF 響應
/config/sample.configMultipleViewResolver → config 解析器 → configFileView瀏覽器顯示純文本 CONFIG 響應
/jsp/sampleMultipleViewResolver 返回 null → jspViewResolver → InternalResourceView渲染 JSP 頁面 JSP 響應

六、擴展建議

  • Controller 使用 @RequestMapping("/path/{fileName}") 支持任意文件名。
  • 增加 ContentNegotiatingViewResolver 支持 Accept Header 協商。
  • 視圖類可擴展支持範本引擎、PDF 生成等動態渲染。

總結

通過 通用視圖類 + 按副檔名分派的復合解析器,實現了:

  1. Controller 完全解耦視圖技術,僅返回邏輯視圖名。
  2. 新增視圖類型只需註冊解析器映射,零修改現有代碼。
  3. 優先級控制精確,JSP 等默認解析器作為最終兜底。
  4. 架構清晰、擴展性強,適合多格式響應的企業級應用。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved