- Chapter14.Integratingwithotherwebframeworks
- 14.1.Introduction
- SpringcanbeeasilyintegratedintoanyJava-basedwebframework.AllyouneedtodoistodeclaretheContextLoaderListenerinyourweb.xmlanduseacontextConfigLocation<context-param>tosetwhichcontextfilestoload.
- The<context-param>:
- <context-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>/WEB-INF/applicationContext*.xml</param-value>
- </context-param>
- The<listener>:
- <listener>
- <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
- </listener>
- NOTE:ListenerswereaddedtotheServletAPIinversion2.3.IfyouhaveaServlet2.2container,youcanusetheContextLoaderServlettoachievethissamefunctionality.
- Ifyoudon'tspecifythecontextConfigLocationcontextparameter,theContextLoaderListenerwilllookfora/WEB-INF/applicationContext.xmlfiletoload.Oncethecontextfilesareloaded,SpringcreatesaWebApplicationContextobjectbasedonthebeandefinitionsandputsitintotheServletContext.
- AllJavawebframeworksarebuiltontopoftheServletAPI,soyoucanusethefollowingcodetogettheApplicationContextthatSpringcreated.
- WebApplicationContextctx=WebApplicationContextUtils.getWebApplicationContext(servletContext);
- TheWebApplicationContextUtilsclassisforconvenience,soyoudon'thavetorememberthenameoftheServletContextattribute.ItsgetWebApplicationContext()methodwillreturnnullifanobjectdoesn'texistundertheWebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTEkey.RatherthanriskgettingNullPointerExceptionsinyourapplication,it'sbettertousethegetRequiredWebApplicationContext()method.ThismethodthrowsanExceptionwhentheApplicationContextismissing.
- OnceyouhaveareferencetotheWebApplicationContext,youcanretrievebeansbytheirnameortype.Mostdevelopersretrievebeansbyname,thencastthemtooneoftheirimplementedinterfaces.
- Fortunately,mostoftheframeworksinthissectionhavesimplerwaysoflookingupbeans.NotonlydotheymakeiteasytogetbeansfromtheBeanFactory,buttheyalsoallowyoutousedependencyinjectionontheircontrollers.Eachframeworksectionhasmoredetailonitsspecificintegrationstrategies.
- 14.2.JavaServerFaces
- JavaServerFaces(JSF)isacomponent-based,event-drivenwebframework.AccordingtoSunMicrosystem'sJSFOverview,JSFtechnologyincludes:
- AsetofAPIsforrepresentingUIcomponentsandmanagingtheirstate,handlingeventsandinputvalidation,definingpagenavigation,andsupportinginternationalizationandaccessibility.
- AJavaServerPages(JSP)customtaglibraryforexpressingaJavaServerFacesinterfacewithinaJSPpage.
- 14.2.1.DelegatingVariableResolver
- TheeasiestwaytointegrateyourSpringmiddle-tierwithyourJSFweblayeristousetheDelegatingVariableResolverclass.Toconfigurethisvariableresolverinyourapplication,you'llneedtoedityourfaces-context.xml.Aftertheopening<faces-config>element,addan<application>elementanda<variable-resolver>elementwithinit.ThevalueofthevariableresolvershouldreferenceSpring'sDelegatingVariableResolver:
- <faces-config>
- <application>
- <variable-resolver>org.springframework.web.jsf.DelegatingVariableResolver</variable-resolver>
- <locale-config>
- <default-locale>en</default-locale>
- <supported-locale>en</supported-locale>
- <supported-locale>es</supported-locale>
- </locale-config>
- <message-bundle>messages</message-bundle>
- </application>
- ByspecifyingSpring'svariableresolver,youcanconfigureSpringbeansasmanagedpropertiesofyourmanagedbeans.TheDelegatingVariableResolverwillfirstdelegatevaluelookupstothedefaultresolveroftheunderlyingJSFimplementation,andthentoSpring'srootWebApplicationContext.ThisallowsyoutoeasilyinjectdependenciesintoyourJSF-managedbeans.
- Managedbeansaredefinedinyourfaces-config.xmlfile.Belowisanexamplewhere#{userManager}isabeanthat'sretrievedfromSpring'sBeanFactory.
- <managed-bean>
- <managed-bean-name>userList</managed-bean-name>
- <managed-bean-class>com.whatever.jsf.UserList</managed-bean-class>
- <managed-bean-scope>request</managed-bean-scope>
- <managed-property>
- <property-name>userManager</property-name>
- <value>#{userManager}</value>
- </managed-property>
- </managed-bean>
- TheDelegatingVariableResolveristherecommendedstrategyforintegratingJSFandSpring.Ifyou'relookingformorerobustintegrationfeatures,youmighttakealookattheJSF-Springproject.
- 14.2.2.FacesContextUtils
- AcustomVariableResolverworkswellwhenmappingyourpropertiestobeansinfaces-config.xml,butattimesyoumayneedtogrababeanexplicitly.TheFacesContextUtilsclassmakesthiseasy.It'ssimilartoWebApplicationContextUtils,exceptthatittakesaFacesContextparameterratherthanaServletContextparameter.
- ApplicationContextctx=FacesContextUtils.getWebApplicationContext(FacesContext.getCurrentInstance());
- 14.3.Struts
- StrutsisthedefactowebframeworkforJavaapplications,mainlybecauseitwasoneofthefirsttobereleased(June2001).InventedbyCraigMcClanahan,StrutsisanopensourceprojecthostedbytheApacheSoftwareFoundation.Atthetime,itgreatlysimplifiedtheJSP/Servletprogrammingparadigmandwonovermanydeveloperswhowereusingproprietaryframeworks.Itsimplifiedtheprogrammingmodel,itwasopensource,andithadalargecommunity,whichallowedtheprojecttogrowandbecomepopularamongJavawebdevelopers.
- TointegrateyourStrutsapplicationwithSpring,youhavetwooptions:
- ConfigureSpringtomanageyourActionsasbeans,usingtheContextLoaderPlugin,andsettheirdependenciesinaSpringcontextfile.
- SubclassSpring'sActionSupportclassesandgrabyourSpring-managedbeansexplicitlyusingagetWebApplicationContext()method.
- 14.3.1.ContextLoaderPlugin
- TheContextLoaderPluginisaStruts1.1+plug-inthatloadsaSpringcontextfilefortheStrutsActionServlet.ThiscontextreferstotherootWebApplicationContext(loadedbytheContextLoaderListener)asitsparent.Thedefaultnameofthecontextfileisthenameofthemappedservlet,plus-servlet.xml.IfActionServletisdefinedinweb.xmlas<servlet-name>action</servlet-name>,thedefaultis/WEB-INF/action-servlet.xml.
- Toconfigurethisplug-in,addthefollowingXMLtotheplug-inssectionnearthebottomofyourstruts-config.xmlfile:
- <plug-inclassName="org.springframework.web.struts.ContextLoaderPlugIn"/>
- Thelocationofthecontextconfigurationfilescanbecustomizedusingthe"contextConfigLocation"property.
- <plug-inclassName="org.springframework.web.struts.ContextLoaderPlugIn">
- <set-propertyproperty="contextConfigLocation"
- value="/WEB-INF/action-servlet.xml.xml,/WEB-INF/applicationContext.xml"/>
- </plug-in>
- Itispossibletousethisplugintoloadallyourcontextfiles,whichcanbeusefulwhenusingtestingtoolslikeStrutsTestCase.StrutsTestCase'sMockStrutsTestCasewon'tinitializeListenersonstartupsoputtingallyourcontextfilesinthepluginisaworkaround.Abughasbeenfiledforthisissue.
- Afterconfiguringthisplug-ininstruts-config.xml,youcanconfigureyourActiontobemanagedbySpring.Spring1.1.3providestwowaystodothis:
- OverrideStruts'defaultRequestProcessorwithSpring'sDelegatingRequestProcessor.
- UsetheDelegatingActionProxyclassinthetypeattributeofyour<action-mapping>.
- BothofthesemethodsallowyoutomanageyourActionsandtheirdependenciesintheaction-context.xmlfile.ThebridgebetweentheActioninstruts-config.xmlandaction-servlet.xmlisbuiltwiththeaction-mapping's"path"andthebean's"name".Ifyouhavethefollowinginyourstruts-config.xmlfile:
- <actionpath="/users".../>
- YoumustdefinethatAction'sbeanwiththe"/users"nameinaction-servlet.xml:
- <beanname="/users".../>
- 14.3.1.1.DelegatingRequestProcessor
- ToconfiguretheDelegatingRequestProcessorinyourstruts-config.xmlfile,overridethe"processorClass"propertyinthe<controller>element.Theselinesfollowthe<action-mapping>element.
- <controller>
- <set-propertyproperty="processorClass"
- value="org.springframework.web.struts.DelegatingRequestProcessor"/>
- </controller>
- Afteraddingthissetting,yourActionwillautomaticallybelookedupinSpring'scontextfile,nomatterwhatthetype.Infact,youdon'tevenneedtospecifyatype.Bothofthefollowingsnippetswillwork:
- <actionpath="/user"type="com.whatever.struts.UserAction"/>
- <actionpath="/user"/>
- Ifyou'reusingStruts'modulesfeature,yourbeannamesmustcontainthemoduleprefix.Forexample,anactiondefinedas<actionpath="/user"/>withmoduleprefix"admin"requiresabeannamewith<beanname="/admin/user"/>.
- NOTE:Ifyou'reusingTilesinyourStrutsapplication,youmustconfigureyour<controller>withtheDelegatingTilesRequestProcessor.
- 14.3.1.2.DelegatingActionProxy
- IfyouhaveacustomRequestProcessorandcan'tusetheDelegatingTilesRequestProcessor,youcanusetheDelegatingActionProxyasthetypeinyouraction-mapping.
- <actionpath="/user"type="org.springframework.web.struts.DelegatingActionProxy"
- name="userForm"scope="request"validate="false"parameter="method">
- <forwardname="list"path="/userList.jsp"/>
- <forwardname="edit"path="/userForm.jsp"/>
- </action>
- Thebeandefinitioninaction-servlet.xmlremainsthesame,whetheryouuseacustomRequestProcessorortheDelegatingActionProxy.
- IfyoudefineyourActioninacontextfile,thefullfeaturesetofSpring'sbeancontainerwillbeavailableforit:dependencyinjectionaswellastheoptiontoinstantiateanewActioninstanceforeachrequest.Toactivatethelatter,addsingleton="false"toyourAction'sbeandefinition.
- <beanname="/user"singleton="false"autowire="byName"
- class="org.example.web.UserAction"/>
- 14.3.2.ActionSupportClasses
- Aspreviouslymentioned,youcanretrievetheWebApplicationContextfromtheServletContextusingtheWebApplicationContextUtilsclass.AneasierwayistoextendSpring'sActionclassesforStruts.Forexample,insteadofsubclassingStruts'Actionclass,youcansubclassSpring'sActionSupportclass.
- TheActionSupportclassprovidesadditionalconveniencemethods,likegetWebApplicationContext().BelowisanexampleofhowyoumightusethisinanAction:
- publicclassUserActionextendsDispatchActionSupport{
- publicActionForwardexecute(ActionMappingmapping,
- ActionFormform,
- HttpServletRequestrequest,
- HttpServletResponseresponse)
- throwsException{
- if(log.isDebugEnabled()){
- log.debug("entering'delete'method...");
- }
- WebApplicationContextctx=getWebApplicationContext();
- UserManagermgr=(UserManager)ctx.getBean("userManager");
- //talktomanagerforbusinesslogic
- returnmapping.findForward("success");
- }
- }
- SpringincludessubclassesforallofthestandardStrutsActions-theSpringversionsmerelyhaveSupportappendedtothename:
- ActionSupport,
- DispatchActionSupport,
- LookupDispatchActionSupportand
- MappingDispatchActionSupport.
- Therecommendedstrategyistousetheapproachthatbestsuitsyourproject.Subclassingmakesyourcodemorereadable,andyouknowexactlyhowyourdependenciesareresolved.However,usingtheContextLoaderPluginallowyoutoeasilyaddnewdependenciesinyourcontextXMLfile.Eitherway,Springprovidessomeniceoptionsforintegratingthetwoframeworks.
- 14.4.Tapestry
- Tapestryisapowerful,component-orientedwebapplicationframeworkfromApache'sJakartaproject(http://jakarta.apache.org/tapestry).WhileSpringhasitsownpowerfulwebuilayer,thereareanumberofuniqueadvantagestobuildingaJ2EEapplicationusingacombinationofTapestryforthewebui,andtheSpringcontainerforthelowerlayers.Thisdocumentattemptstodetailafewbestpracticesforcombiningthesetwoframeworks.ItisexpectedthatyouarerelativelyfamiliarwithbothTapestryandSpringFrameworkbasics,sotheywillnotbeexplainedhere.GeneralintroductorydocumentationforbothTapestryandSpringFrameworkareavailableontheirrespectivewebsites.
- 14.4.1.Architecture
- AtypicallayeredJ2EEapplicationbuiltwithTapestryandSpringwillconsistofatopUIlayerbuiltwithTapestry,andanumberoflowerlayers,hostedoutofoneormoreSpringApplicationContexts.
- UserInterfaceLayer:
- -concernedwiththeuserinterface
- -containssomeapplicationlogic
- -providedbyTapestry
- -asidefromprovidingUIviaTapestry,codeinthislayerdoesitsworkviaobjectswhichimplementinterfacesfromtheServiceLayer.TheactualobjectswhichimplementtheseservicelayerinterfacesareobtainedfromaSpringApplicationContext.
- ServiceLayer:
- -applicationspecific'service'code
- -workswithdomainobjects,andusestheMapperAPItogetthosedomainobjectsintoandoutofsomesortofrepository(database)
- -hostedinoneormoreSpringcontexts
- -codeinthislayermanipulatesobjectsinthedomainmodel,inanapplicationspecificfashion.Itdoesitsworkviaothercodeinthislayer,andviatheMapperAPI.Anobjectinthislayerisgiventhespecificmapperimplementationsitneedstoworkwith,viatheSpringcontext.
- -sincecodeinthislayerishostedintheSpringcontext,itmaybetransactionallywrappedbytheSpringcontext,asopposedtomanagingitsowntransactions
- DomainModel:
- -domainspecificobjecthierarchy,whichdealswithdataandlogicspecifictothisdomain
- -althoughthedomainobjecthierarchyisbuiltwiththeideathatitispersistedsomehowandmakessomegeneralconcessionstothis(forexample,bidirectionalrelationships),itgenerallyhasnoknowledgeofotherlayers.Assuch,itmaybetestedinisolation,andusedwithdifferentmappingimplementationsforproductionvs.testing.
- -theseobjectsmaybestandalone,orusedinconjunctionwithaSpringapplicationcontexttotakeadvantageofsomeofthebenefitsofthecontext,e.g.,isolation,inversionofcontrol,differentstrategyimplementations,etc.
- DataSourceLayer:
- -MapperAPI(alsocalledDataAccessObjects):anAPIusedtopersistthedomainmodeltoarepositoryofsomesort(generallyaDB,butcouldbethefilesystem,memory,etc.)
- -MapperAPIimplementations:oneormorespecificimplementationsoftheMapperAPI,forexample,aHibernate-specificmapper,aJDO-specificmapper,JDBC-specificmapper,oramemorymapper.
- -mapperimplementationsliveinoneormoreSpringApplicationContexts.Aservicelayerobjectisgiventhemapperobjectsitneedstoworkwithviathecontext.
- Database,filesystem,orotherrepositories:
- -objectsinthedomainmodelarestoredintooneormorerepositoriesviaoneormoremapperimplementations
- -arepositorymaybeverysimple(e.g.filesystem),ormayhaveitsownrepresentationofthedatafromthedomainmodel(i.e.aschemainadb).Itdoesnotknowaboutotherlayershowerver.
- 14.4.2.Implementation
- Theonlyrealquestion(whichneedstobeaddressedbythisdocument),ishowTapestrypagesgetaccesstoserviceimplementations,whicharesimplybeansdefinedinaninstanceoftheSpringApplicationContext.
- 14.4.2.1.Sampleapplicationcontext
- AssumewehavethefollowingsimpleApplicationContextdefinition,inxmlform:
- <?xmlversion="1.0"encoding="UTF-8"?>
- <!DOCTYPEbeansPUBLIC"-//SPRING//DTDBEAN//EN"
- "http://www.springframework.org/dtd/spring-beans.dtd">
- <beans>
- <!--=========================GENERALDEFINITIONS=========================-->
- <!--=========================PERSISTENCEDEFINITIONS=========================-->
- <!--theDataSource-->
- <beanid="dataSource"class="org.springframework.jndi.JndiObjectFactoryBean">
- <propertyname="jndiName"><value>java:DefaultDS</value></property>
- <propertyname="resourceRef"><value>false</value></property>
- </bean>
- <!--defineaHibernateSessionfactoryviaaSpringLocalSessionFactoryBean-->
- <beanid="hibSessionFactory"
- class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
- <propertyname="dataSource"><refbean="dataSource"/></property>
- </bean>
- <!--
- -Definesatransactionmanagerforusageinbusinessordataaccessobjects.
- -Nospecialtreatmentbythecontext,justabeaninstanceavailableasreference
- -forbusinessobjectsthatwanttohandletransactions,e.g.viaTransactionTemplate.
- -->
- <beanid="transactionManager"
- class="org.springframework.transaction.jta.JtaTransactionManager">
- </bean>
- <beanid="mapper"
- class="com.whatever.dataaccess.mapper.hibernate.MapperImpl">
- <propertyname="sessionFactory"><refbean="hibSessionFactory"/></property>
- </bean>
- <!--=========================BUSINESSDEFINITIONS=========================-->
- <!--AuthenticationService,includingtxinterceptor-->
- <beanid="authenticationServiceTarget"
- class="com.whatever.services.service.user.AuthenticationServiceImpl">
- <propertyname="mapper"><refbean="mapper"/></property>
- </bean>
- <beanid="authenticationService"
- class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
- <propertyname="transactionManager"><refbean="transactionManager"/></property>
- <propertyname="target"><refbean="authenticationServiceTarget"/></property>
- <propertyname="proxyInterfacesOnly"><value>true</value></property>
- <propertyname="transactionAttributes">
- <props>
- <propkey="*">PROPAGATION_REQUIRED</prop>
- </props>
- </property>
- </bean>
- <!--UserService,includingtxinterceptor-->
- <beanid="userServiceTarget"
- class="com.whatever.services.service.user.UserServiceImpl">
- <propertyname="mapper"><refbean="mapper"/></property>
- </bean>
- <beanid="userService"
- class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
- <propertyname="transactionManager"><refbean="transactionManager"/></property>
- <propertyname="target"><refbean="userServiceTarget"/></property>
- <propertyname="proxyInterfacesOnly"><value>true</value></property>
- <propertyname="transactionAttributes">
- <props>
- <propkey="*">PROPAGATION_REQUIRED</prop>
- </props>
- </property>
- </bean>
- </beans>
- InsidetheTapestryapplication,weneedtoloadthisapplicationcontext,andallowTapestrypagestogettheauthenticationServiceanduserServicebeans,whichimplementtheAuthenticationServiceandUserServiceinterfaces,respectively.
- 14.4.2.2.ObtainingbeansinTapestrypages
- Atthispoint,theapplicationcontextisavailabletoawebapplicationbycallingSpring'sstaticutilityfunctionWebApplicationContextUtils.getApplicationContext(servletContext),whereservletContextisthestandardServletContextfromtheJ2EEServletspecification.Assuch,onesimplemechanismforapagetogetaninstanceoftheUserService,forexample,wouldbewithcodesuchas:
- WebApplicationContextappContext=WebApplicationContextUtils.getApplicationContext(
- getRequestCycle().getRequestContext().getServlet().getServletContext());
- UserServiceuserService=(UserService)appContext.getBean("userService");
- ...somecodewhichusesUserService
- Thismechanismdoeswork.Itcanbemadealotlessverbosebyencapsulatingmostofthefunctionalityinamethodinthebaseclassforthepageorcomponent.However,insomerespectsitgoesagainsttheInversionofControlapproachwhichSpringencourages,whichisbeingusedinotherlayersofthisapp,inthatideallyyouwouldlikethepagetonothavetoaskthecontextforaspecificbeanbyname,andinfact,thepagewouldideallynotknowaboutthecontextatall.
- Luckily,thereisamechanismtoallowthis.WerelyuponthefactthatTapestryalreadyhasamechanismtodeclarativelyaddpropertiestoapage,anditisinfactthepreferredapproachtomanageallpropertiesonapageinthisdeclarativefashion,sothatTapestrycanproperlymanagetheirlifecycleaspartofthepageandcomponentlifecycle.
- 14.4.2.3.ExposingtheapplicationcontexttoTapestry
- FirstweneedtomaketheApplicationContextavailabletotheTapestrypageorComponentwithouthavingtohavetheServletContext;thisisbecauseatthestageinthepage's/component'slifecyclewhenweneedtoaccesstheApplicationContext,theServletContextwon'tbeeasilyavailabletothepage,sowecan'tuseWebApplicationContextUtils.getApplicationContext(servletContext)directly.OnewayisbydefiningacustomversionoftheTapestryIEnginewhichexposesthisforus:
- packagecom.whatever.web.xportal;
- ...
- import...
- ...
- publicclassMyEngineextendsorg.apache.tapestry.engine.BaseEngine{
- publicstaticfinalStringAPPLICATION_CONTEXT_KEY="appContext";
- /**
- *@seeorg.apache.tapestry.engine.AbstractEngine#setupForRequest(org.apache.tapestry.request.RequestContext)
- */
- protectedvoidsetupForRequest(RequestContextcontext){
- super.setupForRequest(context);
- //insertApplicationContextinglobal,ifnotthere
- Mapglobal=(Map)getGlobal();
- ApplicationContextac=(ApplicationContext)global.get(APPLICATION_CONTEXT_KEY);
- if(ac==null){
- ac=WebApplicationContextUtils.getWebApplicationContext(
- context.getServlet().getServletContext()
- );
- global.put(APPLICATION_CONTEXT_KEY,ac);
- }
- }
- }
- ThisengineclassplacestheSpringApplicationContextasanattributecalled"appContext"inthisTapestryapp's'Global'object.MakesuretoregisterthefactthatthisspecialIEngineinstanceshouldbeusedforthisTapestryapplication,withanentryintheTapestryapplicationdefinitionfile.Forexample:
- file:xportal.application:
- <?xmlversion="1.0"encoding="UTF-8"?>
- <!DOCTYPEapplicationPUBLIC
- "-//ApacheSoftwareFoundation//TapestrySpecification3.0//EN"
- "http://jakarta.apache.org/tapestry/dtd/Tapestry_3_0.dtd">
- <application
- name="WhateverxPortal"
- engine-class="com.whatever.web.xportal.MyEngine">
- </application>
- 14.4.2.4.Componentdefinitionfiles
- Nowinourpageorcomponentdefinitionfile(*.pageor*.jwc),wesimplyaddproperty-specificationelementstograbthebeansweneedoutoftheApplicationContext,andcreatepageorcomponentpropertiesforthem.Forexample:
- <property-specificationname="userService"
- type="com.whatever.services.service.user.UserService">
- global.appContext.getBean("userService")
- </property-specification>
- <property-specificationname="authenticationService"
- type="com.whatever.services.service.user.AuthenticationService">
- global.appContext.getBean("authenticationService")
- </property-specification>
- TheOGNLexpressioninsidetheproperty-specificationspecifiestheinitialvaluefortheproperty,asabeanobtainedfromthecontext.Theentirepagedefinitionmightlooklikethis:
- <?xmlversion="1.0"encoding="UTF-8"?>
- <!DOCTYPEpage-specificationPUBLIC
- "-//ApacheSoftwareFoundation//TapestrySpecification3.0//EN"
- "http://jakarta.apache.org/tapestry/dtd/Tapestry_3_0.dtd">
- <page-specificationclass="com.whatever.web.xportal.pages.Login">
- <property-specificationname="username"type="java.lang.String"/>
- <property-specificationname="password"type="java.lang.String"/>
- <property-specificationname="error"type="java.lang.String"/>
- <property-specificationname="callback"type="org.apache.tapestry.callback.ICallback"persistent="yes"/>
- <property-specificationname="userService"
- type="com.whatever.services.service.user.UserService">
- global.appContext.getBean("userService")
- </property-specification>
- <property-specificationname="authenticationService"
- type="com.whatever.services.service.user.AuthenticationService">
- global.appContext.getBean("authenticationService")
- </property-specification>
- <beanname="delegate"class="com.whatever.web.xportal.PortalValidationDelegate"/>
- <beanname="validator"class="org.apache.tapestry.valid.StringValidator"lifecycle="page">
- <set-propertyname="required"expression="true"/>
- <set-propertyname="clientScriptingEnabled"expression="true"/>
- </bean>
- <componentid="inputUsername"type="ValidField">
- <static-bindingname="displayName"value="Username"/>
- <bindingname="value"expression="username"/>
- <bindingname="validator"expression="beans.validator"/>
- </component>
- <componentid="inputPassword"type="ValidField">
- <bindingname="value"expression="password"/>
- <bindingname="validator"expression="beans.validator"/>
- <static-bindingname="displayName"value="Password"/>
- <bindingname="hidden"expression="true"/>
- </component>
- </page-specification>
- 14.4.2.5.Addingabstractaccessors
- NowintheJavaclassdefinitionforthepageorcomponentitself,allweneedtodoisaddanabstractgettermethodforthepropertieswehavedefined,toaccessthem.WhenthepageorcomponentisactuallyloadedbyTapestry,itperformsruntimecodeinstrumentationontheclassfiletoaddthepropertieswhichhavebeendefined,andhookuptheabstractgettermethodstothenewlycreatedfields.Forexample:
- //ourUserServiceimplementation;willcomefrompagedefinition
- publicabstractUserServicegetUserService();
- //ourAuthenticationServiceimplementation;willcomefrompagedefinition
- publicabstractAuthenticationServicegetAuthenticationService();
- Forcompleteness,theentireJavaclass,foraloginpageinthisexample,mightlooklikethis:
- packagecom.whatever.web.xportal.pages;
- /**
- *Allowstheusertologin,byprovidingusernameandpassword.
- *Aftersuccessfullyloggingin,acookieisplacedontheclientbrowser
- *thatprovidesthedefaultusernameforfuturelogins(thecookie
- *persistsforaweek).
- */
- publicabstractclassLoginextendsBasePageimplementsErrorProperty,PageRenderListener{
- /**thekeyunderwhichtheauthenticateduserobjectisstoredinthevisitas*/
- publicstaticfinalStringUSER_KEY="user";
- /**
- *Thenameofacookietostoreontheuser'smachinethatwillidentify
- *themnexttimetheylogin.
- **/
- privatestaticfinalStringCOOKIE_NAME=Login.class.getName()+".username";
- privatefinalstaticintONE_WEEK=7*24*60*60;
- //---attributes
- publicabstractStringgetUsername();
- publicabstractvoidsetUsername(Stringusername);
- publicabstractStringgetPassword();
- publicabstractvoidsetPassword(Stringpassword);
- publicabstractICallbackgetCallback();
- publicabstractvoidsetCallback(ICallbackvalue);
- publicabstractUserServicegetUserService();
- publicabstractAuthenticationServicegetAuthenticationService();
- //---methods
- protectedIValidationDelegategetValidationDelegate(){
- return(IValidationDelegate)getBeans().getBean("delegate");
- }
- protectedvoidsetErrorField(StringcomponentId,Stringmessage){
- IFormComponentfield=(IFormComponent)getComponent(componentId);
- IValidationDelegatedelegate=getValidationDelegate();
- delegate.setFormComponent(field);
- delegate.record(newValidatorException(message));
- }
- /**
- *Attemptstologin.
- *
- *<p>Iftheusernameisnotknown,orthepasswordisinvalid,thenanerror
- *messageisdisplayed.
- *
- **/
- publicvoidattemptLogin(IRequestCyclecycle){
- Stringpassword=getPassword();
- //Doalittleextraworktoclearoutthepassword.
- setPassword(null);
- IValidationDelegatedelegate=getValidationDelegate();
- delegate.setFormComponent((IFormComponent)getComponent("inputPassword"));
- delegate.recordFieldInputValue(null);
- //Anerror,fromavalidationfield,mayalreadyhaveoccurred.
- if(delegate.getHasErrors())
- return;
- try{
- Useruser=getAuthenticationService().login(getUsername(),getPassword());
- loginUser(user,cycle);
- }
- catch(FailedLoginExceptionex){
- this.setError("Loginfailed:"+ex.getMessage());
- return;
- }
- }
- /**
- *Setsupthe{@linkUser}astheloggedinuser,creates
- *acookiefortheirusername(forsubsequentlogins),
- *andredirectstotheappropriatepage,or
- *aspecifiedpage).
- *
- **/
- publicvoidloginUser(Useruser,IRequestCyclecycle){
- Stringusername=user.getUsername();
- //Getthevisitobject;thiswilllikelyforcethe
- //creationofthevisitobjectandanHttpSession.
- Mapvisit=(Map)getVisit();
- visit.put(USER_KEY,user);
- //Afterloggingin,gototheMyLibrarypage,unlessotherwise
- //specified.
- ICallbackcallback=getCallback();
- if(callback==null)
- cycle.activate("Home");
- else
- callback.performCallback(cycle);
- //I'vefoundthatfailingtosetamaximumageandapathmeansthat
- //thebrowser(IE5.0anyway)quietlydropsthecookie.
- IEngineengine=getEngine();
- Cookiecookie=newCookie(COOKIE_NAME,username);
- cookie.setPath(engine.getServletPath());
- cookie.setMaxAge(ONE_WEEK);
- //Recordtheuser'susernameinacookie
- cycle.getRequestContext().addCookie(cookie);
- engine.forgetPage(getPageName());
- }
- publicvoidpageBeginRender(PageEventevent){
- if(getUsername()==null)
- setUsername(getRequestCycle().getRequestContext().getCookieValue(COOKIE_NAME));
- }
- }
- 14.4.3.Summary
- Inthisexample,we'vemanagedtoallowservicebeansdefinedintheSpringApplicationContexttobeprovidedtothepageinadeclarativefashion.Thepageclassdoesnotknowwheretheserviceimplementationsarecomingfrom,andinfactitiseasytoslipinanotherimplementation,forexample,duringtesting.ThisinversionofcontrolisoneoftheprimegoalsandbenefitsoftheSpringFramework,andwehavemanagedtoextenditallthewayuptheJ2EEstackinthisTapestryapplication.
- 14.5.WebWork
- WebWorkisawebframeworkdesignedwithsimplicityinmind.It'sbuiltontopofXWork,whichisagenericcommandframework.XWorkalsohasanIoCcontainer,butitisn'tasfull-featuredasSpringandwon'tbecoveredinthissection.WebWorkcontrollersarecalledActions,mainlybecausetheymustimplementtheActioninterface.TheActionSupportclassimplementsthisinterface,anditismostcommonparentclassforWebWorkactions.
- WebWorkmaintainsitsownSpringintegrationproject,locatedonjava.netinthexwork-optionalproject.Currently,threeoptionsareavailableforintegratingWebWorkwithSpring:
- SpringObjectFactory:overrideXWork'sdefaultObjectFactorysoXWorkwilllookforSpringbeansintherootWebApplicationContext.
- ActionAutowiringInterceptor:useaninterceptortoautomaticallywireanAction'sdependenciesasthey'recreated.
- SpringExternalReferenceResolver:lookupSpringbeansbasedonthenamedefinedinan<external-ref>elementofan<action>element.
- AllofthesestrategiesareexplainedinfurtherdetailinWebWork'sDocumentation.
- --------------------------------------------------------------------------------
- Prev
spring与其它框架集成
最新推荐文章于 2022-12-29 22:07:10 发布