Kiedy używać <ui: include>, plików znaczników, komponentów złożonych i / lub komponentów niestandardowych?

102

Niedawno zacząłem używać JSF 2.0 z Facelets i zaintrygowały mnie nowe komponenty kompozytowe, znając istniejące <ui:include>i inne techniki tworzenia szablonów oferowane przez Facelets 1.x.

Jaka jest różnica między tymi podejściami? Funkcjonalnie wydają się oferować mniej więcej to samo: <ui:param>vs <cc:attribute>, <ui:insert>+ <ui:define>vs pliki tagów, ponowne wykorzystanie istniejących szablonów. Czy jest coś oprócz składni i jasnej specyfikacji interfejsu w przypadku komponentów kompozytowych? Czy wydajność może się różnić?

mrembisz
źródło

Odpowiedzi:

176

Jaka jest różnica między tymi podejściami?

Szablony facelet

Zastosowanie Facelet szablony (jak w <ui:composition>, <ui:include>i <ui:decorate>), jeżeli chcesz podzielić główne fragmenty układu strony do reuseable szablonów. Np. Nagłówek, menu, treść, stopka itp.

Przykłady:

Pliki znaczników facelet

Użyj plików znaczników Facelet, jeśli chcesz mieć grupę komponentów do ponownego wykorzystania, aby zapobiec / zminimalizować powielanie kodu. Np. Grupa elementów etykieta + wejście + wiadomość. Główna różnica w porównaniu ze składnikami złożonymi polega na tym, że wynik pliku znaczników Facelet nie reprezentuje pojedynczego elementu UIComponenti może w pewnych okolicznościach być jedynym rozwiązaniem, gdy składnik złożony nie jest wystarczający. Ogólnie rzecz biorąc, posiadanie <ui:include>z co najmniej jednym, <ui:param>który przekazuje właściwość zarządzanego komponentu bean (a zatem nie jest wartością zakodowaną na stałe), jest sygnałem, że plik dołączany może lepiej być plikiem znaczników.

Przykłady:

Komponenty kompozytowe

Użyj komponentów złożonych, jeśli chcesz utworzyć pojedynczy niestandardowy i wielokrotnego użytku UIComponentz jedną odpowiedzialnością za pomocą czystego XML. Taki komponent złożony zazwyczaj składa się z wielu istniejących komponentów i / lub HTML i jest fizycznie renderowany jako pojedynczy komponent i powinien być powiązany z pojedynczą właściwością ziarna. Np. Komponent, który reprezentuje pojedynczą java.util.Datewłaściwość przez 3 zależne <h:selectOneMenu>komponenty lub komponent, który łączy <p:fileUpload>i <p:imageCropper>tworzy jedną, <my:uploadAndCropImage>odnoszącą się do pojedynczej com.example.Imagejednostki niestandardowej jako właściwość.

Przykłady:

Komponenty niestandardowe

Użyj komponentu niestandardowego, gdy funkcjonalność nie może być osiągnięta za pomocą plików znaczników Facelet lub komponentów kompozytowych z powodu braku wsparcia w standardowym / dostępnym zestawie komponentów. Przykłady można znaleźć w każdym miejscu w kodzie źródłowym bibliotek komponentów open source, takich jak PrimeFaces i OmniFaces .

Programy obsługi tagów

Jeśli chcesz sterować budowaniem drzewa komponentów JSF zamiast renderować wyjście HTML, powinieneś użyć procedury obsługi tagów zamiast komponentu.

Przykłady:

Przykładowe projekty

Oto kilka przykładowych projektów, które wykorzystują wszystkie wymienione powyżej techniki.


Czy wydajność może się różnić?

Technicznie rzecz biorąc, problem z wydajnością jest znikomy. Wyboru należy dokonać na podstawie konkretnych wymagań funkcjonalnych oraz ostatecznego stopnia abstrakcji, możliwości ponownego wykorzystania i utrzymania implementacji. Każde podejście ma swój własny, dobrze określony cel i ograniczenia.

Komponenty złożone mają jednak znaczny narzut podczas tworzenia / przywracania widoku (w szczególności: podczas zapisywania / przywracania stanu widoku). W starszych wersjach Mojarra komponenty kompozytowe miały problemy z wydajnością przy przypisywaniu wartości domyślnych, zostało to już naprawione od 2.1.13. Ponadto Mojarra miał wyciek pamięci, gdy a <cc:attribute method-signature>jest używany do wyrażeń metod, w zasadzie całe drzewo komponentów jest ponownie przywoływane w sesji HTTP, zostało to naprawione od 2.1.29 / 2.2.8. Wyciek pamięci można ominąć w starszych wersjach 2.1, jak poniżej:

