【问题标题】:How to use multiple ViewResolvers in Spring?如何在 Spring 中使用多个 ViewResolver?
【发布时间】:2010-11-04 23:28:12
【问题描述】:

我正在开发一个 web 应用程序,我的大部分页面都使用 apache tile (2.1.2),但其中一些只需要纯 jsps。

我遇到了一个问题,InternalResourceViewResolverUrlBasedViewResolver 无论如何都会尝试解析视图,因此无论我使用哪种排序,它要么在普通 JSP 页面上失败,要么在图块页面上。

这里是配置:

<bean id="tilesViewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
    <property name="viewClass" value="org.springframework.web.servlet.view.tiles2.TilesView"/>
    <property name="order" value="0"/>
</bean>

<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/"/>
    <property name="suffix" value=".jsp"/>
    <property name="order" value="1"/>
</bean>

为了更清楚我想要做什么,我需要能够拥有这样的视图状态:

<view-state id="someState" view="/someDir/foo"><!--render foo.jsp -->
    <transition on="foo" to="bar"/>
</view-state>

<view-state id="someState" view="something.core"><!--render tile defintion named 'something.core' -->
    <transition on="foo" to="bar"/>
</view-state>

有谁知道如何配置东西,以便我可以让它渲染图块定义和纯 jsps?

