82
Lars Röwekamp | open knowledge GmbH | @mobileLarson Hidden Features JSF 2 Best Practices

JSF 2: Best Practices und Hidden Features

Embed Size (px)

DESCRIPTION

Speaker: Lars Röwekamp W-JAX 2012 Eine Webanwendung auf Basis von JSF 2 zu bauen ist nicht immer nur lustig. Ein ungewohntes Programmiermodell, scheinbare Spezifikationslücken und eine Menge Ungereimtheiten. Wer soll da noch durchsteigen? Die Session zeigt anhand eines praktischen Beispiels essenzielle Best Practices und Hidden Features von JSF. Zusätzlich werden einige wirklich nützliche JSF Libraries und Frameworks vorgestellt.

Citation preview

Page 1: JSF 2: Best Practices und Hidden Features

Lars Röwekamp | open knowledge GmbH | @mobileLarson

Hidden Features

JSF 2

Best

Pra

ctic

es

Page 2: JSF 2: Best Practices und Hidden Features

Don‘t ask me, RTFS!

Page 3: JSF 2: Best Practices und Hidden Features

„Come on, that‘s way to much.“*

*JSF 2 Spec: > 500P

Page 4: JSF 2: Best Practices und Hidden Features

Bookmarking

Validation

Ajax

ComponentsBehavior

Stuff

Page 5: JSF 2: Best Practices und Hidden Features

Ajax

Page 6: JSF 2: Best Practices und Hidden Features

It‘s sooo easy!

Page 7: JSF 2: Best Practices und Hidden Features

Ajax

2.) „Was soll gerendert werden?“

1.) „Was soll ausgeführt werden?“

Page 8: JSF 2: Best Practices und Hidden Features

Ajax> Asynchrones Request/Response Handling> Partitial Execute/Rendering via Lifecycle> JSF Component Tree > Ajax Request Status Handling> Ajax Request Error Handling

> Easy to use: f:ajax-Tag > Total control: jsf.ajax.request( )

Page 9: JSF 2: Best Practices und Hidden Features

Ajax<!-- Das AJAX TAG --><h:form ...> <h:commandButton value=“Update“> <f:ajax execute=“@form“ render=“updateMe“ /> </h:commandButton>

<h:outputTextField value=“#{aBeansValue}“ id=“updateMe“ /></h:form>

Page 10: JSF 2: Best Practices und Hidden Features

Ajax<f:ajax execute = „wen ausführen?“ render = „wen updaten?“ event = „auf was reagieren?“ listener = „wen interessiert‘s noch?“ onevent = „zusätzliche JavaScript Callback-Funktion“ onerror = „zusätzliche JavaScript Callback-Fehler-Funktion“ />

Page 11: JSF 2: Best Practices und Hidden Features

Ajax<!-- Das AJAX TAG (Master / Detail) --><h:selectOneMenu id="master" value="#{demo.master}"> <f:selectItems value="#{demo.masterItems}"/> <f:ajax render="detail" listener="#{demo.masterChanged}"/></h:selectOneMenu>

<h:selectOneMenu id="detail" value="#{demo.detail}"> <f:selectItems value="#{demo.detailItems}"/></h:selectOneMenu>

Page 12: JSF 2: Best Practices und Hidden Features

Ajax<f:ajax execute = „wen ausführen?“ render = „wen updaten?“ event = „auf was reagieren?“ listener = „wen interessiert‘s?“ onevent = „zusätzliche JavaScript Callback-Funktion“ onerror = „zusätzliche JavaScript Callback-Fehler-Funktion“ />

Page 13: JSF 2: Best Practices und Hidden Features

Ajax<f:ajax execute = @this render = @none event = action (Button/Link) valueChange (sonst) listener = @none onevent = status: begin, complete, success source: triggering DOM event responseCode, responseText/XML/>

Page 14: JSF 2: Best Practices und Hidden Features

Ajax<!-- Die JavaScript API (Master/Detail) --><h:selectOneMenu id="master" value="#{demo.master}" valueChangeListener="#{demo.masterChanged}" onChange="jsf.ajax.request( this, event, {render: detail});"/>

