JSF 1.2
Tartalomjegyzék
rövidítések
-
PV -> Process Validation fázis
-
PV+ -> PV utáni process event fázis
-
AR -> Apply Request Values fázis
-
AR+ -> Apply Request Values utáni process event fázis
-
Au -> Application utility (általunk írt osztály mely a konkrét alkalmazáshoz kötődik)
-
Fu -> Faces utility (általunk írt osztály mely független az alkalmazástól, de a JSF technológiához kötődik)
adattípusok
-
A bean-ben lévő adattípusok nekik megfelelő UI-val, illetve nekik megfelelő converter-rel,
validator-ral (CV) használhatók.
-
Szöveg:
Bean: String típus javasolt.
UI: <h:inputText> vagy <h:inputTextarea>, de más UI is használható.
CV: <f:validateLength>, de működik az <f:validateLongRange>,
<f:validateDoubleRange> is
-
Egész szám:
Bean: Long, Integer javasolt a null értékek miatt. Ha biztos nincs null értéke akkor
jó lehet a primitív long vagy int is,
de akkor feltétlenül kell az UI required="true" attribútuma.
UI: <h:inputText>, de más UI is használható kivéve a <h:selectBooleanCheckbox> -ot.
CV: <f:validateLongRange>
-
Lebegőpontos szám:
Bean: Double javasolt a null érték miatt. Ha biztos nincs null értéke akkor jó lehet a primitív double is,
de akkor feltétlenül kell az UI required="true" attribútuma.
UI: <h:inputText>, de más UI is használható kivéve a <h:selectBooleanCheckbox> -ot.
CV: <f:validateDoubleRange>
-
Dátum:
Bean: java.util.Date
UI: <h:inputText>, de más UI is használható kivéve a <h:selectBooleanCheckbox> -ot.
CV: Kötelező az <f:convertDateTime> használata !
Az <f:convertDateTime> java.util.Date típusra konvertálja az adatot.
Például: <f:convertDateTime pattern="yyyy.MM.dd" />
esetén pontosan éjféli dátum áll elő.
-
Logikai:
Bean: boolean vagy Boolean
UI: <h:selectBooleanCheckbox>
-
Megjegyzés az <f:selectItems>-el feltölthető UI elemekhez, mint például: <h:selectOneRadio>,
<h:selectOneMenu>:
Úgy működnek mintha az <f:selectItems>-ben megadott objektumok string-re konvertálódnának,
így az UI úgy viselkedik mintha
egy <h:inputText> lenne a mezőbe beírható meghatározott string értékekkel.
Így <h:inputText>-ként is felfogható a működésük.
binding attribútum
-
Egy form-komponenshez lehetőség van csak "value", csak "binding", vagy mindkettő hozzárendelésére.
-
Amennyiben a form-komponens rendelkezik binding-gel, akkor a neki megfelelő UIViewRoot elem a bean-ben tárolódik,
így könnyebben elérhető.
-
<h:inputText value="#{bean.ev}" binding="#{bean.evInput}"> esetén az evInput típusa kötelezően UIInput
és természetesen ennek is biztosítani kell a getter és setter metódusát is.
bug
-
Reloading bug: akkor fordul elő amikor egy form űrlap invalid adatot tartalmaz,
és a submit gombra nem a felhasználó által gépelt adatok maradnak a mezőben, hanem a mező mögötti bean-ből
töltődnek vissza az adatok. Ilyen eset előfordul h:dataTable esetén, illetve
olyan mezőnél amiből kitöröltük a tartalmat.
h:dataTable esetén a hiba már javítva van a JSF2-es verzióban.
converter
-
Készíteni kell egy converter osztályt:
public class MyConverter implements Converter {
public Object getAsObject(FacesContext fc, UIComponent component, String value) {...}
public String getAsString(FacesContext fc, UIComponent component, Object object) {...}
}
-
A getAsObject() metódusnak a megfelelő java osztályt kell visszaadnia.
A value-ban kapjuk meg a formmező-ben lévő értéket, de a component által is hozzáférhetünk.
Ha a value-ban ""-t kapunk, akkor általában null-t kell visszaadnunk.
Konverziós hiba esetén hibát dobunk: throw new ConverterException(new FacesMessage(...))
-
Hivatkozás a faces-config.xml -ben (manuális módon):
<converter>
<converter-class>base.MyConverter</converter-class>
<converter-id>myc</converter-id>
</converter>
Ekkor nem rendelődik hozzá automatikusan a form-mezőhöz, hanem külön kell kérni:
<h:inputText ...>
<f:converter converterId="myc" />
</h:inputText>
vagy
<h:inputText ... converter="myc" />
-
Hivatkozás a faces-config.xml -ben (automatikus módon):
<converter>
<converter-class>base.MyConverter</converter-class>
<converter-for-class>java.awt.Color</converter-for-class>
</converter>
Ekkor azokhoz a form-mezőkhöz rendelődik hozzá automatikusan kérés nélkül,
amelyek mögött a bean-ben megfelelő típus áll (a példában: java.awt.Color típus)
életciklus
-
A PV fázisban lezajlik minden "nem immediate" mező conversion-je és a validation-je(ha a mező conversion-je sikeres)
-
Az AR fázisban lezajlik minden "immediate" mező conversion-je és validation-je(ha a mező conversion-je sikeres)
glassfish 2/3
-
Egy JSF-es alkalmazást fel lehet készíteni arra hogy a glassfish2-vel és a glassfish3-mal is működjön egyszerre.
Ehhez kell lennie egy sun-web.xml fájlnak (glassfish2 használja) és egy glassfish-web.xml
fájlnak (glassfish3 használja) is.
-
A sun-web.xml-nek ezt kell tartalmaznia:
-
A glassfish-web.xml-nek ezt kell tartalmaznia:
javascript használat
-
Egy 3 elemből álló rádiógombnál a 3. elemre (2-es indexű) így lehet rátenni a bejelölést:
document.getElementById("formID:radiogombID:2").checked = true;
message kezelés
-
Amennyiben a default angol nyelvű üzeneteket magyarítani szeretnénk, a jsf-impl.jar (jsf-api.jar) fájlban található
Messages.properties fájlról készítsünk egy másolatot messages_hu.properties névvel. Amennyiben többnyelvű lesz
a program akkor a nyelveknek megfelelően készítsük el a messages_xx.properties fájlokat, ahol xx a 2 karakteres
országkódot jelöli. Ezeket a fájlokat tegyük be a java források közé, példásul a "base" package-be.
Az utóbbi verziókban a Messages.properties fájl átkerült a jsf-api.jar fájlba.
Amit magyarítani kell benne a "javax.faces" kezdetű sorok.
-
Az elkészült új messages_xx.properties fájlokat regisztrálni kell a faces-config.xml -ben:
<application>
<message-bundle>base.messages</message-bundle>
<resource-bundle>
<base-name>base.messages</base-name>
<var>msg</var>
</resource-bundle>
</application>
A "resource-bundle" részt azért alkalmazzuk hogy ne kelljen minden jsp-lapon
f:loadBundle taggal elérni a message fájlokat.
-
Hivatkozás a JSP lapokon (pl. a magyar üzenet fájlra):
<f:view locale="hu">
...
<h:commandButton value="#{msg.login_submit}" />
Vagy pedig egy session-bean -ből jön a "locale" értéke,
így a user-ek külön-külön választhatnak nyelvi beállítást.
-
Üzenet felvétele programozottan a (magyar) properties fájlból:
ResourceBundle bundle = ResourceBundle.getBundle("base.messages", new Locale("hu"));
String messageText = bundle.getString("...");
navigation-handler használat
-
Az alkalmazásokban lehetőség van arra hogy felülírjuk a default navigációt, és a navigationhandler-ben
mondjuk ki a végső szót,
hová is navigáljunk. Megjegyzendő hogy a nem bejelentkezett user (vagy session timeout) esetén ne ezt a
módszert alkalmazzuk,
hanem inkább servlet filtert.
Működés: ha lehetséges egy formról az elnavigálás (mert pl. a valid-ok nem akadályozzák meg),
akkor a submit gombnak lefut az action-je,
és visszaadja hová szeretne navigálni (outcome). Ezután aktiválódik a saját navigationhandler-ünk amely még
módosíthat a navigáción, vagy változatlanul hagyja.
Egy példa a megvalósításra:
package base;
import javax.faces.application.*;
import javax.faces.context.*;
import javax.servlet.http.*;
public class MyNavigationHandler extends NavigationHandler {
// ====
private NavigationHandler base2;
// ====
public MyNavigationHandler(NavigationHandler base) {
super();
base2 = base;
}
// ====
public void handleNavigation(FacesContext fc, String actionMethod, String actionName) {
if (...) base2.handleNavigation(fc, actionMethod, actionName); // default navigáció
else base2.handleNavigation(fc, null, "mashova"); // navigáció mashova.jsp lapra
}
}
-
faces-config.xml bejegyzés:
<application>
<navigation-handler>base.MyNavigationHandler</navigation-handler>
</application>
-
Az az elem, melyre kattintva a popup funkció aktivizálható:
<h:outputLink value="#" onclick="ownPopup('form1:telepules')">
<h:graphicImage value="/image/list.gif" styleClass="border: 0px;" title="választás" />
</h:outputLink>
-
A javascript eljárás mely popup ablakot nyit, majd a rejtett formot(form2) meghívja hogy az a "popup"
nevű ablakba submit-áljon:
<script type="text/javascript">
function ownPopup(hivoMezoId) {
popup = window.open('','popup','height=400,width=400,toolbar=no,menubar=no,
scrollbars=yes,resizable=yes');
popup.focus();
document.getElementById('form2:hivoMezoId').value = hivoMezoId;
document.getElementById('form2:hivoMezoTartalom').value =
document.getElementById(hivoMezoId).value;
document.getElementById('form2:go').onclick();
}
</script>
-
A rejtett form(form2):
<h:form id="form2" target="popup">
<h:inputHidden id="hivoMezoId" value="#{bean.hivoMezoId}" />
<h:inputHidden id="hivoMezoTartalom" value="#{bean.hivoMezoTartalom}" />
<h:commandLink id="go" action="#{bean.telepulesQuery}" />
</h:form>
-
A meghívott JSP-lap (érték visszaadó rész):
<h:outputLink value="#" onclick="ownBack('#{bean.nev}'); return false;">
<h:outputText value="#{bean.nev}" />
</h:outputLink>
-
A meghívott JSP-lap (javascript rész):
<script type="text/javascript">
function ownBack(retval) {
<h:outputText
value="opener.document.getElementById('#{bean.hivoMezoId}').value = retval;" />
window.close();
}
</script>
-
Egy igen egyszerű megoldás, ahol a popup ablakban behívunk egy másik jsf lapot paraméter átadással:
problémák és megoldások
-
Probléma: Hogy lehet a JSF verziót lekérdezni ?
Megoldás: a jsf-api.jar vagy jsf-impl.jar fájl tartalmazza a MANIFEST.MF fájlt, abból lehet kiolvasni.
-
Probléma: Be lehetne állítani hogy a "required" jellemző a space-eket se engedje ?
Megoldás: nincs (de saját validátort írhatunk)
-
Probléma: Session bean-ek esetén (hosszabb folyamatoknál) a felhasználó többször rányomhat gombra/linkre,
így több pogramszál futhat
ugyanazon metóduson, konkurrensen írva a bean változóit ami problémához vezethet (JSF2-nél is létezik e probléma).
Megoldás1: az ilyen hosszan futó folyamatoknál lássuk el a metódust "synchronized" kulcsszóval,
így egyszerre egy szál hajthatja végre.
Megoldás2: ez egy globálisabb megoldás, így nem kell minden metódushoz synchronized-ot írni,
hanem csak a webalkalmazás
servlet filteréhez (ami mindig fut), és a chain.dofilter()-t szinkronizáljuk session-re.
Ez még annyiban is előnyösebb hogy nemcsak egy futó metódus van szinkronizálva,
hanem az egész jsp lap végrehajtása is.
HttpServletRequest request = (HttpServletRequest)req;
HttpSession session = request.getSession();
synchronized(session) {
chain.doFilter(req, res);
}
-
Probléma: A jsp lapokon lévő value expression többször meghívódik, pl. a rendered-nél használt kifejezés.
Megoldás: Ez nem lehet probléma ha nem ide teszünk be adatbázis parancsokat
(ellenben többször futhat egy lassú SELECT, vagy többször
történik INSERT az adatbázisba). Tehát megfelelően készítsük el a bean-t, gondoljunk ezen működésre !
-
Probléma: Session bean timeout. Ha a usernek nem kell login-álni (így sosincs átirányítás egy login lapra),
és a user egy lapon addig várakozik míg a session bean-jei lejárnak(timeout), majd ezután menne tovább másik lapra,
akkor nem kiszámítható a működés hiszen már nincsenek meg a session bean-ek.
Megoldás: Servlet filterben "filter-session-check" módszer alkalmazása:
if (request.getSession().getAttribute("filter-session-check") == null) {
request.getSession().setAttribute("filter-session-check", "x");
filterConfig.getServletContext().getRequestDispatcher("/index.html").forward(req, res);
// átirányítás index.html lapra
return;
}
-
Probléma: az alkalmazás nem a saját jsf library-t használja hanem a glassfish-ben lévőt.
Ez nem jó mivel más glassfish esetén máshogy fog működni.
Megoldás: a sun-web.xml fájlba ez kell:
UI komponens kezelés
-
UIview gyökérelem elérése:
UIViewRoot view = FacesContext.getCurrentInstance().getViewRoot();
-
form elemének elérése:
UIInput mezo = (UIInput)view.findComponent("formId:mezoId");
-
mező attribútum (pl. label) olvasása:
String ertek = mezo.getAttributes().get("label").toString();
-
mező valid-e:
mezo.isValid()
-
Csak valid mező esetén (pl. Integer típusnál) szabad a mező local értékét olvasni:
Integer ertek = (Integer)mezo.getLocalValue();
-
Csak invalid mező esetén szabad a mező submitted értékét olvasni:
String hibasErtek = mezo.getSubmittedValue();
validátor
-
Egy validátor nem fut ha a hozzátartozó converter getAsObject() metódusa null-t ad vissza
(tipikusan üres formmező esetén)
-
Validátor önálló osztályként:
public class MyValidator implements Validator {
public void validate(FacesContext context, UIComponent component, Object value) {...}
}
A value-ban kapjuk a converter által elkészített objektumot, de a component által is hozzáférhetünk.
Invalid adat esetén hibát dobunk: throw new ValidatorException(new FacesMessage(...))
A hozzátartozó faces-config.xml bejegyzés:
<validator>
<validator-id>myv</validator-id>
<validator-class>base.MyValidator</validator-class>
</validator>
Hivatkozás a formmező-ben:
<h:inputText ...>
<f:validator validatorId="myv" />
</h:inputText>
-
Validátor bean metódusként:
A bean-nek a következő metódust kell tartalmaznia:
public void myValidator(FacesContext fc, UIComponent component, Object value) {...}
Hivatkozás a formmező-ben:
<h:inputText validator="#{bean.myValidator}" ... />
-
Többmezős (form)validátor:
Valójában egy normál mező-validátor, de ő egy hidden mezőn van mely a form utolsó tagja
(ez biztosítja hogy utoljára fusson).
Fontos hogy a hidden mező value-ban valami legyen hogy fusson a validátor.
Ne felejtsük hogy az itt dobott ValidatorException a hidden mezőre vonatkozik, de meg kell jelennie a képernyőn.
A form mezőinek elérése view-kezeléssel lehetséges.
-
Egy mezőhöz rendelt több validátor:
A JSF mindegyiket lefuttatja (függetlenül attól hogy az egyik dob-e ValidatorException-t),
olyan sorrendben ahogy a JSP lapon definiáltuk őket.
A mezőhöz az első ValidatorException üzenet jelenik meg.
valueChangeListener attribútum
-
A form-komponens amelyhez a listenert rendeljük, általában a következő jellemzőkkel rendelkezik:
valueChangeListener="#{bean.vclMetodus}" onchange="submit()" immediate="true"
-
A bean metódusának egy ValueChangeEvent típusú paraméter kell:
public void vclMetodus(ValueChangeEvent event) {...}
-
A bean metódusa hozzáfér a form-komponens értékéhez: event.getNewValue()
és hozzáfér a többi form-komponenshez az UIViewRoot-on keresztül, sőt módosítani is tudja őket.
-
Ha egy "nem immediate" mezőhöz van valueChangeListener rendelve, az a PV+ fázisban fut le,
de pontosan csak akkor ha a mező valid.
-
Ha egy "immediate" mezőhöz van valueChangeListener rendelve, az AR+ fázisban fut le,
de pontosan csak akkor ha a mező valid.
-
Példa arra amikor egy valueChangeListener metódusban, átállítunk egy text mezőt, és egy checkboxot.
Fontos hogy ezt csak az UIViewRoot-on keresztül lehet megtenni.
UIViewRoot view = FacesContext.getCurrentInstance().getViewRoot();
UIInput textmezo = (UIInput)view.findComponent("form1:hatosag_telepules");
textmezo.setSubmittedValue("Szeged");
UISelectBoolean checkbox = (UISelectBoolean)view.findComponent("form1:illetekesseg");
checkbox.setSubmittedValue("false");
<f:facet>
-
Az <f:facet>...</f:facet> elemek között csak egy elem állhat. Ha több elem van
akkor csak az elsőt veszi figyelembe.
Ha mégis több elemet szeretnénk belerakni, akkor rakjuk őket egy szülőelembe pl: <h:panelGroup> -ba.
<f:validateLongRange>
-
Sajnos nem engedi meg a minimum, és maximum attribútumában hogy int-nél nagyobb értéket beírjunk,
pl. maximum="9999999999".
Ebben az esetben a bean-ben kell felvenni ezt a long értéket és a bean-re kell hivatkozni a minimim,
maximum attribútumban.
<f:verbatim>
-
Ennek az elemnek a használata nem javasolt, mivel a belsejében nem működik a <h:commandLink>
és <h:commandButton> !
<h:dataTable>
-
Az egész táblázatnak adhatunk header-t és footer-t, úgy hogy az <f:facet name="header">
és <f:facet name="footer">-t
nem a <h:column> elemen belülre, hanem kívülre tesszük.
<h:panelGroup>
-
Az elem nagyon jól használható arra hogy a JSP lapon egy nagyobb (sok elemből álló) részt elrejtsünk,
vagy összefogjunk egy elemnek:
Elrejtésnél ezt a nagyobb rész beletesszük egy <h:panelGroup rendered="false">...</h:panelGroup>
belsejébe.