Tapestry与Spring的整合(在Tapestry页面中获得Spring Bean)

How  can  you  reference  Spring  beans  from  Tapestry  4?  In  earlier  versions  of  Tapestry,  
the  most  common  method  was  to  extend  the  BaseEngine  class.  However,  in  Tapestry  4  the  BaseEngine  class  is  deprecated,  and  we  now  need  to  extend  SpringBeanFactoryHolder.  

(Basic  knowledge  of  Java,  Tapestry,  and  Spring  assumed.) 

Step  1:  Hivemind  Configuration
Note:  You  can  skip  this  step  by  downloading  tapestry-spring.jar  from    http://sourceforge.net/projects/diaphragma  and  placing  it  on  your  classpath. 

Continue  reading,  if  you're  interested  in  how  it  works...  

Tapestry  uses  Hivemind,  behind  the  scenes,  for  dependency-injection.  Hivemind's  XML  configuration  is  similar  to  Spring.  The  easiest  way  to  contribute  to  the  whole  Hivemind  registry  is  by  creating  hivemodule.xml  in  your  WEB-INF  directory.  

Here  is  what  you  need  in  this  project  to  provide  a  new  implementation  of  the  DefaultSpringBeanFactoryHolder

<?xml version="1.0"?>

<module id="diaphragma.tapspr"        version="1.0.0">
    <!-- 覆盖默认的服务 -->
    <implementation
        service-id="hivemind.lib.DefaultSpringBeanFactoryHolder">
        <invoke-factory>
            <construct autowire-services="false"
                class="diaphragma.tapspr.XSpringBeanFactoryHolderImpl">

                <event-listener
                    service-id="hivemind.ShutdownCoordinator" />

                <set-object property="context"
                    value="service:tape    stry.globals.WebContext" />

            </construct>
        </invoke-factory>
    </implementation>
</module>

Next  job  is  to  create  XSpringBeanFactoryHolderImpl.java.  It  look  like  this: 

package diaphragma.tapspr;

import java.io.PrintStream;
import org.apache.hivemind.events.RegistryShutdownListener;
import org.apache.hivemind.lib.impl.SpringBeanFactoryHolderImpl;
import org.apache.tapestry.web.WebContext;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ConfigurableApplicationContext;


public class XSpringBeanFactoryHolderImpl extends SpringBeanFactoryHolderImpl
    implements RegistryShutdownListener
{
    private  WebContext context;

    public  XSpringBeanFactoryHolderImpl()
    {
    }

    public  void setContext(WebContext webcontext)
    {
        context = webcontext;
    }

    public  WebContext getContext()
    {
        return context;
    }

    public  BeanFactory getBeanFactory()
    {
        if(super.getBeanFactory() == null  )
            super.setBeanFactory(XWebApplicationContextUtils.getWebApplicationContext(getContext()));
        return  super.getBeanFactory();
    }

    public void registry DidShutdown()
    {
        ((ConfigurableApplicationContext)super.getBeanFactory()).close();
    }

}

As  we  can  see,  this  class  extends  the  default  SpringBeanFactoryHolder.  The  important  thing  is  what  you  see  in  getBeanFactory()  method,  there  you  define  where  our  BeanFactory  located.  In  this  example,  I  use  WebApplicationContextUtils.getRequiredWebApplicationContext()  method.  There  is  another  method  which  doesn't  throw  exception  WebApplicationContextUtils.getWebApplicationContext().  
Next,  we  implement  XWebApplicationContextUtils.java 

package diaphragma.tapspr;

import org.apache.tapestry.web.WebContext;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

public class XWebApplicationContextUtils extends WebApplicationContextUtils
{

    public XWebApplicationContextUtils()
    {
    }

    public static WebApplicationContext getWebApplicationContext(WebContext webcontext)
    {
        Object obj = webcontext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
        if(obj == null)
            return null;
        if(obj instanceof RuntimeException )
            throw (RuntimeException)obj;
        if(obj instanceof Error)
            throw (Error)obj;
        if(!(obj instanceof WebApplicationContext))
            throw new IllegalStateException((new StringBuilder()).append("Root context attribute is not of type WebApplicationContext: ").append(obj).toString());
        else
            return (WebApplicationContext)obj;
    }