<h:selectOneMenu id="detail" value="#{demo.detail}"> <f:selectItems value="#{demo.detailItems}"/></h:selectOneMenu>

Page 15: JSF 2: Best Practices und Hidden Features

Ajax<!-- Die JavaScript API (Master/Detail) --><h:selectOneMenu id="master" value="#{demo.master}" valueChangeListener="#{demo.masterChanged}" onChange="jsf.ajax.request( this, event, {render: detail});"/>

<h:selectOneMenu id="detail" value="#{demo.detail}"> <f:selectItems value="#{demo.detailItems}"/></h:selectOneMenu>

Source Option(s)Event

Page 16: JSF 2: Best Practices und Hidden Features

AjaxPitfalls> inner/outer Component IDs> Ajax in Custom Components> Ajax Status Feedback

Page 17: JSF 2: Best Practices und Hidden Features

„Want some cool stuff?“

Page 18: JSF 2: Best Practices und Hidden Features

Ajax<!-- axaj response manipulation via PartitialResponseWriter (PrimeFaces style)--><partial-response> <changes> <update id="abc">...</update> <update id="xyz“>...</update> <extension ln="primefaces" type="args"> {"loggedIn":false} </extension> </changes></partial-response>

http://www.primefaces.org/showcase/ui/dialogLogin.jsf

Page 19: JSF 2: Best Practices und Hidden Features

Ajax<!-- axaj response handling inside JSF view (PrimeFaces style)--><script type="text/javascript">    function handleLoginRequest(xhr, status, args) {      if(args.validationFailed || !args.loggedIn) {        jQuery('#dialog') .effect("shake", { times:3 }, 100);      } else {        dlg.hide();        jQuery('#loginLink').fadeOut();      }    }  </script>  

Page 20: JSF 2: Best Practices und Hidden Features

Ajax// PartitialResponseWriter (PrimeFaces style)

@Overridepublic void endDocument() throws IOException {  Map<String, String> attributes = new HashMap<String, String>();  attributes.put("ln", "primefaces");  attributes.put("type", "args");  startExtension(attributes);  write("{"loggedIn":false}");  endExtension();  super.endDocument();}

Page 21: JSF 2: Best Practices und Hidden Features

Behavior

Page 22: JSF 2: Best Practices und Hidden Features

Behavior> Idee: Komponente um clientseitige Funktionalität erweitern, die vom Autor ursprünglich nicht vorgesehen war.

> Mittel: JSF Behavior API zur Erweiterung beliebiger Komponenten um Client-side Scripting

Page 23: JSF 2: Best Practices und Hidden Features

Behavior<!-- Behavior in Action --><h:form ...> <h:commandButton value=“Update“> <f:ajax execute=“@form“ render=“updateMe“ /> </h:commandButton>

<h:outputTextField value=“#{aValue}“ id=“updateMe“ /></h:form>

Standard Behavior

Page 24: JSF 2: Best Practices und Hidden Features

Behavior> Client-side Validation> Client-side Logging> DOM & Style Manipulation> Animationen & visuelle Effekte> Alerts & Confirmation Dialoge> Lazy Data Fetching> Integration mit 3rd Party Libraries> ...

Page 25: JSF 2: Best Practices und Hidden Features

BehaviorMain Player

> ClientBehavior a.k.a. Script Generator: zuständig für Generierung von passendem Skript

> ClientBehaviorHolder a.k.a. Vermittler: zuständig für das Wiring zwischen Komponente, Event und ClientBehavior

Page 26: JSF 2: Best Practices und Hidden Features

Behavior<!-- BEHAVIOR in action -->

// chain of behaviors <h:commandButton value=“Update“>

// 1. ask user for permission <mystuff:confirm event=“click“ />

// 2. if YES send AJAX call <f:ajax event=“click“ render=“updateMe“ />

</h:commandButton>

„My“ Behavior

Standard Behavior

Page 27: JSF 2: Best Practices und Hidden Features

Behaviorpackage de.openknowledge.example.behavior; @FacesBehavior(xyz.behavior.Confirm)public class ConfirmBehavior

