Java springmvc:基于用户代理解析视图

Java springmvc:基于用户代理解析视图,java,spring,spring-mvc,velocity,Java,Spring,Spring Mvc,Velocity,Spring版本:2.5.6 我想根据用户代理头的值将视图解析为特定的velocity文件 我目前的思路是一个类似于UrlBasedViewResolver的实现,这样用户代理的值就可以(通过上下文)根据匹配的正则表达式(键)映射到特定的目录(值) 我几乎可以肯定有一个更简单的方法 以前也曾发布过一个关于基于用户代理的主题确定的类似问题。然而,我的理解是,主题更多地涉及静态(css、js)内容,而不是哪个文件处理实际的响应构造(HTML、XML等) 不需要在ViewResolver中进行配置的替

Spring版本:2.5.6

我想根据用户代理头的值将视图解析为特定的velocity文件

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

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


以前也曾发布过一个关于基于用户代理的主题确定的类似问题。然而,我的理解是,主题更多地涉及静态(css、js)内容,而不是哪个文件处理实际的响应构造(HTML、XML等)

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

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

然而,实现一个新的或扩展一个现有的ViewResolver是一个非常简单的解决方案,也是我应该采用的方法。

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

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

在我们的移动项目(使用Spring2.5.6)中,我们最终在SimpleRhlHandler中使用了拦截器。这捕获了所有传入的请求,并将-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>

我在我的博客(关于令人兴奋的移动网络开发新世界)上更详细地讨论了这一点:

还有其他建议

然而,我决定扩展一个方法并覆盖resolveViewName方法,我调用了我的ViewResolverHttpHeaderParamViewResolver。扩展方法如下所示:

@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头参数,在bean xml中定义),然后对其求值并确定viewName。在我的例子中,HttpHeaderParamViewResolver可以配置一个映射,其中键是要附加到实际viewName的前缀,值是一个用于计算header param值的RegExp。在应用程序上下文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>

移动网络工具包
iPhone。*苹果。*手机。*Safari
移动bb
黑莓([0-9]{0,4})([a-zA-Z])?
这样,如果我的控制器调用一个名为userDetails的视图,并且正在使用IPhone访问应用程序,则第一个模式会捕获该视图并附加mobile webkit后缀,因此该视图现在是mobile webkit userDetails,然后将其传递给生成实际视图的TileView解析器

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

不利的一面是,你可能会被诱惑过度专门化视图,并最终导致大量视图文件,使应用程序成为可维护的噩梦


希望这会有帮助。

如果1)没有成千上万的用户代理,2)用户代理不会被欺骗,那么这就行了。通常,如果要检测用户代理,很可能已经做错了。@Esko“很可能已经做错了”?有很多需求,但并不是所有的需求都涉及到一万个用户代理。有时候,为了让某些浏览器能够正常工作,你不得不做出牺牲。通过一个自定义的视图解析器将是非常容易的,我不认为你会得到任何比这更简单的。是的,更新:Spring 3.0提供了一个开箱即用的解决方案,使用新的ContentNegotingViewResolver。这只在Spring 3.0上有效,因为以前的版本中没有ContentNegotingViewResolver
<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>