    public static WebApplicationContext getRequiredWebApplicationContext(WebContext webcontext)
        throws IllegalStateException
    {
        WebApplicationContext webapplicationcontext = getWebApplicationContext(webcontext);
        if(webapplicationcontext ==  null)
            throw new IllegalStateException( "No WebApplicationContext found: no ContextLoaderListener registered?");
        else
            return webapplicationcontext;
    }
}

Step  2:  Spring  Configuration
Spring  in  servlet  mode  need  two  things,  it  needs  the  XML  file  for  bean  configuration  and  also  a  filter  in  web.xml.  In  web.xml,  you  will  have  to  add  this: 

<context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
        <listener-class>
                org.springframework.web.context.ContextLoaderListener
        </listener-class>
</listener>

And  now  let  us  try  a  simple  XML  file  (place  it  under  WEB-INF/  as  applicationContext.xml). 

<?xml version="1.0" encoding=    "UTF-8"?>

<!DOCTYPE beans public "-//SPRING//DTD BEAN//EN" 
        "http://www.springframework.org/dtd/spring-beans.dtd">

<beans>
        <bean id="person"    class="com.example.model.Person">
        <property name="name  ">
                <value>Nanda Firdausi</value>
        </property>
        </bean>
</beans>

It  defines  one  object  with  one  property. 

Step  3:  Access  Spring  property  from  Tapestry  page  specification
Now  time  to  see  whether  our  bean  can  be  accessed  from  a  Tapestry  page.  First,  let  us  create  the  page  specification  (Home.page). 

<?xml version="1.0" encoding="UTF-8"?>
        
<!DOCTYPE page-specification PUBLIC
        "-//Apache Software Foundation//Tapestry Specification 4.0//EN"
        "http://jakarta.apache.org/tapestry/dtd/Tapestry_4_0.dtd">
        
<page-specification class="org.apache.tapestry.html.BasePage">
        <inject property="person"    object="spring:person"      />
</page-specification>


The page template is trivial, one super-simple-example is like this (Home.html). 

<span jwcid="@Insert"    value="ognl:person.name" />

Please make comments, suggestions, and any other things related to this tutorial.

This  information  was  originally  written  in  an  email  to  the  Tapestry  User's  List  on  March  7,  2005  by  Nanda  Firdausi  

HowardLewisShip:  This  is  pretty  much  overkill,  since  you  can  just  acquire  your  AC  and  store  it  into  the  DefaultSpringBeanFactoryHolder  service  with  no  additional  work.  I  do  like  that  you  have  a  shutdown  option,  though.  I'm  putting  together  a  proper  implementation  for  Tapestry  @  JavaForge.  

HowardLewisShip:  I've  put  together  a  basic  Spring  integration  module:    tapestry-spring.  The  solution  on  this  page  is  a  little  more  flexible,  however  (at  least  for  the  moment).  

NandaFirdausi:  I've  seen  your  implementation,  and  I  like  it  too,  just  like  your  other  code  ;).  I  thing  your  implementation  doesn't  need  spring  listener  anymore,  am  I  right?  If  so,  then  the  choice  to  the  user  is  if  they  do  have  another  spring  wep  application  with  nothing  to  do  with  tapestry,  it's  better  to  set  the  spring  listener  and  do  like  this  page  says.  If  your  web  application  is  all  tapestry  based  (with  spring  as  back-end  support),  then  your  code  looks  cleaner  for  me    

Tapestry  4  (another  solution)
JarekWoloszyn:  Here  is  another  solution  for  Tapestry4.  

We  need  a  helper  class  which  will  create  WebApplicationContext  for  the  ServletContext.  Hivemind  can't  call  factory  methods  (from  WebApplicationContextUtils),  so  we  create  a  POJO. 
Spring  Context  is  re-created  everytime  we  change  ServletContext. 

package org.your.application;

import javax.servlet.ServletContext;

import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;


public class SpringContextFactory {
    private  ServletContext servletContext;
    private  WebApplicationContext appContext;
    