extends ClientBehaviorBase {

@Override public String getScript(

ClientBehaviorContext behaviorContext) { return “return confirm(‘Are your sure?‘)“;

}}

„My“ Behavior

Page 28: JSF 2: Best Practices und Hidden Features

Behavior<?xml version='1.0' encoding='UTF-8'?><facelet-taglib xmlns="..." version="2.0"> <namespace>http://xyz.de/mystuff</namespace> <tag> <tag-name>confirm</tag-name> <behavior> <behavior-id> xyz.behavior.Confirm </behavior-id> </behavior> </tag></facelet-taglib>

Facelets TagLib

in WEB-INF o. META-INF

Page 29: JSF 2: Best Practices und Hidden Features

Server-side Action?

Page 30: JSF 2: Best Practices und Hidden Features

Behavior<!-- BEHAVIOR with server-side action -->

// input field with behavior <h:inputText value=“#{someValue}“>

// inject jsf.ajax.request/show suggestions <foo:suggest suggestions=“#{serverSuggestions}“ />

</h:inputText>Server-side Action

Page 31: JSF 2: Best Practices und Hidden Features

Behavior// BEHAVIOR with server-side action

// participate in request decodingpublic void decode(FacesContext context, UIComponent uiComponent) {

// create suggestion list via // behavior directly or via service or ... ...}

Server-side Action

Page 32: JSF 2: Best Practices und Hidden Features

Component

Page 33: JSF 2: Best Practices und Hidden Features

It‘s so easy, again!

Page 34: JSF 2: Best Practices und Hidden Features

Components<html xmlns=“http://www.w3.org/1999/xhtml“ xmlns:composite=“.../jsf/composite“ > <!--INTERFACE --> <composite:interface> ... </composite:interface>

<!--IMPLEMENTATION --> <composite:implementation> ... </composite:implementation></html>

Komponente liegt unter: ./resources/comp/util/myComp.xhtml

Comp Interface

Comp Implementation

Page 35: JSF 2: Best Practices und Hidden Features

Components<html xmlns=“http://www.w3.org/1999/xhtml“ ... xmnls:util= “http://java.sun.com/jsf/composite/ comp/util“ > ... <util:myComp ... /> ...

</html>

Komponente liegt unter: ./resources/comp/util/myComp.xhtml

Comp in Action

Page 36: JSF 2: Best Practices und Hidden Features

Components> XHTML plus> Interface & Implementation> Convention over Configuration> Convention over Code

> Pitfall „couldn‘t find ID“> Pitfall „couldn‘t find ACTION“> Pitfall „couldn‘t add VALIDATOR “> Pitfall „couldn‘t add CHILDS“> Pitfall „couldn‘t add I18N“

Page 37: JSF 2: Best Practices und Hidden Features

Components> XHTML plus> Interface & Implementation> Convention over Configuration> Convention over Code

> Pitfall „couldn‘t find ID“> Pitfall „couldn‘t find ACTION“> Pitfall „couldn‘t add VALIDATOR “> Pitfall „couldn‘t add CHILDS“> Pitfall „couldn‘t add I18N“

Page 38: JSF 2: Best Practices und Hidden Features

Components

Page 39: JSF 2: Best Practices und Hidden Features

Components

Page 40: JSF 2: Best Practices und Hidden Features

Components<html xmlns= ... > <!--INTERFACE --> <composite:interface> <composite:attribute name=“user“ /> <composite:attribute name=“userLabel“ /> <composite:attribute name=“pwdLabel“ /> <composite:attribute name=“loginBtnLabel“/> <composite:attribute name=“action“ method-signature=“java.lang.String action()“/> </composite:interface>

...

</html>

Page 41: JSF 2: Best Practices und Hidden Features

Components<html xmlns= ... > <!--INTERFACE --> <composite:interface> <composite:attribute name=“user“ /> <composite:attribute name=“userLabel“ /> <composite:attribute name=“pwdLabel“ /> <composite:attribute name=“loginBtnLabel“/> <composite:attribute name=“action“ method-signature=“java.lang.String action()“/> </composite:interface>

...

</html>Reserved Qualifier!

