SlideShare une entreprise Scribd logo
1  sur  24
Sức mạnh của JSF 2, Phần 2: Tạo khuôn mẫu và các thành phần
phức hợp
Triển khai các giao diện người dùng mở rộng với JavaServer Faces 2
Java™Server Faces (JSF) 2 cho phép bạn triển khai thực hiện các giao diện
người dùng (UI), dễ dàng sửa đổi và mở rộng với hai tính năng mạnh mẽ: tạo
khuôn mẫu và các thành phần phức hợp. Trong bài viết này — bài thứ hai
trong loạt bài ba phần về các đặc tính mới của JSF 2 — David Geary, thành viên
nhóm chuyên gia JSF 2.0 cho bạn thấy các ứng dụng Web của mình có thể tận
dụng tốt nhất việc tạo khuôn mẫu và các thành phần phức hợp như thế nào.
Trở lại năm 2000, khi tôi tham gia vào một danh sách gửi thư về JavaServer Pages
(JSP), tôi đã gặp Craig McClanahan, người đang làm việc cho một khung công tác Web
mới sinh ra có tên là Struts. Quay lại thời đó, khi di chuyển từ Swing sang lập trình Java
phía máy chủ, tôi đã thực hiện một khung công tác nhỏ để tách biệt cách bài trí khung
nhìn của JSP khỏi nội dung của nó, tương tự với tinh thần của các trình quản lý cách
bài trí của Swing. Craig đã hỏi tôi có muốn cho phép đưa thư viện tạo khuôn mẫu của
tôi vào trong Struts không và tôi đã vui lòng đồng ý. Thư viện khuôn mẫu của Struts
(Struts Template Library), được đóng gói cùng với Struts 1.0, đã trở thành cơ sở cho
thư viện Tiles phổ biến của Strut, để cuối cùng thư viện này đã trở thành một khung
công tác Apache hàng đầu.
Hiện nay, công nghệ hiển thị mặc định của JSF 2 — Facelets — là một khung công tác
tạo khuôn mẫu phần lớn dựa vào Tiles. JSF 2 cũng cung cấp một cơ chế mạnh, được
gọi là các thành phần phức hợp, xây dựng trên các đặc tính tạo khuôn mẫu của
Facelets để cho bạn có thể triển khai thực hiện các thành phần tùy chỉnh không cần mã
Java và không có cấu hình XML nào. Trong bài này, tôi sẽ giới thiệu cho bạn về tạo
khuôn mẫu và các thành phần phức hợp với ba lời khuyên để khai thác tốt nhất JSF 2:
 Lời khuyên 1: Giữ nguyên tắc DRY (Đừng lặp lại chính mình).
 Lời khuyên 2: Hãy dùng cách hợp thành.
 Lời khuyên 3: Hãy nghĩ theo kiểu LEGO.
Facelets và JSF 2
Trong khi chuẩn hoá việc thực hiện Facelets mã nguồn mở, Nhóm chuyên gia JSF 2
(JSF 2 Expert Group) đã thực hiện một số thay đổi cho các API Facelets bên dưới
nhưng giữ lại khả năng tương thích lùi với thư viện thẻ. Điều đó có nghĩa là các khung
nhìn hiện có, được triển khai thực hiện bằng phiên bản mã nguồn mở của Facelets sẽ
làm việc được với JSF 2.
Bạn có thể tìm hiểu thêm về nhiều tính năng của Facelets trong bài viết của Rick
Hightower "Facelets vừa khít với JSF" (Facelets Fits JSF like a Glove) và "Lập trình
Facelets nâng cao (Advanced Facelets programming)."
Lời khuyên 1: Giữ nguyên tắc DRY
Trong công việc đầu tiên của tôi với vai trò nhà phát triển phần mềm, tôi đã triển khai
thực hiện một giao diện người dùng đồ họa (GUI) cho các hệ thống thiết kế có hỗ trợ
của máy tính và hệ thống chế tác có hỗ trợ của máy tính (CAD/CAM) dựa trên UNIX®.
Ban đầu tất cả đã diễn ra khá tốt, nhưng theo thời gian, mã của tôi đã trở nên ngày
càng có nhiều vấn đề. Vào lúc chúng tôi phát hành, hệ thống đã dễ mắc lỗi đến mức tôi
đã sợ hãi việc sửa lỗi và bản phát hành gây ra ngay một luồng tới tấp các báo cáo lỗi.
Nếu tôi đã theo nguyên tắc DRY — Đừng lặp lại chính mình — khi làm dự án đó, thì tôi
có thể đã đã bớt được cho mình nhiều sự phiền toái. Nguyên tắc DRY, do Dave
Thomas và Andy Hunt đặt ra (xem Tài nguyên), nói rõ:
Mỗi một mảnh kiếnthức phải được biểu diễnduy nhất, không lập lờ và
chính thức trong một hệ thống.
Ứng dụng CAD/CAM của tôi không theo nguyên tắc DRY — nó đã có quá nhiều sự kết
dính giữa các mối quan tâm — vì vậy các thay đổi trong một khu vực đã gây ra những
thay đổi bất ngờ ở nơi khác.
JSF 1 đã vi phạm nguyên tắc DRY trong một số khía cạnh, ví dụ bằng cách buộc bạn
cung cấp hai biểu diễn của bean được quản lý của bạn — một trong XML và một trong
mã Java. Nhu cầu có nhiều biểu diễn đã làm cho khó khăn hơn khi tạo ra và thay đổi
bean được quản lý. Như tôi đã chỉ ra cho bạn trong Phần 1, JSF 2 cho phép bạn sử
dụng các chú giải thay vì XML để cấu hình bean được quản lý, cho bạn một cách biểu
diễn duy nhất, chính thức của bean được quản lý của bạn.
Gác lại Bean được quản lý sang một bên, ngay cả các thói quen hình như vô hại —
chẳng hạn như bao gồm bảng định kiểu (stylesheet) giống nhau trong tất cả các khung
nhìn của bạn — cũng vi phạm nguyên tắc DRY và có thể gây ra lo lắng. Nếu bạn thay
đổi tên của bảng định kiểu, bạn phải thay đổi nhiều khung nhìn. Tốt hơn là gói kín việc
bao gồm thêm bảng định kiểu nếu bạn có thể làm được.
Nguyên tắc DRY cũng áp dụng để thiết kế mã của bạn. Nếu bạn có nhiều phương thức
mà tất cả đều chứa mã để duyệt đi qua một cây chẳng hạn, thì một ý tưởng tốt sẽ là gói
kín thuật toán duyệt đi qua một cây, có thể là trong một lớp con.
Giữ nguyên tắc DRY đặc biệt quan trọng khi bạn thực hiện một giao diện người dùng,
là nơi (người ta cho rằng) những thay đổi hay xảy ra nhất trong quá trình phát triển.
Tạo khuôn mẫu JSF 2
Một trong nhiều cách trong đó JSF 2 hỗ trợ nguyên tắc DRY là tạo khuôn
mẫu (templating). Các khuôn mẫu bao gói các chức năng phổ biến trong số các khung
nhìn trong ứng dụng của bạn, vì vậy bạn cần phải xác định chức năng đó chỉ một lần.
Một khuôn mẫu được sử dụng bởi nhiều cấu kiện để tạo ra các khung nhìn trong một
ứng dụng JSF 2.
Ứng dụng các địa điểm, mà tôi đã giới thiệu trong Phần 1, có ba khung nhìn như thấy
trong Hình 1:
Hình 1. Khung nhìn ứng dụng các địa điểm: Đăng nhập, xem mã nguồn và các địa điểm
Giống như nhiều ứng dụng Web, ứng dụng các địa điểm có chứa nhiều khung nhìn
dùng chung cách bố trí giống nhau. Tạo khuôn mẫu JSF cho phép bạn bao kín cách bố
trí đó — cùng với các tạo phẩm dùng chung khác, chẳng hạn như mã JavaScript và
Cascading Style Sheets (Bảng định kiểu nhiều tầng-CSS) — trong một khuôn mẫu. Liệt
kê 1 là khuôn mẫu cho ba khung nhìn được hiển thị trong Hình 1:
Liệt kê 1. Khuôn mẫu các địa điểm: /templates/masterLayout.xhtml
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head>
<title>
<ui:insert name="windowTitle">
#{msgs.placesWindowTitle}
</ui:insert>
</title>
</h:head>
<h:body>
<h:outputScript library="javascript" name="util.js" target="head"/>
<h:outputStylesheet library="css" name="styles.css" target="body"/>
<div class="pageHeading">
<ui:insert name="heading">
#{msgs.placesHeading}
</ui:insert>
</div>
<div class="menuAndContent">
<div class="menuLeft">
<ui:insert name="menuLeft"/>
</div>
<div class="content" style="display: #{places.showContent}">
<ui:insert name="content"/>
</div>
<div class="menuRight">
<ui:insert name="menuRight">
<ui:include src="/sections/shared/sourceViewer.xhtml"/>
</ui:insert>
</div>
</div>
</h:body>
</html>
Khuôn mẫu trong Liệt kê 1 cung cấp cơ sở hạ tầng sau đây cho tất cả các khung nhìn
của ứng dụng:
 Các thẻ HTML <head>, <body> và <title>
 Một tiêu đề (title) mặc định (có thể bị ghi đè bởi các cấu kiện sử dụng
khuôn mẫu).
 Một bảng định kiểu CSS.
 Một số tiện ích JavaScript.
 Một cách bố trí dưới dạng các <div> và các lớp CSS tương ứng.
 Nội dung mặc định cho phần đầu (head) (có thể bị ghi đè).
 Nội dung mặc định cho trình đơn bên phải (có thể bị ghi đè).
Như Liệt kê 1 minh họa, các khuôn mẫu chèn nội dung vào trong cách bố trí của chúng
bằng thẻ <ui:insert>.
Nếu bạn quy định một phần thân cho một thẻ <ui:insert>, như tôi đã thực hiện đối với
tiêu đề cửa sổ, phần đầu và trình đơn bên phải trong Liệt kê 1, JSF sử dụng phần thân
của thẻ như nội dung mặc định. Các cấu kiện sử dụng khuôn mẫu có thể định nghĩa nội
dung hoặc ghi đè lên nội dung mặc định bằng thẻ <ui:define>, như đã chứng tỏ trong
Liệt kê 2, hiển thị tài liệu đánh dấu siêu văn bản của khung nhìn đăng nhập:
Liệt kê 2. Khung nhìn đăng nhập
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
template="/templates/masterLayout.xhtml">
<ui:define name="menuLeft">
<ui:include src="/sections/login/menuLeft.xhtml"/>
</ui:define>
<ui:define name="content">
<ui:include src="/sections/login/content.xhtml"/>
</ui:define>
</ui:composition>
Khung nhìn đăng nhập sử dụng nội dung mặc định của khuôn mẫu cho tiêu đề cửa sổ,
phần đầu và trình đơn bên phải. Nó chỉ định nghĩa chức năng cụ thể riêng cho khung
nhìn đăng nhập: phần nội dung và trình đơn bên trái.
Bằng cách cung cấp một thẻ <ui:define> cho tiêu đề cửa sổ, phần đầu hoặc trình đơn
bên phải, tôi có thể đã ghi đè nội dung mặc định do khuôn mẫu định nghĩa. Ví dụ, Liệt
kê 3 cho thấy khung nhìn xem mã nguồn (hình ảnh ở giữa trong Hình 1):
Liệt kê 3. Khung nhìn xem-mã nguồn
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
template="/templates/masterLayout.xhtml">
<ui:define name="content">
<ui:include src="/sections/showSource/content.xhtml"/>
</ui:define>
<ui:define name="menuLeft">
<ui:include src="/sections/showSource/menuLeft.xhtml"/>
</ui:define>
<ui:define name="menuRight">
<ui:include src="/sections/showSource/menuRight.xhtml"/>
</ui:define>
</ui:composition>
Khung nhìn-xem mã nguồn định nghĩa nội dung cho phần nội dung và cho trình đơn
bên phải. Nó cũng ghi đè nội dung mặc định, được khuôn mẫu định nghĩa trong Liệt kê
1, cho trình đơn bên trái.
Liệt kê 4 cho thấy khung nhìn các địa điểm (hình dưới cùng trong Hình 1):
Liệt kê 4. Khung nhìn các địa điểm
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
template="/templates/masterLayout.xhtml">
<ui:define name="menuLeft">
<ui:include src="/sections/places/menuLeft.xhtml"/>
</ui:define>
<ui:define name="content">
<ui:include src="/sections/places/content.xhtml"/>
</ui:define>
</ui:composition>
Tạo khuôn mẫu JSF 2
Khái niệm phía sau tạo khuôn mẫu là đơn giản. Bạn định nghĩa chỉ một khuôn mẫu bao
gói các chức năng phổ biến trong nhiều khung nhìn. Mỗi khung nhìn bao gồm một cấu
kiện và một khuôn mẫu.
Khi JSF tạo một khung nhìn, nó nạp khuôn mẫu của cấu kiện và sau đó chèn nội dung
được định nghĩa bởi cấu kiện đó vào khuôn mẫu đó.
Chú ý các nét giống nhau trong các Liệt kê 2, 3 và 4. Cả ba khung nhìn xác định rõ
khuôn mẫu của chúng và định nghĩa nội dung. Cũng để ý việc tạo các khung nhìn mới
dễ dàng như thế nào, bởi vì hầu hết cơ sở hạ tầng của khung nhìn được bao gói trong
một khuôn mẫu và các tệp bao gồm thêm.
Một khía cạnh thú vị khác khi sử dụng tạo khuôn mẫu JSF là các khung nhìn giống như
các khung nhìn trong các Liệt kê 2, 3 và 4 không thay đổi nhiều theo thời gian, vì vậy
một phần đáng kể của mã khung nhìn của bạn về cơ bản không yêu cầu phải bảo trì.
Cũng giống như các khung nhìn có sử dụng chúng, các khuôn mẫu cũng có xu hướng
rất ít thay đổi. Và vì bạn đã bao gói rất nhiều chức năng phổ biến như vậy vào trong các
mã lệnh hầu như không cần bảo trì, bạn có thể tập trung vào nội dung thực tế của
khung nhìn của bạn — những gì diễn ra trong trình đơn bên trái của trang đăng nhập
chẳng hạn. Việc tập trung vào nội dung thực tế của khung nhìn của bạn là tất cả những
gì mà lời khuyên tiếp theo bàn đến.
Về đầu trang
Lời khuyên 2: Hãy dùng cách hợp thành
Không lâu sau khi bản GUI CAD/CAM của tôi đã được phát hành, tôi đã dành một vài
tháng tiếp tục làm việc với một nhà phát triển có tên là Bob, trong một dự án không có
liên quan gì. Chúng tôi đã làm việc trên cơ sở mã của Bob và chúng tôi đã có thể thay
đổi và sửa lỗi dễ dàng đến không ngờ.
Tôi sớm đã nhận ra rằng chỉ có một sự khác biệt lớn nhất giữa mã của Bob và của tôi
là ông đã viết các phương thức rất nhỏ— thường là từ 5 đến 15 dòng mã — và toàn bộ
hệ thống của ông đã được lắp ráp với nhau từ các phương thức rất nhỏ đó. Trong khi
mà tôi đánh vật để sửa đổi các phương thức dài, làm nhiều việc trong dự án trước đây
của tôi, Bob nhanh nhẹn phối hợp các phương thức nhỏ với chức năng nguyên tử
(atomic - không chia nhỏ được nữa). Sự khác biệt trong khả năng bảo trì và mở rộng
được giữa mã của Bob và của tôi giống như so sánh đêm với ngày và từ đó trở đi, các
phương thức rất nhỏ đã thuyết phục tôi.
Cả Bob lẫn tôi vào lúc đó đều chưa biết, nhưng chúng tôi đã sử dụng một mẫu thiết kế
từ Smalltalk có tên là Phương thức hợp thành (Composed Method) (xem Tài nguyên):
Hãy chia phầnmềm của bạnthành các phương thức thực hiệnmột nhiệm
vụ có thể nhậnbiết được, ở chỉ một mức trừu tượng.
Những lợi ích của việc sử dụng mẫu hình Phương thức hợp thành là có tài liệu hướng
dẫn tốt. (Xem "Kiến trúc tiến hóa và thiết kế nổi dần: Phương thức hợp thành và SLAP"
của Neal Ford với các giải thích chi tiết tuyệt vời). Ở đây, tôi sẽ tập trung vào cách bạn
có thể sử dụng mẫu hình Phương thức hợp thành với các khung nhìn JSF của bạn như
thế nào.
JSF 2 khuyến khích bạn hợp thành khung nhìn của mình từ các mảnh khung nhìn nhỏ
hơn. Việc tạo khuôn mẫu bao gói các chức năng chung, do đó chia các khung nhìn của
bạn thành các mảnh nhỏ hơn. JSF 2 cũng cung cấp một thẻ <ui:include>, như tôi đã
giải thích trong các liệt kê trước, cho phép bạn tiếp tục chia nhỏ hơn nữa các khung
nhìn của mình thành mảnh chức năng nhỏ hơn. Ví dụ, Hình 2 cho thấy trình đơn bên
trái của trang đăng nhập của ứng các địa điểm:
Hình 2. Trình đơn bên trái của trang đăng nhập
Và Liệt kê 5 cho thấy tệp định nghĩa nội dung của trình đơn đó:
Liệt kê 5. Triển khai thực hiện của trình đơn bên trái của khung nhìn đăng nhập
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets">
<div class="menuLeftText">
#{msgs.welcomeGreeting}
<div class="welcomeImage">
<h:graphicImage library="images" name="cloudy.gif"/>
</div>
</div>
</html>
Tài liệu đánh dấu siêu văn bản trong Liệt kê 5 là đơn giản, làm cho tệp dễ đọc, dễ hiểu,
dễ duy trì và mở rộng. Nếu cũng những mã này được nhồi nhét vào trong chỉ một trang
XHTML dài có chứa tất cả mọi thứ cần thiết để thực hiện khung nhìn đăng nhập, thì sẽ
rất nặng nề khi thay đổi.
Hình 3 cho thấy trình đơn bên trái của khung nhìn các địa điểm:
Hình 3. Trình đơn bên trái của khung nhìn các địa điểm
Triển khai thực hiện của trình đơn bên trái của khung nhìn các địa điểm được hiển thị
trong Liệt kê 6.
Liệt kê 6. Thực hiện trình đơn bên trái của khung nhìn các địa điểm
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:util="http://java.sun.com/jsf/composite/components/util">
<div class="placesSearchForm">
<div class="placesSearchFormHeading">
#{msgs.findAPlace}
</div>
<h:form prependId="false">
<h:panelGrid columns="2">
#{msgs.streetAddress}
<h:inputText value="#{place.streetAddress}" size="15"/>
#{msgs.city} <h:inputText value="#{place.city}" size="10"/>
#{msgs.state} <h:inputText value="#{place.state}" size="3"/>
#{msgs.zip} <h:inputText value="#{place.zip}" size="5"/>
<h:commandButton value="#{msgs.goButtonText}"
style="font-family:Palatino;font-style:italic"
action="#{place.fetch}"/>
</h:panelGrid>
</h:form>
</div>
<util:icon image="#{resource['images:back.jpg']}"
actionMethod="#{places.logout}"
style="border: thin solid lightBlue"/>
</ui:composition>
Liệt kê 6 Liệt kê 6 thực hiện một biểu mẫu và nó sử dụng một thành phần biểu tượng.
(Tôi sẽ thảo luận thành phần biểu tượng đó trong mụcThành phần biểu tượng (The icon
component), ngay sau đây. Tạm thời bây giờ, chỉ cần biết rằng tác giả của trang có thể
kết hợp một hình ảnh và một phương thức một với một biểu tượng). Hình ảnh cho biểu
tượng đăng xuất được hiển thị ở dưới cùng của Hình 3 và phương thức của biểu tượng
đăng xuất —places.logout()— được hiển thị trong Liệt kê 7:
Liệt kê 7. Phương thức Places.logout()
package com.clarity;
...
@ManagedBean()
@SessionScoped
public class Places {
private ArrayList<Place> places = null;
...
private static SelectItem[] zoomLevelItems = {
...
public String logout() {
FacesContext fc = FacesContext.getCurrentInstance();
ELResolver elResolver = fc.getApplication().getELResolver();
User user = (User)elResolver.getValue(
fc.getELContext(), null, "user");
user.setName("");
user.setPassword("");
setPlacesList(null);
return "login";
}
}
Đối với tôi, Liệt kê 6 — phần mã thực hiện trình đơn bên trái của khung nhìn các địa
điểm — đang đến gần ngưỡng quá nhiều mã với khoảng 30 dòng lệnh ngôn ngữ đánh
dấu. Liệt kê này hơi khó đọc và có hai thứ trong đoạn mã đó có thể được cấu trúc lại
thành các tệp riêng của chúng: biểu mẫu và biểu tượng. Liệt kê 8 cho thấy phiên bản
cấu trúc lại của Liệt kê 6 gói biểu mẫu và biểu tượng trong các tệp XHTML riêng của
chúng:
Liệt kê 8. Cấu trúc lại trình đơn bên trái của khung nhìn các địa điểm
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets">
<div class="placesSearchForm">
<div class="placesSearchFormHeading">
#{msgs.findAPlace}
</div>
<ui:include src="addressForm.xhtml">
<ui:include src="logoutIcon.xhtml">
</div>
</ui:composition>
Liệt kê 9 cho thấy tệp addressForm.xhtml:
Liệt kê 9. addressForm.xhtml
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:form prependId="false">
<h:panelGrid columns="2">
#{msgs.streetAddress}
<h:inputText value="#{place.streetAddress}" size="15"/>
#{msgs.city} <h:inputText value="#{place.city}" size="10"/>
#{msgs.state} <h:inputText value="#{place.state}" size="3"/>
#{msgs.zip} <h:inputText value="#{place.zip}" size="5"/>
<h:commandButton value="#{msgs.goButtonText}"
style="font-family:Palatino;font-style:italic"
action="#{place.fetch}"/>
</h:panelGrid>
</h:form>
</ui:composition>
Liệt kê 10 cho thấy tệp logoutIcon.xhtml:
Liệt kê 10. logoutIcon.xhtml
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:util="http://java.sun.com/jsf/composite/components/util">
<util:icon image="#{resource['images:back.jpg']}"
actionMethod="#{places.logout}"
style="border: thin solid lightBlue"/>
</ui:composition>
Khi bạn hợp thành các khung nhìn của bạn từ nhiều tệp nhỏ, bạn được hưởng các lợi
ích của mẫu hình Phương thức hợp thành của Smalltalk. Bạn cũng có thể tổ chức các
tệp của bạn làm cho nó dễ dàng phản ứng hơn nữa với các thay đổi. Ví dụ, Hình 4 cho
thấy các tệp, tạo thành ba khung nhìn trong ứng dụng các địa điểm:
Hình 4. Khung nhìn của ứng dụng các địa điểm
Ba thư mục mà tôi đã tạo — views (các khung nhìn), sections (các phần) và templates
(các khuôn mẫu) — có chứa hầu hết các tệp XHTML được sử dụng để triển khai thực
hiện các khung nhìn của ứng dụng các địa điểm. Bởi vì các tệp trong các thư mục
views và templates hiếm khi thay đổi, nên tôi có thể tập trung vào thư mục sections.
Nếu tôi muốn thay đổi biểu tượng trong trình đơn bên trái của trang đăng nhập, ví dụ
thế, tôi biết chính xác cần đi tới đâu: sections/login/menuLeft.xhtml.
Bạn có thể sử dụng bất kỳ cấu trúc thư mục nào bạn muốn để tổ chức các tệp XHTML
của bạn. Một cấu trúc hợp lý giúp cho dễ dàng xác định vị trí mã mà bạn cần phải sửa
đổi hơn.
Bên cạnh việc giữ vững nguyên tắc DRY và việc sử dụng mẫu hình Phương thức hợp
thành, việc bao gói các chức năng trong các thành phần tùy chỉnh cũng là một ý tưởng
tốt. Các thành phần là một cơ chế tái sử dụng mạnh mẽ và bạn nên tận dụng lợi thế
của sức mạnh đó. Không giống như JSF 1, JSF 2 giúp bạn dễ dàng triển khai thực hiện
các thành phần tùy chỉnh.
Về đầu trang
Lời khuyên 3: Hãy nghĩ theo kiểu LEGO
Khi còn là một cậu bé, tôi đã có hai đồ chơi ưa thích: một bộ hóa học và bộ LEGO. Cả
hai đều cho tôi tạo ra nhiều thứ bằng cách kết hợp các khối xây dựng cơ bản, điều mà
đã trở thành một niềm đam mê suốt đời dưới cái vỏ phát triển phần mềm.
Sức mạnh của JSF đã luôn ở trong mô hình thành phần của nó, nhưng sức mạnh đó
cho đến nay đã không được nhận biết hoàn toàn vì rất khó để triển khai thực hiện các
thành phần tùy chỉnh với JSF 1. Bạn phải viết mã Java, chỉ rõ cấu hình XML và có một
sự hiểu biết tốt về vòng đời của JSF. Với JSF 2, bạn có thể triển khai thực hiện các
thành phần tùy chỉnh:
 Không cần cấu hình nào, XML hay cáchnào khác.
 Không có mã Java.
 Các nhà phát triển có thể gắn chức năng cho nó.
 Và triển khai nóng khi được sửa đổi.
Phần còn lại của bài viết này, tôi sẽ hướng dẫn bạn thông qua việc thực hiện ba thành
phần tùy chỉnh cho ứng dụng các địa điểm: một biểu tượng, một ô đăng nhập và một ô
để hiển thị bản đồ và thông tin thời tiết của một địa chỉ. Nhưng trước tiên, tôi sẽ cho
bạn một tổng quan về các thành phần phức hợp của JSF 2.
Thực hiện các thành phần tùy chỉnh
JSF 2 phối hợp việc tạo khuôn mẫu Facelets (Facelets templating), xử lý tài nguyên (đã
thảo luận trong Phần 1) và một quy ước đặt tên đơn giản để triển khai thực hiện các
thành phần phức hợp. Các thành phần phức hợp, như tên gọi cho thấy, cho phép bạn
hợp thành một thành phần từ các thành phần hiện có.
Bạn thực hiện các thành phần phức hợp bằng XHTML ở một nơi nào đó trong thư mục
tài nguyên và liên kết chúng, thuần túy theo quy ước, tới một vùng tên và một thẻ. Hình
5 cho thấy tôi đã tổ chức các thành phần phức hợp cho ứng dụng các địa điểm như thế
nào:
Hình 5. Các thành phần của ứng dụng các địa điểm
Để sử dụng các thành phần phức hợp, bạn khai báo một vùng tên và sử dụng các thẻ.
Các vùng tên luôn luôn làhttp://java.sun.com/jsf/composite cộng với tên của thư
mục trong đó có chứa các thành phần, dưới thư mục tài nguyên. Tên của chính thành
phần là tên của tệp XHTML của nó, không có phần mở rộng .xhtml. Quy ước này tránh
được sự cần thiết phải có bất kỳ cấu hình nào. Ví dụ, để sử dụng thành
phần login (đăng nhập) trong ứng dụng các địa điểm, bạn sẽ làm như sau:
<html xmlns="http://www.w3.org/1999/xhtml"
...
xmlns:util="http://java.sun.com/jsf/composite/component/util">
...
<util:login.../>
...
<html>
Và để sử dụng thành phần icon (biểu tượng), bạn sẽ làm thế này:
<html xmlns="http://www.w3.org/1999/xhtml"
...
xmlns:util="http://java.sun.com/jsf/composite/components/util">
...
<util:icon.../>
...
<html>
Cuối cùng, bạn sử dụng thành phần địa điểm như thế này:
<html xmlns="http://www.w3.org/1999/xhtml"
...
xmlns:util="http://java.sun.com/jsf/composite/components/places">
...
<places:place.../>
...
<html>
Thành phần icon: Một phần phức hợp đơn giản
Ứng dụng các địa điểm sử dụng hai biểu tượng được hiển thị trong Hình 6:
Hình 6. Các biểu tượng trong ứng dụng các địa điểm
Mỗi biểu tượng là một đường liên kết. Khi người dùng nhấn vào biểu tượng bên trái
trong Hình 6, JSF sẽ hiển thị tài liệu đánh dấu siêu văn bản của khung nhìn hiện tại,
trong khi đó, nếu kích hoạt vào biểu tượng bên phải sẽ đăng xuất người sử dụng thoát
khỏi ứng dụng.
Bạn có thể chỉ định một tên lớp (className) CSS và một hình ảnh cho các đường liên
kết và bạn cũng có thể đính kèm các phương thức tới các đường liên kết. JSF gọi các
phương thức đó khi người dùng nhấn vào một đường liên kết gắn với nó.
Liệt kê 11 cho thấy thành phần icon được sử dụng trong ứng dụng các địa điểm để
hiển thị tài liệu đánh dấu siêu văn bản như thế nào:
Liệt kê 11. Sử dụng thành phần icon để hiển thị tài liệu đánh dấu siêu văn bản
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:util="http://java.sun.com/jsf/composite/components/util">
<util:icon actionMethod="#{sourceViewer.showSource}"
image="#{resource['images:disk-icon.jpg']}"/>
...
</html>
Liệt kê 12 cho thấy thành phần icon được sử dụng để đăng xuất như thế nào:
Liệt kê 12. Sử dụng thành phần icon để đăng xuất
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:util="http://java.sun.com/jsf/composite/components/util">
<util:icon actionMethod="#{places.logout}"
image="#{resource['images:back-arrow.jpg']}"/>
...
</html>
Liệt kê 13 cho thấy mã cho thành phần icon:
Liệt kê 13. Thành phần icon
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:composite="http://java.sun.com/jsf/composite">
<!-- INTERFACE -->
<composite:interface>
<composite:attribute name="image"/>
<composite:attribute name="actionMethod"
method-signature="java.lang.String action()"/>
</composite:interface>
<!-- IMPLEMENTATION -->
<composite:implementation>
<h:form>
<h:commandLink action="#{cc.attrs.actionMethod}" immediate="true">
<h:graphicImage value="#{cc.attrs.image}"
styleClass="icon"/>
</h:commandLink>
</h:form>
</composite:implementation>
</html>
Giống như tất cả các thành phần phức hợp, thành phần icon trong Liệt kê 13 có hai
phần: <composite:interface> và<composite:implementation>.
Phần <composite:interface> định nghĩa một giao diện mà bạn có thể sử dụng để cấu
hình thành phần đó. Thành phần icon có hai thuộc tính: image (hình ảnh), định nghĩa
thành phần trông như thế nào và actionMethod, xác định nó hoạt động như thế nào.
Phần <composite:implementation> chứa triển khai thực hiện của thành phần. Nó dùng
biểu thức #{cc.attrs.ATTRIBUTE_NAME} để truy cập vào các thuộc tính được định
nghĩa trong giao diện của thành phần. (cc, là một từ khóa dành riêng trong ngôn ngữ
biểu thức của JSF 2, viết tắt của composite component - thành phần phức hợp.)
Chú ý là thành phần icon trong Liệt kê 13 chỉ rõ một lớp CSS cho hình ảnh của nó bằng
thuộc tính styleClass của <h:graphicImage>. Tên của lớp CSS này được mã cố định
là icon, vì vậy bạn chỉ có thể chỉ định một lớp CSS với tên đó và JSF sẽ sử dụng lớp đó
cho tất cả các biểu tượng trong một ứng dụng. Nhưng sẽ thế nào nếu bạn muốn ghi đè
lên tên lớp CSS đó? Trong trường hợp này, tôi có thể thêm thuộc tính khác cho tên lớp
CSS và cung cấp một mặc định sẽ được JSF sử dụng khi thuộc tính này không được
chỉ rõ. Liệt kê 14 cho thấy thuộc tính đó sẽ trông giống như thế nào:
Liệt kê 14. Thành phần icon, được cấu trúc lại
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
<html xmlns="http://www.w3.org/1999/xhtml"
...
xmlns:composite="http://java.sun.com/jsf/composite">
<composite:interface>
...
<composite:attribute name="styleClass" default="icon" required="false"/>
...
</composite:interface>
<composite:implementation>
...
<h:graphicImage value="#{cc.attrs.image}"
styleClass="#{cc.attrs.styleClass}"/>
...
</composite:implementation>
</html>
Trong Liệt kê 14, tôi đã thêm một thuộc tính cho giao diện của thành phần icon có tên
là styleClass và tham chiếu thuộc tính đó trong khi thực hiện của thành phần. Với sự
thay đổi này, bây giờ bạn có thể chỉ định một lớp CSS tùy chọn cho hình ảnh của biểu
tượng, như sau:
<util:icon actionMethod="#{places.logout}"
image="#{resource['images:back-arrow.jpg']}"
styleClass="customIconClass"/>
Nếu bạn không chỉ rõ thuộc tính styleClass, JSF sẽ sử dụng giá trị mặc định, đó
là icon.
Thành phần login (đăng nhập): Một thành phần cấu hình được đầy đủ
Với JSF 2, bạn có thể triển khai thực hiện các thành phần phức hợp cấu hình được đầy
đủ. Ví dụ, ứng dụng các địa điểm có chứa một thành phần login, thể hiện trong Hình 7:
Hình 7. Thành phần login của ứng dụng các địa điểm
Liệt kê 15 cho thấy ứng dụng các địa điểm sử dụng thành phần login như thế nào:
Liệt kê 15. Sử dụng thành phần login
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
...
xmlns:comp="http://java.sun.com/jsf/composite/component/util">
<util:login loginPrompt="#{msgs.loginPrompt}"
namePrompt="#{msgs.namePrompt}"
passwordPrompt="#{msgs.passwordPrompt}"
loginAction="#{user.login}"
loginButtonText="#{msgs.loginButtonText}"
managedBean="#{user}">
<f:actionListener for="loginButton"
type="com.clarity.LoginActionListener"/>
</util:login>
...
</html>
Liệt kê 15 không chỉ tham số hóa các thuộc tính của thành phần login, chẳng hạn như
nhắc tên và mật khẩu, mà nó còn gắn một trình lắng nghe hành động vào nút Log
In (đăng nhập) của thành phần. Nút đó được giao diện của thành phần login trưng ra,
như hiển thị trong Liệt kê 16:
Liệt kê 16. Thành phần login
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:composite="http://java.sun.com/jsf/composite">
<!-- INTERFACE -->
<composite:interface>
<composite:actionSource name="loginButton" targets="form:loginButton"/>
<composite:attribute name="loginButtonText" default="Log In" required="true"/>
<composite:attribute name="loginPrompt"/>
<composite:attribute name="namePrompt"/>
<composite:attribute name="passwordPrompt"/>
<composite:attribute name="loginAction"
method-signature="java.lang.String action()"/>
<composite:attribute name="managedBean"/>
</composite:interface>
<!-- IMPLEMENTATION -->
<composite:implementation>
<h:form id="form" prependId="false">
<div class="prompt">
#{cc.attrs.loginPrompt}
</div>
<panelGrid columns="2">
#{cc.attrs.namePrompt}
<h:inputText id="name" value="#{cc.attrs.managedBean.name}"/>
#{cc.attrs.passwordPrompt}
<h:inputSecret id="password" value="#{cc.attrs.managedBean.password}" />
</panelGrid>
<p>
<h:commandButton id="loginButton"
value="#{cc.attrs.loginButtonText}"
action="#{cc.attrs.loginAction}"/>
</p>
</h:form>
<div class="error" style="padding-top:10px;">
<h:messages layout="table"/>
</div>
</composite:implementation>
</html>
Trong giao diện của thành phần login, tôi đã trưng ra nút Log In dưới tên loginButton.
Tên đó nhằm vào nút Log In nằm trong biểu mẫu có tên là form, do đó giá trị của thuộc
tính targets là: form:loginButton.
Trình lắng nghe hành động được kết hợp với nút Log In trong Liệt kê 16 như thấy trong
Liệt kê 17:
Liệt kê 17. Trình nghe hành động của nút Log in
package com.clarity;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.ActionEvent;
import javax.faces.event.ActionListener;
public class LoginActionListener implements ActionListener {
public void processAction(ActionEvent e)
throws AbortProcessingException {
System.out.println("logging in ...........");
}
}
Trình nghe hành động trong Liệt kê 17 chỉ dành cho mục đích minh họa — khi người sử
dụng đăng nhập, tôi chỉ đơn giản viết lại thông báo vào tệp log của thùng chứa servlet.
Nhưng bạn hiểu được ý tưởng: Với JSF 2, bạn có thể triển khai thực hiện các thành
phần cấu hình được đầy đủ và bạn có thể gắn chức năng cho các thành phần đó, tất cả
mà không có một dòng mã Java hoặc cấu hình XML. Đó là một vài miếng võ mạnh
(N.D: fu - tạm dịch là miếng võ – tác giả mượn từ gốc tiếng Hán, dùng với nghĩa trong
từ Kung Fu).
Thành phần place (địa điểm): Lồng các thành phần phức hợp vào nhau
JSF 2 cho phép bạn thực hiện các thành phần cấu hình được đầy đủ mà không có bất
kỳ mã Java hoặc cấu hình nào. Bạn cũng có thể lồng các thành phần phức hợp vào
nhau, cho phép bạn chia cắt các thành phần phức hợp thành các mảnh nhỏ hơn, dễ
dùng hơn. Ví dụ, Hình 8 cho thấy thành phần place, hiển thị một bản đồ và thông tin
thời tiết của một địa chỉ đã cho:
Hình 8. Thành phần place của ứng dụng các địa điểm
Liệt kê 18 cho thấy ứng dụng các địa điểm sử dụng thành phần place như thế nào:
Liệt kê 18. Sử dụng thành phần place
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:places="http://java.sun.com/jsf/composite/components/places">
<h:form id="form">
<ui:repeat value="#{places.placesList}" var="place">
<places:place location="#{place}"/>
</ui:repeat>
</h:form>
</ui:composition>
Mã cho thành phần place được hiển thị trong Liệt kê 19:
Liệt kê 19. Thành phần place
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:composite="http://java.sun.com/jsf/composite"
xmlns:places="http://java.sun.com/jsf/composite/components/places">
<!-- INTERFACE -->
<composite:interface>
<composite:attribute name="location" required="true"/>
</composite:interface>
<!-- IMPLEMENTATION -->
<composite:implementation>
<div class="placeHeading">
<places:map title="Map"/> <places:weather title="Weather"/>
</div>
</composite:implementation>
</html>
Trong Liệt kê 19, thành phần place sử dụng hai thành phần lồng
nhau: <places:map> và <places:weather>. Liệt kê 20 cho thấy thành phần map (bản đồ):
Liệt kê 20. Thành phần map
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:composite="http://java.sun.com/jsf/composite">
<!-- INTERFACE -->
<composite:interface>
<composite:attribute name="title"/>
</composite:interface>
<!-- IMPLEMENTATION -->
<composite:implementation>
<div class="map">
<div style="padding-bottom: 10px;">
<h:outputText value="#{cc.attrs.title}"
style="color: blue"/>
</div>
<h:panelGrid columns="1">
<h:panelGroup>
<div style="padding-left: 5px;">
<i>
<h:outputText value="#{cc.parent.attrs.location.streetAddress}, "/>
</i>
<h:outputText value=" #{cc.parent.attrs.location.city}" />
<h:outputText value="#{cc.parent.attrs.location.state}"/><hr/>
</div>
</h:panelGroup>
<h:panelGrid columns="2">
<div style="padding-right: 10px;margin-bottom: 10px;font-size:14px">
#{msgs.zoomPrompt}
</div>
<h:selectOneMenu onchange="submit()"
value="#{cc.parent.attrs.location.zoomIndex}"
valueChangeListener="#{cc.parent.attrs.location.zoomChanged}"
style="font-size:13px;font-family:Palatino">
<f:selectItems value="#{cc.parent.attrs.location.zoomLevelItems}"/>
</h:selectOneMenu>
</h:panelGrid>
<h:graphicImage url="#{cc.parent.attrs.location.mapUrl}"
style="border: thin solid gray"/>
</h:panelGrid>
</div>
</composite:implementation>
</html>
Cấu trúc lại thành phần phức hợp
Liệt kê 20 — tài liệu đánh dấu siêu văn bản của thành phần map— hơi dài một chút theo
khẩu vị của tôi. Nhìn thoáng qua lần đầu, nó hơi khó hiểu và sự phức tạp của nó có thể
gây ra các vấn đề về sau này.
Bạn có thể dễ dàng cấu trúc lại Liệt kê 20 thành nhiều tệp dễ quản lý hơn, như tôi đã
làm ở trên khi tôi cấu trúc lại trình đơn bên trái của khung nhìn các địa điểm trong các
Liệt kê 8, 9 và 10. Trong trường hợp này, tôi sẽ dành lại việc tái cấu trúc như là một bài
tập cho bạn.
Hãy chú ý việc sử dụng biểu
thức #{cc.parent.attrs.location.ATTRIBUTE_NAME}trong Liệt kê 20. Bạn có thể sử
dụng một thuộc tính parent (cha mẹ) của thành phần phức hợp để truy cập các thuộc
tính của thành phần cha mẹ, tạo thuận lợi lớn cho việc lồng nhau của các thành phần.
Nhưng bạn không cần hoàn toàn dựa vào các thuộc tính cha mẹ trong các thành phần
lồng nhau. Như tôi đã làm trong thành phần place trong Liệt kê 19, bạn có thể vượt qua
các thuộc tính, chẳng hạn như tiêu đề của bản đồ, từ một thành phần cha mẹ tới thành
phần lồng nhau của nó, cũng giống như bạn sẽ vượt qua các thuộc tính đến bất kỳ
thành phần khác nào, có lồng nhau hay không.
Nó có hơi giảm một chút, nhưng Liệt kê 21 cho thấy thành phần weather (thời tiết):
Liệt kê 21. Thành phần weather
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:composite="http://java.sun.com/jsf/composite">
<!-- INTERFACE -->
<composite:interface>
<composite:attribute name="title"/>
</composite:interface>
<!-- IMPLEMENTATION -->
<composite:implementation>
<div class="weather">
<div style="padding-bottom: 10px;">
<h:outputText value="#{cc.attrs.title}"
style="color: blue"/>
</div>
<div style="margin-top: 10px;width:250px;">
<h:outputText style="font-size: 12px;"
value="#{cc.parent.attrs.location.weather}"
escape="false"/>
</div>
</div>
</composite:implementation>
</html>
Thành phần weather, giống như thành phần map, sử dụng cả một thuộc tính thành phần
cha mẹ (weather HTML từ dịch vụ Web thời tiết) và một thuộc tính thành phần cụ thể
(tiêu đề). (Xem Phần 1 để thấy ứng dụng nhận được bản đồ và thông tin thời tiết với
một địa điểm cụ thể như thế nào).
Vì vậy, khi bạn thực hiện các thành phần lồng nhau, bạn có một sự lựa chọn. Bạn có
thể để cho thành phần lồng nhau dựa vào các thuộc tính của thành phần cha mẹ của
nó hoặc bạn có thể yêu cầu thành phần cha mẹ chuyển qua các thuộc tính rõ ràng đến
thành phần lồng nhau. Ví dụ, thành phần place trong Liệt kê 19 rõ ràng vượt qua các
thuộc tính tiêu đề đến các thành phần lồng nhau của nó, nhưng các thành phần lồng
nhau dựa vào các thuộc tính của cha mẹ, chẳng hạn như URL bản đồ (map URL) và
HTML thời tiết (weather HTML).
Bạn chọn thực hiện các thuộc tính thành phần rõ ràng hoặc dựa vào các thuộc tính cha
mẹ là một sự thỏa hiệp giữa việc kết nối và tiện lợi. Trong trường hợp này, các thành
phần map và weather được kết nối chặt chẽ cùng với thành phần cha mẹ của chúng
(thành phần place), vì chúng dựa vào các thuộc tính của thành phần cha mẹ. Tôi có thể
đã tách rời các thành phần map và weather ra khỏi thành phần placebằng cách xác định
tất cả các thuộc tính của thành phần map và weather như là thuộc tính rõ ràng. Nhưng
trong trường hợp đó, tôi đã mất đi một số tiện nghi, vì thành phần place rõ ràng cần
phải vượt qua tất cả các thuộc tính đến các thành phần map và weather.
Về đầu trang
Tiếp theo ...
Trong bài này, tôi đã cho bạn thấy cách sử dụng JSF 2 UIS để triển khai thực hiện các
UI dễ dàng để duy trì và mở rộng thông qua việc tạo khuôn mẫu và các thành phần
phức hợp. Bài cuối cùng của loạt bài này sẽ chỉ cho bạn cách sử dụng JavaScript trong
các thành phần phức hợp, làm thế nào để sử dụng mô hình sự kiện mới của JSF 2 và
làm thế nào để tận dụng lợi thế của sự hỗ trợ có sẵn của JSF 2 cho Ajax.

Contenu connexe

Tendances

Sức mạnh của jsf 2, phần 1 hợp lý hóa việc phát triển ứng dụng web
Sức mạnh của jsf 2, phần 1 hợp lý hóa việc phát triển ứng dụng webSức mạnh của jsf 2, phần 1 hợp lý hóa việc phát triển ứng dụng web
Sức mạnh của jsf 2, phần 1 hợp lý hóa việc phát triển ứng dụng web
Tuyet Tam
 
Sức mạnh của jsf 2, phần 3 xử lý sự kiện, java script và ajax
Sức mạnh của jsf 2, phần 3 xử lý sự kiện, java script và ajaxSức mạnh của jsf 2, phần 3 xử lý sự kiện, java script và ajax
Sức mạnh của jsf 2, phần 3 xử lý sự kiện, java script và ajax
Tuyet Tam
 
Mvc4 seminar - hoclaptrinhweb.com - Tài liệu Nhất Nghệ
Mvc4 seminar - hoclaptrinhweb.com - Tài liệu Nhất NghệMvc4 seminar - hoclaptrinhweb.com - Tài liệu Nhất Nghệ
Mvc4 seminar - hoclaptrinhweb.com - Tài liệu Nhất Nghệ
MasterCode.vn
 

Tendances (20)

Tài liệu Zend Framework 2 - Cài đặt và cấu hình Zend Framework 2 - Bài 2
Tài liệu Zend Framework 2 - Cài đặt và cấu hình Zend Framework 2 - Bài 2Tài liệu Zend Framework 2 - Cài đặt và cấu hình Zend Framework 2 - Bài 2
Tài liệu Zend Framework 2 - Cài đặt và cấu hình Zend Framework 2 - Bài 2
 
MVC
MVCMVC
MVC
 
Sức mạnh của jsf 2, phần 1 hợp lý hóa việc phát triển ứng dụng web
Sức mạnh của jsf 2, phần 1 hợp lý hóa việc phát triển ứng dụng webSức mạnh của jsf 2, phần 1 hợp lý hóa việc phát triển ứng dụng web
Sức mạnh của jsf 2, phần 1 hợp lý hóa việc phát triển ứng dụng web
 
Aspnet 3.5_03
Aspnet 3.5_03Aspnet 3.5_03
Aspnet 3.5_03
 
Sức mạnh của jsf 2, phần 3 xử lý sự kiện, java script và ajax
Sức mạnh của jsf 2, phần 3 xử lý sự kiện, java script và ajaxSức mạnh của jsf 2, phần 3 xử lý sự kiện, java script và ajax
Sức mạnh của jsf 2, phần 3 xử lý sự kiện, java script và ajax
 
Mô hình mvc trong ASP
Mô hình mvc trong ASPMô hình mvc trong ASP
Mô hình mvc trong ASP
 
Bài 6 Lập trình PHP (phần 4) Làm việc với cookie và session - Giáo trình FPT
Bài 6 Lập trình PHP (phần 4) Làm việc với cookie và session - Giáo trình FPTBài 6 Lập trình PHP (phần 4) Làm việc với cookie và session - Giáo trình FPT
Bài 6 Lập trình PHP (phần 4) Làm việc với cookie và session - Giáo trình FPT
 
Gioi thieu joomla
Gioi thieu joomlaGioi thieu joomla
Gioi thieu joomla
 
TÀI LIỆU HƯỚNG DẪN ĐÓNG GÓI MODULE MAGENTO 1.7
TÀI LIỆU HƯỚNG DẪN ĐÓNG GÓI MODULE  MAGENTO 1.7TÀI LIỆU HƯỚNG DẪN ĐÓNG GÓI MODULE  MAGENTO 1.7
TÀI LIỆU HƯỚNG DẪN ĐÓNG GÓI MODULE MAGENTO 1.7
 
Tim+hieu+jquery
Tim+hieu+jqueryTim+hieu+jquery
Tim+hieu+jquery
 
The First 2015 Saigon WordPress Meetup
The First 2015 Saigon WordPress MeetupThe First 2015 Saigon WordPress Meetup
The First 2015 Saigon WordPress Meetup
 
Java fx
Java fxJava fx
Java fx
 
Học Zend Framework - Khóa học lập trình Zend Framework
Học Zend Framework - Khóa học lập trình Zend FrameworkHọc Zend Framework - Khóa học lập trình Zend Framework
Học Zend Framework - Khóa học lập trình Zend Framework
 
Thuyet trinh java fx
Thuyet trinh java fxThuyet trinh java fx
Thuyet trinh java fx
 
Web203 slide 5
Web203   slide 5Web203   slide 5
Web203 slide 5
 
Joomla CMS framework (1.6 - Old version)
Joomla CMS framework (1.6 - Old version) Joomla CMS framework (1.6 - Old version)
Joomla CMS framework (1.6 - Old version)
 
Mvc4 seminar - hoclaptrinhweb.com - Tài liệu Nhất Nghệ
Mvc4 seminar - hoclaptrinhweb.com - Tài liệu Nhất NghệMvc4 seminar - hoclaptrinhweb.com - Tài liệu Nhất Nghệ
Mvc4 seminar - hoclaptrinhweb.com - Tài liệu Nhất Nghệ
 
Mysql Workbench hướng dẫn cài đặt - Video tiếng Việt
Mysql Workbench hướng dẫn cài đặt - Video tiếng ViệtMysql Workbench hướng dẫn cài đặt - Video tiếng Việt
Mysql Workbench hướng dẫn cài đặt - Video tiếng Việt
 
Tài liệu tìm hiểu jQuery dành cho người mới bắt đầu
Tài liệu tìm hiểu jQuery dành cho người mới bắt đầuTài liệu tìm hiểu jQuery dành cho người mới bắt đầu
Tài liệu tìm hiểu jQuery dành cho người mới bắt đầu
 
Bài 4: Lập trình với CSDL ADO.NET & Kiến trúc không kết nối & Lập trình giao ...
Bài 4: Lập trình với CSDL ADO.NET & Kiến trúc không kết nối & Lập trình giao ...Bài 4: Lập trình với CSDL ADO.NET & Kiến trúc không kết nối & Lập trình giao ...
Bài 4: Lập trình với CSDL ADO.NET & Kiến trúc không kết nối & Lập trình giao ...
 

En vedette

FIA INSIGHT 1 Passion Article
FIA INSIGHT 1 Passion ArticleFIA INSIGHT 1 Passion Article
FIA INSIGHT 1 Passion Article
Kobus Kleyn CFP®
 
Core java server faces
Core java server facesCore java server faces
Core java server faces
Tuyet Tam
 
แบบฝึกหัดท้ายบทที่6 (บันทึกอัตโนมัติ)
แบบฝึกหัดท้ายบทที่6 (บันทึกอัตโนมัติ)แบบฝึกหัดท้ายบทที่6 (บันทึกอัตโนมัติ)
แบบฝึกหัดท้ายบทที่6 (บันทึกอัตโนมัติ)
0833592360
 

En vedette (12)

Stroke Know-how Boards
Stroke Know-how Boards Stroke Know-how Boards
Stroke Know-how Boards
 
aos_sales_spring_high
aos_sales_spring_highaos_sales_spring_high
aos_sales_spring_high
 
บทที่6
บทที่6บทที่6
บทที่6
 
งานนำเสนอ1
งานนำเสนอ1งานนำเสนอ1
งานนำเสนอ1
 
บทที่8
บทที่8บทที่8
บทที่8
 
FIA INSIGHT 1 Passion Article
FIA INSIGHT 1 Passion ArticleFIA INSIGHT 1 Passion Article
FIA INSIGHT 1 Passion Article
 
บทที่ 6 การใช้งานโปรแกรมประมวลผลคำ
บทที่ 6 การใช้งานโปรแกรมประมวลผลคำบทที่ 6 การใช้งานโปรแกรมประมวลผลคำ
บทที่ 6 การใช้งานโปรแกรมประมวลผลคำ
 
Core java server faces
Core java server facesCore java server faces
Core java server faces
 
บทที่6
บทที่6บทที่6
บทที่6
 
Mis by Ali
Mis by AliMis by Ali
Mis by Ali
 
แบบฝึกหัดท้ายบทที่6 (บันทึกอัตโนมัติ)
แบบฝึกหัดท้ายบทที่6 (บันทึกอัตโนมัติ)แบบฝึกหัดท้ายบทที่6 (บันทึกอัตโนมัติ)
แบบฝึกหัดท้ายบทที่6 (บันทึกอัตโนมัติ)
 
エフェクト、アニメーション、演出のデータ作るの大変じゃないですか? DeNAではこうしてます。
エフェクト、アニメーション、演出のデータ作るの大変じゃないですか? DeNAではこうしてます。エフェクト、アニメーション、演出のデータ作るの大変じゃないですか? DeNAではこうしてます。
エフェクト、アニメーション、演出のデータ作るの大変じゃないですか? DeNAではこうしてます。
 

Similaire à Sức mạnh của jsf 2, phần 2 tạo khuôn mẫu và các thành phần phức hợp

1.+tai+lieu+thiet+ke
1.+tai+lieu+thiet+ke1.+tai+lieu+thiet+ke
1.+tai+lieu+thiet+ke
Linh Hoang
 
Bai tap lap trinh web voi joomla csau
Bai tap   lap trinh web voi joomla csauBai tap   lap trinh web voi joomla csau
Bai tap lap trinh web voi joomla csau
Giang Nguyễn
 

Similaire à Sức mạnh của jsf 2, phần 2 tạo khuôn mẫu và các thành phần phức hợp (20)

Joomla developermanual
Joomla developermanualJoomla developermanual
Joomla developermanual
 
Tìm hiểu về Joomla
Tìm hiểu về Joomla Tìm hiểu về Joomla
Tìm hiểu về Joomla
 
TÀI LIỆU HƯỚNG DẪN VIẾT MODULE CHO SUGARCRM
TÀI LIỆU HƯỚNG DẪN VIẾT MODULE CHO SUGARCRMTÀI LIỆU HƯỚNG DẪN VIẾT MODULE CHO SUGARCRM
TÀI LIỆU HƯỚNG DẪN VIẾT MODULE CHO SUGARCRM
 
1.+tai+lieu+thiet+ke
1.+tai+lieu+thiet+ke1.+tai+lieu+thiet+ke
1.+tai+lieu+thiet+ke
 
template magento
template magentotemplate magento
template magento
 
Bai tap lap trinh web voi joomla csau
Bai tap   lap trinh web voi joomla csauBai tap   lap trinh web voi joomla csau
Bai tap lap trinh web voi joomla csau
 
Lap trinh-joomla-15-theo-mo-hinh-mvc
Lap trinh-joomla-15-theo-mo-hinh-mvcLap trinh-joomla-15-theo-mo-hinh-mvc
Lap trinh-joomla-15-theo-mo-hinh-mvc
 
jquery.pdf
jquery.pdfjquery.pdf
jquery.pdf
 
J query
J queryJ query
J query
 
Giao Trinh Jquery
Giao Trinh JqueryGiao Trinh Jquery
Giao Trinh Jquery
 
Basic Views Drupal 7
Basic Views Drupal 7Basic Views Drupal 7
Basic Views Drupal 7
 
Asp control
Asp controlAsp control
Asp control
 
Hdsd eclipse
Hdsd eclipseHdsd eclipse
Hdsd eclipse
 
Mo hinh-3-lop
Mo hinh-3-lopMo hinh-3-lop
Mo hinh-3-lop
 
Hoc Jquery Trong 1h
Hoc Jquery Trong 1hHoc Jquery Trong 1h
Hoc Jquery Trong 1h
 
Asp.net mvc framework qua cac vi du
Asp.net mvc framework  qua cac vi duAsp.net mvc framework  qua cac vi du
Asp.net mvc framework qua cac vi du
 
Spring mvc
Spring mvcSpring mvc
Spring mvc
 
Giao trinh 3 dcb+nc archshop
Giao trinh 3 dcb+nc  archshopGiao trinh 3 dcb+nc  archshop
Giao trinh 3 dcb+nc archshop
 
Tài liệu HTML5-CSS3
Tài liệu HTML5-CSS3Tài liệu HTML5-CSS3
Tài liệu HTML5-CSS3
 
Yii
YiiYii
Yii
 

Sức mạnh của jsf 2, phần 2 tạo khuôn mẫu và các thành phần phức hợp

  • 1. Sức mạnh của JSF 2, Phần 2: Tạo khuôn mẫu và các thành phần phức hợp Triển khai các giao diện người dùng mở rộng với JavaServer Faces 2 Java™Server Faces (JSF) 2 cho phép bạn triển khai thực hiện các giao diện người dùng (UI), dễ dàng sửa đổi và mở rộng với hai tính năng mạnh mẽ: tạo khuôn mẫu và các thành phần phức hợp. Trong bài viết này — bài thứ hai trong loạt bài ba phần về các đặc tính mới của JSF 2 — David Geary, thành viên nhóm chuyên gia JSF 2.0 cho bạn thấy các ứng dụng Web của mình có thể tận dụng tốt nhất việc tạo khuôn mẫu và các thành phần phức hợp như thế nào. Trở lại năm 2000, khi tôi tham gia vào một danh sách gửi thư về JavaServer Pages (JSP), tôi đã gặp Craig McClanahan, người đang làm việc cho một khung công tác Web mới sinh ra có tên là Struts. Quay lại thời đó, khi di chuyển từ Swing sang lập trình Java phía máy chủ, tôi đã thực hiện một khung công tác nhỏ để tách biệt cách bài trí khung nhìn của JSP khỏi nội dung của nó, tương tự với tinh thần của các trình quản lý cách bài trí của Swing. Craig đã hỏi tôi có muốn cho phép đưa thư viện tạo khuôn mẫu của tôi vào trong Struts không và tôi đã vui lòng đồng ý. Thư viện khuôn mẫu của Struts (Struts Template Library), được đóng gói cùng với Struts 1.0, đã trở thành cơ sở cho thư viện Tiles phổ biến của Strut, để cuối cùng thư viện này đã trở thành một khung công tác Apache hàng đầu. Hiện nay, công nghệ hiển thị mặc định của JSF 2 — Facelets — là một khung công tác tạo khuôn mẫu phần lớn dựa vào Tiles. JSF 2 cũng cung cấp một cơ chế mạnh, được gọi là các thành phần phức hợp, xây dựng trên các đặc tính tạo khuôn mẫu của Facelets để cho bạn có thể triển khai thực hiện các thành phần tùy chỉnh không cần mã Java và không có cấu hình XML nào. Trong bài này, tôi sẽ giới thiệu cho bạn về tạo khuôn mẫu và các thành phần phức hợp với ba lời khuyên để khai thác tốt nhất JSF 2:  Lời khuyên 1: Giữ nguyên tắc DRY (Đừng lặp lại chính mình).  Lời khuyên 2: Hãy dùng cách hợp thành.  Lời khuyên 3: Hãy nghĩ theo kiểu LEGO. Facelets và JSF 2 Trong khi chuẩn hoá việc thực hiện Facelets mã nguồn mở, Nhóm chuyên gia JSF 2 (JSF 2 Expert Group) đã thực hiện một số thay đổi cho các API Facelets bên dưới nhưng giữ lại khả năng tương thích lùi với thư viện thẻ. Điều đó có nghĩa là các khung
  • 2. nhìn hiện có, được triển khai thực hiện bằng phiên bản mã nguồn mở của Facelets sẽ làm việc được với JSF 2. Bạn có thể tìm hiểu thêm về nhiều tính năng của Facelets trong bài viết của Rick Hightower "Facelets vừa khít với JSF" (Facelets Fits JSF like a Glove) và "Lập trình Facelets nâng cao (Advanced Facelets programming)." Lời khuyên 1: Giữ nguyên tắc DRY Trong công việc đầu tiên của tôi với vai trò nhà phát triển phần mềm, tôi đã triển khai thực hiện một giao diện người dùng đồ họa (GUI) cho các hệ thống thiết kế có hỗ trợ của máy tính và hệ thống chế tác có hỗ trợ của máy tính (CAD/CAM) dựa trên UNIX®. Ban đầu tất cả đã diễn ra khá tốt, nhưng theo thời gian, mã của tôi đã trở nên ngày càng có nhiều vấn đề. Vào lúc chúng tôi phát hành, hệ thống đã dễ mắc lỗi đến mức tôi đã sợ hãi việc sửa lỗi và bản phát hành gây ra ngay một luồng tới tấp các báo cáo lỗi. Nếu tôi đã theo nguyên tắc DRY — Đừng lặp lại chính mình — khi làm dự án đó, thì tôi có thể đã đã bớt được cho mình nhiều sự phiền toái. Nguyên tắc DRY, do Dave Thomas và Andy Hunt đặt ra (xem Tài nguyên), nói rõ: Mỗi một mảnh kiếnthức phải được biểu diễnduy nhất, không lập lờ và chính thức trong một hệ thống. Ứng dụng CAD/CAM của tôi không theo nguyên tắc DRY — nó đã có quá nhiều sự kết dính giữa các mối quan tâm — vì vậy các thay đổi trong một khu vực đã gây ra những thay đổi bất ngờ ở nơi khác. JSF 1 đã vi phạm nguyên tắc DRY trong một số khía cạnh, ví dụ bằng cách buộc bạn cung cấp hai biểu diễn của bean được quản lý của bạn — một trong XML và một trong mã Java. Nhu cầu có nhiều biểu diễn đã làm cho khó khăn hơn khi tạo ra và thay đổi bean được quản lý. Như tôi đã chỉ ra cho bạn trong Phần 1, JSF 2 cho phép bạn sử dụng các chú giải thay vì XML để cấu hình bean được quản lý, cho bạn một cách biểu diễn duy nhất, chính thức của bean được quản lý của bạn. Gác lại Bean được quản lý sang một bên, ngay cả các thói quen hình như vô hại — chẳng hạn như bao gồm bảng định kiểu (stylesheet) giống nhau trong tất cả các khung nhìn của bạn — cũng vi phạm nguyên tắc DRY và có thể gây ra lo lắng. Nếu bạn thay đổi tên của bảng định kiểu, bạn phải thay đổi nhiều khung nhìn. Tốt hơn là gói kín việc bao gồm thêm bảng định kiểu nếu bạn có thể làm được. Nguyên tắc DRY cũng áp dụng để thiết kế mã của bạn. Nếu bạn có nhiều phương thức mà tất cả đều chứa mã để duyệt đi qua một cây chẳng hạn, thì một ý tưởng tốt sẽ là gói kín thuật toán duyệt đi qua một cây, có thể là trong một lớp con.
  • 3. Giữ nguyên tắc DRY đặc biệt quan trọng khi bạn thực hiện một giao diện người dùng, là nơi (người ta cho rằng) những thay đổi hay xảy ra nhất trong quá trình phát triển. Tạo khuôn mẫu JSF 2 Một trong nhiều cách trong đó JSF 2 hỗ trợ nguyên tắc DRY là tạo khuôn mẫu (templating). Các khuôn mẫu bao gói các chức năng phổ biến trong số các khung nhìn trong ứng dụng của bạn, vì vậy bạn cần phải xác định chức năng đó chỉ một lần. Một khuôn mẫu được sử dụng bởi nhiều cấu kiện để tạo ra các khung nhìn trong một ứng dụng JSF 2. Ứng dụng các địa điểm, mà tôi đã giới thiệu trong Phần 1, có ba khung nhìn như thấy trong Hình 1: Hình 1. Khung nhìn ứng dụng các địa điểm: Đăng nhập, xem mã nguồn và các địa điểm
  • 4. Giống như nhiều ứng dụng Web, ứng dụng các địa điểm có chứa nhiều khung nhìn dùng chung cách bố trí giống nhau. Tạo khuôn mẫu JSF cho phép bạn bao kín cách bố trí đó — cùng với các tạo phẩm dùng chung khác, chẳng hạn như mã JavaScript và
  • 5. Cascading Style Sheets (Bảng định kiểu nhiều tầng-CSS) — trong một khuôn mẫu. Liệt kê 1 là khuôn mẫu cho ba khung nhìn được hiển thị trong Hình 1: Liệt kê 1. Khuôn mẫu các địa điểm: /templates/masterLayout.xhtml <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets"> <h:head> <title> <ui:insert name="windowTitle"> #{msgs.placesWindowTitle} </ui:insert> </title> </h:head> <h:body> <h:outputScript library="javascript" name="util.js" target="head"/> <h:outputStylesheet library="css" name="styles.css" target="body"/> <div class="pageHeading"> <ui:insert name="heading"> #{msgs.placesHeading} </ui:insert> </div> <div class="menuAndContent"> <div class="menuLeft"> <ui:insert name="menuLeft"/> </div> <div class="content" style="display: #{places.showContent}"> <ui:insert name="content"/> </div> <div class="menuRight"> <ui:insert name="menuRight"> <ui:include src="/sections/shared/sourceViewer.xhtml"/> </ui:insert> </div> </div> </h:body> </html> Khuôn mẫu trong Liệt kê 1 cung cấp cơ sở hạ tầng sau đây cho tất cả các khung nhìn của ứng dụng:  Các thẻ HTML <head>, <body> và <title>  Một tiêu đề (title) mặc định (có thể bị ghi đè bởi các cấu kiện sử dụng khuôn mẫu).  Một bảng định kiểu CSS.
  • 6.  Một số tiện ích JavaScript.  Một cách bố trí dưới dạng các <div> và các lớp CSS tương ứng.  Nội dung mặc định cho phần đầu (head) (có thể bị ghi đè).  Nội dung mặc định cho trình đơn bên phải (có thể bị ghi đè). Như Liệt kê 1 minh họa, các khuôn mẫu chèn nội dung vào trong cách bố trí của chúng bằng thẻ <ui:insert>. Nếu bạn quy định một phần thân cho một thẻ <ui:insert>, như tôi đã thực hiện đối với tiêu đề cửa sổ, phần đầu và trình đơn bên phải trong Liệt kê 1, JSF sử dụng phần thân của thẻ như nội dung mặc định. Các cấu kiện sử dụng khuôn mẫu có thể định nghĩa nội dung hoặc ghi đè lên nội dung mặc định bằng thẻ <ui:define>, như đã chứng tỏ trong Liệt kê 2, hiển thị tài liệu đánh dấu siêu văn bản của khung nhìn đăng nhập: Liệt kê 2. Khung nhìn đăng nhập <ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" template="/templates/masterLayout.xhtml"> <ui:define name="menuLeft"> <ui:include src="/sections/login/menuLeft.xhtml"/> </ui:define> <ui:define name="content"> <ui:include src="/sections/login/content.xhtml"/> </ui:define> </ui:composition> Khung nhìn đăng nhập sử dụng nội dung mặc định của khuôn mẫu cho tiêu đề cửa sổ, phần đầu và trình đơn bên phải. Nó chỉ định nghĩa chức năng cụ thể riêng cho khung nhìn đăng nhập: phần nội dung và trình đơn bên trái. Bằng cách cung cấp một thẻ <ui:define> cho tiêu đề cửa sổ, phần đầu hoặc trình đơn bên phải, tôi có thể đã ghi đè nội dung mặc định do khuôn mẫu định nghĩa. Ví dụ, Liệt kê 3 cho thấy khung nhìn xem mã nguồn (hình ảnh ở giữa trong Hình 1): Liệt kê 3. Khung nhìn xem-mã nguồn <ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" template="/templates/masterLayout.xhtml"> <ui:define name="content"> <ui:include src="/sections/showSource/content.xhtml"/> </ui:define> <ui:define name="menuLeft"> <ui:include src="/sections/showSource/menuLeft.xhtml"/> </ui:define> <ui:define name="menuRight">
  • 7. <ui:include src="/sections/showSource/menuRight.xhtml"/> </ui:define> </ui:composition> Khung nhìn-xem mã nguồn định nghĩa nội dung cho phần nội dung và cho trình đơn bên phải. Nó cũng ghi đè nội dung mặc định, được khuôn mẫu định nghĩa trong Liệt kê 1, cho trình đơn bên trái. Liệt kê 4 cho thấy khung nhìn các địa điểm (hình dưới cùng trong Hình 1): Liệt kê 4. Khung nhìn các địa điểm <ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" template="/templates/masterLayout.xhtml"> <ui:define name="menuLeft"> <ui:include src="/sections/places/menuLeft.xhtml"/> </ui:define> <ui:define name="content"> <ui:include src="/sections/places/content.xhtml"/> </ui:define> </ui:composition> Tạo khuôn mẫu JSF 2 Khái niệm phía sau tạo khuôn mẫu là đơn giản. Bạn định nghĩa chỉ một khuôn mẫu bao gói các chức năng phổ biến trong nhiều khung nhìn. Mỗi khung nhìn bao gồm một cấu kiện và một khuôn mẫu. Khi JSF tạo một khung nhìn, nó nạp khuôn mẫu của cấu kiện và sau đó chèn nội dung được định nghĩa bởi cấu kiện đó vào khuôn mẫu đó. Chú ý các nét giống nhau trong các Liệt kê 2, 3 và 4. Cả ba khung nhìn xác định rõ khuôn mẫu của chúng và định nghĩa nội dung. Cũng để ý việc tạo các khung nhìn mới dễ dàng như thế nào, bởi vì hầu hết cơ sở hạ tầng của khung nhìn được bao gói trong một khuôn mẫu và các tệp bao gồm thêm. Một khía cạnh thú vị khác khi sử dụng tạo khuôn mẫu JSF là các khung nhìn giống như các khung nhìn trong các Liệt kê 2, 3 và 4 không thay đổi nhiều theo thời gian, vì vậy một phần đáng kể của mã khung nhìn của bạn về cơ bản không yêu cầu phải bảo trì. Cũng giống như các khung nhìn có sử dụng chúng, các khuôn mẫu cũng có xu hướng rất ít thay đổi. Và vì bạn đã bao gói rất nhiều chức năng phổ biến như vậy vào trong các mã lệnh hầu như không cần bảo trì, bạn có thể tập trung vào nội dung thực tế của khung nhìn của bạn — những gì diễn ra trong trình đơn bên trái của trang đăng nhập
  • 8. chẳng hạn. Việc tập trung vào nội dung thực tế của khung nhìn của bạn là tất cả những gì mà lời khuyên tiếp theo bàn đến. Về đầu trang Lời khuyên 2: Hãy dùng cách hợp thành Không lâu sau khi bản GUI CAD/CAM của tôi đã được phát hành, tôi đã dành một vài tháng tiếp tục làm việc với một nhà phát triển có tên là Bob, trong một dự án không có liên quan gì. Chúng tôi đã làm việc trên cơ sở mã của Bob và chúng tôi đã có thể thay đổi và sửa lỗi dễ dàng đến không ngờ. Tôi sớm đã nhận ra rằng chỉ có một sự khác biệt lớn nhất giữa mã của Bob và của tôi là ông đã viết các phương thức rất nhỏ— thường là từ 5 đến 15 dòng mã — và toàn bộ hệ thống của ông đã được lắp ráp với nhau từ các phương thức rất nhỏ đó. Trong khi mà tôi đánh vật để sửa đổi các phương thức dài, làm nhiều việc trong dự án trước đây của tôi, Bob nhanh nhẹn phối hợp các phương thức nhỏ với chức năng nguyên tử (atomic - không chia nhỏ được nữa). Sự khác biệt trong khả năng bảo trì và mở rộng được giữa mã của Bob và của tôi giống như so sánh đêm với ngày và từ đó trở đi, các phương thức rất nhỏ đã thuyết phục tôi. Cả Bob lẫn tôi vào lúc đó đều chưa biết, nhưng chúng tôi đã sử dụng một mẫu thiết kế từ Smalltalk có tên là Phương thức hợp thành (Composed Method) (xem Tài nguyên): Hãy chia phầnmềm của bạnthành các phương thức thực hiệnmột nhiệm vụ có thể nhậnbiết được, ở chỉ một mức trừu tượng. Những lợi ích của việc sử dụng mẫu hình Phương thức hợp thành là có tài liệu hướng dẫn tốt. (Xem "Kiến trúc tiến hóa và thiết kế nổi dần: Phương thức hợp thành và SLAP" của Neal Ford với các giải thích chi tiết tuyệt vời). Ở đây, tôi sẽ tập trung vào cách bạn có thể sử dụng mẫu hình Phương thức hợp thành với các khung nhìn JSF của bạn như thế nào. JSF 2 khuyến khích bạn hợp thành khung nhìn của mình từ các mảnh khung nhìn nhỏ hơn. Việc tạo khuôn mẫu bao gói các chức năng chung, do đó chia các khung nhìn của bạn thành các mảnh nhỏ hơn. JSF 2 cũng cung cấp một thẻ <ui:include>, như tôi đã giải thích trong các liệt kê trước, cho phép bạn tiếp tục chia nhỏ hơn nữa các khung nhìn của mình thành mảnh chức năng nhỏ hơn. Ví dụ, Hình 2 cho thấy trình đơn bên trái của trang đăng nhập của ứng các địa điểm: Hình 2. Trình đơn bên trái của trang đăng nhập
  • 9. Và Liệt kê 5 cho thấy tệp định nghĩa nội dung của trình đơn đó: Liệt kê 5. Triển khai thực hiện của trình đơn bên trái của khung nhìn đăng nhập <ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets"> <div class="menuLeftText"> #{msgs.welcomeGreeting} <div class="welcomeImage"> <h:graphicImage library="images" name="cloudy.gif"/> </div> </div> </html> Tài liệu đánh dấu siêu văn bản trong Liệt kê 5 là đơn giản, làm cho tệp dễ đọc, dễ hiểu, dễ duy trì và mở rộng. Nếu cũng những mã này được nhồi nhét vào trong chỉ một trang XHTML dài có chứa tất cả mọi thứ cần thiết để thực hiện khung nhìn đăng nhập, thì sẽ rất nặng nề khi thay đổi. Hình 3 cho thấy trình đơn bên trái của khung nhìn các địa điểm: Hình 3. Trình đơn bên trái của khung nhìn các địa điểm Triển khai thực hiện của trình đơn bên trái của khung nhìn các địa điểm được hiển thị trong Liệt kê 6. Liệt kê 6. Thực hiện trình đơn bên trái của khung nhìn các địa điểm <ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:util="http://java.sun.com/jsf/composite/components/util">
  • 10. <div class="placesSearchForm"> <div class="placesSearchFormHeading"> #{msgs.findAPlace} </div> <h:form prependId="false"> <h:panelGrid columns="2"> #{msgs.streetAddress} <h:inputText value="#{place.streetAddress}" size="15"/> #{msgs.city} <h:inputText value="#{place.city}" size="10"/> #{msgs.state} <h:inputText value="#{place.state}" size="3"/> #{msgs.zip} <h:inputText value="#{place.zip}" size="5"/> <h:commandButton value="#{msgs.goButtonText}" style="font-family:Palatino;font-style:italic" action="#{place.fetch}"/> </h:panelGrid> </h:form> </div> <util:icon image="#{resource['images:back.jpg']}" actionMethod="#{places.logout}" style="border: thin solid lightBlue"/> </ui:composition> Liệt kê 6 Liệt kê 6 thực hiện một biểu mẫu và nó sử dụng một thành phần biểu tượng. (Tôi sẽ thảo luận thành phần biểu tượng đó trong mụcThành phần biểu tượng (The icon component), ngay sau đây. Tạm thời bây giờ, chỉ cần biết rằng tác giả của trang có thể kết hợp một hình ảnh và một phương thức một với một biểu tượng). Hình ảnh cho biểu tượng đăng xuất được hiển thị ở dưới cùng của Hình 3 và phương thức của biểu tượng đăng xuất —places.logout()— được hiển thị trong Liệt kê 7: Liệt kê 7. Phương thức Places.logout() package com.clarity; ... @ManagedBean() @SessionScoped public class Places { private ArrayList<Place> places = null; ... private static SelectItem[] zoomLevelItems = { ... public String logout() { FacesContext fc = FacesContext.getCurrentInstance(); ELResolver elResolver = fc.getApplication().getELResolver(); User user = (User)elResolver.getValue( fc.getELContext(), null, "user");
  • 11. user.setName(""); user.setPassword(""); setPlacesList(null); return "login"; } } Đối với tôi, Liệt kê 6 — phần mã thực hiện trình đơn bên trái của khung nhìn các địa điểm — đang đến gần ngưỡng quá nhiều mã với khoảng 30 dòng lệnh ngôn ngữ đánh dấu. Liệt kê này hơi khó đọc và có hai thứ trong đoạn mã đó có thể được cấu trúc lại thành các tệp riêng của chúng: biểu mẫu và biểu tượng. Liệt kê 8 cho thấy phiên bản cấu trúc lại của Liệt kê 6 gói biểu mẫu và biểu tượng trong các tệp XHTML riêng của chúng: Liệt kê 8. Cấu trúc lại trình đơn bên trái của khung nhìn các địa điểm <ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets"> <div class="placesSearchForm"> <div class="placesSearchFormHeading"> #{msgs.findAPlace} </div> <ui:include src="addressForm.xhtml"> <ui:include src="logoutIcon.xhtml"> </div> </ui:composition> Liệt kê 9 cho thấy tệp addressForm.xhtml: Liệt kê 9. addressForm.xhtml <ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets"> <h:form prependId="false"> <h:panelGrid columns="2"> #{msgs.streetAddress} <h:inputText value="#{place.streetAddress}" size="15"/> #{msgs.city} <h:inputText value="#{place.city}" size="10"/> #{msgs.state} <h:inputText value="#{place.state}" size="3"/> #{msgs.zip} <h:inputText value="#{place.zip}" size="5"/> <h:commandButton value="#{msgs.goButtonText}" style="font-family:Palatino;font-style:italic" action="#{place.fetch}"/> </h:panelGrid> </h:form>
  • 12. </ui:composition> Liệt kê 10 cho thấy tệp logoutIcon.xhtml: Liệt kê 10. logoutIcon.xhtml <ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:util="http://java.sun.com/jsf/composite/components/util"> <util:icon image="#{resource['images:back.jpg']}" actionMethod="#{places.logout}" style="border: thin solid lightBlue"/> </ui:composition> Khi bạn hợp thành các khung nhìn của bạn từ nhiều tệp nhỏ, bạn được hưởng các lợi ích của mẫu hình Phương thức hợp thành của Smalltalk. Bạn cũng có thể tổ chức các tệp của bạn làm cho nó dễ dàng phản ứng hơn nữa với các thay đổi. Ví dụ, Hình 4 cho thấy các tệp, tạo thành ba khung nhìn trong ứng dụng các địa điểm: Hình 4. Khung nhìn của ứng dụng các địa điểm Ba thư mục mà tôi đã tạo — views (các khung nhìn), sections (các phần) và templates (các khuôn mẫu) — có chứa hầu hết các tệp XHTML được sử dụng để triển khai thực hiện các khung nhìn của ứng dụng các địa điểm. Bởi vì các tệp trong các thư mục views và templates hiếm khi thay đổi, nên tôi có thể tập trung vào thư mục sections.
  • 13. Nếu tôi muốn thay đổi biểu tượng trong trình đơn bên trái của trang đăng nhập, ví dụ thế, tôi biết chính xác cần đi tới đâu: sections/login/menuLeft.xhtml. Bạn có thể sử dụng bất kỳ cấu trúc thư mục nào bạn muốn để tổ chức các tệp XHTML của bạn. Một cấu trúc hợp lý giúp cho dễ dàng xác định vị trí mã mà bạn cần phải sửa đổi hơn. Bên cạnh việc giữ vững nguyên tắc DRY và việc sử dụng mẫu hình Phương thức hợp thành, việc bao gói các chức năng trong các thành phần tùy chỉnh cũng là một ý tưởng tốt. Các thành phần là một cơ chế tái sử dụng mạnh mẽ và bạn nên tận dụng lợi thế của sức mạnh đó. Không giống như JSF 1, JSF 2 giúp bạn dễ dàng triển khai thực hiện các thành phần tùy chỉnh. Về đầu trang Lời khuyên 3: Hãy nghĩ theo kiểu LEGO Khi còn là một cậu bé, tôi đã có hai đồ chơi ưa thích: một bộ hóa học và bộ LEGO. Cả hai đều cho tôi tạo ra nhiều thứ bằng cách kết hợp các khối xây dựng cơ bản, điều mà đã trở thành một niềm đam mê suốt đời dưới cái vỏ phát triển phần mềm. Sức mạnh của JSF đã luôn ở trong mô hình thành phần của nó, nhưng sức mạnh đó cho đến nay đã không được nhận biết hoàn toàn vì rất khó để triển khai thực hiện các thành phần tùy chỉnh với JSF 1. Bạn phải viết mã Java, chỉ rõ cấu hình XML và có một sự hiểu biết tốt về vòng đời của JSF. Với JSF 2, bạn có thể triển khai thực hiện các thành phần tùy chỉnh:  Không cần cấu hình nào, XML hay cáchnào khác.  Không có mã Java.  Các nhà phát triển có thể gắn chức năng cho nó.  Và triển khai nóng khi được sửa đổi. Phần còn lại của bài viết này, tôi sẽ hướng dẫn bạn thông qua việc thực hiện ba thành phần tùy chỉnh cho ứng dụng các địa điểm: một biểu tượng, một ô đăng nhập và một ô để hiển thị bản đồ và thông tin thời tiết của một địa chỉ. Nhưng trước tiên, tôi sẽ cho bạn một tổng quan về các thành phần phức hợp của JSF 2. Thực hiện các thành phần tùy chỉnh JSF 2 phối hợp việc tạo khuôn mẫu Facelets (Facelets templating), xử lý tài nguyên (đã thảo luận trong Phần 1) và một quy ước đặt tên đơn giản để triển khai thực hiện các thành phần phức hợp. Các thành phần phức hợp, như tên gọi cho thấy, cho phép bạn hợp thành một thành phần từ các thành phần hiện có.
  • 14. Bạn thực hiện các thành phần phức hợp bằng XHTML ở một nơi nào đó trong thư mục tài nguyên và liên kết chúng, thuần túy theo quy ước, tới một vùng tên và một thẻ. Hình 5 cho thấy tôi đã tổ chức các thành phần phức hợp cho ứng dụng các địa điểm như thế nào: Hình 5. Các thành phần của ứng dụng các địa điểm Để sử dụng các thành phần phức hợp, bạn khai báo một vùng tên và sử dụng các thẻ. Các vùng tên luôn luôn làhttp://java.sun.com/jsf/composite cộng với tên của thư mục trong đó có chứa các thành phần, dưới thư mục tài nguyên. Tên của chính thành phần là tên của tệp XHTML của nó, không có phần mở rộng .xhtml. Quy ước này tránh được sự cần thiết phải có bất kỳ cấu hình nào. Ví dụ, để sử dụng thành phần login (đăng nhập) trong ứng dụng các địa điểm, bạn sẽ làm như sau: <html xmlns="http://www.w3.org/1999/xhtml" ... xmlns:util="http://java.sun.com/jsf/composite/component/util"> ... <util:login.../> ... <html> Và để sử dụng thành phần icon (biểu tượng), bạn sẽ làm thế này: <html xmlns="http://www.w3.org/1999/xhtml" ... xmlns:util="http://java.sun.com/jsf/composite/components/util"> ... <util:icon.../> ... <html> Cuối cùng, bạn sử dụng thành phần địa điểm như thế này: <html xmlns="http://www.w3.org/1999/xhtml" ... xmlns:util="http://java.sun.com/jsf/composite/components/places"> ... <places:place.../> ... <html> Thành phần icon: Một phần phức hợp đơn giản
  • 15. Ứng dụng các địa điểm sử dụng hai biểu tượng được hiển thị trong Hình 6: Hình 6. Các biểu tượng trong ứng dụng các địa điểm Mỗi biểu tượng là một đường liên kết. Khi người dùng nhấn vào biểu tượng bên trái trong Hình 6, JSF sẽ hiển thị tài liệu đánh dấu siêu văn bản của khung nhìn hiện tại, trong khi đó, nếu kích hoạt vào biểu tượng bên phải sẽ đăng xuất người sử dụng thoát khỏi ứng dụng. Bạn có thể chỉ định một tên lớp (className) CSS và một hình ảnh cho các đường liên kết và bạn cũng có thể đính kèm các phương thức tới các đường liên kết. JSF gọi các phương thức đó khi người dùng nhấn vào một đường liên kết gắn với nó. Liệt kê 11 cho thấy thành phần icon được sử dụng trong ứng dụng các địa điểm để hiển thị tài liệu đánh dấu siêu văn bản như thế nào: Liệt kê 11. Sử dụng thành phần icon để hiển thị tài liệu đánh dấu siêu văn bản <html xmlns="http://www.w3.org/1999/xhtml" xmlns:util="http://java.sun.com/jsf/composite/components/util"> <util:icon actionMethod="#{sourceViewer.showSource}" image="#{resource['images:disk-icon.jpg']}"/> ... </html> Liệt kê 12 cho thấy thành phần icon được sử dụng để đăng xuất như thế nào: Liệt kê 12. Sử dụng thành phần icon để đăng xuất <html xmlns="http://www.w3.org/1999/xhtml" xmlns:util="http://java.sun.com/jsf/composite/components/util"> <util:icon actionMethod="#{places.logout}" image="#{resource['images:back-arrow.jpg']}"/> ... </html> Liệt kê 13 cho thấy mã cho thành phần icon: Liệt kê 13. Thành phần icon <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:composite="http://java.sun.com/jsf/composite"> <!-- INTERFACE --> <composite:interface> <composite:attribute name="image"/> <composite:attribute name="actionMethod" method-signature="java.lang.String action()"/> </composite:interface> <!-- IMPLEMENTATION --> <composite:implementation>
  • 16. <h:form> <h:commandLink action="#{cc.attrs.actionMethod}" immediate="true"> <h:graphicImage value="#{cc.attrs.image}" styleClass="icon"/> </h:commandLink> </h:form> </composite:implementation> </html> Giống như tất cả các thành phần phức hợp, thành phần icon trong Liệt kê 13 có hai phần: <composite:interface> và<composite:implementation>. Phần <composite:interface> định nghĩa một giao diện mà bạn có thể sử dụng để cấu hình thành phần đó. Thành phần icon có hai thuộc tính: image (hình ảnh), định nghĩa thành phần trông như thế nào và actionMethod, xác định nó hoạt động như thế nào. Phần <composite:implementation> chứa triển khai thực hiện của thành phần. Nó dùng biểu thức #{cc.attrs.ATTRIBUTE_NAME} để truy cập vào các thuộc tính được định nghĩa trong giao diện của thành phần. (cc, là một từ khóa dành riêng trong ngôn ngữ biểu thức của JSF 2, viết tắt của composite component - thành phần phức hợp.) Chú ý là thành phần icon trong Liệt kê 13 chỉ rõ một lớp CSS cho hình ảnh của nó bằng thuộc tính styleClass của <h:graphicImage>. Tên của lớp CSS này được mã cố định là icon, vì vậy bạn chỉ có thể chỉ định một lớp CSS với tên đó và JSF sẽ sử dụng lớp đó cho tất cả các biểu tượng trong một ứng dụng. Nhưng sẽ thế nào nếu bạn muốn ghi đè lên tên lớp CSS đó? Trong trường hợp này, tôi có thể thêm thuộc tính khác cho tên lớp CSS và cung cấp một mặc định sẽ được JSF sử dụng khi thuộc tính này không được chỉ rõ. Liệt kê 14 cho thấy thuộc tính đó sẽ trông giống như thế nào: Liệt kê 14. Thành phần icon, được cấu trúc lại <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" <html xmlns="http://www.w3.org/1999/xhtml" ... xmlns:composite="http://java.sun.com/jsf/composite"> <composite:interface> ... <composite:attribute name="styleClass" default="icon" required="false"/> ... </composite:interface> <composite:implementation> ... <h:graphicImage value="#{cc.attrs.image}" styleClass="#{cc.attrs.styleClass}"/> ... </composite:implementation> </html>
  • 17. Trong Liệt kê 14, tôi đã thêm một thuộc tính cho giao diện của thành phần icon có tên là styleClass và tham chiếu thuộc tính đó trong khi thực hiện của thành phần. Với sự thay đổi này, bây giờ bạn có thể chỉ định một lớp CSS tùy chọn cho hình ảnh của biểu tượng, như sau: <util:icon actionMethod="#{places.logout}" image="#{resource['images:back-arrow.jpg']}" styleClass="customIconClass"/> Nếu bạn không chỉ rõ thuộc tính styleClass, JSF sẽ sử dụng giá trị mặc định, đó là icon. Thành phần login (đăng nhập): Một thành phần cấu hình được đầy đủ Với JSF 2, bạn có thể triển khai thực hiện các thành phần phức hợp cấu hình được đầy đủ. Ví dụ, ứng dụng các địa điểm có chứa một thành phần login, thể hiện trong Hình 7: Hình 7. Thành phần login của ứng dụng các địa điểm Liệt kê 15 cho thấy ứng dụng các địa điểm sử dụng thành phần login như thế nào: Liệt kê 15. Sử dụng thành phần login <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" ... xmlns:comp="http://java.sun.com/jsf/composite/component/util"> <util:login loginPrompt="#{msgs.loginPrompt}" namePrompt="#{msgs.namePrompt}" passwordPrompt="#{msgs.passwordPrompt}" loginAction="#{user.login}" loginButtonText="#{msgs.loginButtonText}" managedBean="#{user}"> <f:actionListener for="loginButton" type="com.clarity.LoginActionListener"/> </util:login> ... </html>
  • 18. Liệt kê 15 không chỉ tham số hóa các thuộc tính của thành phần login, chẳng hạn như nhắc tên và mật khẩu, mà nó còn gắn một trình lắng nghe hành động vào nút Log In (đăng nhập) của thành phần. Nút đó được giao diện của thành phần login trưng ra, như hiển thị trong Liệt kê 16: Liệt kê 16. Thành phần login <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:composite="http://java.sun.com/jsf/composite"> <!-- INTERFACE --> <composite:interface> <composite:actionSource name="loginButton" targets="form:loginButton"/> <composite:attribute name="loginButtonText" default="Log In" required="true"/> <composite:attribute name="loginPrompt"/> <composite:attribute name="namePrompt"/> <composite:attribute name="passwordPrompt"/> <composite:attribute name="loginAction" method-signature="java.lang.String action()"/> <composite:attribute name="managedBean"/> </composite:interface> <!-- IMPLEMENTATION --> <composite:implementation> <h:form id="form" prependId="false"> <div class="prompt"> #{cc.attrs.loginPrompt} </div> <panelGrid columns="2"> #{cc.attrs.namePrompt} <h:inputText id="name" value="#{cc.attrs.managedBean.name}"/> #{cc.attrs.passwordPrompt} <h:inputSecret id="password" value="#{cc.attrs.managedBean.password}" /> </panelGrid> <p> <h:commandButton id="loginButton" value="#{cc.attrs.loginButtonText}" action="#{cc.attrs.loginAction}"/> </p> </h:form> <div class="error" style="padding-top:10px;"> <h:messages layout="table"/> </div> </composite:implementation>
  • 19. </html> Trong giao diện của thành phần login, tôi đã trưng ra nút Log In dưới tên loginButton. Tên đó nhằm vào nút Log In nằm trong biểu mẫu có tên là form, do đó giá trị của thuộc tính targets là: form:loginButton. Trình lắng nghe hành động được kết hợp với nút Log In trong Liệt kê 16 như thấy trong Liệt kê 17: Liệt kê 17. Trình nghe hành động của nút Log in package com.clarity; import javax.faces.event.AbortProcessingException; import javax.faces.event.ActionEvent; import javax.faces.event.ActionListener; public class LoginActionListener implements ActionListener { public void processAction(ActionEvent e) throws AbortProcessingException { System.out.println("logging in ..........."); } } Trình nghe hành động trong Liệt kê 17 chỉ dành cho mục đích minh họa — khi người sử dụng đăng nhập, tôi chỉ đơn giản viết lại thông báo vào tệp log của thùng chứa servlet. Nhưng bạn hiểu được ý tưởng: Với JSF 2, bạn có thể triển khai thực hiện các thành phần cấu hình được đầy đủ và bạn có thể gắn chức năng cho các thành phần đó, tất cả mà không có một dòng mã Java hoặc cấu hình XML. Đó là một vài miếng võ mạnh (N.D: fu - tạm dịch là miếng võ – tác giả mượn từ gốc tiếng Hán, dùng với nghĩa trong từ Kung Fu). Thành phần place (địa điểm): Lồng các thành phần phức hợp vào nhau JSF 2 cho phép bạn thực hiện các thành phần cấu hình được đầy đủ mà không có bất kỳ mã Java hoặc cấu hình nào. Bạn cũng có thể lồng các thành phần phức hợp vào nhau, cho phép bạn chia cắt các thành phần phức hợp thành các mảnh nhỏ hơn, dễ dùng hơn. Ví dụ, Hình 8 cho thấy thành phần place, hiển thị một bản đồ và thông tin thời tiết của một địa chỉ đã cho: Hình 8. Thành phần place của ứng dụng các địa điểm
  • 20. Liệt kê 18 cho thấy ứng dụng các địa điểm sử dụng thành phần place như thế nào: Liệt kê 18. Sử dụng thành phần place <ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:places="http://java.sun.com/jsf/composite/components/places"> <h:form id="form">
  • 21. <ui:repeat value="#{places.placesList}" var="place"> <places:place location="#{place}"/> </ui:repeat> </h:form> </ui:composition> Mã cho thành phần place được hiển thị trong Liệt kê 19: Liệt kê 19. Thành phần place <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:composite="http://java.sun.com/jsf/composite" xmlns:places="http://java.sun.com/jsf/composite/components/places"> <!-- INTERFACE --> <composite:interface> <composite:attribute name="location" required="true"/> </composite:interface> <!-- IMPLEMENTATION --> <composite:implementation> <div class="placeHeading"> <places:map title="Map"/> <places:weather title="Weather"/> </div> </composite:implementation> </html> Trong Liệt kê 19, thành phần place sử dụng hai thành phần lồng nhau: <places:map> và <places:weather>. Liệt kê 20 cho thấy thành phần map (bản đồ): Liệt kê 20. Thành phần map <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:composite="http://java.sun.com/jsf/composite"> <!-- INTERFACE --> <composite:interface> <composite:attribute name="title"/> </composite:interface> <!-- IMPLEMENTATION --> <composite:implementation> <div class="map"> <div style="padding-bottom: 10px;"> <h:outputText value="#{cc.attrs.title}" style="color: blue"/> </div>
  • 22. <h:panelGrid columns="1"> <h:panelGroup> <div style="padding-left: 5px;"> <i> <h:outputText value="#{cc.parent.attrs.location.streetAddress}, "/> </i> <h:outputText value=" #{cc.parent.attrs.location.city}" /> <h:outputText value="#{cc.parent.attrs.location.state}"/><hr/> </div> </h:panelGroup> <h:panelGrid columns="2"> <div style="padding-right: 10px;margin-bottom: 10px;font-size:14px"> #{msgs.zoomPrompt} </div> <h:selectOneMenu onchange="submit()" value="#{cc.parent.attrs.location.zoomIndex}" valueChangeListener="#{cc.parent.attrs.location.zoomChanged}" style="font-size:13px;font-family:Palatino"> <f:selectItems value="#{cc.parent.attrs.location.zoomLevelItems}"/> </h:selectOneMenu> </h:panelGrid> <h:graphicImage url="#{cc.parent.attrs.location.mapUrl}" style="border: thin solid gray"/> </h:panelGrid> </div> </composite:implementation> </html> Cấu trúc lại thành phần phức hợp Liệt kê 20 — tài liệu đánh dấu siêu văn bản của thành phần map— hơi dài một chút theo khẩu vị của tôi. Nhìn thoáng qua lần đầu, nó hơi khó hiểu và sự phức tạp của nó có thể gây ra các vấn đề về sau này. Bạn có thể dễ dàng cấu trúc lại Liệt kê 20 thành nhiều tệp dễ quản lý hơn, như tôi đã làm ở trên khi tôi cấu trúc lại trình đơn bên trái của khung nhìn các địa điểm trong các Liệt kê 8, 9 và 10. Trong trường hợp này, tôi sẽ dành lại việc tái cấu trúc như là một bài tập cho bạn. Hãy chú ý việc sử dụng biểu thức #{cc.parent.attrs.location.ATTRIBUTE_NAME}trong Liệt kê 20. Bạn có thể sử dụng một thuộc tính parent (cha mẹ) của thành phần phức hợp để truy cập các thuộc tính của thành phần cha mẹ, tạo thuận lợi lớn cho việc lồng nhau của các thành phần.
  • 23. Nhưng bạn không cần hoàn toàn dựa vào các thuộc tính cha mẹ trong các thành phần lồng nhau. Như tôi đã làm trong thành phần place trong Liệt kê 19, bạn có thể vượt qua các thuộc tính, chẳng hạn như tiêu đề của bản đồ, từ một thành phần cha mẹ tới thành phần lồng nhau của nó, cũng giống như bạn sẽ vượt qua các thuộc tính đến bất kỳ thành phần khác nào, có lồng nhau hay không. Nó có hơi giảm một chút, nhưng Liệt kê 21 cho thấy thành phần weather (thời tiết): Liệt kê 21. Thành phần weather <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:composite="http://java.sun.com/jsf/composite"> <!-- INTERFACE --> <composite:interface> <composite:attribute name="title"/> </composite:interface> <!-- IMPLEMENTATION --> <composite:implementation> <div class="weather"> <div style="padding-bottom: 10px;"> <h:outputText value="#{cc.attrs.title}" style="color: blue"/> </div> <div style="margin-top: 10px;width:250px;"> <h:outputText style="font-size: 12px;" value="#{cc.parent.attrs.location.weather}" escape="false"/> </div> </div> </composite:implementation> </html> Thành phần weather, giống như thành phần map, sử dụng cả một thuộc tính thành phần cha mẹ (weather HTML từ dịch vụ Web thời tiết) và một thuộc tính thành phần cụ thể (tiêu đề). (Xem Phần 1 để thấy ứng dụng nhận được bản đồ và thông tin thời tiết với một địa điểm cụ thể như thế nào). Vì vậy, khi bạn thực hiện các thành phần lồng nhau, bạn có một sự lựa chọn. Bạn có thể để cho thành phần lồng nhau dựa vào các thuộc tính của thành phần cha mẹ của nó hoặc bạn có thể yêu cầu thành phần cha mẹ chuyển qua các thuộc tính rõ ràng đến thành phần lồng nhau. Ví dụ, thành phần place trong Liệt kê 19 rõ ràng vượt qua các thuộc tính tiêu đề đến các thành phần lồng nhau của nó, nhưng các thành phần lồng
  • 24. nhau dựa vào các thuộc tính của cha mẹ, chẳng hạn như URL bản đồ (map URL) và HTML thời tiết (weather HTML). Bạn chọn thực hiện các thuộc tính thành phần rõ ràng hoặc dựa vào các thuộc tính cha mẹ là một sự thỏa hiệp giữa việc kết nối và tiện lợi. Trong trường hợp này, các thành phần map và weather được kết nối chặt chẽ cùng với thành phần cha mẹ của chúng (thành phần place), vì chúng dựa vào các thuộc tính của thành phần cha mẹ. Tôi có thể đã tách rời các thành phần map và weather ra khỏi thành phần placebằng cách xác định tất cả các thuộc tính của thành phần map và weather như là thuộc tính rõ ràng. Nhưng trong trường hợp đó, tôi đã mất đi một số tiện nghi, vì thành phần place rõ ràng cần phải vượt qua tất cả các thuộc tính đến các thành phần map và weather. Về đầu trang Tiếp theo ... Trong bài này, tôi đã cho bạn thấy cách sử dụng JSF 2 UIS để triển khai thực hiện các UI dễ dàng để duy trì và mở rộng thông qua việc tạo khuôn mẫu và các thành phần phức hợp. Bài cuối cùng của loạt bài này sẽ chỉ cho bạn cách sử dụng JavaScript trong các thành phần phức hợp, làm thế nào để sử dụng mô hình sự kiện mới của JSF 2 và làm thế nào để tận dụng lợi thế của sự hỗ trợ có sẵn của JSF 2 cho Ajax.