    public  WebApplicationContext getAppContext() {
        return appContext;
    }    
    
    public  ServletContext getServletContext() {
        return servletContext;
    }

    public void setServletContext(ServletContext servletContext) {
        this..servletContext = servletContext;
        appContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
    }     
}

Tapestry  4  has  Spring  integration  out  of  the  box.  We  must  only  say  which  BeanFactory  should  be  used.  In  hivemind.xml,  we  define  a  service-point  for  our  helper  class.  This  class  takes  ServletContext  as  parameter.  We  configure  then  Hivemind  to  use  appContext  member  as  spring-bean  factory.

<?xml version="1.0"?>
<module id="app" version=   "1.0.0"    package="org.your.application">
  
  <contribution configuration-id=  "hivemind.ApplicationDefaults">
    <default symbol="hivemind.lib.spring-bean-factory"
                                                    <!-- 这里的app是module id,可以不加的吧? -->
       value="service-property:app.SpringContextFactory:appContext"/>
  </contribution>
  
    <service-point id="SpringContextFactory">        
        Create WebApplicatonContext for Spring  
        <invoke-factory>
            <construct class="SpringContextFactory" >
                <!-- 将ServletContext传递给SpringContextFactory -->
                <set-service property="servletContext"         
                   <!-- tapestry.globals.*定义了好多tapestry的常量 -->
                   service-id="tapestry.globals.ServletContext"/>
            </construct>
        </invoke-factory>       
    </service-point>
</module>


And  that's  all.  Now  you  can  use  spring:  prefix  to  access  Spring  beans:  

       //不需要再在.page文件里 <inject../>了
       @InjectObject("spring:DAOFactory")
       public  abstract  DAOFactory  getDao();

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 推荐使用官方的比较方便,就是把官方的http: //howardlewisship.com/repository/com/javaforge/tapestry/tapestry-spring/0.1.2/tapestry -spring-0.1.2.jar拷贝到WEB-INF/lib目录下就可以。

 

 

一种是官方提供的 http://howardlewisship.com/tapestry-javaforge/tapestry-spring/

 

 官方的有局限性:

Provides Tapestry integration with Spring. This plugin relies on依赖 the normal Spring setup in web.xml (as described in the Spring documentation), but then wires things up so that所以 the "spring:" object prefix will access beans from that context.

 

This only works with servlet Tapestry; support for Tapestry portlets is forthcoming即将.

Injecting Spring beans that are not singletons doesn't work properly. This represents a fundamental difference between HiveMind and Spring; Spring forces your code to be aware of知道 the lifecycle of the bean (i.e., you must know that your code has to keep asking Spring for new copies of the bean). HiveMind always provides a proxy that shields保护 your code from the lifecycle of the service.

 

 

 

 

另一种是根据

参考地址http://wiki.apache.org/tapestry/Tapestry4Spring

 

研究出来的:

注意在web.xml文件中listener在servlet和servlet-mapping文件之前

参考这个DTD里面有说明.

================================

 

下面是web.xml内容:

 

================================


<?xml version="1.0" encoding="UTF-8"?>
<!--
 Copyright 2006 Howard M. Lewis Ship
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at
 
 http://www.apache.org/licenses/LICENSE-2.0
 
 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
-->

<!DOCTYPE web-app
      PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
      "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
 <display-name>application</display-name>

 <!-- for Spring -->
 <context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>/WEB-INF/applicationContext.xml</param-value>
 </context-param>

 <filter>
  <filter-name>redirect</filter-name>
  <filter-class>org.apache.tapestry.RedirectFilter</filter-class>
 </filter>

 <filter-mapping>
  <filter-name>redirect</filter-name>
  <url-pattern>/</url-pattern>
 </filter-mapping>

 <listener>
  <listener-class>
   org.springframework.web.context.ContextLoaderListener
  </listener-class>
 </listener>

 <servlet>
  <servlet-name>template</servlet-name>
  <servlet-class>
   org.apache.tapestry.ApplicationServlet
  </servlet-class>
  <load-on-startup>0</load-on-startup>
 </servlet>

 <servlet-mapping>
  <servlet-name>template</servlet-name>
  <url-pattern>/app</url-pattern>
 </servlet-mapping>

 <session-config>
  <session-timeout>15</session-timeout>
 </session-config>
