【问题标题】:Spring MVC: Resolving the view based on User-AgentSpring MVC:基于User-Agent解析视图
【发布时间】:2009-12-08 17:59:25
【问题描述】:

春季版:2.5.6

我想根据 User-Agent 标头的值将视图解析为特定的速度文件。

我目前的思路是一个类似于 UrlBasedViewResolver 的实现,这样用户代理值根据匹配的正则表达式(键)映射(通过上下文)到特定目录(值)。

我几乎可以肯定有更简单的方法。

之前发布了一个类似的问题,关于基于 User-Agent 的主题确定。但是,我的理解是,主题更多地与静态(css、js)内容相关,而不是哪个文件处理实际的响应构造(HTML、XML 等)。

【问题讨论】:

  • 自定义视图解析器会非常简单,我认为您不会比这更简单。
  • 是的,只是确保我没有忽略一些明显的东西。

标签: java spring spring-mvc velocity


【解决方案1】:

还有另一个选项建议here

但是,我解决了扩展 ContentNegotiatingViewResolver 并覆盖 resolveViewName 方法,我将 ViewResolver 称为 HttpHeaderParamViewResolver。扩展方法如下所示:

@Override
public View resolveViewName(String viewName, Locale locale) throws Exception {
    //Get the HTTP Header param "User-Agent"
    String headerParamValue = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest().getHeader(headerParam);

    viewName = setViewName(viewName, headerParamValue);

    return super.resolveViewName(viewName, locale);
}

headerParam="User-Agent" (或您喜欢的任何其他 HTTp Header 参数,这是在 bean xml 中定义的),然后评估它并确定 viewName。在我的情况下,HttpHeaderParamViewResolver 可以配置一个 Map,其中键是要附加到实际 viewName 的前缀,值是用于评估标头参数值的 RegExp。它在 App Context XML 中看起来像这样:

<bean id="HttpHeaderViewResolver" class="com.application.viewresolver.HttpHeaderParamViewResolver">
    <property name="viewResolvers">
        <list>
            <ref bean="tilesViewResolver"/>
        </list>
    </property>
    <property name="headerParam" value="User-Agent"/>
    <property name="viewPrefixPattern">
        <map>
            <entry>
                <key>
                    <value>mobile-webkit</value>
                </key>
                <value>iPhone.*Apple.*Mobile.*Safari</value>
            </entry>
            <entry>
                <key>
                    <value>mobile-bb</value>
                </key>
                <value>BlackBerry([0-9]{0,4})([a-zA-Z])?</value>
            </entry>
        </map>
    </property>
</bean>

这样,如果我的控制器调用一个名为 userDetails 的视图并使用 iPhone 访问应用程序,第一个模式会捕获它并附加 mobile-webkit 后缀,因此视图现在是 mobile-webkit-userDetails,然后将其传递给生成实际视图的 tilesViewResolver

我探索了很多可能性,我认为这是我能想到的最简单、最灵活的方法。在这种情况下,选择完全不同的视图的能力至关重要,因为我们支持各种各样的用户代理,从 WAP 到 iPhone 4 和支持 WebKit 的手机,因此视图从用户代理到用户代理的变化很大。另一个优点是您不再需要在视图上处理此问题,因为您可以拥有任意专业的视图。另一个好的方面是,您可以很容易地实现这一点,而无需删除或更改您可能已经拥有的视图解析器,因为 ContentNegotiatingViewResolver 能够按照您的特定顺序将视图调用委托给其他视图解析器定义。

不利的一面是,您可能会倾向于过度专门化视图并最终得到大量视图文件,从而使应用程序成为可维护的噩梦。

希望对你有帮助。

【讨论】:

  • 这仅适用于 Spring 3.0,因为之前的版本中没有 ContentNegotiatingViewResolver
【解决方案2】:

几个月前我也遇到过同样的问题!

在我们的移动项目(使用 Spring 2.5.6)中,我们最终使用了带有 SimpleUrlHandler 的拦截器。这会捕获所有传入的请求并将 -m.jsp 添加到任何 mobile 请求的末尾。

它涉及两个步骤:

1) 向我们的标准 URL 映射器声明一个拦截器:

 <bean id="handlerMapping"
 class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
 <!--   This interceptor catches all
 requests and redirects them to portal
 or mobile html content.
 --> 
<property name="interceptors">    <list>
      <ref bean="MultiViewController"/>    </list> </property>

和 2) 实现拦截器,在用户代理中查找“移动”一词。

public class MultiViewController extends HandlerInterceptorAdapter {

我在我的博客(关于移动 Web 开发的新的激动人心的世界)帖子中更详细地讨论了它:http://plumnash.com/it/iphone-web-development-using-spring/

【讨论】:

    【解决方案3】:

    不需要在 ViewResolver 中进行配置的替代方法可能涉及顶级 Velocity 文件,然后有条件地解析具有以下内容的子文件。

    #if ($userAgent1)
      #parse ("user-agent-1.vm")
    #elseif ($userAgent2)
      #parse ("user-agent-2.vm")
    #end
    

    但是,实现新的或扩展现有的 ViewResolver 是一个非常简单的解决方案,并且是我会采用的方式。

    【讨论】:

    • 如果有 1) 没有数以万计的用户代理 2) 用户代理不能被欺骗,这将起作用。一般来说,如果你想检测用户代理,你很可能已经做错了什么。
    • @Esko“很可能已经做错了什么”?那里有很多需求,但并非所有需求都涉及到一万个用户代理。
    • 有时你必须做出牺牲才能让某些浏览器正常工作。 Internet Explorer
    【解决方案4】:

    我将使用 cmets 中建议的自定义视图解析器。 (并将我的应用升级到 Spring 3.0.0)

    【讨论】:

    • 更新:Spring 3.0 使用新的 ContentNegotiatingViewResolver 提供了一个开箱即用的解决方案。
    猜你喜欢
    • 1970-01-01
    • 2010-09-14
    • 2022-11-16
    • 1970-01-01
    • 2015-03-11
    • 2013-01-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多