整合彈簧,速度和瓷磚

我喜歡 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.pswp.cn/news/372016.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/372016.shtml
英文地址,請注明出處:http://en.pswp.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…