</web-app>
================================================================

 如果直接在WEB-INF/lib目录下加入tapestry-spring.jar(下载地址: http://sourceforge.net/projects/diaphragma )就可以不用WEB-INF/hivemodule.xml的文件了

 

也可以像下面一样自己写spring 与hivemodule的桥代码

hivemodule.xml 内容如下:

 

==============================================================

<?xml version="1.0"?>
<module id="workbench" version="1.0.0" package="com.hc.tapestry.web">
 <implementation service-id="hivemind.lib.DefaultSpringBeanFactoryHolder">
     <invoke-factory>
         <construct autowire-services="false" class="com.hc.web.tapestry.XSpringBeanFactoryHolderImpl">
    <event-listener service-id="hivemind.ShutdownCoordinator" />
                <set-object property="context" value="service:tapestry.globals.WebContext" />
            </construct>
        </invoke-factory>
    </implementation>
</module>

==============================================================

增加三个java文件:HibernateRequestFilter.java   XSpringBeanFactoryHolderImpl.java  XWebApplicationContextUtils.java 代码如下:

 

HibernateRequestFilter.java

 

=========================================

package com.hc.web.tapestry;

import java.io.IOException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hivemind.lib.SpringBeanFactoryHolder;
import org.apache.tapestry.Tapestry;
import org.apache.tapestry.services.ServiceConstants;
import org.apache.tapestry.services.WebRequestServicer;
import org.apache.tapestry.services.WebRequestServicerFilter;
import org.apache.tapestry.web.WebRequest;
import org.apache.tapestry.web.WebResponse;
import org.hibernate.FlushMode;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.orm.hibernate3.SessionFactoryUtils;
import org.springframework.orm.hibernate3.SessionHolder;
import org.springframework.transaction.support.TransactionSynchronizationManager;

public class HibernateRequestFilter implements WebRequestServicerFilter {

  private static Log logger = LogFactory.getLog(HibernateRequestFilter.class);

  public static final String DEFAULT_SESSION_FACTORY_BEAN_NAME = "sessionFactory";

  private String sessionFactoryBeanName = DEFAULT_SESSION_FACTORY_BEAN_NAME;

  private SpringBeanFactoryHolder _beanFactoryHolder;

  /**
   * Set the bean name of the SessionFactory to fetch from Spring's root
   * application context. Default is "sessionFactory".
   *
   * @see #DEFAULT_SESSION_FACTORY_BEAN_NAME
   */
  public void setSessionFactoryBeanName(String sessionFactoryBeanName) {
    this.sessionFactoryBeanName = sessionFactoryBeanName;
  }

  /**
   * Return the bean name of the SessionFactory to fetch from Spring's root
   * application context.
   */
  protected String getSessionFactoryBeanName() {
    return sessionFactoryBeanName;
  }

  public void service(WebRequest request, WebResponse response,
      WebRequestServicer servicer) throws IOException {
    String svcValue = request.getParameterValue(ServiceConstants.SERVICE);
    if (Tapestry.ASSET_SERVICE.equals(svcValue)) {
      servicer.service(request, response);
      return;
    }
    logger.debug("entering into Hibernate Request Filter " + " service:" + svcValue
        + " context:" + request.getContextPath() + " activation:"
        + request.getActivationPath() + " path:" + request.getPathInfo());
    SessionFactory sessionFactory = lookupSessionFactory(request);
    Session session = null;

    // single session mode

    logger.debug("Opening single Hibernate Session in OpenSessionInViewFilter");
    session = getSession(sessionFactory);
    TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(
        session));

    try {
      servicer.service(request, response);
    }

    finally {
      // single session mode
      TransactionSynchronizationManager.unbindResource(sessionFactory);
      logger.debug("Closing single Hibernate Session in OpenSessionInViewFilter");
      try {
        closeSession(session, sessionFactory);
      } catch (RuntimeException ex) {
        logger.error("Unexpected exception on closing Hibernate Session", ex);
      }
    }

  }

  /** For injection. */
  public final void setBeanFactoryHolder(SpringBeanFactoryHolder beanFactoryHolder) {
    _beanFactoryHolder = beanFactoryHolder;
  }

  protected SessionFactory lookupSessionFactory(WebRequest request) {
    if (logger.isDebugEnabled()) {
      logger.debug("Using SessionFactory '" + getSessionFactoryBeanName()
          + "' for OpenSessionInViewFilter");
    }
    return (SessionFactory) _beanFactoryHolder.getBeanFactory().getBean(
        getSessionFactoryBeanName(), SessionFactory.class);
  }

  protected Session getSession(SessionFactory sessionFactory)
      throws DataAccessResourceFailureException {
    return openSession(sessionFactory);
  }

  protected Session openSession(SessionFactory sessionFactory)
      throws DataAccessResourceFailureException {
    Session session = SessionFactoryUtils.getSession(sessionFactory, true);
    // session.setFlushMode(FlushMode.NEVER);
    session.setFlushMode(FlushMode.COMMIT);
    return session;
  }

  protected void closeSession(Session session, SessionFactory sessionFactory) {
    session.close();
    // SessionFactoryUtils.releaseSession(session, sessionFactory);
  }

}