<context-param>
    <param-name>com.sun.faces.serializeServerState</param-name>
    <param-value>true</param-value>
</context-param>

Lub w starszych wersjach 2.2, jak poniżej:

<context-param>
    <param-name>javax.faces.SERIALIZE_SERVER_STATE</param-name>
    <param-value>true</param-value>
</context-param>

Mimo to, gdy masz stosunkowo „dużo” komponentów kompozytowych i masz javax.faces.STATE_SAVING_METHODustawione client, to wydajność będzie uciążliwa. Nie nadużywaj komponentów złożonych, jeśli potrzebujesz jedynie podstawowej funkcjonalności, która jest już możliwa dzięki prostemu plikowi dołączania lub pliku znacznika. Nie używaj łatwości konfiguracji (czytaj: *.taglib.xmlplik nie jest potrzebny) jako wymówki, aby preferować komponenty złożone od plików znaczników.

Korzystając z Mojarra 2.2.10 lub starszej, nie zapomnij wyłączyć stosunkowo krótkiego okresu odświeżania Facelets dla trybu produkcyjnego:

<context-param>
    <param-name>javax.faces.FACELETS_REFRESH_PERIOD</param-name>
    <param-value>-1</param-value>
</context-param>

Nie używaj tego ustawienia do programowania, w przeciwnym razie musisz ponownie uruchomić cały serwer, aby zmiany w plikach Facelets zostały odzwierciedlone! Mojarra 2.2.11 i nowsze, a MyFaces już domyślnie ustawia -1kiedy javax.faces.PROJECT_STAGEnie jest ustawione na Development.

BalusC
źródło
dlaczego miałbyś chcieć renderować 1 komponent (komponent złożony) zamiast powiedzmy 3 (plik znacznika facelet)? Chodzi mi o to, że w słoneczny dzień może poczujesz się jak 1 zamiast 3 ... ale myślę, że kryje się za tym coś jeszcze. W swoim przykładzie rozszerzasz UINamingContainer ... czy może to być jeden z powodów, dla których warto zdecydować się na cc (aby móc nadpisać niektóre funkcje specyficzne dla implementacji jsf)?
Toskan
2
Plik znacznika należy traktować jako rodzaj dołączenia. Komponent złożony powinien być postrzegany jako komponent rzeczywisty. Komponent złożony wymaga zaimplementowania NamingContainer, w przeciwnym razie pojawią się problemy z duplikatami identyfikatorów, gdy ten sam komponent jest wielokrotnie używany.
BalusC
@BalusC Powiedzmy, że mam kilka HTML i JSF, które tworzą „blok”, który pozwala mi dodawać lub usuwać adresy (i wszystkie jego atrybuty: ulica, numer, miasto itp.). Muszę użyć tego samego bloku na 2 lub 3 stronach. Czy to pasuje do twojego opisu komponentu kompozytowego?
RinaldoPJr
1
@Rinaldo: Myślę, że użyłbym do tego pliku tagów z dynamicznie wypełnianymi identyfikatorami komponentów, jak pokazano na stackoverflow.com/questions/5713718/… . IMO, jeśli można to zrobić z plikiem tagów, użyj go. Jeśli nie można tego zrobić z plikiem tagów, użyj kompozytu. Jeśli potrzebujesz wielu komponentów do manipulowania jedną nieruchomością (nie adres, ale np. Nazwa ulicy + numer domu, które powinny znajdować się w jednej nieruchomości), jedynym rozwiązaniem byłby komponent złożony.
BalusC
2
@Tarik: kompozyty mają dużo narzutów w porównaniu z tagami. Innymi słowy: słaba wydajność. Użyj go tylko wtedy, gdy musisz utworzyć pojedynczy niestandardowy składnik interfejsu użytkownika na podstawie zestawu ściśle powiązanych istniejących składników. Nie można tego zrobić za pomocą pliku tagów. Na przykład witryna ZEEF.com ma tylko jeden element złożony: przesyłanie / pobieranie / przycinanie obrazu typu „wszystko w jednym”, które jest używane w obrazie strony, zdjęciu profilowym, nagłówku bloku linków, blokach obrazu itp. Jest powiązany tylko z Imagewłaściwością w fasoli.
BalusC