【问题讨论】:

    标签: spring spring-mvc spring-webflow


    【解决方案1】:

    正如您所说,您不能将这些链接在一起。这两种情况的 javadoc 都清楚地表明它们都必须位于解析器链的末尾。

    我建议,如果您确实需要将这些结合使用,那么您编写一个简单的 ViewResolver 自定义实现,它采用视图名称,并决定委托给您的两个“真实”视图解析器中的哪一个。这假设您可以根据视图名称判断要调用哪个解析器。


    所以你可以像这样定义一个自定义 ViewResolver:

    public class MyViewResolver implements ViewResolver {
    
        private ViewResolver tilesResolver;
        private ViewResolver jspResolver;
    
        public void setJspResolver(ViewResolver jspResolver) {
            this.jspResolver = jspResolver;
        }
    
        public void setTilesResolver(ViewResolver tilesResolver) {
            this.tilesResolver = tilesResolver;
        }
    
        public View resolveViewName(String viewName, Locale locale) throws Exception {
            if (isTilesView(viewName)) {
                return tilesResolver.resolveViewName(viewName, locale);
            } else {
                return jspResolver.resolveViewName(viewName, locale);
            }
        }
    
        private boolean isTilesView(String viewName) {
        .....
        }
    }
    

    您需要实现 isTilesView 方法来决定委托给哪个解析器。

    在 XML 配置中,定义这个新的视图解析器,并确保它出现在 其他的之前。

    <bean class="MyViewResolver">
        <property name="tilesResolver" ref="tilesViewResolver"/>
        <property name="jspResolver" ref="viewResolver"/>
    </bean>
    

    【讨论】:

    • 您能详细说明一下吗?我不确定如何将控制权转移到另一个视图解析器。
    • 看起来不错,会试试,谢谢!之前尝试过类似的方法,但基于返回 null 以便继续沿链向下运行,但它无法正常工作。
    • 完美运行,谢谢。读完之后绝对是一个“duh”的时刻。
    【解决方案2】:

    我刚刚通过将*-servlet.xml 配置文件一分为二解决了同样的问题;在我的例子中,主应用程序使用 Tiles,但我希望 QUnit 测试是简单的 JSP。

    app-servlet.xml 仅包含 Tiles 视图解析器,tests-servlet.xml 仅包含 JSP 视图解析器,web.xml 映射根据 URL 将请求分派到正确的 servlet。

    <servlet-mapping>
      <servlet-name>app</servlet-name> <!-- will reach app-servlet.xml -->
      <url-pattern>/foo</url-pattern> <!-- will use "foo" Tile -->
      <url-pattern>/bar</url-pattern> <!-- will use "bar" Tile -->
    </servlet-mapping>
    
    <servlet-mapping>
      <servlet-name>tests</servlet-name> <!-- will reach tests-servlet.xml -->
      <url-pattern>/foo-test</url-pattern> <!-- will use foo-test.jsp -->
      <url-pattern>/bar-test</url-pattern> <!-- will use bar-test.jsp -->
    </servlet-mapping>
    

    【讨论】:

      【解决方案3】:

      看起来您走在正确的轨道上,但要记住的是,某些视图解析器的行为就好像它们总是解析视图一样。您需要确保将此类解析器放在订购的最后。我相信 Tiles 视图就是这样一种。

      编辑:哎呀...是的,另一张海报是正确的,这两个解析器都会“始终匹配”,因此您不能同时使用它们。如果找不到配置的平铺视图,另一种选择是尝试扩展 TilesView 以执行简单的 JSP 渲染。

      【讨论】:

      • 他们总是那样做,这就是问题的根源。
      【解决方案4】:

      是的,您可以在您的项目中使用任意数量的视图解析器。

      因此,您可以在同一个项目中同时使用“tiles View resolver”和“Internal view resolver”。 .

      你必须配置一个 ContentNegotiatingViewResolver 。 .

      并在您的视图解析器中给出订单值。

      <property name="order" value="int Value here" />
      

      就像我给了tiles view resolver 2和internalviewresolver 3一样。如果在tiles中找不到视图,它将首先检查tiles定义,它将在InternaiViewResolver中检查

      这里有一些适合我的配置。

          <bean
              class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
              <property name="order" value="1" />
              <property name="mediaTypes">
                  <map>
                      <entry key="json" value="application/json" />
                      <entry key="html" value="text/html" />
                  </map>
              </property>
              <property name="parameterName" value="accept"></property>
              <property name="favorParameter" value="true"></property>
              <property name="defaultContentType" value="text/html"></property>
              <property name="viewResolvers">
                  <list>
                      <ref bean="tilesViewResolver" />
                      <ref bean="internalViewResolver" />
                  </list>
              </property>
              <property name="defaultViews">
                  <list>
                      <bean
                          class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
                  </list>
              </property>
              <property name="ignoreAcceptHeader" value="true" />
          </bean>
      
      <!--    Configures the Tiles layout system  -->
          <bean class="org.springframework.web.servlet.view.tiles2.TilesConfigurer"
              id="tilesConfigurer">
              <property name="definitions">
                  <list>
                      <value>/WEB-INF/layouts/layouts.xml</value>
                  <!-- Scan views directory for Tiles configurations  -->
                      <value>/WEB-INF/views/**/views.xml</value>
                  </list>
              </property>
          </bean>
          <bean id="tilesViewResolver"
              class="org.springframework.web.servlet.view.UrlBasedViewResolver"
              p:viewClass="org.springframework.web.servlet.view.tiles2.TilesView">
              <property name="order" value="3" />
          </bean>
      
      
          <bean id="internalViewResolver"
              class="org.springframework.web.servlet.view.InternalResourceViewResolver">
              <property name="order" value="2" />
              <property name="prefix">
                  <value>/WEB-INF/views/</value>
              </property>
              <property name="suffix">
                  <value>.jsp</value>
              </property>
          </bean>
      

      【讨论】:

        【解决方案5】:

        我通过简单地为普通 jsp 的布局添加图块定义来解决这个问题,如下所示:

          <definition name="plain-jsp.layout" template="/WEB-INF/layouts/plainJsp.jspx" >
            <put-attribute name="content" value=""/>
          </definition>
        

        然后你就可以使用这个布局作为模板来包含你的简单jsp文件了。

          <definition name="catalog/details" extends="plain-jsp.layout">
            <put-attribute name="content" value="/WEB-INF/views/catalog/details.jspx"/>
          </definition>
        

        及布局模板文件:

        <html xmlns:tiles="http://tiles.apache.org/tags-tiles"
              xmlns:jsp="http://java.sun.com/JSP/Page" version="2.0">
        
          <jsp:output doctype-root-element="HTML"/>
          <jsp:directive.page contentType="text/html;charset=UTF-8" />  
          <jsp:directive.page pageEncoding="UTF-8" />
        
          <head>
            <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
            <meta http-equiv="X-UA-Compatible" content="IE=8" />      
          </head>
          <body>
            <div id="content">
              <tiles:insertAttribute name="content"/>
            </div>
          </body>
        </html>
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-01-31
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多