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

Documentos relacionados