Apache Tiles 2 + Spring MVC 3 使用多组视图定义
这是一个复杂的问题,所以请耐心听我详细的解释。
当前场景
我们使用 Spring MVC 3.0.5 和 Apache Tiles 2.2。目前,我们基于 Spring 的图块配置如下所示:
<bean id="tilesConfigurer"
class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">
<property name="definitions">
<list>
<value>/WEB-INF/**/views.xml</value>
</list>
</property>
<!-- resolving preparer names as Spring bean definition names -->
<property name="preparerFactoryClass"
value="org.springframework.web.servlet.view.tiles2.SpringBeanPreparerFactory" />
</bean>
<bean id="tilesViewResolver"
class="org.springframework.web.servlet.view.UrlBasedViewResolver"
p:order="1" p:viewClass="org.springframework.web.servlet.view.tiles2.TilesView" />
(Tiles) 视图定义是从所有 views.xml
文件中读取的,当 Spring 控制器生成“homepage”作为逻辑视图名称时,渲染后,将显示名称为“homepage”的相应 Tiles 定义。
目标
我们现在打算允许 Web 应用程序中不同目录的不同视图定义集。原因是,不同的用户群体会根据他们的群体有定制的模板。
假设我当前的所有视图定义都位于
/WEB-INF/default-views/**/views.xml
,并且我想添加第二个文件夹
/WEB-INF/administrator-views/**/views.xml
,第二个文件夹应包含与 default-views
文件夹中同名的视图定义。但根据 URL 模式,应显示其中之一。以下是两个示例:
http://example.com/default/foobar
==> Controller yields logical view name "foobar"
==> definition "foobar" from "default-views" folder shall be displayed
http://example.com/admin/foobar
==> Controller yields logical view name "foobar"
==> definition "foobar" from "administrator-views" folder shall be displayed
此外,我们希望允许后备机制。当相应的视图文件夹中不存在专用视图名称(上例中的“admin”)时,我们希望显示其他文件夹中的默认版本。
到目前为止
,我正在考虑几个出发点。也许我可以调整TilesConfigurer
。它将 Tiles 视图定义保留在单个属性中,而不区分视图定义所在的文件夹。
另一种选择是尝试使用 链式视图解析器,专用视图解析器位于链的更上方,默认解析器位于链的末尾。
第三种选择是使用不同的视图名称和 使用 HandlerInterceptor 拦截来自控制器的视图名称响应,将其映射到专用视图(如果不存在,则可能不起作用)。
问题
- 实现这种视图解析机制有哪些好的选择?
- 允许视图定义被其他/更专业的视图定义覆盖
- 根据请求的 URL 模式进行显示
目前,我的选项 #2 听起来最有说服力,因为我想防止摆弄 Springs 类当它不是真正必要的时候。但我缺少链接视图解析器和 TilesConfigurer 中的视图定义列表之间的连接。
感谢您到目前为止的耐心阅读。
This is a complex question, so please bear with me through the long explanation.
Current scenario
We are using Spring MVC 3.0.5 with Apache Tiles 2.2. Currently our Spring-based tiles configuration looks like this:
<bean id="tilesConfigurer"
class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">
<property name="definitions">
<list>
<value>/WEB-INF/**/views.xml</value>
</list>
</property>
<!-- resolving preparer names as Spring bean definition names -->
<property name="preparerFactoryClass"
value="org.springframework.web.servlet.view.tiles2.SpringBeanPreparerFactory" />
</bean>
<bean id="tilesViewResolver"
class="org.springframework.web.servlet.view.UrlBasedViewResolver"
p:order="1" p:viewClass="org.springframework.web.servlet.view.tiles2.TilesView" />
The (Tiles) view definitions are read from all views.xml
files and when a Spring controller yields, say, "homepage" as logical view name to be rendered, the corresponding Tiles definition with name "homepage" gets displayed.
Aim
We now intend to allow different sets of view definitions from different directories within our web application. Reason is, that different user groups will have customized templates according to their group.
Let's say all my current view definitons reside in
/WEB-INF/default-views/**/views.xml
And I want to add a second folder
/WEB-INF/administrator-views/**/views.xml
This second folder shall contain view definitions with the same names as in the default-views
folder. But depending on a URL pattern, either the one or the other shall be displayed. Here are two samples:
http://example.com/default/foobar
==> Controller yields logical view name "foobar"
==> definition "foobar" from "default-views" folder shall be displayed
http://example.com/admin/foobar
==> Controller yields logical view name "foobar"
==> definition "foobar" from "administrator-views" folder shall be displayed
In addition, we would like to allow a fallback mechanism. When a specialized view name (for "admin" in the example above) does not exist in the corresponding views folder, we want to display the default version from the other folder.
So far
Currently I am thinking about several starting points. Maybe I could be tweaking the TilesConfigurer
. which keeps Tiles view definitions in a single property without distinction for the folders from where the view definitions came.
Another option is trying to accomplish this using chained view resolvers with the specialized ones being further up in the chain and the default ones at the end.
A third option is using different view names and intercept the view name response from the controller using a HandlerInterceptor
to map it to the specialized view (may not work if it does not exists).
Questions
- What are good options to implement this view-resolution mechanism?
- Allowing view-defintions to be overridden by others / more specialized ones
- Making the display depend on the URL pattern of the request
At the moment, my option #2 sound most convincing since I would like to prevent from twiddling with Springs classes when it's not really necessary. But I am missing the connection between chained view resolvers and the view definition list in TilesConfigurer
.
Thanks for your patience and reading thus far.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
对于可能遇到此类问题的任何人,我们的实现方式如下:
HandlerInterceptorAdapter#postHandle(..)
实现将 URL 路径组件转换为逻辑视图名称前缀views.xml
文件中具有这些 URL 前缀的定义名称都UrlBasedViewResolver#loadView(..)
实现来首先尝试Controller 给出的视图名称
和HandlerInterceptor
,如果它不存在(super.loadView(..)
产生 null),请尝试使用默认前缀,我希望这足够清楚。
Just for anybody who might encounter an issue like this, here's how we've implemented it:
HandlerInterceptorAdapter#postHandle(..)
implementation to translate URL path components into logical view name prefixesviews.xml
filesUrlBasedViewResolver#loadView(..)
implementation to first try the view name as given byController
andHandlerInterceptor
, and if it does not exist (super.loadView(..)
yields null) try the default prefix insteadI hope this is clear enough.