mfc 弹簧
目标
使用tile时,我不喜欢tiles.xml
的默认(?)方法。 我不想将JS和CSS的导入,页面标题,导航,正文等放入各自的文件中,如下面的代码片段所示,因为这使我可以在编辑器窗口之间切换。
<definition name='hello' template='/WEB-INF/templates/main.jsp'><put-attribute name='title' value='Hello' type='string' /><put-attribute name='head' value='/WEB-INF/templates/hello-js-and-css.jsp' /><put-attribute name='nav' value='/WEB-INF/templates/hello-nav.jsp' /><put-attribute name='body' value='/WEB-INF/templates/hello.jsp' />
</definition>
显然,我也不想在tiles.xml
放置太多细节。
我真正喜欢的是每页一个文件,将模板组装在一个位置,例如这段JSP:
<tiles:insertTemplate template='template.jsp'><tiles:putAttribute name='title' value='Hello' /><tiles:putAttribute name='head'><script type='text/javascript' src='/js/jQuery.js' /><script type='text/javascript' src='/js/hello.js' /></tiles:putAttribute><tiles:putAttribute name='body'><div>Hello, world!</div></tiles:putAttribute>
</tiles:insertTemplate>
在Velocity中,应该看起来像这样 :
#tiles_insertTemplate({'template': 'template.vm'})#tiles_putAttribute({'name':'title', 'value': 'Hello'})#end#tiles_putAttribute({'name':'head'})<script type='text/javascript' src='/js/jQuery.js' /><script type='text/javascript' src='/js/hello.js' />#end#tiles_putAttribute({'name':'body'})<div>Hello, world!</div>#end
#end
但是, 有关集成的文档确实旨在向基于Tiles的应用程序添加一些Velocity支持,而我想要的却恰恰相反:在我丰富的Velocity应用程序中使用Tiles,并完全支持spring上下文,宏等。
解
简而言之,我们要做的是:
- 使用
VelocityViewResolver
解析和渲染页面 - 向此Velocity渲染引擎添加对Tiles宏的支持
- 扩展Tiles渲染器以全面支持Velocity,包括Spring上下文,宏等。最终,我们将使其使用Spring创建的原始Velocity引擎。
github上以最小,完整的Web应用程序形式提供了完整的源代码。 有关详细信息,请参见下文。
弹簧和速度->瓷砖
第一步,我们像这样定义viewResolver
和velocityConfig
:
@Bean
public VelocityConfig velocityConfig() {VelocityConfigurer cfg = new VelocityConfigurer();cfg.setResourceLoaderPath('/WEB-INF/velocity/');cfg.setConfigLocation(context.getResource('/WEB-INF/velocity.properties'));return cfg;
}@Bean
public ViewResolver viewResolver() {VelocityViewResolver resolver = new VelocityViewResolver();resolver.setViewClass(VelocityToolboxView.class);resolver.setSuffix('.vm');return resolver;
}
重要的是我们在那里使用VelocityToolboxView
,否则tile指令将不起作用。
我们还需要在velocity.properties
以下内容:
userdirective=org.apache.tiles.velocity.template.AddAttributeDirective,\org.apache.tiles.velocity.template.AddListAttributeDirective,\org.apache.tiles.velocity.template.DefinitionDirective,\org.apache.tiles.velocity.template.GetAsStringDirective,\org.apache.tiles.velocity.template.ImportAttributeDirective,\org.apache.tiles.velocity.template.InsertAttributeDirective,\org.apache.tiles.velocity.template.InsertDefinitionDirective,\org.apache.tiles.velocity.template.InsertTemplateDirective,\org.apache.tiles.velocity.template.PutAttributeDirective,\org.apache.tiles.velocity.template.PutListAttributeDirective
这为Velocity增加了对Tiles指令的基本支持,但是它仍然没有用,因为一旦Velocity将渲染移交给Tiles,Tile就无法渲染Velocity并只会忽略它(将#directives
语法渲染到浏览器。
瓷砖->速度
我们需要教导Tiles使用Velocity。 为此,我们需要一个自定义的TilesInitializer
:
@Bean
public TilesConfigurer tilesConfigurer() {TilesConfigurer cfg = new TilesConfigurer();cfg.setTilesInitializer(new VelocityTilesInitializer(velocityConfig()));return cfg;
}
public class VelocityTilesInitializer extends DefaultTilesInitializer {private VelocityConfig velocityConfig;public VelocityTilesInitializer(VelocityConfig velocityConfig) {this.velocityConfig = velocityConfig;}@Overrideprotected AbstractTilesContainerFactory createContainerFactory(TilesApplicationContext context) {return new BasicTilesContainerFactory() {@Overrideprotected List<TilesRequestContextFactory> getTilesRequestContextFactoriesToBeChained(ChainedTilesRequestContextFactory parent) {List<TilesRequestContextFactory> factories = super.getTilesRequestContextFactoriesToBeChained(parent);registerRequestContextFactory(VelocityTilesRequestContextFactory.class.getName(),factories, parent);return factories;}@Overrideprotected AttributeRenderer createTemplateAttributeRenderer(BasicRendererFactory rendererFactory,TilesApplicationContext applicationContext,TilesRequestContextFactory contextFactory,TilesContainer container,AttributeEvaluatorFactory attributeEvaluatorFactory) {ContextPassingVelocityAttributeRenderer var = new ContextPassingVelocityAttributeRenderer(velocityConfig.getVelocityEngine());var.setApplicationContext(applicationContext);var.setRequestContextFactory(contextFactory);var.setAttributeEvaluatorFactory(attributeEvaluatorFactory);var.commit();return var;}};}
}
我们快到了,但是有一点棘手。 通常在第31-32行中,您将放置velocityAttributeRenderer
。 但是,此渲染器完全忽略了Tiles从Velocity接收到的Spring增强的Velocity上下文和引擎。 它创建自己的VelocityEngine
并进行渲染,丢弃所有Spring和tile指令以及上下文对象。
在Tiles中无法更改此行为(否则在设计模式和可扩展性方面似乎是一项有趣的研究)。 我什至为此创建了两个JIRA问题: 541用于转发上下文,而542用于注入VelocityEngine
。
同时,我们必须解决此变通方法(有关完整源,请参见github ):
public class ContextPassingVelocityAttributeRenderer extendsAbstractTypeDetectingAttributeRenderer {// ...private VelocityEngine engine;public ContextPassingVelocityAttributeRenderer(VelocityEngine engine) {this.engine = engine;}// ...public void commit() {velocityView = new VelocityView(new TilesApplicationContextJeeConfig());velocityView.setVelocityEngine(engine);}@Overridepublic void write(Object value, Attribute attribute,TilesRequestContext request) throws IOException {if (value != null) {if (value instanceof String) {InternalContextAdapter adapter = (InternalContextAdapter) ((VelocityTilesRequestContext) request).getRequestObjects()[0];Context context = adapter.getInternalUserContext();Template template = velocityView.getTemplate((String) value);velocityView.merge(template, context, request.getWriter());} else {throw new InvalidTemplateException('Cannot render a template that is not a string: '+ value.toString());}} else {throw new InvalidTemplateException('Cannot render a null template');}}// ...
它可以解决JIRA的两个问题,并让我们实现最终目标:
- 该
VelocityEngine
注入VelocityView
原来这里是VelocityEngine
从春天。 除其他外,它支持Spring指令和上下文相关工具。 -
write
方法中的TilesRequestContext
仍然包含从Spring脚手架创建的原始Velocity上下文。VelocityAttributeRenderer
标准实现只是将其丢弃。 上面的变通办法提取原始上下文并将其用于呈现。
结论
这段旅程花了比我想象更多的时间。 尚无此类案例的文档,因此我花了数小时进行调试,阅读源代码,进行实验,祈祷和诅咒。 当我对Spring视图分辨率和渲染引擎以及Tiles和Velocity的内部知识几乎为零时,它变得更加有趣。
自从我学到了很多有关所有这些技术的知识之后,最终能够以一种相当优雅的方式解决它,这真是令人满足。 但这也是一个令人沮丧且耗时的难题,我希望这篇文章可以避免给别人带来麻烦。
更新–速度工具
不久之后,我发现此解决方案不支持Velocity Tools属性。 添加方法如下: Spring&Velocity Tools 。
参考:我们的JCG合作伙伴 Konrad Garus在Squirrel的博客上集成了Spring,Velocity和Tiles 。
翻译自: https://www.javacodegeeks.com/2012/07/integrating-spring-velocity-and-tiles.html
mfc 弹簧