Page 42: JSF 2: Best Practices und Hidden Features

Components<html xmlns= ... > <!--INTERFACE --> <composite:interface> <composite:attribute name=“user“ /> <composite:attribute name=“userLabel“ /> <composite:attribute name=“pwdLabel“ /> <composite:attribute name=“loginBtnLabel“/> <composite:attribute name=“loginAction“ method-signature=“java.lang.String action()“/> </composite:interface>

...

</html>

Page 43: JSF 2: Best Practices und Hidden Features

Components<html xmlns= ... > ... <!--IMPLEMENTATION --> <composite:implementation> <h:form id=“form“> <h:panelGrid columns=“2“> #{cc.attrs.namePrompt} <h:inputText id=“name“ value=“#{cc.attrs.user.name}“/> ... </h:panelGrid> <h:commandButton id=“loginBtn“ value=“#{cc.attrs.loginBtnLabel}“ action=“#{cc.attrs.loginAction}“ /> </h:form> <p>Die Super-Login-Komponente von open knowledge</p> </composite:implementation/></html>

Page 44: JSF 2: Best Practices und Hidden Features

Components<html xmlns= ... > ... <!--IMPLEMENTATION --> <composite:implementation> <h:form id=“form“> <h:panelGrid columns=“2“> #{cc.attrs.namePrompt} <h:inputText id=“name“ value=“#{cc.attrs.user.name}“/> ... </h:panelGrid> <h:commandButton id=“loginBtn“ value=“#{cc.attrs.loginBtnLabel}“ action=“#{cc.attrs.loginAction}“ /> </h:form> <p>Die Super-Login-Komponente von open knowledge</p> </composite:implementation/></html>

Dependency to User

Page 45: JSF 2: Best Practices und Hidden Features

Components<html xmlns= ... > ... <!--IMPLEMENTATION --> <composite:implementation> <h:form id=“form“> <h:panelGrid columns=“2“> #{cc.attrs.namePrompt} <h:inputText id=“name“ value=“#{cc.attrs.user.name}“/> ... </h:panelGrid> <h:commandButton id=“loginBtn“ value=“#{cc.attrs.loginBtnLabel}“ action=“#{cc.attrs.loginAction}“ /> </h:form> <p>Die Super-Login-Komponente von open knowledge</p> </composite:implementation/></html>

Dependency to User

I18N

Page 46: JSF 2: Best Practices und Hidden Features

Components<html xmlns= ... > ... <!--IMPLEMENTATION --> <composite:implementation> <h:form id=“form“> <h:panelGrid columns=“2“> #{cc.attrs.namePrompt} <h:inputText id=“name“ value=“#{cc.attrs.user.name}“/> ... </h:panelGrid> <h:commandButton id=“loginBtn“ value=“#{cc.attrs.loginBtnLabel}“ action=“#{cc.attrs.loginAction}“ /> </h:form> <p>Die Super-Login-Komponente von open knowledge</p> </composite:implementation/></html>

Dependency to User

I18N

id=“form:name“

Page 47: JSF 2: Best Practices und Hidden Features

Components<html xmlns= ... > ... <!--IMPLEMENTATION --> <composite:implementation> <h:form id=“form“> <h:panelGrid columns=“2“> #{cc.attrs.namePrompt} <h:inputText id=“name“ value=“#{cc.attrs.user.name}“/> ... </h:panelGrid> <h:commandButton id=“loginBtn“ value=“#{cc.attrs.loginBtnLabel}“ action=“#{cc.attrs.loginAction}“ /> </h:form> <p>Die Super-Login-Komponente von open knowledge</p> </composite:implementation/></html>

Dependency to User

I18N

id=“form:name“

Child Tags, Facets,...?

Page 48: JSF 2: Best Practices und Hidden Features

Components<html xmlns= ... > <!--INTERFACE --> <composite:interface> <composite:attribute name=“user“ /> <composite:attribute name=“userName“ /> <composite:attribute name=“userPwd“ /> ...

</composite:interface>

...

</html>

Dependency to User

Page 49: JSF 2: Best Practices und Hidden Features

