简体   繁体   English

Spring MVC:基于User-Agent解析视图

[英]Spring MVC: Resolving the view based on User-Agent

Spring Version: 2.5.6 春季版:2.5.6

I want to resolve the view to a specific velocity file based on the value of the User-Agent header. 我想根据User-Agent标头的值将视图解析为特定的速度文件。

My current line of thinking is an implementation similar to the UrlBasedViewResolver such that the user-agent value is Map'd (via context) to a specific directory(value) based on a matching a regular expression(key). 我目前的思路是类似于UrlBasedViewResolver的实现,使得用户代理值基于匹配的正则表达式(键)映射到(通过上下文)到特定目录(值)。

I am almost certain there is an easier way. 我几乎可以肯定有一种更简单的方法。

A similar question was previously posted regarding Theme determination based on User-Agent. 之前发布了一个类似的问题,涉及基于User-Agent的主题确定。 However, my understanding is that Themes relate more to static (css,js) content, not which file handles the actual response construction (HTML,XML,etc). 但是,我的理解是主题更多地涉及静态(css,js)内容,而不是哪个文件处理实际的响应构造(HTML,XML等)。

There is an other option suggested here 有建议的其他选择在这里

However I resolved Extending a ContentNegotiatingViewResolver and overriding the resolveViewName method, I called my ViewResolver HttpHeaderParamViewResolver . 但是,我解决了扩展ContentNegotiatingViewResolver并覆盖resolveViewName方法,我调用了我的ViewResolver HttpHeaderParamViewResolver The extended method looks something like this: 扩展方法看起来像这样:

@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);
}

Where headerParam="User-Agent" (or any other HTTp Header parameter you like, this is defined in the bean xml), after that you evaluate it and determine the viewName. 其中headerParam =“User-Agent” (或您喜欢的任何其他HTTp Header参数,这是在bean xml中定义的),之后您对其进行评估并确定viewName。 In My case the HttpHeaderParamViewResolver can be configured with a Map where the key is a prefix to be appended to the actual viewName and the value is a RegExp that will be used to evaluate the value of the header param. 在我的情况下,可以使用Map配置HttpHeaderParamViewResolver ,其中键是要附加到实际viewName的前缀,值是将用于评估标头参数值的RegExp。 It looks something like this in the App Context XML: 它在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>

That way the if my controller calls a view called userDetails and is accessing the application with an IPhone the first pattern catchs it and appends the mobile-webkit suffix so the view is now mobile-webkit-userDetails and its then passed to the tilesViewResolver which generates the actual view. 这样,如果我的控制器调用一个名为userDetails的视图并使用IPhone访问应用程序,则第一个模式捕获它并附加mobile-webkit后缀,以便视图现在是mobile-webkit-userDetails ,然后传递给tilesViewResolver生成实际观点。

I explored a lot of possibilities and I think this is the easiest and most flexible I was able to came up with. 我探索了很多可能性,我认为这是我能够提出的最简单,最灵活的方法。 In this case the ability to choose an entire different view was critical because we support a wide variety of user agents, from WAP to IPhone 4 and WebKit capable mobiles, so views change dramatically from user agent to user agent. 在这种情况下,选择整个不同视图的能力至关重要,因为我们支持各种用户代理,从WAP到IPhone 4和支持WebKit的移动设备,因此视图从用户代理变为用户代理。 Other advantage is that you no longer require to handle this issue on the view since you can have views as specialized as you like. 其他优点是您不再需要在视图上处理此问题,因为您可以根据需要使用专门的视图。 Other bright side is that you can implement this quite easily without having to remove or change the view resolvers you might already have since ContentNegotiatingViewResolver has the ability to delegate the view call to other view resolvers in the specific sequence you define. 另一个好的方面是,您可以非常轻松地实现这一点,而无需删除或更改您可能已经拥有的视图解析器,因为ContentNegotiatingViewResolver能够以您定义的特定顺序将视图调用委托给其他视图解析器。

The down side is that you may be tempted to over specialize the views and end up with a ton of view files rendering the app a maintainable nightmare. 不足之处在于,您可能会过度专注于视图并最终获得大量视图文件,从而使应用程序成为可维护的噩梦。

Hope it is helpful. 希望它有所帮助。

I had the same problem a few months back! 几个月前我遇到了同样的问题!

On our mobile project (using Spring 2.5.6) we ended up using an interceptor with our SimpleUrlHandler. 在我们的移动项目中(使用Spring 2.5.6),我们最终使用了一个带有SimpleUrlHandler的拦截器。 This caught all incoming requests and add -m.jsp to the end of any mobile requests. 这捕获了所有传入的请求,并将-m.jsp添加到任何移动请求的末尾。

It involved two steps: 它涉及两个步骤:

1) declaring an interceptor to our standard URL Mapper: 1)向我们的标准URL Mapper声明一个拦截器:

 <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>

and 2) implementing the Interceptor, which looked for the word 'Mobile' in the user-agent. 2)实现拦截器,在用户代理中寻找“移动”一词。

public class MultiViewController extends HandlerInterceptorAdapter {

I talk about it in more detail on my blog (about the new exciting world of mobile web development) post: http://plumnash.com/it/iphone-web-development-using-spring/ 我在我的博客上更详细地谈论它(关于新的令人兴奋的移动网络开发世界)帖子: http//plumnash.com/it/iphone-web-development-using-spring/

An alternative that doesn't require configuration in a ViewResolver might involve a top-level Velocity file, then conditionally parsing sub-files that has something like the following. 在ViewResolver中不需要配置的替代方案可能涉及顶级Velocity文件,然后有条件地解析具有类似以下内容的子文件。

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

However, implementing a new or extending an existing ViewResolver is a pretty simple solution and would be the way I'd go with. 但是,实现一个新的或扩展现有的ViewResolver是一个非常简单的解决方案,并且将是我的方式。

I am going with a custom view resolver as suggested in comments. 我将按照评论中的建议使用自定义视图解析器。 (and upgrading my app to Spring 3.0.0) (并将我的应用程序升级到Spring 3.0.0)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM