Tworzenie aplikacji J2EE w technologii JavaServer Faces

Transkrypt

Tworzenie aplikacji J2EE w technologii JavaServer Faces
229
Tworzenie aplikacji J2EE
w technologii JavaServer Faces
(JSF)
230
Plan prezentacji
• Wprowadzenie do JavaServer Faces (JSF)
• Podstawy JavaServer Faces
– Nawigacja, backing beans, język wyrażeń JSF
• Tworzenie aplikacji JSF w środowisku JDeveloper 10g
• Rozbudowa aplikacji JavaServer Faces
– Walidacja, konwersja, obsługa zdarzeń
– Wsparcie dla aplikacji wielojęzycznych
• Tworzenie aplikacji bazodanowych w JavaServer Faces
– Prezentowanie danych tabelarycznych
– Dostęp do wyników zapytań
• Podsumowanie
231
Wprowadzenie
232
Czym jest JavaServer Faces (JSF)?
• Wg firmy Sun: „server-side user interface
component framework for Java technology-based
web applications”
• Główne elementy technologii JSF to:
– API do reprezentowania komponentów interfejsu
użytkownika i zarządzania ich stanem, obsługi zdarzeń,
walidacji po stronie serwera, definiowania nawigacji
między stronami, wspierania aplikacji wielojęzycznych
– Dwie biblioteki znaczników dla JavaServer Pages (JSP)
• Do odwoływania się do komponentów interfejsu użytkownika ze
stron JSP
• Do wiązania komponentów z obiektami po stronie serwera
233
Historia JavaServer Faces
• Jedna z młodszych specyfikacji w ramach J2EE
• Opracowana w ramach Java Community Process jako JSR
127 (Java Specification Request) przez grupę ekspertów
wywodzących się z projektów:
– Jakarta Struts (w tym Craig McClanahan – twórca Struts)
– Oracle Application Server, Sun Java Studio, IBM WebSphere
Studio, ATG, ...
• Pierwsza wczesna wersja specyfikacji (JSF 1.0 EA) we
wrześniu 2002
• Ostateczna wersja 1.0 opublikowana w marcu 2004
– Wraz z nią referencyjna implementacja firmy Sun
– Aktualna wersja JSF 1.1 Maintainance Release
– Trwają prace nad JSF 1.2
Specyfikacja, implementacje
i biblioteki komponentów JSF
• Technologię JavaServer Faces definiuje specyfikacja firmy
Sun jako część J2EE
• Do tworzenia i uruchamiania aplikacji korzystających
opartych o technologię JSF konieczna jest implementacja
JSF
– JavaServer Faces RI (referencyjna implementacja Sun)
– Apache MyFaces (http://myfaces.apache.org)
• Dostępne biblioteki komponentów JSF:
– Dodatkowe komponenty MyFaces
– Oracle ADF Faces (podarowane Apache Software Foundation)
• Oracle wykorzystuje implementację firmy Sun (wersja 1.1
w JDeveloper 10.1.3), oferując swoją bibliotekę
komponentów ADF Faces
234
235
Nadzieje wiązane z JSF (1/2)
• Zalety platformy J2EE w porównaniu z .NET:
– Niezależność od konkretnego producenta
– Dostępność narzędzi i serwerów open source
• W zakresie wygody tworzenia oprogramowania
przewaga leżała dotychczas po stronie Microsoft
.NET
– Dopracowane środowisko RAD: Visual Studio
– Aplikacje internetowe tworzone w stylu bardzo
zbliżonym do tradycyjnych aplikacji (WebForms)
236
Nadzieje wiązane z JSF (2/2)
• Technologia JSF jest standardem, który
w połączeniu ze wspierającymi go środowiskami
IDE ma ułatwić i ustandaryzować tworzenie
interfejsu użytkownika w aplikacjach J2EE
– Koncepcja JSF zbliżona do WebForms w .NET
– JSF jako standard ma szanse na większe wsparcie przez
dostawców narzędzi programistycznych niż inne
proponowane szkielety aplikacji J2EE
• Popularne opinie o JSF:
– „rapid user-interface development brought to Java”
– „Swing for server-side applications”
– „combination of Swing and Struts”
JSF – Interfejs użytkownika po stronie
serwera
Browser
Web Container
HTTP request
page.jsp
renders HTML
jsfUI
HTTP response
• Interfejs użytkownika pracuje po stronie serwera i jest
„renderowany” jako HTML wysyłany klientowi
• Strona JSP odwołuje się do komponentów interfejsu
zaimplementowanych w JSF poprzez znaczniki
• Interfejs użytkownika zarządza komponentami
i związanymi z nimi walidatorami, konwerterami itp.
237
238
JSF jako implementacja idei MVC
• Głównym zadaniem JSF jest dostarczenie modelu
komponentów do tworzenia interfejsu użytkownika
(widoku)
– Komponenty konfigurowalne, rozszerzalne, stanowe i niezależne
od technologii prezentacji
– Gotowe komponenty + możliwość tworzenia własnych
– JSP jako podstawowe środowisko „renderowania”
komponentów JSF
• Każda implementacja JSF musi wspierać JSP
• JSF dostarcza implementację kontrolera w postaci
konfigurowalnego serwletu FacesServlet
• JSF nie wspiera tworzenia modelu. Udostępnia jedynie
mechanizmy wiążące obiekty modelu z pozostałymi
komponentami aplikacji
239
Komponenty JSF
• Podstawą specyfikacji JSF jest opis modelu komponentów
interfejsu użytkownika
– Zestaw standardowych, gotowych komponentów
– API (Application Programming Interface) do rozszerzania
standardowych komponentów i projektowania zupełnie nowych
• Przykłady standardowych komponentów:
– UIRoot – korzeń drzewa komponentów interfejsu
– UIForm – formularz do przesyłania danych do aplikacji
– Proste komponenty interjejsu np. UIInput, UICommand,
UISelectBoolean, ...
– Złożone komponenty interfejsu np. UIData - tabele
• Każdy komponent interfejsu użytkownika może być
uzupełniony o mechanizmy:
– Konwersji i walidacji
– Obsługi zdarzeń i błędów
240
Relacje JSF z JSP i Struts
• JSF nie wymaga JSP jako technologii widoku, ale JSP jest
domyślną technologią do renderowania komponentów JSF
– Każda implementacja JSF musi posiadać wsparcie dla JSP
– Definiowane przez specyfikację biblioteki znaczników JSF dla JSP
ułatwiają i standaryzują korzystanie z JSF w połączeniu z JSP
– Renderowanie komponentów JSF możliwe również np. w Velocity
– JSF zakłada wersję JSP 1.2, współpracuje z JSP 2.0, ale dopiero
przyszłe wersje JSF będą wykorzystywać możliwości JSP 2.0
• Funkcjonalność JSF pokrywa się ze Struts w zakresie
obsługi nawigacji i walidacji
– JSF uproszczone w porównaniu ze Struts
– JSF i Struts mogą (i zakłada się, że często będą!) współpracować
w ramach jednej aplikacji:
• JSF wykorzystane do komponentów interfejsu użytkownika
• Struts jako szkielet całej aplikacji do obsługi nawigacji
241
Porównanie JSF i Struts
• Inny cel, choć funkcjonalność się nakłada:
– Struts - Java web application framework
– JSF - user-interface framework for Java web applications
• Zalety JSF w porównaniu ze Struts:
–
–
–
–
–
Model komponentów interfejsu użytkownika
Prostszy kontroler i prostsza konfiguracja aplikacji
Lepszy, zwięzły język wyrażeń
Większa szansa na wsparcie ze strony narzędzi IDE
Wsparcie dla innych technologii prezentacji niż HTML (np. dla PDA)
• Wady JSF w porównaniu ze Struts
–
–
–
–
Słabsze standardowe komponenty walidujące
Brak aplikacji startowej (na wzór struts-blank)
Brak walidacji po stronie klienta (jak oparta o JavaScript w Struts)
Struts już ma dobrą pozycję na rynku, JSF dopiero „się przebija”
242
JSF w Oracle JDeveloper 10g
• Pełne wsparcie dla JSF w wersji
JDeveloper 10g 10.1.3:
–
–
–
–
Domyślnie implementacja Sun JavaServer Faces RI
Możliwość wykorzystania implementacji MyFaces
Biblioteka komponentów Oracle ADF Faces
Wizualny edytor nawigacji, wsparcie dla edycji i generacja plików
konfiguracyjnych, palety komponentów ze znacznikami JSF dla JSP
• W przypadku wersji JDeveloper 10g 10.1.2
i wcześniejszych konieczne ręczne dodanie wsparcia dla JSF
– Należy zarejestrować biblioteki JSF i znaczników JSF dla JSP oraz
dodać biblioteki znaczników do palety komponentów
– Wymagana „ręczna” konfiguracja plików web.xml
i faces-config.xml
– Brak wizualnych narzędzi do edycji reguł nawigacji aplikacji JSF
243
JSF w Eclipse
• Aby uzyskać wsparcie dla wizualnego
projektowania JSF na poziomie JDeveloper 10.1.3
należy zainstalować wtyczkę (plug-in) np.
Faces IDE
244
Podstawy JavaServer Faces
- nawigacja
- backing beans, managed beans
- język wyrażeń JSF
245
Przykładowa aplikacja
• Opis aplikacji:
– Aplikacja obejmuje 3 strony
– Pierwsza strona prezentuje formularz logowania
– Po weryfikacji nazwy użytkownika i hasła następuje przekierowanie
do strony informującej o sukcesie lub niepowodzeniu logowania
246
Przepływ sterowania w aplikacji JSF
1) Zbiór komponentów stanowiących interfejs jest
zaprezentowany użytkownikowi w postaci
formularza
2) Formularz wywołuje sam siebie
– Atrybut ACTION zawiera adres formularza
3) Tworzony jest Java Bean zawierający dane
z formularza (tzw. backing bean)
4) Wywoływana jest akcja związana
z zatwierdzeniem formularza
– Metoda akcji zwraca warunek
5) Prezentowana jest strona związana z warunkiem
Podstawowe kroki tworzenia
aplikacji JSF
1) Utworzenie stron z wykorzystaniem znaczników
odwołujących się do komponentów JSF
2) Zdefiniowanie nawigacji między stronami
w pliku konfiguracyjnym aplikacji
3) Implementacja komponentów Java Bean
reprezentujących dane z formularzy
(backing beans)
4) Zadeklarowanie backing beans
w pliku konfiguracyjnym aplikacji
UWAGA: Powyższe kroki mogą być realizowane
współbieżnie lub w dowolnej kolejności
247
248
Pliki konfiguracyjne aplikacji JSF
• web.xml (w katalogu WEB-INF/)
– Standardowy plik konfiguracyjny modułu webowego
aplikacji J2EE
– Zawiera deklarację serwletu kontrolera aplikacji
i mapowanie odpowiadającego mu wzorca adresu
• faces-config.xml (w katalogu WEB-INF/)
– Specyficzny plik konfiguracyjny aplikacji JSF
– Zawiera reguły nawigacji, deklaracje backing beans,
itd.
Deklaracja i mapowanie dla serwletu
kontrolera JSF
web.xml
<!DOCTYPE web-app PUBLIC ... >
<web-app>
...
<!--Faces Servlet -->
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1 </load-on-startup>
</servlet>
<!--Faces Servlet Mapping -->
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.faces</url-pattern>
</servlet-mapping>
</web-app>
•
Mapowanie rekomendowane przez specyfikację JSF:
–
•
<url-pattern>*.faces</url-pattern>
Alternatywne popularne mapowania:
–
–
<url-pattern>/faces/*</url-pattern>
<url-pattern>*.jsf</url-pattern>
(domyślny w JDeveloper)
249
Struktura kodu formularzy do
wprowadzania danych JSP/JSF
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<f:view>
znaczniki HTML
<h:form>
znaczniki HTML + znaczniki h: JSF (+ zagnieżdżone f:)
</h:form>
znaczniki HTML
</f:view>
Strona zawierająca znaczniki JSF jest reprezentowana
w postaci drzewa komponentów.
Korzeniem drzewa jest komponent UIViewRoot,
reprezentowany przez znacznik <f:view>.
Dlatego wszystkie znaczniki JSF użyte na stronie muszą
być zawarte wewnątrz elementu <f:view></f:view>.
<h:form> reprezentuje formularz HTML <FORM>.
ACTION automatycznie wskazuje na bieżącą stronę
(strona wywołuje sama siebie).
METHOD przyjmuje wartość POST (obowiązkowo).
Biblioteka znaczników JSF
reprezentujących znaczniki
HTML (w tym elementy
formularzy)
(zwyczajowy prefiks: h)
Biblioteka znaczników JSF
niezależnych od technologii
prezentacji (np. do walidacji,
obsługi zdarzeń, ...)
(zwyczajowy prefiks: f)
250
251
Formularz logowania
login.jsp
<%@ page contentType="text/html;charset=windows-1250"%>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<f:view>
<html>
<head>...<title>Logowanie</title></head>
<body><h:form>
<p>Użytkownik: <h:inputText value="#{loginBean.username}"
id="username"/>
<p>Hasło: <h:inputSecret value="#{loginBean.password}"
id="password"/>
<p><h:commandButton value="Zaloguj"
id="submitButton"
action="#{loginBean.register}"/>
</h:form></body>
</html>
</f:view>
•
Strona w pliku .jsp, uruchomienie poprzez
FacesServlet, URL zależy od mapowania w pliku
web.xml
252
Nawigacja statyczna
login.jsp
...
<h:commandButton value="Zaloguj"
id="submitButton"
action="success"/>
...
Nawigacja statyczna:
Wynik akcji zaszyty na stałe
w deklaracji przycisku
faces-config.xml
<navigation-rule>
<from-view-id>/login.jsp</from-view-id>
<navigation-case>
<from-outcome>success</from-outcome>
<to-view-id>/ok.jsp</to-view-id>
</navigation-case>
</navigation-rule>
Uwaga: Gdy cel nawigacji
zależy od wprowadzonych
danych, konieczna
nawigacja dynamiczna
253
Komponenty backing beans
• Komponenty backing beans definiują właściwości i metody
powiązane z komponentami interfejsu użytkownika
– Każda właściwość powiązania z wartością lub instancją komponentu
– Dodatkowo backing bean może zawierać metody:
• Do walidacji danych komponentu
• Do obsługi zdarzeń generowanych przez komponent
• Do przetwarzania związanego z nawigacją
• Ich klasy muszą spełniać reguły Java Beans:
– Bezargumentowy konstruktor
– Brak publicznych pól
– Dostęp do właściwości poprzez metody setXXX/getXXX:
• public
public
• public
public
String getName()
void setName(String n)
boolean isActive()
void setActive(boolean a)
254
Koncepcja managed beans
• JSF oferuje deklaratywny mechanizm tworzenia
komponentów JavaBean
– Backing beans – komponenty o zasięgu request,
związane z konkretną stroną
– Application logic beans – niepełniące roli backing beans,
zawierające kod i właściwości niezwiązane z konkretną stroną
• Komponenty skonfigurowane w pliku faces-config.xml
określane są jako managed beans
– Runtime JSF utworzy instancję na żądanie, gdy napotka wyrażenie
odwołujące się do komponentu
• Odwołania do managed beans z poziomu kodu strony JSF
realizowane są za pomocą języka wyrażeń JSF
255
Język wyrażeń JSF
• Język wyrażeń JSF (JSF Expression Language)
składniowo jest identyczny z JSP Expression Language
– Dostępnym od JSP 2.0
– Wykorzystywanym również przez JSTL
• Różnica polega na tym że w JSP/JSTL wyrażenia służą
jedynie do wyświetlania wartości, a w JSF do
wyświetlania i ustawiania właściwości
– JSP EL wywołuje tylko metody getXXX
– JSF EL wywołuje metody getXXX i setXXX
• Powyższa różnica jest powodem innej notacji
w JSF (#{...}) niż w JSP i JSTL (${...})
• Uwagi:
– Używany tylko w atrybutach znaczników JSF
– Dostęp do managed beans i zasięgów request, session, application
Backing bean dla formularza logowania
(1/2)
256
Login.java
package view.backing;
public class Login {
private String username;
private String password;
public
public
public
public
Definicja klasy
komponentu
void setUsername(String t) { this.username = t; }
String getUsername()
{ return username; }
void setPassword(String t) { this.password = t; }
String getPassword()
{ return password; }
}
faces-config.xml
Deklaracja komponentu (dzięki niej implementacja JSF sama
utworzy instancję komponentu gdy będzie potrzebna managed bean)
<faces-config ...>
...
<managed-bean>
<managed-bean-name>loginBean</managed-bean-name>
<managed-bean-class>view.backing.Login</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
</faces-config>
Backing bean dla formularza logowania
(2/2)
257
login.jsp
<%@ page contentType="text/html;charset=windows-1250"%>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<f:view>
<html>
<head>...<title>Logowanie</title></head>
<body><h:form>
<p>Użytkownik: <h:inputText value="#{loginBean.username}"
id="username"/>
<p>Hasło: <h:inputSecret value="#{loginBean.password}"
id="password"/>
...
</h:form></body>
</html>
Po zatwierdzeniu formularza i wysłaniu wprowadzonych danych
</f:view>
do serwera, zostaną one automatycznie umieszczone we wskazanych
właściwościach wskazanego komponentu
Do wiązania komponentów interfejsu użytkownika z właściwościami
komponentu backing bean wykorzystany język wyrażeń JSF (#{...})
Sposoby wiązania backing beans
z komponentami interfejsu
258
• Backing bean to komponent Java Bean, powiązany
z komponentami interfejsu używanymi na stronie
• Każda z właściwości komponentu backing bean powiązana
jest z wartością lub instancją komponentu
• Powiązanie właściwości z wartością komponentu:
– np. <h:inputText id="uName" value="#{UserBean.userName}" />
(właściwość typu String, Integer, int, double, ...)
– Zalecane w większości sytuacji
• Automatyczne konwersje typów danych
• Komponent backing bean nie odwołuje się do JSF API
• Powiązanie właściwości z instancją komponentu:
– np. <h:inputText binding="#{UserBean.userNameComponent}" />
(właściwość typu UIInput)
– Wymagane gdy istnieje potrzeba programowego modyfikowania
właściwości komponentu
– Wykorzystywane przez kreator w JDeveloperze
259
Przekazywanie wartości między
stronami poprzez backing beans
ok.jsp
<%@ page contentType="text/html;charset=windows-1250"%>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<f:view>
<html>
<head><title>Ok</title></head>
<body><h:form>
<p>Witaj <h:outputText value="#{loginBean.username}"/>!
<p>Twoje hasło to: <h:outputText value="#{loginBean.password}"/>.
</h:form></body>
</html>
</f:view>
Dostęp do właściwości komponentu
backing bean
za pomocą znacznika h:outputText
260
Nawigacja dynamiczna (1/2)
login.jsp
success
ok.jsp
marek
***
failure
error.jsp
login.jsp
<h:commandButton value="Zaloguj"
id="submitButton„
action="#{loginBean.register}"/>
Login.java
public class Login {
private String username;
private String password;
...
public String register() {
if (username.equals(password))
return "success";
else
return "failure";
}
}
Wynik akcji zwracany przez
metodę (właściwość)
komponentu backing bean
261
Nawigacja dynamiczna (2/2)
faces-config.xml
...
<navigation-rule>
<from-view-id>/login.jsp</from-view-id>
<navigation-case>
<from-outcome>success</from-outcome>
<to-view-id>/ok.jsp</to-view-id>
</navigation-case>
<navigation-case>
<from-outcome>failure</from-outcome>
<to-view-id>/error.jsp</to-view-id>
</navigation-case>
</navigation-rule>
...
Jeśli metoda akcji zwróci wartość nieuwzględnioną w regule
nawigacji, nastąpi ponowne wywołanie bieżącej strony
262
Tworzenie aplikacji JSF
w środowisku JDeveloper 10g (10.1.3)
263
Wsparcie JSF w JDeveloper 10.1.3
• Kompletny zbiór standardowych komponentów JSF
• Biblioteka komponentów ADF Faces
• Zintegrowane środowisko wizualnego tworzenia aplikacji:
– Wizualna edycja nawigacji między stronami
– Paleta właściwości do przeglądania i edycji właściwości
komponentów na stronie
– Automatyczne definiowanie backing beans
– Okna dialogowe wspierające tworzenie powiązań w JSF EL
– Wizualna edycja pliku faces-config.xml
264
Tworzenie nowej aplikacji
Tu można wybrać szablon
uwzględniający JSF, wtedy
projekty dla modelu i widoku
oraz plik faces-config.xml
w projekcie widoku zostaną
utworzone automatycznie
Utworzenie pliku konfiguracyjnego
aplikacji JSF
265
Wybór wersji
specyfikacji
serwletów / JSP
Wraz z plikiem faces-config.xml
tworzona jest cała struktura
aplikacji webowej J2EE
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>/faces/*</url-pattern>
</servlet-mapping>
266
Wizualny edytor nawigacji
• Umożliwia:
– Graficzną edycję reguł nawigacji na diagramie
– Dodawanie nowych stron do diagramu
• Tworzenie nowych z palety komponentów
• Dodawanie wcześniej utworzonych stron JSP/JSF z nawigatora
obiektów (drag & drop)
267
Tworzenie nowej strony
Dwuklik
na ikonie
Utworzenie nowego,
automatycznie zarządzanego
komponentu backing bean,
z którego właściwościami będą
wiązane komponenty interfejsu
na stronie (opcjonalnie)
268
Tworzenie nowej strony – efekt (1/2)
login.jsp
<%@ page contentType="text/html;charset=windows-1250"%>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<f:view>
<html>
<head>
<meta http-equiv="Content-Type" content="..."/> <title>login</title>
</head>
<body><h:form binding="#{loginBean.form1}" id="form1"></h:form></body>
</html>
</f:view>
<%-- oracle-jdev-comment:auto-binding-backing-bean-name:loginBean--%>
269
Tworzenie nowej strony – efekt (2/2)
Login.java
package mypackage.backing;
import javax.faces.component.html.HtmlForm;
public class Login {
private HtmlForm form1;
public void setForm1(HtmlForm form1) {
this.form1 = form1;
}
public HtmlForm getForm1() {
return form1;
}
}
faces-config.xml
<faces-config xmlns="http://java.sun.com/JSF/Configuration">
<managed-bean>
<managed-bean-name>loginBean</managed-bean-name>
<managed-bean-class>mypackage.backing.Login</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
<!--oracle-jdev-comment:managed-bean-jsp-link:1login.jsp-->
</managed-bean>
</faces-config>
270
Wizualna edycja formularza JSP/JSF
• Edycja strony (drag & drop)
– Elementy formularza z palety JSF HTML
– Można do dekoracji wykorzystywać elementy HTML Common
(np. tabelka)
– Źródło strony i klasa backing bean (!) uaktualniane na bieżąco
Zmiana etykiety przycisku
w kodzie lub w palecie
właściwości (value)
Wizualna edycja formularza JSP/JSF –
wynikowa klasa
package mypackage.backing;
import
import
import
import
Login.java
javax.faces.component.html.HtmlCommandButton;
javax.faces.component.html.HtmlForm;
javax.faces.component.html.HtmlInputSecret;
javax.faces.component.html.HtmlInputText;
JDeveloper generuje klasę
public class Login {
private HtmlForm form1;
private HtmlInputText inputText1;
private HtmlInputSecret inputSecret1;
private HtmlCommandButton commandButton1;
backing bean z właściwościami
odpowiadającymi instancjom
komponentów a nie ich
wartościom! (elastyczniejsze
z dwóch możliwych rozwiązań)
public void setForm1(HtmlForm form1) { this.form1 = form1; }
public HtmlForm getForm1()
{ return form1; }
public void setInputText1(HtmlInputText inputText1) {
this.inputText1 = inputText1; }
public HtmlInputText getInputText1() { return inputText1; }
public void setInputSecret1(HtmlInputSecret inputSecret1) {
this.inputSecret1 = inputSecret1; }
public HtmlInputSecret getInputSecret1() { return inputSecret1; }
public void setCommandButton1(HtmlCommandButton commandButton1) {
this.commandButton1 = commandButton1; }
public HtmlCommandButton getCommandButton1() { return commandButton1; }
}
271
Wizualna edycja formularza JSP/JSF –
wynikowa strona JSP
login.jsp
<f:view>
<body>
<h:form binding="#{loginBean.form1}" id="form1">
<!– Pominięte znaczniki definiujące tabelkę HTML -->
Użytkownik:
<h:inputText binding="#{loginBean.inputText1}" id="inputText1"/>
Hasło:
<h:inputSecret binding="#{loginBean.inputSecret1}"
id="inputSecret1"/>
<h:commandButton value="Zaloguj"
binding="#{loginBean.commandButton1}"
id="commandButton1"/>
</h:form>
</body>
</f:view>
Powiązanie z instancją komponentu, a nie z wartością,
a więc poprzez atrybut binding, a nie value!
272
273
Wizualna edycja reguł nawigacji
Pierwsza strzałka
domyślnie dostaje
etykietę „success”
(etykiety można
zmienić na diagramie)
faces-config.xml
<navigation-rule>
<from-view-id>/login.jsp</from-view-id>
<navigation-case>
<from-outcome>success</from-outcome>
<to-view-id>/ok.jsp</to-view-id>
</navigation-case>
<navigation-case>
<from-outcome>failure</from-outcome>
<to-view-id>/error.jsp</to-view-id>
</navigation-case>
</navigation-rule>
274
Utworzenie metody akcji
Login.java
...
public String commandButton1_action() {
// Add event code here...
return null;
}
...
Dwuklik
na przycisku
Ręczna edycja
...
public String commandButton1_action() {
String user = (String) inputText1.getValue();
String pass = (String) inputSecret1.getValue();
if (user.equals(pass))
return "success";
else
return "failure";
}
...
275
Dostęp do danych przekazanych poprzez
backing beans (1/2)
Dwuklik na ikonie
Strona nie służy do wprowadzania
danych, więc można nie
deklarować dla niej komponentu
backing bean
Do wyświetlenia danych
przekazanych przez backing bean
służy element h:outputText
Powiązanie outputText
z właściwością backing bean
za pomocą palety właściwości
276
Dostęp do danych przekazanych poprzez
backing beans (2/2)
Wprowadzenie wartości #{
uaktywnia przycisk wywołujący
okno dialogowe pozwalający
na powiązanie z właściwością
komponentu backing bean
(lub innego dostępnego obiektu
np. powiązań z modelem)
277
Gotowa aplikacja
marek/marek
marek/xxx
278
Rozbudowa aplikacji
JavaServer Faces
- walidacja
- konwersja
- obsługa zdarzeń
- wsparcie dla aplikacji wielojęzycznych
- ukrycie źródeł JSP przed dostępem
Walidacja danych w aplikacjach
webowych
• Typowe cele walidacji w aplikacjach webowych:
– Sprawdzenie czy zostały wprowadzone wartości do
wszystkich wymaganych pól formularza i czy format
wartości jest odpowiedni
– Ponowne wyświetlenie formularza w przypadku błędów
• Z komunikatami o błędach
• Z zachowaniem poprawnych wartości
279
280
Walidacja danych w aplikacjach JSF
• Walidacja ręczna
– Walidacja w metodach setXXX i/lub metodzie akcji
– Metoda akcji zwraca null by wymusić ponowne wyświetlenie formularza
• Niejawna walidacja automatyczna
–
–
–
–
Użycie atrybutu required
Właściwości backing beans typów prostych
System wyświetla formularz ponownie gdy błąd konwersji
Wyświetlanie komunikatów o błędach: h:message
• Jawna walidacja automatyczna
– Użycie predefiniowanych walidatorów:
• f:validateLength,
• f:validateDoubleRange, f:validateLongRange
– System wyświetla formularz ponownie gdy błąd walidacji
– Wyświetlanie komunikatów o błędach: h:message
• Walidatory aplikacji (custom validators)
– Implementują interfejs Validator
– Rejestrowane w faces-config.xml
281
Przykłady walidacji w JSF (1/2)
• Obowiązkowa nazwa użytkownika:
– Ustawienie atrybutu required
– Dodanie elementu h:message i powiązanie go z polem formularza
<h:inputText
binding="#{loginBean.inputText1}"
id="inputText1" required="true"/>
<h:message for="inputText1"
binding="#{loginBean.message1}" id="message1"/>
282
Przykłady walidacji w JSF (2/2)
• Hasło od 4 do 6 znaków:
– Dodanie walidatora f:validateLength i ustawienie jego właściwości
– Dodanie elementu h:message i powiązanie go z polem formularza
<h:inputSecret
binding="#{loginBean.inputSecret1}"
id="inputSecret1">
<f:validateLength maximum="6" minimum="4"/>
</h:inputSecret>
<h:message for="inputSecret1"
binding="#{loginBean.message2}"
id="message2"/>
283
Konwertery
• Konwertery są używane gdy:
– Wymagana jest inna konwersja niż standardowa dokonywana
automatycznie (do typów takich jak int, float, Integer, Boolean, ...)
– Wymagane jest zaawansowane formatowanie (liczb, dat)
• Konwersja a walidacja
– Konwerter może służyć do walidacji – generuje wyjątek i tworzy
komunikat o błędzie gdy konwersja się nie powiedzie
– Konwerter również zmienia format wyświetlania, a nie tylko konwertuje
wprowadzane dane
– Walidatory mogą być używane tylko z komponentami do wprowadzania
danych, a konwertery również z h:outputText
• Standardowe konwertery:
– f:convertNumber, f:convertDateTime
• Niestandardowe konwertery tworzy się implementując interfejs
Converter
<h:outputText value="#{user.lastLogin}">
<f:convertDateTime dateStyle="full" />
</h:outputText>
<h:outputText value="#{user.lastLogin}">
<f:convertDateTime
pattern="EEEEEEEE, MMM dd, yyyy" />
</h:outputText>>
Warunkowe renderowanie
i aktywacja komponentów
• Poprzez zmianę wartości atrybutu rendered można
spowodować, że komponent nie będzie wyświetlany
(domyślnie true)
<h:commandButton value="Zaloguj"
binding="#{loginBean.commandButton1}"
action="#{loginBean.commandButton1_action}"
rendered="false"/>
• Poprzez zmianę wartości atrybutu disabled można
spowodować, że komponent nie będzie aktywny
(domyślnie false)
<h:commandButton value="Zaloguj"
binding="#{loginBean.commandButton1}"
action="#{loginBean.commandButton1_action}"
disabled="true"/>
Możliwe odwołanie do metody backing bean: #{}
284
285
Obsługa zdarzeń w aplikacji JSF
• Zdarzenia zachodzące w aplikacji JSF można podzielić na
dwie kategorie:
– Zdarzenia inicjujące przetwarzanie po stronie logiki biznesowej
– Zdarzenia wpływające jedynie na interfejs użytkownika
• Kategorie „procedur” obsługi zdarzeń w JSF:
– Action controllers (metody akcji)
• Uruchamiane po wypełnieniu komponentu backing bean danymi
i po walidacji
• Zwracają wartości decydujące o nawigacji
– Event listeners
• Często uruchamiane przed wypełnieniem komponentu backing bean
danymi i z pominięciem walidacji
• Nie wpływają bezpośrednio na nawigację
286
Rodzaje Event Listeners
• ActionListener
– Wywoływany przez przyciski, mapy obrazkowe
i linki z kodem JavaScript
– Elementy te automatycznie zatwierdzają formularz
• ValueChangeListener
– Wywoływany przez listy rozwijane, pola wyboru, grupy
radiowe, pola tekstowe, itp.
– Elementy te automatycznie nie zatwierdzają formularza
• Konieczne wymuszenie zatwierdzenia formularza poprzez kod
JavaScript: submit() w onchange lub onclick
287
ActionListener - Przykład
<h:commandButton
actionListener= "#{bean.sideEffect}"
immediate="true" />
Metoda obsługująca zdarzenie
zwyczajowo w klasie
komponentu backing bean
Przypomnienie:
Dla zdarzeń powodujących
nawigację: atrybut action
public void sideEffect(ActionEvent event) {
// np. aktywacja/deaktywacja innych
// elementów formularza
}
Umożliwia obsługę zdarzeń przed
walidacją innych komponentów
Metoda w klasie komponentu
backing bean, zwracająca void
288
ValueChangeListener – Przykład (1/2)
• Pole wyboru uaktywniające przycisk zatwierdzający
formularz logowania
disabled= ”true”
Wpisanie w palecie właściwości nazwy
metody powoduje utworzenie szkieletu
metody w klasie backing bean
public void checkbox1Changed(ValueChangeEvent valueChangeEvent) {
// Add event code here...
if (selectBooleanCheckbox1.isSelected())
commandButton1.setDisabled(false);
else
commandButton1.setDisabled(true);
}
289
ValueChangeListener – Przykład (2/2)
<h:selectBooleanCheckbox
binding="#{loginBean.selectBooleanCheckbox1}"
id="selectBooleanCheckbox1"
valueChangeListener="#{loginBean.checkbox1Changed}"
onchange="submit()"/>
Wymagany JavaScript, aby zmiana stanu
pola wyboru zatwierdzała formularz
(należy wpisać ręcznie lub przez paletę)
Problem: Po zmianie stanu pola wyboru
„budzi się” walidacja pól tekstowych!
• Rozwiązanie problemu „niechcianej” walidacji:
– Dodanie immediate="true" w elemencie pola wyboru (domyślnie jest false),
aby obsługa zdarzenia miała miejsce przed walidacją
– Dodanie poniższego kodu na końcu metody obsługi zdarzenia:
FacesContext context = FacesContext.getCurrentInstance();
context.renderResponse(); // skraca normalne przetwarzanie
UWAGA: W niektórych wersjach Internet Explorer, zdarzenie onchange wystąpi dopiero gdy
focus znajdzie się na innym elemencie (jest to raczej bug...). Rozwiązaniem jest onclick
290
Nawigacja za pomocą linków
• Nawigacja następuje w wyniku zwrócenia konkretnej
etykiety przez metodę akcji
• Akcję nawigacyjną oprócz przycisków mogą wywoływać
również linki
– Tworzone za pomocą znacznika h:commandLink
– Renderowane z wykorzystaniem kodu JavaScript, zatwierdzającego
formularz (JavaScript w przeglądarce musi być włączony!)
error.jsp
<h:form>
<h:commandButton value="Powrót"
action="success"/>
<h:commandLink action="success">
<h:outputText value="Powrót"/>
</h:commandLink>
</h:form>
291
Backing beans o zasięgu sesji
• Backing beans najczęściej mają zasięg obsługi żądania (request)
• Można zwiększyć ich czas życia do zasięgu sesji (session) lub aplikacji
(application), jeśli mają służyć do przechowywania danych między
kolejnymi żądaniami
loginBean
scope=request
loginBean
scope=session
<managed-bean>
faces-config.xml
<managed-bean-name>loginBean</managed-bean-name>
<managed-bean-class>mypackage.backing.Login</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
292
Pliki .properties w JSF
• Plik .properties to tekstowy plik zawierający pary
klucz=wartość
• Aplikacja JSF może pobierać teksty do wyświetlenia
z plików .properties (Resource Bundles)
• Pliki .properties umieszczane są tam gdzie klasy
(WEB-INF/classes)
• Do ładowania plików .properties służy znacznik
f:loadBundle wskazujący:
– Nazwę pliku (bez rozszerzenia, z prefiksem pakietu)
– Nazwę zmiennej (typu Map) do przechowania odczytanych danych
<f:loadBundle basename="komunikaty" var="kom"/>
#{kom.klucz}
293
Plik .properties - Przykład
New->Simple files->File
komunikaty.properties
sorryPrompt=Sorry
backLabel=Back
error.jsp
<f:view>
<f:loadBundle basename="komunikaty" var="kom"/>
...
<h:outputText value="#{kom.sorryPrompt}"/>
<h:outputText value="#{loginBean.inputText1.value}"/>...
<h:form>
<h:commandButton value="#{kom.backLabel}"
action="success"/>
<h:commandLink action="success">
<h:outputText value="#{kom.backLabel}"/>
</h:commandLink>
</h:form>
...
</f:view>
294
Internacjonalizacja aplikacji
• Należy przygotować zestaw plików .properties dla
poszczególnych języków (różniących się kodem
lokalizacji w przyrostku nazwy):
– komunikaty.properties, komunikaty_pl.properties, ...
• W znaczniku f:view należy umieścić atrybut
locale
– Może to nie być konieczne (serwer może ustawić sam)
– Wartość locale wyznaczoną przez ustawienia
przeglądarki użytkownika można odczytać
z FacesContext
– Odczyt pliku i wyświetlanie komunikatów bez zmian!
295
Internacjonalizacja aplikacji - Przykład
komunikaty.properties
komunikaty_pl.properties
sorryPrompt=Sorry
backLabel=Back
sorryPrompt=Przykro nam
backLabel=Powrót
UWAGA: Polskie
znaki (poza „ó”)
w kostaci kodów
Unicode (\uXXXX)
error.jsp
<f:view
locale="#{facesContext.externalContext.request.locale}">
<f:loadBundle basename="komunikaty" var="kom"/>
...
<h:outputText value="#{kom.sorryPrompt}"/>
<h:outputText value="#{loginBean.inputText1.value}"/>...
<h:form>
<h:commandButton value="#{kom.backLabel}"
action="success"/>
<h:commandLink action="success">
<h:outputText value="#{kom.backLabel}"/>
</h:commandLink>
</h:form>
...
</f:view>
296
Podmiana i internacjonalizacja komunikatów ze
standardowych walidatorów (1/2)
• Należy wykonać dwa kroki:
– Przygotować pliki .properties dla poszczególnych
języków zawierające nowe komunikaty przypisane do
predefiniowanych kluczy
– Wskazać przygotowane pliki jako message bundle
zawierający dostosowane komunikaty w konfiguracji
aplikacji (faces-config.xml)
komunikaty_pl.properties
javax.faces.component.UIInput.REQUIRED=Pole jest wymagane!
javax.faces.validator.LengthValidator.MINIMUM=Minimalna wymagana
liczba znaków to {0}!
javax.faces.validator.LengthValidator.MAXIMUM=Maksymalna wymagana
liczba znaków to {0}!
W miejsce {0} będzie wstawiany parametr
ograniczenia np. limit na liczbę znaków
Podmiana i internacjonalizacja komunikatów ze
standardowych walidatorów (2/2)
faces-config.xml
<application>
<message-bundle>
komunikaty
</message-bundle>
</application>
Interaktywny edytor zawartości
faces-config.xml
297
298
Problem dostępu do stron JSP
• Domyślnie źródłowe strony JSP nie są chronione
przed bezpośrednim dostępem
• Dostęp do stron JSP zawierających znaczniki JSF
bez pośrednictwa kontrolera FacesServlet
powoduje błędy
• Jest to jedna z wad JSF!
299
Ochrona źródłowych stron JSP
• Nie można umieścić stron JSP w WEB-INF gdyż
w JSF URL musi odpowiadać lokalizacji pliku:
– strona.jsp -> strona.faces lub faces/strona.jsp
• Rozwiązaniem jest wykorzystanie security-constraint
w pliku web.xml
web.xml
<security-constraint>
<web-resource-collection>
<web-resource-name>Raw JSPs
</web-resource-name>
<url-pattern>/login.jsp</url-pattern>
<url-pattern>/ok.jsp</url-pattern>
...
</web-resource-collection>
<auth-constraint>
<description>No roles, no direct access</description>
</auth-constraint>
</security-constraint>
300
Tworzenie aplikacji bazodanowych
w JavaServer Faces
- prezentowanie danych tabelarycznych
- dostęp do wyników zapytań
301
Prezentacja danych tabelarycznych
• Często aplikacja musi przedstawić kolekcję danych
w postaci tabelarycznej
– Na etapie projektowania strony liczba wierszy jest
nieznana
– Typowy scenariusz przy zapytaniach do bazy danych
• JSF umożliwia prezentację danych tabelarycznych
bez konstrukcji pętli za pomocą komponentu
h:dataTable
– h:dataTable zawiera definicję jednego wiersza
– Struktura wiersza jest powielona dla elementów kolekcji
• Można wskazać szczególną zawartość dla nagłówka i stopki za
pomocą elementu f:facet
• Można wskazać od którego elementu kolekcji (numeracja od 0)
i ile wierszy ma być wyświetlonych (atrybuty first i rows)
302
Dane źródłowe dla h:dataTable
•
•
•
•
•
Lista komponentów Java Bean
Tablica komponentów Java Bean
Pojedynczy komponent Java Bean
java.sql.ResultSet
javax.servlet.jsp.jstl.sql.Result
– Użyteczna alternatywa dla java.sql.ResultSet
– Nie traci zawartości po zamknięciu połączenia z bazą
• javax.sql.RowSet
• javax.faces.model.DataModel
– Wszystkie źródła danych muszą być jawnie lub niejawnie
opakowane w DataModel
• Podklasy ScalarDataModel, ListDataModel,
ArrayDataModel, ResultSetDataModel, ResultDataModel
303
h:dataTable dla tablicy obiektów (1/4)
BookBean.java
Book.java
public class Book {
private String author;
private String title;
public class BooksBean {
public Book [] getBooks() {
Book [] books = {
new Book("Adam Mickiewicz", "Pan Tadeusz"),
new Book("Joanna Chmielewska", "Depozyt"),
new Book("Ernest Hemingway", "Komu bije"),
new Book("William Wharton", "Ptasiek") };
return books;
}
public Book() {}
}
public Book(String a, String t) {
this.author = a;
this.title = t;
}
public
public
public
public
}
void setAuthor(String author) {...}
String getAuthor() {...}
void setTitle(String title) {...}
String getTitle() {...}
304
h:dataTable dla tablicy obiektów (2/4)
Rejestracja źródła danych jako managed bean w faces-config.xml
faces-config.xml
<managed-bean>
<managed-bean-name>
booksBean
</managed-bean-name>
<managed-bean-class>
mypackage.BooksBean
</managed-bean-class>
<managed-bean-scope>
request
</managed-bean-scope>
</managed-bean>
Dodanie komponentu dataTable na stronie
305
h:dataTable dla tablicy obiektów (3/4)
Wskazanie właściwości
komponentu managed bean
jako źródłowej kolekcji danych
Podanie klasy reprezentującej
strukturę elementu kolekcji jest
opcjonalne. Umożliwia
kreatorowi automatyczne
wypełnienie zawartości kolumn
i ich nagłówków!
Ręczne wprowadzenie nazwy
zmiennej, która będzie reprezentować kolejne elementy
306
h:dataTable dla tablicy obiektów (4/4)
ksiazki.jsp
h:column definuje
kolumnę tabeli
f:facet w tabeli
definiuje nagłówek
(header) i stopkę
(footer)
Uwaga: Zawartość nie-JSF
(np. HTML) musi być ujęta w
element f:verbatim, aby
była wyświetlona we
właściwym miejscu
<h:dataTable value="#{booksBean.books}" var="book">
<h:column>
<f:facet name="header">
<h:outputText value="Title"/>
</f:facet>
<h:outputText value="#{book.title}"/>
</h:column>
<h:column>
<f:facet name="header">
<f:verbatim>Author</f:verbatim>
</f:facet>
<h:outputText value="#{book.author}"/>
</h:column>
</h:dataTable>
307
Dostosowywanie wyglądu – Klasy CSS
• Elementy z biblioteki znaczników JSF HTML zawierają atrybut
styleClass wskazujący klasę zdefiniowaną
w dołączonym arkuszu stylów CSS
• Element h:dataTable zawiera kilka atrybutów umożliwiających
specyfikację stylu:
– styleClass
– columnClasses, footerClass, headerClass, rowClasses
styl.css
ksiazki.jsp
.nieparzysty
{
background-color:
Yellow;
color: black;
}
.parzysty
{
background-color:
Cyan;
color: black;
}
<head>
<link href="css/styl.css"
rel="stylesheet"/>
...
</head>
...
<h:dataTable value="#{booksBean.books}"
var="book"
rowClasses="nieparzysty, parzysty">
</h:dataTable>
h:dataTable – Prezentacja wyników
zapytań do bazy danych
• Sposoby przygotowania danych źródłowych:
– Wydobycie danych ze zbioru wynikowego JDBC i ich
umieszczenie w tablicy lub liście obiektów
• Wymaga wielu linii kodu i utworzenia klasy reprezentującej
wiersze wyniku zapytania
• Sensowne przy wykorzystaniu technologii mapowania
obiektowo-relacyjnego i wspierających je kreatorów
(np. Oracle TopLink + JDeveloper)
– Bezpośrednie wykorzystanie ResultSet JDBC
• ResultSet wymaga utrzymania połączenia z bazą danych...
– Wykorzystanie klasy ResultSupport z JSTL
• Przejmuje dane z ResultSet (jedna linia kodu!)
• Odłączony od bazy danych
308
309
h:dataTable dla wyniku zapytania (1/2)
EmpsBean.java
public class EmpsBean {
public Result getEmps() {
Result r = null;
try {
Context ctx = new InitialContext();
DataSource ds = (DataSource)ctx.lookup ("jdbc/marek8iDS");
Connection conn = ds.getConnection();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("select ENAME, SAL from EMP");
r = ResultSupport.toResult(rs);
} catch (Exception e) {}
return r;
}
}
faces-config.xml
<managed-bean>
<managed-bean-name>empsBean</managed-bean-name>
<managed-bean-class>mypackage.EmpsBean</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
310
h:dataTable dla wyniku zapytania (2/2)
pracownicy.jsp
<h:dataTable value="#{empsBean.emps}" var="emp" border="1">
<h:column>
<f:facet name="header">
<f:verbatim>Nazwisko</f:verbatim>
</f:facet>
<h:outputText value="#{emp.ename}"/>
</h:column>
<h:column>
<f:facet name="header">
<f:verbatim>Płaca</f:verbatim>
</f:facet>
<h:outputText value="#{emp.sal}"/>
</h:column>
</h:dataTable>
DataModel udostępnia wiersz
wyniku zapytania w postaci obiektu,
zawierającego właściwości
odpowiadające wartościom atrybutów
311
Podsumowanie
312
JSF – Podsumowanie (1/2)
• JSF to technologia tworzenia interfejsu użytkownika
pracującego po stronie serwera w aplikacjach J2EE
– Obejmuje również obsługę nawigacji (kontroler)
• Nadzieja dla programistów J2EE na dorównanie .NET
w zakresie prostoty tworzenia interfejsu użytkownika
w aplikacjach webowych
• W pewnym stopniu alternatywa dla Struts
– Wykorzystuje doświadczenia twórców Struts i innych szkieletów
aplikacji
– Uproszczony kontroler
– Ograniczone możliwości walidacji
– Nacisk na interfejs użytkownika
– Struts i JSF mogą współpracować
313
JSF – Podsumowanie (2/2)
• JSF oferuje stanowe, rozszerzalne i konfigurowalne
komponenty interfejsu i możliwość tworzenia dodatkowych
• Podstawowym środowiskiem do renderowania
komponentów jest JSP
– Specyfikacja JSF definiuje dwie biblioteki znaczników
• JSF w Oracle JDeveloper 10g
– Podstawowa technologia tworzenia widoków i kontrolera od 10.1.3
– Pełne wsparcie z bogactwem kreatorów i edytorów wizualnych

Podobne dokumenty