Components<html xmlns= ... > ... <!--IMPLEMENTATION --> <composite:implementation> <h:form id=“form“> ... </h:form>

<p>Die Super-Login-Komponente von open knowledge</p> <p>#{cc.resourceBundleMap.myFooterText}</p> </composite:implementation/></html>

I18N

Page 50: JSF 2: Best Practices und Hidden Features

Components<html xmlns= ... > ... <!--IMPLEMENTATION --> <composite:implementation> <h:form id=“form“> ... </h:form>

<p>Die Super-Login-Komponente von open knowledge</p> <p>#{cc.resourceBundleMap.myFooterText}</p> </composite:implementation/></html>

I18N

Page 51: JSF 2: Best Practices und Hidden Features

Components<html xmlns= ... > <!--INTERFACE --> <composite:interface>

<composite:attribute name=“userName“ /><composite:attribute name=“userPwd“ />

<composite:editableValueHolder name=“userName“ targets=“form:name“/> <composite:editableValueHolder name=“userPwd“ targets=“form:pwd“/> <composite:editableValueHolder name=“allFields“ targets=“form:name form:pwd“/> <composite:actionSource name=“loginButton“ targets=“form:loginBtn“/> ... </composite:interface> ...</html>

Expose Components

Page 52: JSF 2: Best Practices und Hidden Features

Components<html xmlns= ... > ... <!--IMPLEMENTATION --> <composite:implementation> <composite:renderFacet name=“header“ /> <h:form id=“form“> ... </h:form> <composite:insertChildren/> </composite:implementation/></html>

Child Tags

Facets

Page 53: JSF 2: Best Practices und Hidden Features

Bookmark

Page 54: JSF 2: Best Practices und Hidden Features
Page 55: JSF 2: Best Practices und Hidden Features

BookmarksJSF erlaubt „Bookmarking“, aber ...

> URLs scheinen hinterher zu hängen> URLs sind unschön> URLs implizieren i.d.R. einen State

Page 56: JSF 2: Best Practices und Hidden Features

Bookmarks

Page 57: JSF 2: Best Practices und Hidden Features

Bookmarks

Page 58: JSF 2: Best Practices und Hidden Features

Bookmarks

Page 59: JSF 2: Best Practices und Hidden Features

BookmarksJSF 1.x „Bookmarking“

> <h:outputLink> für GET> PhaseListener zur Manipulation> redirect um aus Post ein Get zu machen

Page 60: JSF 2: Best Practices und Hidden Features

BookmarksJSF 1.x „Bookmarking“

> <h:outputLink> für GET> PhaseListener zur Manipulation> redirect um aus Post ein Get zu machen

Page 61: JSF 2: Best Practices und Hidden Features

JSF 2.x „Bookmarking“

> <h:link> oder <h:button> für GET> <f:viewParam> zum Setzen von Params> <f:event type=“preRenderView“ zum Laden von benötigten Daten

Bookmarks

Page 62: JSF 2: Best Practices und Hidden Features

Bookmarks

<!-- ! Bookmarkable link for user, e.g.: ! <a href=“/context/user.xhtml?id=1234“>..</a>!-->!<h:link value=“Details von #{user.name}“! outcome="user">! <f:param name="id" value="#{user.id}" />!</h:link>!

Step 1: Create URL

userList.xhtml

Page 63: JSF 2: Best Practices und Hidden Features

Bookmarks<!-- ! Use bookmarkable link for user, e.g.: ! <a href=“/context/user.xhtml?id=1234“>..</a>!-->!<f:metadata>! <f:viewParam name="id" ! value="#{userManager.userId}" />! <f:event type="preRenderView" ! listener="#{userManager.loadUser}" />!</f:metadata>!<h:head>...</h:head>!<h:body>! ... <!-- display user details -->!</h:body>!

Step 2: Use URL

user.xhtml

Page 64: JSF 2: Best Practices und Hidden Features

Bookmarks<!-- ! Use bookmarkable link for user, e.g.: ! <a href=“/context/user.xhtml?id=1234“>..</a>!-->!<f:metadata>! <f:viewParam name="id" ! value="#{userManager.userId}" />! <f:viewAction action="#{userManager.loadUser}" />!!</f:metadata>!<h:head>...</h:head>!<h:body>! ... <!-- display user details -->!</h:body>!

