YOU ARE DOWNLOADING DOCUMENT

Please tick the box to continue:

Transcript
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


Related Documents