整合弹簧,速度和瓷砖

我喜欢 Tiles, 并且听到了很多有关 Velocity的信息 。 它们似乎有不同的用途,并且据说很容易结合在一起,所以我决定试一试,并在Spring Web应用程序中同时使用它们。 集成实际上花费了许多小时,并且是一次真正的过山车,在此期间,我对这三种技术都学到了很多东西。 希望这篇文章可以使别人免于这种乐趣,并使他们专注于业务。

目标

使用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上下文,宏等。

简而言之,我们要做的是:

  1. 使用VelocityViewResolver解析和渲染页面
  2. 向此Velocity渲染引擎添加对Tiles宏的支持
  3. 扩展Tiles渲染器以完全支持Velocity,包括Spring上下文,宏等。最终,我们将使用Spring创建的原始Velocity引擎。

GitHub上以最小,完整的Web应用程序形式提供了完整的源代码。 有关详细信息,请参见下文。

弹簧和速度->瓷砖

第一步,我们像这样定义viewResolvervelocityConfig

@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的两个问题,并让我们实现最终目标:

  1. VelocityEngine注入VelocityView原来这里是VelocityEngine从春天。 除其他外,它支持Spring指令和上下文相关工具。
  2. write方法中的TilesRequestContext仍然包含从Spring脚手架创建的原始Velocity上下文。 VelocityAttributeRenderer标准实现只是将其丢弃。 上面的解决方法提取原始上下文并将其用于呈现。

结论

这段旅程花了比我想象更多的时间。 尚无此类案例的文档,因此我花了数小时进行调试,阅读源代码,进行实验,祈祷和诅咒。 当我对Spring视图分辨率和渲染引擎以及Tiles和Velocity的内部知识几乎为零时,它变得更加有趣。

自从我学到了很多有关所有这些技术的知识之后,最终能够以一种相当优雅的方式解决它,这是非常令人满意的。 但这也是一个令人沮丧且耗时的难题,我希望这篇文章可以避免给别人带来麻烦。

更新–速度工具

不久之后,我发现此解决方案不支持Velocity Tools属性。 添加方法如下: Spring&Velocity Tools 。

参考:来自我们的JCG合作伙伴 Konrad Garus的Spring,Velocity和Tiles的集成,在Squirrel的博客上。


翻译自: https://www.javacodegeeks.com/2012/07/integrating-spring-velocity-and-tiles.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/372016.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android 软键盘自动弹出和关闭

在我们写修改信息或者搜索&#xff0c;修改密码等界面的时候&#xff0c;用户进入这个界面的主要目的就是输入修改/查找 某些信息&#xff0c;为了用户体验应该自动弹出软键盘而不是让用户主动点击输入框才弹出。 1.软键盘的自动弹出 private void showKeyboard(){InputMethodM…

android adb杀死服务,Android app是如何杀掉的

1. adb shell kill -9 pid_of_appAMS定义了AppDeathRecipientAPP 在 attachApplication -> attachApplicationLockedAMS里会注册 App 进程的 BinderDeath通知AppDeathRecipient adr new AppDeathRecipient(app, pid, thread);thread.asBinder().linkToDeath(adr, 0);当App进…

iOS学习笔记39-ReactiveCocoa入门

FRP&#xff0c;全称为Functional Reactive Programming&#xff0c;是一种响应变化的编程范式&#xff0c;最近几年比较火&#xff0c;大概的理解就像这样&#xff1a; 当a的值或者b的值发生变化时&#xff0c;c的值会自动响应a的值或b的值变化的信号&#xff0c;自动更正自己…

使用密码摘要生成器扩展JMeter

最近&#xff0c;我不得不处理一个带有50,000条用户记录的OpenLDAP实例&#xff0c;并进行一些压力测试。 JMeter是填充LDAP的最佳选择。 但是&#xff0c;在我的情况下&#xff0c;OpenLDAP配置为不接受任何明文密码。 因此&#xff0c;我无法使用通过JMeter LDAP Request采…

制造业数字化转型核心不止是技术

一、制造业的数字化转型意味着什么&#xff1f; 在当今的制造业领域&#xff0c;数字化转型意味着通过集成数字技术来增强传统的制造方法、产品和劳动力的过程。这些技术包括一系列创新&#xff0c;如自动化软件、电子商务系统、传感器、工业机器人等。 二、制造业数字化转型的…

分类测试以减少构建时间

在继续本文的主要内容之前&#xff0c;让我们先进行一些定义。 单元测试 单元测试是小型的&#xff08;测试一种用例或单元&#xff09;&#xff0c;在内存中运行&#xff08;不与数据库&#xff0c;消息队列等交互&#xff09;&#xff0c;可重复且快速的测试。 对于我们的对…

android横向展示状态,【报Bug】Android横屏状态下启动App,即使在App.vue中锁定竖屏,但是首页nvue中的rpx单位是按照启动的横竖屏状态显示的!...