Step 2: Use URL

ab JSF 2.2!

user.xhtml

Page 65: JSF 2: Best Practices und Hidden Features

Geht da noch mehr?

Page 66: JSF 2: Best Practices und Hidden Features

JSF 2.x URIs

> Ugly www.demo.de/faces/showCust?id=54

> Nice www.demo.de/customer/meier/hans

Bookmarks

Page 67: JSF 2: Best Practices und Hidden Features

JSF 2.x URIs

> WTH? www.demo.de/list?type=cust&f=a&t=d

> Ahh, alles klarwww.demo.de/customerlist/from/a/to/d

Bookmarks

Page 68: JSF 2: Best Practices und Hidden Features

JSF meets

PrettyFaces

Page 69: JSF 2: Best Practices und Hidden Features

Pretty Faces - URL Rewriting

> localhost:8080/faces/start.xhtml> localhost:8080/start

<url-mapping id="start“> <pattern value="/start" /> <view-id>/faces/start.xhtml</view-id></url-mapping>

Bookmarks

Page 70: JSF 2: Best Practices und Hidden Features

Pretty Faces - URL Rewriting

> .../faces/cust/d.xhtml?c=mobileLarson > .../customer/mobileLarson

<url-mapping id=“customerDetails“> <pattern value=“/customer/ #{name : custBean.username}" /> <view-id>/faces/cust/d.xhtml</view-id></url-mapping>

Bookmarks

Page 71: JSF 2: Best Practices und Hidden Features

Pretty Faces - URL Rewriting

> .../customer/mobileLarson

<url-mapping id=“customerDetails“> <pattern> ... </pattern> <view-id> ... </view-id> <action>#{custBean.loadCust}</action></url-mapping>

Bookmarks

Page 72: JSF 2: Best Practices und Hidden Features

Validation

Page 73: JSF 2: Best Practices und Hidden Features

Ready to use!

Page 74: JSF 2: Best Practices und Hidden Features

Validation

> Component Validation - check> Cross-Layer Validierung - kind of check> Cross-Component Validation - what?

Page 75: JSF 2: Best Practices und Hidden Features

Validation

> Component Validation - check> Cross-Layer Validierung - kind of check> Cross-Component Validation - what?

Page 76: JSF 2: Best Practices und Hidden Features

ValidationCross-Component Validation

> Validierung über mehrere Komponenten

> username != password> password == password repeat> password Validation wie in Klasse XYZ

Page 77: JSF 2: Best Practices und Hidden Features

ValidationCross-Component Validation

> Alternative A: externe Validation Lib, z.B. Apache MyFaces ExtVal

> Alternative B: Self-Made Validator inkl. Zugriff auf Komponente(n)

> Alternative C: JSF System Events, d.h. pre/postValidate Callbacks

Page 78: JSF 2: Best Practices und Hidden Features

Stuff

Page 79: JSF 2: Best Practices und Hidden Features

Stuff<!-- classic “debugging“ via ui:remove --><html><h:head /><h:body><h:form>   Text to display.   <ui:remove>Text to remove</ui:remove>   Text to display.</h:form></body></html>

Page 80: JSF 2: Best Practices und Hidden Features

Stuff<!-- classic “debugging“ via ui:debug --><html ... ><h:head> ... </h:head><body> ... <ui:debug hotkey="0" rendered= "#{initParam['javax.faces.PROJECT_STAGE'] eq 'Development'}" />

</body></html>

Page 81: JSF 2: Best Practices und Hidden Features

Stuff<!-- classic “debugging“ via ui:debug --><html ... ><h:head> ... </h:head><body> ... <ui:debug hotkey="0" rendered= "#{initParam['javax.faces.PROJECT_STAGE'] eq 'Development'}" />

</body></html>

Page 82: JSF 2: Best Practices und Hidden Features

Lars Röwekamp | CIO New Technologies | @mobileLarson

Hidden Features

Thankyou

Best

Pra

ctic

es