=====================================

 

XSpringBeanFactoryHolderImpl.java

 

======================================

package com.hc.web.tapestry;

import org.apache.hivemind.events.RegistryShutdownListener;
import org.apache.hivemind.lib.impl.SpringBeanFactoryHolderImpl;
import org.apache.tapestry.web.WebContext;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ConfigurableApplicationContext;


public class XSpringBeanFactoryHolderImpl extends SpringBeanFactoryHolderImpl
    implements RegistryShutdownListener
{
    private WebContext context;

    public XSpringBeanFactoryHolderImpl()
    {
    }

    public void setContext(WebContext webcontext)
    {
        context = webcontext;
    }

    public WebContext getContext()
    {
        return context;
    }

    public BeanFactory getBeanFactory()
    {
        if(super.getBeanFactory() == null)
            super.setBeanFactory(XWebApplicationContextUtils.getWebApplicationContext(getContext()));
        return super.getBeanFactory();
    }

    public void registryDidShutdown()
    {
        ((ConfigurableApplicationContext)super.getBeanFactory()).close();
    }

}

=========================================

 

XWebApplicationContextUtils.java

 

=========================================

 package com.hc.web.tapestry;

import org.apache.tapestry.web.WebContext;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

public class XWebApplicationContextUtils extends WebApplicationContextUtils
{

    public XWebApplicationContextUtils()
    {
    }

    public static WebApplicationContext getWebApplicationContext(WebContext webcontext)
    {
        Object obj = webcontext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
        if(obj == null)
            return null;
        if(obj instanceof RuntimeException)
            throw (RuntimeException)obj;
        if(obj instanceof Error)
            throw (Error)obj;
        if(!(obj instanceof WebApplicationContext))
            throw new IllegalStateException((new StringBuilder()).append("Root context attribute is not of type WebApplicationContext: ").append(obj).toString());
        else
            return (WebApplicationContext)obj;
    }

    public static WebApplicationContext getRequiredWebApplicationContext(WebContext webcontext)
        throws IllegalStateException
    {
        WebApplicationContext webapplicationcontext = getWebApplicationContext(webcontext);
        if(webapplicationcontext == null)
            throw new IllegalStateException("No WebApplicationContext found: no ContextLoaderListener registered?");
        else
            return webapplicationcontext;
    }
     =================================

 

log4j.properties

 

=================================

# For all other servers: Comment out the Log4J listener in web.xml to activate Log4J.
log4j.rootLogger=INFO, stdout, logfile
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - <%m>%n
log4j.appender.logfile=org.apache.log4j.RollingFileAppender
log4j.appender.logfile.File=D:/log/Log.log
log4j.appender.logfile.MaxFileSize=512KB
# Keep three backup files.
log4j.appender.logfile.MaxBackupIndex=3
# Pattern to output: date priority [category] - message
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值