Java Server Faces
comment1, http://bxcpsionm42.wikispaces.com/animal+girl+sex animal girl sex, jvw, http://ttgupdiyn96.wikispaces.com/analsex analsex, 8[[[, http://vkxzyhmqm79.wikispaces.com/aishwarya+rai+sex+clips aishwarya rai sex clips, :-), http://pjrthfhew15.wikispaces.com/amateur+housewife+sex+video amateur housewife sex video, eowqso, http://krgqifrbt03.wikispaces.com/adventure+sex adventure sex, rsiiux, http://zwgmjkvac23.wikispaces.com/alissa+milano+sex+video alissa milano sex video, 661466, http://ybydcvwaa22.wikispaces.com/adult+sex+toy+distributors+parties adult sex toy distributors parties, xyf,
Obsah
Popis, jak to funguje
MVC
JSF jsou silně založeny na konceptu MVC, i když se jedná pouze o prezentační vrstvu třívrstvé architektury.
- Model vrstva by měla být tvořena ideálně pomocí java beanů nesoucí data. V JEE 5 aplikaci se jedná např. o entitní beany.
- View vrstva používá RenderKit a JSP stránky. V JSP stránkách se vytvoří strom komponent z dvou knihoven JSF (Core a HTML RenderKit) a případných dalších komponenty 3. stran. Strom komponent je provázán na Model a Controller pomocí EL (Expression Language).
- Controller vrstva je tvořena pomocí tzv. Backing (Managed, jak se vám líbí) beans, což jsou obyčejné JavaBeans, které obstarávají přístup k Modelu a mají za úkol řídit běh aplikace. Tyto beany lze nahradit pomocí EJB 3.0, nicméně toto řešení přináší smíchání prezentační a aplikační vrstvy třívrstvé aplikace.
Model Vrstva
Model vrstva není přímo modelována pomocí JSF, ale velice často se přebírá z aplikace, kdy jsou entitní beany uloženy v Backing beanu a pomocí EL jsou v JSP vyzobávány do formuláře jednotlivá políčka. I v JSF existují ovšem třídy, které slouží jako proxy (wrappery) pro JSF komponentky.
- DataModel slouží pro operace nad tabulkovými daty, jeho potomci (ArrayDataModel, ListDataModel, ResultDataModel, ResultSetDataModel, ScalarDataModel) umožňují konkrétní adaptaci na aplikační data.
- SelectItem s potomkem SelectItemGroup slouží jako model pro UISelectMany a UISelectOne komponentky.
Controller Vrstva = Backing Bean
Backing bean, jak bylo již uvedeno, je obykle normální java bean. Tento bean zpracovává události, řídí běh prezentační vrstvy a interaguje s business vrstvou aplikace.
- Musí obsahovat bezparametrický konstruktor, aby jej mohlo JSF dynamicky za běhu instanciovat.
- Většinou obsahuje Gettery/Settery pro přístup k Modelu.
- Obsahuje validační metody.
- Obsahuje metody pro zpracování událostí.
- Protože se jedná o Controller obsahuje bezparametrické metody řídící běh aplikace, které vždy vrací akci (String) pro navigaci.
V deklarativní konfiguraci beanu v faces-config.xml můžeme nastavit scope beanu a dokonce i fiktivní atributy, které v definici třídy neexistují:
<managed-bean> <managed-bean-name>indexForm</managed-bean-name> <managed-bean-class>jsf.backingbean.IndexManagedBean</managed-bean-class> <managed-bean-scope>session</managed-bean-scope> <managed-property> <property-name>nonExistingProperty</property-name> <property-class>long</property-class> <value>0</value> </managed-property> </managed-bean>
V JSP se poté odkazujeme na bean pomocí EL (v rámci IndexManagedBean musí existovat metoda public String processSubmit()):
<h:form> <h:inputText value="#{indexForm.nonExistingProperty}" /> <h:commandButton action="#{indexForm.processSubmit}" /> </h:form>
View vrstva
View se skládá z UI komponent a JSP stránek, kde jsou jednotlivé komponenty seskládány do stromu, který je přístupný pomocí FacesContext.getCurrentInstance().getViewRoot(). Nicméně lze místo JSP použít i jiné technologie, které je ovšem třeba zvlášť deklarovat.
User Interface Components
JSF přináší základní sadů komponentek, které by měly pokrývat většinu potřeb formulářových aplikací.
- Komponenta jako taková je java třída rozšiřují UIComponent.
- K ní by měl existovat Renderer, který danou komponentu vykresluje. Každý Renderer vždy patří do nějakého RenderKitu. Lze ovšem i udělat vyjímky, kdy se vykresluje sám potomek UIComponent bez Rendereru. Jedna komponentka může mít dokonce více rendererů (např. UICommand má HTMLCommandLink a HTMLCommandButton).
- Aby se komponenta dala použít v JSP, jsou v JSF vytvořeny dva základní tagliby: JSF Core (prefix f:) a JSF HTML (prefix h:). Ty obsahují Tagy pro jednotlivé komponenty.
JSP
V rámci JSP se vkládají jednotlivé komponentky na stránku. Všechny komponentky na stránce musí být umístěny do <f:view> tagu. JSF HTML obsahuje všechny důležité komponentky pro formulářové aplikace, které jsou většinou poděděny z UIInput a UIOutput. Formulářové komponentky musí být uvnitř <f:form> tagu.
Existují dva používané způsoby, jak používat komponentky v aplikaci.
- Komponentka je pouze na stránce a pomocí EL se váže pouze Model:
private String ter; public void setter(String ter){this.ter = ter;} public String getter(String ter){this.ter = ter;}
Ter: <h:inputText value="#{mujBackingBean.ter}" />
- Komponentka je v Backing beanu a referencuje se z JSP:
private HTMLInputText inputText = new HTMLInputText(); public void setInputText(HTMLInputText inputText){this.inputText = inputText;} public String getInputText(HTMLInputText inputText){this.inputText = inputText;} private String ter; public void setter(String ter){this.ter = ter;} public String getter(String ter){this.ter = ter;}
Ter: <h:inputText value="#{mujBackingBean.ter}" binding="#{mujBackingBean.inputText}/>
Konfigurace JSF aplikace
Aby kontejner dokázal obsloužit JSF stránky, je třeba zadeklarovat ve web.xml FacesServlet
a namapovat jej na nějakou (jakoukoliv) URL:
<servlet> <display-name>FacesServlet</display-name> <servlet-name>FacesServlet</servlet-name> <servlet-class>javax.faces.webapp.FacesServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>FacesServlet</servlet-name> <url-pattern>*.jsf</url-pattern> </servlet-mapping>
Takže když příjde Request, webový kontejner spustí FacesServlet, který již sám řídí běh aplikace. Zde je vidno, že je možné používat zároveň JSF s dalšími technologiemi, protože JSF obsluhuje jen ta URL, na které je servlet namapován (v našem případě *.jsf, ale obecně to může být například /javaserverfaces/* či *.tatoStrankaJeObsluhovanaPomociJavaServerFacesHehe ;)).
Celá JSF aplikace se konfiguruje pomocí souboru /WEB-INF/faces-config.xml
.
//faces-config.xml <managed-bean> <description> The backing bean that backs up the guessNumber Web application </description> <managed-bean-name>UserNumberBean</managed-bean-name> <managed-bean-class>guessNumber.UserNumberBean</managed-bean-class> <managed-bean-scope>session</managed-bean-scope> <managed-property> <property-name>minimum</property-name> <property-class>long</property-class> <value>0</value> </managed-property> <managed-property> <property-name>maximum</property-name> <property-class>long</property-class> <value>10</value> </managed-property> </managed-bean>
Ve verzi JavaEE 5.0 (~JSF 1.2) byl sjednocen JSTL EL a JSF EL do jednoho Unified EL jazyka:
- výrazy
${neco}
označují výrazy pro čtení - výrazy
#{neco}
označují výrazy, které umožňují i zápis, volání metod a odložené vyhodnocování výrazů
K výše uvedenému managed JavaBeanu můžete tedy přistupovat např. pomocí
<%@ page contentType="text/html; charset=utf-8" %> <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> <body bgcolor="white"> <f:view> <h:form id="mujForm" > max: <h:outputText value="#{UserNumberBean.maximum}"/> <br> min: <h:outputText value="#{UserNumberBean.minimum}"/> <br> Novy max: <h:inputText id="newMax" value="#{UserNumberBean.maximum}" > </h:inputText><br> Novy min: <h:inputText id="newMin" value="#{UserNumberBean.minimum}" > </h:inputText><br> <h:commandButton id="submit" action="success" value="Submit" /> </h:form> </f:view> </body>
Data jsou ve dvou formách - ve tvaru pro model, např. integer, a ve tvaru pro prezentaci, typicky řetězce. JSF zajišťuje konverze mezi těmito dvěma tvary.
Navigace mezi stránkami se konfiguruje opět ve /WEB-INF/faces-config.xml
.
<navigation-rule> <from-view-id>/moje.jsp</from-view-id> <navigation-case> <from-outcome>dobre</from-outcome> <to-view-id>/dobre.jsp</to-view-id> </navigation-case> <navigation-case> <from-outcome>spatne</from-outcome> <to-view-id>/spatne.jsp</to-view-id> </navigation-case> </navigation-rule>
Ve stránce pak lze specifikovat, že výstup z akce poskytuje určité metoda:
<h:commandButton id="submit" action="#{mujManagedBean.jakDopadlo}" value="Submit" />
a metoda musí vracet jeden z očekávaných řetězců:
public String jakDopadlo() { if(...) return "dobre"; else return "spatne"; }
Životní cyklus stránky
Zpracování JSF stránky je komplikovanější než JSP stránky samotné. Viz obrázek.
Rozlišují se dva druhy volání:
- initial requests - při prvním zobrazené stránky, provádí se pouze restore view a render response fáze
- postbacks - uživatel odeslal formulář na stránce, aktivují se všechny fáze.
Životní cyklus řídí FacesServlet (normální Servlet, je třeba deklarovat v rámci web.xml), který provádí jednotlivé fáze:
- Restore View - obnoví (vytvoří) strom komponent
- Apply Request Values; process events - nastaví hodnoty z requestu jednotlivým komponentám ve stromu a zpracuje možné události
- Process Validation; process events - provede validaci stromu komponent a zpracuje možné události
- Update Model Values; process events - nastaví zvalidované hodnoty ze stromu komponent do Modelu a zpracuje možné události
- Invoke Application; process events - předání řízení Controlleru, tj. backing beanům a zpracuje možné události
- Render Response - vygeneruje strom komponent pomocí daného RenderKitu
Validace
Validace se provádějí ve fázi Process Validation (obr. JSF#.C5.BDivotn.C3.AD_cyklus_str.C3.A1nky). Po skončení fáze se testuje, zdali existují chyby. Pokud jakákoliv validace neprojde, pokračuje se fází Render Response a řízení se předává zpět webovému kontejneru.
Chyby (hlášky) je poté možné zobrazit pomocí
-
<h:message for="idNejakehoInputku" />
, který vypíše chyby přímo inputku s uvedeným ID - nebo je možné vypsat všechny zprávy pomocí
<h:messages />
Je třeba dát pozor na validaci povinnosti. Ta se definuje pomocí atributu required v rámci UIInput. Pokud tato validace neprojde, specifikuje se výstupní hláška pomocí property javax.faces.component.UIInput.REQUIRED v resource bundlu, který je deklarován ve faces-config.xml.
Pro validace lze obecně použít dvě cesty.
Validace metodou
Validace se provede pomocí metody v Backing beanu, kdy se komponentka implementující EditableValueHolder prováže přímo na speciální metodu Backing beanu.
Number: <h:inputText validator="#{mujBackingBean.validateNumber}" ...
// validation against 42! public void validateNumber(FacesContext context, UIComponent component, Object value) throws ValidatorException { if(!(value instanceof Integer)){ throw new ValidatorException(new FacesMessage("Wrong data type!")); } Integer val = (Integer) value; if(val.intValue() != 42){ ResourceBundle res = ResourceBundle.getBundle("jsf.resource.validation", FacesContext.getCurrentInstance().getViewRoot().getLocale()); FacesMessage message = new FacesMessage(res.getString("validation.numberNot42")); throw new ValidatorException(message); } }
Validace validátorem
JSF obsahuje několik vestavěných validátorů, které se nacházejí v JSF Core (prefix f:)
- LengthValidator - validuje délku Stringu v rámci UIInput,
- LongRangeValidator a DoubleRangeValidator - validují povolený rozsah Long či Double v rámci UIInput
Hlášky při špatné validaci se opět nastavují v ResourceBundle v rámci faces-config.xml, konkrétní názvy polí jsou v JavaDocu příslušné třídy.
Typické použití:
<h:inputText id="username" value="#{LoginBean.username}" required="true"> <f:validateLength maximum="15" minimum="3" /> </h:inputText>
JSF podporuje také vytvořit vlastní validátor. Tvorba ovšem podmiňuje všechny tyto kroky :( :
- Vytvořit Java třídu implementující rozhraní Validator
- Implementovat metodu
public void validate(FacesContext context, UIComponent component, java.lang.Object value) throws ValidatorException
, která při chybné validaci vyhodí vyjímku ValidatorException. - Definovat validátor a jeho položky ve faces-config.xml, např.
<validator> <validator-id>RegExpValidator</validator-id> <validator-class>jsf.validator.RegExpValidator</validator-class> <property> <property-name>regExp</property-name> <property-class>java.lang.String</property-class> </property> </validator>
- Vytvořit Tag pro validátor rozšiřující
ValidatorTag
private String regExp; public void setRegExp(String p){this.regExp = p;} public String getRegExp(){return this.regExp;} public RegExpValidatorTag(){ super(); super.setValidatorId("RegExpValidator"); // definovano ve faces-config.xml } protected Validator createValidator() throws JspException { RegExpValidator result = (RegExpValidator) super.createValidator(); result.setRegExp(regExp); return result; }
- Přidat Tag do nějakého našeho TLD (např. /WEB-INF/nase.tld)
<tag> <name>regExpValidator</name> <tag-class>jsf.tags.RegExpValidatorTag</tag-class> <body-content>empty</body-content> <display-name>regExpValidator</display-name> <description></description> <attribute> <name>regExp</name> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute> </tag>
- Použít validátor
<%@ taglib uri="/WEB-INF/neco.tld" prefix="neco" %> ... <h:inputText ... <neco:regExpValidator regExp=".+@.+\\..+" /> </h:inputText>
Konvertory
Konvertory slouží pro převod aplikačního Model objektu do Stringu pro použití View vrstvou a naopak. JSF obsahuje konvertory pro všechny primitivní typy.
Pokud chceme použít neprimitivní typ (nějaký náš Model bean) na stránce, který nelze jednoduše zabalit např. do SelectItem (viz JSF#Model_Vrstva), je třeba vytvořit vlastní konvertor. K tomu je třeba:
- Implementovat rozhraní Converter, v něm metody
public java.lang.Object getAsObject(javax.faces.context.FacesContext context, javax.faces.component.UIComponent component, java.lang.String value) public java.lang.String getAsString(javax.faces.context.FacesContext context, javax.faces.component.UIComponent component, java.lang.Object value)
- Zadeklarovat jej ve faces-config.xml
<converter> <converter-id>converterNasehoBeanu</converter-id> <converter-class>jsf.converters.ConverterNasehoBeanu</converter-class> </converter>
- Použít v JSP (2 způsoby)
<h:selectOneRadio converter="converterNasehoBeanu" value="#{mujBackingBean.vybranyNasBean}"> <f:selectItems value="#{mujBackingBean.seznamNasichBeanu}"/> </h:selectOneRadio>
<h:selectOneRadio value="#{mujBackingBean.vybranyNasBean}"> <f:selectItems value="#{mujBackingBean.seznamNasichBeanu}"/> <f:converter converterId="converterNasehoBeanu" /> </h:selectOneRadio>
Lokalizace
- JSF podporují lokalizaci a internacionalizaci pomocí <f:loadBundle /> tagu v rámci JSP
- a pomocí deklarace v faces-config.xml, kde se mimo nastavuje ResourceBundle pro JSF komponentky
V rámci JSP se používá:
<f:loadBundle basename="jsf.resource.Messages" var="bundle"/> ... <title><h:outputText value="#{bundle.welcome_title}" /></title>
nebo
<f:loadBundle basename="js.resource.Messages" var="bundle"/> ... <title>${bundle.welcome_title}</title>
Bohužel <f:loadBundle /> nepodporuje tečkovou notaci kvůli EL, takže nemůžeme použít například <h:outputText value="#{bundle.welcomeJSP.title}" />
Deklarace ve faces-config.xml:
<application> <locale-config> <default-locale>en</default-locale> <supported-locale>cs</supported-locale> </locale-config> <message-bundle>jsf.resource.FacesMessages</message-bundle> </application>
Běh
Jak již bylo několikrát zmíněno, běh a životní cyklus řídí FacesServlet
. Aby mohlo být předáno řízení FacesServletu, je třeba, aby příchozí request obsahoval URL, na které je FacesServlet namapován.
Pokud je výchozí JSP index.jsp, potom se používá např. tato konstrukce:
<!-- web.xml --> <welcome-file-list> <welcome-file>redirectToJSF.jsp</welcome-file> </welcome-file-list>
//redirectToJSF.jsp <% response.sendRedirect("index.jsf"); %>
Nyní již odchytí běh FacesServlet, který použije třídu Lifecycle pro spuštění životního cyklu request-response ([JSF#.C5.BDivotn.C3.AD_cyklus_str.C3.A1nky]]).
Implementace JSF
V současné době se používají dvě hlavní implementace JSF.
- RI (reference implementation) je od Sunu ve verzi 1.2
- MyFaces je taktéž již ve verzi 1.2
3rd party komponentky nad JSF
- MyFaces Tomahawk (běží i nad RI)
- Apache Trinidad - core pro ADF Faces od Oracle
- Rich Faces využívající Ajax4JSF
- Tobago
- ICEfaces
Frameworky pracující s JSF
Facelets
Pozn.: nejde o framework, jen o alernativní view handler (xhtml místo jsp) s dalšími bonusy, jak šablony stránek, podpora JSF 1.2 bez vyžadování JSP 2.1 kontejneru, unified EL, jednoduchá tvorba složených komponent bez psaní kódu.
Seam
- ONJava.com: JBoss Seam by Thomas Heute, 03/15/2006]
Podle všeho moc pěkný framework, který obohacuje prezenční vrstvu o celou řadu skvělých věcí, jako koncept konverzace (řada za sebou jdoucích a souvisejících requestů - snaží se řešit problém současného užití více oken prohlížeče). Silně inspiroval nové JSR 311 zv. Web Beans.
Od verze 2.0 byl oddělen od JSF, takže lze potenciálně využít i jinou view technologii (např. GWT, Google Web Toolkit).
- Je třeba opatrně využívat EJB jako Backing Bean - možnost míchání aplikační logiky s UI vrstvou.
JSF a AJAX
- Ajax4JSF - jednoduchá knihovna, která zapouzdřuje Ajax průhledně do JSF
JSF a Portlety (JSR 168)
Pro obě implementace existují předvytvořené portlety, které slouží jako proxy mezi Portlet Containerem a web Containerem. Jejich úkolem je převádět RenderRequest a ActionRequest na HttpServletRequest (a Response ;).
Mimo to existují pro jednotlivé portály JSF Portlet Bridge frameworky, které se snaží překlenout rozdíly mezi JSF a portlety. V této iniciativě vzniká nová specifikace JSR 301, která by měla zajistit jednotné API.
MyFaces
Obsahují třídu MyFacesGenericPortlet
, který slouží jako proxy.
How-To
Sun RI
Obsahují javaserverfaces_portlet.class
balík pro zprovoznění JSF v rámci portletů.
How-To
Budoucnost
- JSR 301 - Portlet Bridge Specification for JavaServer Faces
- JSF 2.0 Wiki, wishlist (JSR 314) JavaServer Faces 2.0
Zdroje
- JSR 127 JavaServer Faces
- JSR 252 JavaServer Faces 1.2
- JSR 314 JavaServer Faces 2.0
- JEE 5 tutorial
- Ed Burns blog