<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    jojo's blog--快樂憂傷都與你同在
    為夢想而來,為自由而生。 性情若水,風起水興,風息水止,故時而激蕩,時又清平……
    posts - 11,  comments - 30,  trackbacks - 0

    15.5. Tapestry
    摘自 Tapestry 主頁...

    “ Tapestry 是用來創建動態、健壯、高伸縮性 Web 應用的一個 Java 開源框架。 Tapestry 組件構建于標準的Java Servlet API 之上,所以它可以工作在任何 Servlet 容器或者應用服務器之上。 ”
    盡管 Spring 有自己的 強有力的 Web 層,但是使用 Tapestry 作為 Web 用戶界面,并且結合 Spring 容器管理其他層次,在構建 J2EE 應用上具有一些獨到的優勢。 這一節將嘗試介紹集成這兩種框架的最佳實踐。

    一個使用 Tapestry 和 Spring 構建的 典型的 J2EE 應用通常由 Tapestry 構建一系列的用戶界面(UI)層,然后通過一個或多個 Spring容器來連接底層設施。 Tapestry 的 參考手冊 包含了這些最佳實踐的片斷。(下面引用中的 [] 部分是本章的作者所加。)

    “ Tapestry 中一個非常成功的設計模式是保持簡單的頁面和組件,盡可能多的將任務 委派(delegate) 給 HiveMind [或者 Spring,以及其他容器] 服務。 Listener 方法應該僅僅關心如何組合成正確的信息并且將它傳遞給一個服務。 ”
    那么關鍵問題就是...如何將協作的服務提供給 Tapestry 頁面?答案是,在理想情況下,應該將這些服務直接 注入到 Tapestry 頁面中。在 Tapestry 中,你可以使用幾種不同的方法 來實現依賴注入。這一節只討論Spring 提供的依賴注入的方法。Spring-Tapestry 集成真正具有魅力的地方是 Tapestry 優雅又不失靈活的設計,它使得注入 Spring 托管的 bean 簡直就像把馬鞍搭在馬背上一樣簡單。(另一個好消息是 Spring-Tapestry 集成代碼的編寫和維護都是由 Tapestry 的創建者 Howard M. Lewis Ship 一手操辦, 所以我們應該為了這個如絲般順暢的集成方案向他致敬。)

    15.5.1. 注入 Spring 托管的 beans
    假設我們有下面這樣一個 Spring 容器定義(使用 XML 格式):
     

     1<?xml version="1.0" encoding="UTF-8"?>
     2<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" 
     3        "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
     4 
     5<beans>
     6    <!-- the DataSource -->
     7    <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
     8        <property name="jndiName" value="java:DefaultDS"/>
     9    </bean>
    10
    11    <bean id="hibSessionFactory" 
    12          class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
    13        <property name="dataSource" ref="dataSource"/>
    14    </bean>
    15
    16    <bean id="transactionManager" 
    17          class="org.springframework.transaction.jta.JtaTransactionManager"/>
    18
    19    <bean id="mapper" 
    20          class="com.whatever.dataaccess.mapper.hibernate.MapperImpl">
    21        <property name="sessionFactory" ref="hibSessionFactory"/>
    22    </bean>
    23
    24    <!-- (transactional) AuthenticationService -->
    25    <bean id="authenticationService" 
    26          class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
    27        <property name="transactionManager" ref="transactionManager"/>
    28        <property name="target">
    29            <bean class="com.whatever.services.service.user.AuthenticationServiceImpl">
    30                <property name="mapper" ref="mapper"/>
    31            </bean>
    32        </property>
    33        <property name="proxyInterfacesOnly" value="true"/>
    34        <property name="transactionAttributes">
    35            <value>
    36                *=PROPAGATION_REQUIRED
    37            </value>
    38        </property>
    39    </bean>  
    40 
    41    <!-- (transactional) UserService -->
    42    <bean id="userService" 
    43          class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
    44        <property name="transactionManager" ref="transactionManager"/>
    45        <property name="target">
    46             <bean class="com.whatever.services.service.user.UserServiceImpl">
    47                 <property name="mapper" ref="mapper"/>
    48             </bean>
    49        </property>
    50        <property name="proxyInterfacesOnly" value="true"/>
    51        <property name="transactionAttributes">
    52            <value>
    53                *=PROPAGATION_REQUIRED
    54            </value>
    55        </property>
    56    </bean>  
    57 
    58 </beans>
    59
    60


    在 Tapestry 應用中,上面的 bean 定義需要 加載到 Spring 容器中, 并且任何相關的 Tapestry 頁面都需要提供(被注入) authenticationService 和 userService 這兩個 bean, 它們分別實現了 AuthenticationService 和 UserService 接口。

    現在,Web 應用可以通過調用 Spring 靜態工具函數 WebApplicationContextUtils.getApplicationContext(servletContext) 來得到application context。這個函數的參數servletContext 是J2EE Servlet 規范所定義的 ServletContext。 這樣一來,頁面可以很容易地得到 UserService 的實例, 就像下面的這個例子:

    WebApplicationContext appContext = WebApplicationContextUtils.getApplicationContext(
        getRequestCycle().getRequestContext().getServlet().getServletContext());
    UserService userService = (UserService) appContext.getBean("userService");
    ... some code which uses UserService
    這種機制可以工作...如果想進一步改進的話,我們可以將大部分的邏輯封裝在頁面或組件基類的一個方法中。 然而,這個機制在某些方面違背了 Spring 所倡導的反向控制方法(Inversion of Control)。在理想情況下,頁面 不必在context中尋找某個名字的 bean。事實上,頁面最好是對context一無所知。

    幸運的是,有一種機制可以做到這一點。這是因為 Tapestry 已經提供了一種給頁面聲明屬性的方法, 事實上,以聲明的方式管理一個頁面上的所有屬性是首選的方法,這樣 Tapestry 能夠將屬性的生命周期 作為頁面和組件生命周期的一部分加以管理。

    注意
    下一節應用于 Tapestry 版本 < 4.0 的情況下。如果你正在使用 Tapestry 4.0+,請參考標有 第 15.5.1.4 節 “將 Spring Beans 注入到 Tapestry 頁面中 - Tapestry 4.0+ 風格” 的小節。

    15.5.1.1. 將 Spring Beans 注入到 Tapestry 頁面中
    首先我們需要 Tapestry 頁面組件在沒有 ServletContext 的情況下訪問 ApplicationContext;這是因為在頁面/組件生命周期里面,當我們需要訪問 ApplicationContext 時,ServletContext 并不能被頁面很方便的訪問到,所以我們不能直接使用 WebApplicationContextUtils.getApplicationContext(servletContext)。 一種解決方法就是實現一個自定義的 Tapestry IEngine 來提供 ApplicationContext:

     

     1 package com.whatever.web.xportal;
     2 
     3 import 
     4 
     5 public class MyEngine extends org.apache.tapestry.engine.BaseEngine {
     6  
     7     public static final String APPLICATION_CONTEXT_KEY = "appContext";
     8  
     9     /**
    10      * @see org.apache.tapestry.engine.AbstractEngine#setupForRequest(org.apache.tapestry.request.RequestContext)
    11      */
    12     protected void setupForRequest(RequestContext context) {
    13         super.setupForRequest(context);
    14      
    15         // insert ApplicationContext in global, if not there
    16         Map global = (Map) getGlobal();
    17         ApplicationContext ac = (ApplicationContext) global.get(APPLICATION_CONTEXT_KEY);
    18         if (ac == null) {
    19             ac = WebApplicationContextUtils.getWebApplicationContext(
    20                 context.getServlet().getServletContext()
    21             );
    22             global.put(APPLICATION_CONTEXT_KEY, ac);
    23         }
    24     }
    25 }
    26 
    27 

    這個引擎類將 Spring application context作為一個名為 “appContext” 的屬性存放在 Tapestry 應用的 “Global” 對象中。在 Tapestry 應用定義文件中必須保證這個特殊的 IEngine 實例在這個 Tapestry 應用中被使用。 舉個例子:

     

     1 file: xportal.application: 
     2 <?xml version="1.0" encoding="UTF-8"?>
     3 <!DOCTYPE application PUBLIC 
     4     "-//Apache Software Foundation//Tapestry Specification 3.0//EN" 
     5     "http://jakarta.apache.org/tapestry/dtd/Tapestry_3_0.dtd">
     6 <application
     7     name="Whatever xPortal"
     8     engine-class="com.whatever.web.xportal.MyEngine">
     9 </application>
    10 

    15.5.1.2. 組件定義文件
    現在,我們在頁面或組件定義文件(*.page 或者 *.jwc)中添加 property-specification 元素就可以 從 ApplicationContext 中獲取 bean,并為這些 bean 創建頁面或 組件屬性。例如:

     

        <property-specification name="userService"
                                type
    ="com.whatever.services.service.user.UserService">
            global.appContext.getBean(
    "userService")
        
    </property-specification>
        
    <property-specification name="authenticationService"
                                type
    ="com.whatever.services.service.user.AuthenticationService">
            global.appContext.getBean(
    "authenticationService")
        
    </property-specification>


    在 property-specification 中定義的 OGNL 表達式使用context中的 bean 來指定屬性的初始值。 整個頁面定義文件如下:

     

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <!DOCTYPE page-specification PUBLIC 
     3     "-//Apache Software Foundation//Tapestry Specification 3.0//EN" 
     4     "http://jakarta.apache.org/tapestry/dtd/Tapestry_3_0.dtd">
     5      
     6 <page-specification class="com.whatever.web.xportal.pages.Login">
     7  
     8     <property-specification name="username" type="java.lang.String"/>
     9     <property-specification name="password" type="java.lang.String"/>
    10     <property-specification name="error" type="java.lang.String"/>
    11     <property-specification name="callback" type="org.apache.tapestry.callback.ICallback" persistent="yes"/>
    12     <property-specification name="userService"
    13                             type="com.whatever.services.service.user.UserService">
    14         global.appContext.getBean("userService")
    15     </property-specification>
    16     <property-specification name="authenticationService"
    17                             type="com.whatever.services.service.user.AuthenticationService">
    18         global.appContext.getBean("authenticationService")
    19     </property-specification>
    20    
    21     <bean name="delegate" class="com.whatever.web.xportal.PortalValidationDelegate"/>
    22  
    23     <bean name="validator" class="org.apache.tapestry.valid.StringValidator" lifecycle="page">
    24         <set-property name="required" expression="true"/>
    25         <set-property name="clientScriptingEnabled" expression="true"/>
    26     </bean>
    27  
    28     <component id="inputUsername" type="ValidField">
    29         <static-binding name="displayName" value="Username"/>
    30         <binding name="value" expression="username"/>
    31         <binding name="validator" expression="beans.validator"/>
    32     </component>
    33    
    34     <component id="inputPassword" type="ValidField">
    35         <binding name="value" expression="password"/>
    36        <binding name="validator" expression="beans.validator"/>
    37        <static-binding name="displayName" value="Password"/>
    38        <binding name="hidden" expression="true"/>
    39     </component>
    40  
    41 </page-specification>
    42 

    15.5.1.3. 添加抽象訪問方法
    現在在頁面或組件本身的 Java 類定義中,我們需要為剛剛定義的屬性添加抽象的 getter 方法。 (這樣才可以訪問那些屬性)。


    下面這個例子總結了前面講述的方法。這是個完整的 Java 類:

     

      1 
      2 package com.whatever.web.xportal.pages;
      3  
      4 /**
      5  *  Allows the user to login, by providing username and password.
      6  *  After successfully logging in, a cookie is placed on the client browser
      7  *  that provides the default username for future logins (the cookie
      8  *  persists for a week).
      9  */
     10 public abstract class Login extends BasePage implements ErrorProperty, PageRenderListener {
     11  
     12     /** the key under which the authenticated user object is stored in the visit as */
     13     public static final String USER_KEY = "user";
     14    
     15     /** The name of the cookie that identifies a user **/
     16     private static final String COOKIE_NAME = Login.class.getName() + ".username";  
     17     private final static int ONE_WEEK = 7 * 24 * 60 * 60;
     18  
     19     public abstract String getUsername();
     20     public abstract void setUsername(String username);
     21  
     22     public abstract String getPassword();
     23     public abstract void setPassword(String password);
     24  
     25     public abstract ICallback getCallback();
     26     public abstract void setCallback(ICallback value);
     27     
     28     public abstract UserService getUserService();
     29     public abstract AuthenticationService getAuthenticationService();
     30  
     31     protected IValidationDelegate getValidationDelegate() {
     32         return (IValidationDelegate) getBeans().getBean("delegate");
     33     }
     34  
     35     protected void setErrorField(String componentId, String message) {
     36         IFormComponent field = (IFormComponent) getComponent(componentId);
     37         IValidationDelegate delegate = getValidationDelegate();
     38         delegate.setFormComponent(field);
     39         delegate.record(new ValidatorException(message));
     40     }
     41  
     42     /**
     43      *  Attempts to login. 
     44      * <p>
     45      *  If the user name is not known, or the password is invalid, then an error
     46      *  message is displayed.
     47      **/
     48     public void attemptLogin(IRequestCycle cycle) {
     49      
     50         String password = getPassword();
     51  
     52         // Do a little extra work to clear out the password.
     53         setPassword(null);
     54         IValidationDelegate delegate = getValidationDelegate();
     55  
     56         delegate.setFormComponent((IFormComponent) getComponent("inputPassword"));
     57         delegate.recordFieldInputValue(null);
     58  
     59         // An error, from a validation field, may already have occurred.
     60         if (delegate.getHasErrors()) {
     61             return;
     62         }
     63 
     64         try {
     65             User user = getAuthenticationService().login(getUsername(), getPassword());
     66            loginUser(user, cycle);
     67         }
     68         catch (FailedLoginException ex) {
     69             this.setError("Login failed: " + ex.getMessage());
     70             return;
     71         }
     72     }
     73  
     74     /**
     75      *  Sets up the {@link User} as the logged in user, creates
     76      *  a cookie for their username (for subsequent logins),
     77      *  and redirects to the appropriate page, or
     78      *  a specified page).
     79      **/
     80     public void loginUser(User user, IRequestCycle cycle) {
     81      
     82         String username = user.getUsername();
     83  
     84         // Get the visit object; this will likely force the
     85         // creation of the visit object and an HttpSession
     86         Map visit = (Map) getVisit();
     87         visit.put(USER_KEY, user);
     88  
     89         // After logging in, go to the MyLibrary page, unless otherwise specified
     90         ICallback callback = getCallback();
     91  
     92         if (callback == null) {
     93             cycle.activate("Home");
     94         }
     95         else {
     96             callback.performCallback(cycle);
     97         }
     98 
     99         IEngine engine = getEngine();
    100         Cookie cookie = new Cookie(COOKIE_NAME, username);
    101         cookie.setPath(engine.getServletPath());
    102         cookie.setMaxAge(ONE_WEEK);
    103  
    104         // Record the user's username in a cookie
    105         cycle.getRequestContext().addCookie(cookie);
    106         engine.forgetPage(getPageName());
    107     }
    108    
    109     public void pageBeginRender(PageEvent event) {
    110         if (getUsername() == null) {
    111             setUsername(getRequestCycle().getRequestContext().getCookieValue(COOKIE_NAME));
    112         }
    113     }
    114 }

    15.5.1.4. 將 Spring Beans 注入到 Tapestry 頁面中 - Tapestry 4.0+ 風格
    在 Tapestry 4.0+ 版本中,將 Spring 托管 beans 注入到 Tapestry 頁面是 非常 簡單的。 你只需要一個 附加函數庫, 和一些(少量)的配置。 你可以將這個庫和Web 應用其他的庫一起部署。(一般情況下是放在 WEB-INF/lib 目錄下。)

    你需要使用 前面介紹的方法 來創建Spring 容器。 然后你就可以將 Spring 托管的 beans 非常簡單的注入給 Tapestry;如果我們使用 Java5, 我們只需要簡單地給 getter 方法添加注釋(annotation),就可以將 Spring 管理的 userService 和 authenticationService 對象注入給頁面。 比如下面 Login 的例子:(為了保持簡潔,許多的類定義在這里省略了)

     

     1 package com.whatever.web.xportal.pages;
     2 
     3 public abstract class Login extends BasePage implements ErrorProperty, PageRenderListener {
     4     
     5     @InjectObject("spring:userService")
     6     public abstract UserService getUserService();
     7     
     8     @InjectObject("spring:authenticationService")
     9     public abstract AuthenticationService getAuthenticationService();
    10 
    11 }
    12 


    我們的任務基本上完成了...剩下的工作就是配置HiveMind,將存儲在 ServletContext 中 的 Spring 容器配置為一個 HiveMind 服務:

     

     1<?xml version="1.0"?>
     2<module id="com.javaforge.tapestry.spring" version="0.1.1">
     3
     4    <service-point id="SpringApplicationInitializer"
     5        interface="org.apache.tapestry.services.ApplicationInitializer"
     6        visibility="private">
     7        <invoke-factory>
     8            <construct class="com.javaforge.tapestry.spring.SpringApplicationInitializer">
     9                <set-object property="beanFactoryHolder"
    10                    value="service:hivemind.lib.DefaultSpringBeanFactoryHolder" />
    11            </construct>
    12        </invoke-factory>
    13    </service-point>
    14
    15    <!-- Hook the Spring setup into the overall application initialization. -->
    16    <contribution
    17        configuration-id="tapestry.init.ApplicationInitializers">
    18        <command id="spring-context"
    19            object="service:SpringApplicationInitializer" />
    20    </contribution>
    21
    22</module>
    23
    24

    如果你使用 Java5(這樣就可以使用annotation),那么就是這么簡單。

    如果你不用 Java5,你沒法通過annotation來注釋你的 Tapestry 頁面; 你可以使用傳統風格的 XML 來聲明依賴注入;例如,在 Login 頁面(或組件)的 .page 或 .jwc 文件中:

    <inject property="userService" object="spring:userService"/>
    <inject property="authenticationService" object="spring:authenticationService"/>
    在這個例子中,我們嘗試使用聲明的方式將定義在 Spring 容器里的 bean 提供給 Tapestry 頁面。 頁面類并不知道服務實現來自哪里,事實上,你也可以很容易地轉換到另一個實現。這在測試中是很有用的。 這樣的反向控制是 Spring 框架的主要目標和優點,我們將它拓展到了Tapestry 應用的整個 J2EE 堆棧上。

    posted on 2008-10-04 23:24 Blog of JoJo 閱讀(683) 評論(0)  編輯  收藏 所屬分類: Programming 相關

    <2025年5月>
    27282930123
    45678910
    11121314151617
    18192021222324
    25262728293031
    1234567

    常用鏈接

    留言簿(6)

    隨筆檔案

    文章分類

    文章檔案

    新聞分類

    新聞檔案

    相冊

    收藏夾

    搜索

    •  

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 久9久9精品免费观看| 美女被暴羞羞免费视频| 成人一区二区免费视频| 亚洲国产一级在线观看| 免费鲁丝片一级在线观看| 亚洲一区电影在线观看| 黄色a三级免费看| 亚洲高清最新av网站| 激情婷婷成人亚洲综合| 四虎影视精品永久免费网站| 亚洲成a∧人片在线观看无码| 成人午夜大片免费7777| 亚洲精品国产首次亮相| 亚洲av片一区二区三区| 一区二区三区免费视频播放器| 国产成人精品久久亚洲| 国产成人免费AV在线播放 | 亚洲香蕉网久久综合影视| 久久久久久久国产免费看| 国产亚洲av片在线观看播放| 99精品视频在线观看免费播放| 亚洲综合激情另类小说区| 成人无码区免费A片视频WWW | 亚洲手机中文字幕| 免费无码肉片在线观看| 国产精品亚洲综合天堂夜夜| 超清首页国产亚洲丝袜| 你懂得的在线观看免费视频| 亚洲福利电影一区二区?| 妞干网免费视频在线观看| 一级毛片不卡免费看老司机| 亚洲AV成人精品网站在线播放| 真人做人试看60分钟免费视频| 色噜噜噜噜亚洲第一| 亚洲一区二区三区自拍公司| 午夜国产精品免费观看| 特黄aa级毛片免费视频播放| 久久精品国产亚洲av影院| 免费播放在线日本感人片| 亚洲免费视频网址| 亚洲国产精品不卡毛片a在线|