JBoss Seam vs. Spring Web Flow
Transcrição
JBoss Seam vs. Spring Web Flow
27.10.2009 Vortrag JBoss Seam vs. Spring Web Flow 1 Speaker Martin Bengl und Alexander Rudat 2 1 27.10.2009 Agenda 1. Architektur 2. Dependency Injection 3. Dialogführung (Conversation vs. Flow) 4. Web Integration 5. Testen 6. Zusammenfassung und Fazit 3 Architektur Seam JSP Facelets Portal Navigation Java Server Faces Kontext JBoss Seam JBoss jBPM JPA Präsentation Hibernate Zustand 4 2 27.10.2009 Architektur Web Flow Spring Web Flow Distribution JSF JSP Portal Spring Faces Spring JavaScript Spring Binding Spring Web Flow Präsentation Navigaton Spring MVC Spring Framework JPA Hibernate Kontext Zustand 5 Architektur Seam Seam Spring Core Spring MVC Spring Web Flow 6 3 27.10.2009 Gemeinsame Ziele • einfache und schnelle Webprogrammierung • Integration mit JSF, JPA • Persistence Context wird als Zwischenspeicher für Entitäten genutzt • Direkte Verwendung von Entitäten in View, keine DTOs • Gültigkeitsbereich von Objekten sehr flexibel • Einfache Dialogführung in Webanwendungen • Abbildung von fachlichen Arbeitsschritten (Workflow) 7 Dependency Injection mit Spring <bean id="emf" class="org.springframework.orm.jpa. LocalContainerEntityManagerFactoryBean"> ... </bean> <bean name="bookingService" class="booking.JpaBookingService"> <property name="entityManagerFactory" ref="emf"/> </bean> package booking; public class JpaBookingService extends JpaDaoSupport implements BookingService { @Override public void setEntityManagerFactory(EntityManagerFactory entityManagerFactory) { ... } public Hotel findHotelById(Long id) { return getJpaTemplate().getEntityManager(). find(Hotel.class, id); } ... } 8 4 27.10.2009 Dependency Injection mit Seam Konfiguration @Name("hotelBooking") @Scope(ScopeType.CONVERSATION) public class HotelBookingAction implements HotelBooking { @In("entityManager") private EntityManager em; @Out private Hotel hotel; @Begin() public void selectHotel(Hotel selectedHotel) { hotel = em.merge(selectedHotel); } } 9 Dependency Injection mit Seam Verwendung … … in main.xhtml: <h:commandButton value="View Hotel“ action="#{hotelBooking.selectHotel(hot)}"/> <h:outputText value="#{hotel.address}" /> … in der pages.xml: <action execute="#{hotelBooking.initialize}"/> … in der components.xml: <persistence:entity-manager-factory name="entityManagerFactory" persistence-unit-name=„pu"/> <persistence:managed-persistence-context name="entityManager" entity-manager-factory="#{entityManagerFactory}" /> 10 5 27.10.2009 Dependency Injection mit Spring <!-- Scans for application @Components to deploy --> <context:component-scan base-package="booking" /> <bean id="entityMangerFactory” class="org.springframework. orm.jpa.LocalContainerEntityManagerFactoryBean"/> package booking @Service("bookingService") public class JpaBookingService implements BookingService { @PersistenceContext private EntityManager em; public Hotel findHotelById(Long id) { return em.find(Hotel.class, id); } ... } <evaluate expression="bookingService.findHotelById(id)" result="viewScope.bookings" /> 11 Vergleich: Dependency Injection Seam • Primär zustandsbasierte Komponenten • dynamische Injection • Bijection : „Outjection in einen Scope“ • Komponenten umhüllt von Interceptoren • Primär Annotationen • wenn XML, dann mit EL Spring • Primäre zustandslose Komponenten • einmalige Injection • Instanziierung via ApplicationContext • Interceptoren bei Bedarf • Annotationen und XMLKonfiguration möglich • wenn Annotation, dann ein wenig XML 12 6 27.10.2009 Beispielanwendung <<Action>> <<View>> <<Action>> <<View>> Hotel suchen Hotelliste Hotels auswählen Hotel Anzeige Buchung abschicken Buchungs formular Zimmer buchen <<Action>> <<View>> <<Action>> <<View>> Bestätigungs formular Bestätigung abschicken <<Action>> 13 Vergleich: Beispielanwendung Hotel Seam / Hotel Web Flow • • • • • • • Fachliche Anforderungen identisch Drei Schichten Architekturen Facelets als View-Technologie Verzicht auf Enterprise Java Beans JPA als OR-Mapper, gleiche Entitäten Apache Tomcat als Webcontainer Apache Derby als Datenbank 14 7 27.10.2009 Dialogführung Allgemein HTTP Session Login Dialog Begin Subdialog Begin HTTP Request Transaction Logout End End Request Response Begin Commit Transaction Persistence Context Scope Subdialog Dialog 15 Dialogführung Allgemein Persistence Context als Cache Persistence Context flush() Datenbank Seite 1 Seite 2 Seite 3 Seite 4 16 8 27.10.2009 Dialogführung mit Seam (1) Konversationen Definition der Konversationsgrenzen mittels XML oder Annotationen: • @Begin startet neue Konversation @Begin(flushMode=FlushModeType.MANUAL) • @End beendet Konversation Alternative in pages.xml: • <begin-conversation/> • <end-conversation/> 17 JBoss Seam JBoss Seam Demo 18 9 27.10.2009 Dialogführung mit Seam (2) JSF Navigation via faces-config.xml <navigation-rule> <from-view-id>/main.xhtml</from-view-id> <navigation-case> <from-action>#{hotelBooking.selectHotel}</from-action> <from-outcome>view</from-outcome> <to-view-id>/hotel.xhtml</to-view-id> <redirect/> </navigation-case> </navigation-rule> 19 Dialogführung mit Seam (3) Navigation mittels pages.xml <s:link id="viewHotel" value="View Hotel" action="#{hotelBooking.selectHotel(hot)}"/> <page view view-id id= ="/main.xhtml“ login-required="true"> <action execute="#{hotelBooking.initialize}"/> <navigation from-action="#{hotelBooking.selectHotel(hot)}"> <redirect view-id="/hotel.xhtml"/> </navigation> </page> 20 10 27.10.2009 Dialogführung mit Seam (4) Navigation mittels pages.xml <page view-id="/hotel.xhtml" conversation-required="true" > <navigation from-action="#{hotelBooking.bookHotel}"> <rule if="#{hotelBooking.bookable}" > <redirect view-id="/book.xhtml"/> </rule> <rule if="#{true}"> <end-conversation/> <redirect view-id="/main.xhtml" > <message>Buchung nicht möglich:#{hotel.name}</message> </redirect> </rule> </navigation> </page> 21 Dialogführung mit Seam (5) Elemente der pages.xml • <page view-id=„/main.xhtml“ /> Für jede Seite wird ein <page /> Tag definiert • <navigation from-action=„…“ /> Definiert einen Navigationspfad • <rule if=„…“ /> Ermöglicht Navigationsentscheidungen • <action execute=„…“ if=„…"/> Aktionen vor Anzeige einer Seite ausführen (z.B. Daten laden) • <restrict>…</restrict> Schützt die Seite vor unberechtigten Zugriff 22 11 27.10.2009 Dialogführung mit Web Flow Was ist ein Flow? • • • • • • Flow ≈ Geschäftsvorfall Ablauf logisch zusammenhängenden Views Kann aus mehreren Subflows bestehen FDL wird als DSL beschrieben Realisierung mittels XML oder Java Besteht aus mehrernen Zuständen (States) die nacheinander durchlaufen werden. 23 Dialogführung mit Web Flow Flow Zustände • view-state <view-state id="..." view="..." /> • action-state <action-state id="..."> • decission-state <decission-state id="..."> • subflow-state <subflow-state id="..." subflow="..."> • end-state <end-state id="..."> 24 12 27.10.2009 Webbasierter Buchungsprozess main--flow main booking--flow booking Hotel suchen Buchungsformular Buchung abschicken Bestätigungsformular Hotel Anzeige Abbrechen Hotel auswählen Fehler Änderung Neue Suche Hotelliste Bestätigung abschicken Zimmer buchen (Buchungsprozess) 25 <<View>> <<Action>> Spring Web Flow Demo 26 13 27.10.2009 Flow Konfiguration <flow ... > <persistence-context/> <input name="hotelId" required="true" /> <on-start> <evaluate expression="bookingService.createBooking(hotelId, currentUser.name)" result="flowScope.booking“/> </on-start> <view-state id="enterBookingDetails" model="booking"> <transition on="proceed" to="reviewBooking" /> <transition on="cancel" to="bookingCancelled" bind="false" /> </view-state> <view-state id="reviewBooking"> <transition on="confirm" to="bookingConfirmed" /> <transition on="revise" to="enterBookingDetails" /> <transition on="cancel" to="bookingCancelled" /> </view-state> <end-state id="bookingConfirmed" commit="true" /> <end-state id="bookingCancelled" /> </flow> 27 Dialogführung mit Seam Navigation mittels jPDL: <start-state name="start" > <transition to="main" /> </start-state> <page name="main" view-id="/main.xhtml" > <transition name="select" to="showHotel" > <action expression="#{hotelBooking.selectHotel(hot)}"/> </transition> </page> <page name="showHotel" view-id="/hotel.xhtml" > <transition name="book" to="bookHotel" > <action expression="#{hotelBooking.selectHotel(hot)}"/> </transition> <transition name="back" to="main" /> </page> <end-state name="quit" /> 28 14 27.10.2009 Dialogführung mit Seam Elemente von jPDL: • < start-state /> Definiert den Anfangszustand • <page view-Id=„…“ /> Wartezustand, veranlasst JSF zum „rendern“ der View • <transition to=„…“ /> Definiert einen Zustandswechseln • <action expression=„…“/> Ermöglicht die Ausführung von Geschäftslogik • <end-state /> Definiert den Endzustand 29 Vergleich der Gültigkeitsbereiche Seam Spring Web Flow • Application • Session • Event • Singleton • Session • Request • • • • • • • • Conversation Sub-Conversation Page Stateless Flow Sub-Flow Flash Prototype Conversation 30 15 27.10.2009 Vergleich: Dialogführung Seam • Stateless/Stateful Navigation • Standard JSF Navigation möglich • Views beinhalten ELAusdrücke um Komponenten aufzurufen (z.B: hotelBooking. selectHotel(hotel) ) Web Flow • nur Stateful Navigation • Serviceaufruf in Konfiguration kann Controller/Action ersetzen • Logische Namen in Views anstelle von Action Aufrufen (z.B. <h:commandButton value=„book“ />) 31 Seam‘s Web Integration AJAX Unterstützung <h:inputText value="#{hotelSearch.searchString}"> <a:support actionListener="#{hotelSearch.find}" event="onkeyup" reRender="searchResults" /> </h:inputText> <a:outputPanel id="searchResults"> <h:outputText value="No Hotels Found" rendered="#{hotels != null and hotels.rowCount==0}" /> <h:dataTable value="#{hotels}" var="hot" rendered="#{hotels.rowCount>0}"> ... </h:dataTable> </a:outputPanel> 32 16 27.10.2009 Seam‘s Web Integration Validierung und Fehleranzeige <s:decorate id="creditCard" template="edit.xhtml"> <ui:define name="label">Credit Card #:</ui:define> <h:inputText value="#{booking.creditCard}" required="true"> <a:support id="onblur" event="onblur“ reRender="creditCard"/> </h:inputText> </s:decorate> @Length(min = 16, max = 16, message = "Credit card number must 16 digits long") @Pattern(regex = "^\\d*$", message = "Credit card number must be numeric") public String getCreditCard() { return creditCard; } 33 Seam‘s Web Integration Validierung und Fehleranzeige 34 17 27.10.2009 Seam‘s Web Integration Template für Fehleranzeige <ui:composition xmlns:s="htp://jboss.com/p/seam/taglib"> <div class="entry"> <s:label styleClass=“ #{invalid?'errors':''}"> <ui:insert name="label"/> <s:span rendered="#{required}">*</s:span> </s:label> <span class="input #{invalid?'errors':''}"> <s:validateAll id="ValidateAll"> <ui:insert/> </s:validateAll> </span> <s:message id="message" styleClass=“errors"/> </div> </ui:composition> 35 Web Flow‘s Web Integration (1) Validierung und Fehleranzeige 1. Client-seitige Validierung <ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html“ xmlns:sf="http://www.springframework.org/tags/faces"> ... <sf:clientTextValidator required="true" regExp="[0-9]{16}" invalidMessage="A 16-digit credit card number is required."> <h:inputText id="creditCard" value="#{booking.creditCard}" required="true"/> </sf:clientTextValidator> 36 18 27.10.2009 Web Flow‘s Web Integration (2) Validierung und Fehleranzeige 2. Server-seitige Validierung @Entity public class Booking implements Serializable { ID des view-state ... public void validateEnterBookingDetails(ValidationContext context) { MessageContext messages = context.getMessageContext(); if (checkinDate.before(today())) { messages.addMessage(new MessageBuilder().error()); } else if (checkoutDate.before(checkinDate)) { messages.addMessage(new MessageBuilder().error()); } } ... } 37 Web Flow‘s Web Integration (3) AJAX Integration • Partielles page rendering im View Sope view.xhtml flow.xml <view-state id="changeSearchCriteria" view="enterSearchCriteria.xhtml" popup="true" > <on-entry> <render fragments="hotelSearchFragment" /> </on-entry> <transition on="search" to="reviewHotels“ /> </view-state> <ui:composition xmlns:ui="http://java.sun.com/jsf/facelets"/> ... <ui:fragment id="hotelSearchFragment"> <div id="hotelSearch" class="section"> <h2>Search Hotels</h2> ... </div> </ui:fragment> 38 19 27.10.2009 Vergleich: Web Integration Seam / RichFaces Web Flow • Standard JSF möglich • Ausgereifte AjaxUnterstützung • Große Komponentenauswahl • Validierung via JSR 303 • Fehleranzeige durch geschickte Kombination von Facelets-Templating und eigenen Seam Tags • Rich Faces & Apache MyFaces Trinidad Unterstützung • Große Komponentenauswahl • Ab Version 3.0 auch BeanValidierung (JSR 303) • Fehleranzeige durch geschickte Kombination von FaceletsTemplating und eigenen Spring Faces Tags 39 Testen mit Spring Web Flow (1) @ContextConfiguration(locations="/test-config.xml") public class BookingServiceTest extends AbstractJUnit4SpringContextTests { @Resource private BookingService bookingService; @Test public void testFindHotel() { Assert.assertNotNull(bookingService.findHotelById(1L)); } } 40 20 27.10.2009 Testen mit Spring Web Flow (2) public class MyFlowTest extends AbstractXmlFlowExecutionTests { @Override protected FlowDefinitionResource getResource(FlowDefinitionResourceFactory resFactory){ return resourceFactory.createFileResource("src/main/ webapp/WEB-INF/flows/main/booking-flow.xml"); } public void testFlow() throws Exception { MockExternalContext context = new MockExternalContext(); context.setCurrentUser("scott"); startFlow(context); ... } } 41 Testen mit JBoss Seam (1) @Name("MyTest") public class MyTest extends SeamComponentTest { @In private MyApplication myApplication; @Test public void testMyIntegration() throws Exception { String rc = myApplication.doSomething(); Assert.assertEquals(rc, "ok"); } } 42 21 27.10.2009 Testen mit JBoss Seam (2) public abstract class SeamComponentTest extends SeamTest { @BeforeMethod public void begin() { super.begin(); TestLifecycle.beginTest(servletContext, new ServletSessionMap(session)); new Component(this.getClass()).inject(this, true); } @AfterMethod public void end() { TestLifecycle.endTest(); super.end(); } } 43 Zusammenfassung & Fazit • Kerngeschäft „Flow Management“ bei beiden Frameworks gut umgesetzt • Seam erweitert JavaServer Faces • Web Flow erweitert Spring MVC • Seam bietet Application Framework Dienste • Web Flow nutzt SpringSource Produkte • Haben Sie Erfahrung mit JSF und ist Spring kein Thema für Sie: Nutzen Sie Seam! • Setzten Sie bereits auf Spring, schauen Sie sich Web Flow an! 44 22 27.10.2009 Sie sahen und hörten… JBoss Seam vs. Spring Web Flow 45 23