详细问题描述(DCloud产品不会有明显的bug&#xff0c;所以你遇到的问题大都是在特定环境下才能重现的问题&#xff0c;请仔细描述你的环境和重现方式&#xff0c;否则DCloud很难排查解决你的问题)[内容]重现步骤[步骤][结果][期望]nvue首页rpx单位能够根据App.vue锁定的屏幕方向…

property修饰关键字

修饰符按作用区分&#xff1a;线程安全相关&#xff0c;内存相关&#xff0c;读写权限相关&#xff0c;set和get,是否可为空, class 一.默认值 property NSArray *dataArray; 默认的是&#xff1a;atomic&#xff0c;strong&#xff08;有的文章写的居然是assign,我认为还是str…

高精度相关模板.

1 2 /*3 高精度加法.4 */5 #include<cstring>6 #include<cstdio>7 #include<iostream>8 #define MAXN 100019 using namespace std;10 int a[MAXN],b[MAXN],c[MAXN],l1,l2,l3;11 char m[MAXN],n[MAXN];12 void slove()13 {14 l3max(l1,l2);15 for(in…

5分钟内Google App Engine上的Vaadin App

在本教程中&#xff0c;您将学习如何创建第一个Vaadin Web应用程序&#xff0c;如何在本地AppEngine开发服务器上运行它以及如何将其部署到Google App Engine基础结构。 所有这些大约需要5到10分钟。 是的&#xff0c;如果您安装了必要的先决条件&#xff0c;则可以立即开始运行…

linux系统调用的封装格式,ARM Linux系统调用的原理

ARM Linux系统调用的原理ARM Linux系统调用的原理操作系统为在用户态运行的进程与硬件设备进行交互提供了一组接口。在应用程序和硬件之间设置一个额外层具有很多优点。首先&#xff0c;这使得编程更加容易&#xff0c;把用户从学习硬件设备的低级编程特性中解放出来。其次&…

(延迟两秒,跳转相应页面)(返回到上一个页面并刷新)

1.setTimeout("window.location.href /moment/reason",2000);2.返回到上一个页面并刷新 self.location document.referrer;2.1常见的几种刷新方式 a.history.go(-1) 返回上一页 b.location.reload() 刷新当前页面 c.history.back() 返回上一页2.2当…

检索字符创 php

strstr()可以返回匹配的值 echo strstr("localhost", "os");返回ost echo substr_count("gggggs", "g"); 返回检索匹配字符创次数 substr_replace 字串替换函数转载于:https://www.cnblogs.com/lidepeng/p/6078064.html

android8强制将app移到sd卡,小内存手机 APP强制转移至SD卡教程

虽然近两年手机的机身内存越做越大&#xff0c;但是身边总还是有些朋友在使用几年前的手机。而面对如今海量的丰富应用&#xff0c;早年的手机中内置的存储空间已经开始捉襟见肘。虽说对于这类机型系统通常都提供了将APP转移至外置内存卡的功能&#xff0c;可是依然有一些顽固的…

在没有XML的情况下测试Spring和Hibernate

我非常热衷于Spring 3中的改进&#xff0c;这些改进最终使您能够在IDE和编译器的适当支持下从XML迁移到纯Java配置。 它并没有改变Spring是一个庞大的套件这一事实&#xff0c;并且有时发现您需要的东西可能需要一段时间。 围绕Hibernate的无XML单元测试就是这样一回事。 我知道…

Observer观察者设计模式

Observer设计模式主要包括以下两种对象: (1)被观察对象:Subject,它往往包含其他对象感兴趣的东西,上面例子中热水器中就是Subject(被监视对象); (2)观察对象:Observer,它观察着Subject,当Subject中的某件事发生后,会告知Observer,Obersver会采取相应的行动。上面例子中显示器和…

最小生成树 prime zoj1586

题意&#xff1a;在n个星球&#xff0c;每2个星球之间的联通需要依靠一个网络适配器&#xff0c;每个星球喜欢的网络适配器的价钱不同&#xff0c;先给你一个n&#xff0c;然后n个数&#xff0c;代表第i个星球喜爱的网络适配器的价钱&#xff0c;然后给出一个矩阵M[i][j]代表第…

android 书架菜单,Android入门3--做一个书架

修改名称创建项目的时候&#xff0c;APP的名字取为英文或者拼音&#xff0c;是为了简便&#xff0c;但是显示在界面上&#xff0c;我们当然希望它是中文的。taoguanstring>我们要做的很简单&#xff0c;就是在string.xml中&#xff0c;将app_name的内容修改为我们希望的名字…

第一节:整体介绍

Python版本3.5.2&#xff0c;Django版本1.10 创建一个Django工程&#xff0c;并且生成一个名字为mainsite的app django-admin.py startproject myblog python3 manage.py startapp mainsite 文件结构如下&#xff1a; x-powerxpower-CW65S:~/chen/myblog$ tree ./ ./ ├── ma…

Spring @Configuration和FactoryBean

考虑使用FactoryBean通过Spring配置文件定义缓存&#xff1a; <cache:annotation-driven /><context:component-scan base-packageorg.bk.samples.cachexml></context:component-scan><bean idcacheManager classorg.springframework.cache.support.Simpl…