text:
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.
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ến thức phải được biểu diễn duy 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">  <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"/>
 <ui:insert name="heading"> #{msgs.placesHeading} </ui:insert>

 <ui:insert name="menuLeft"/>

 <ui:insert name="content"/>

 <ui:insert name="menuRight"> <ui:include src="/sections/shared/sourceViewer.xhtml"/> </ui:insert>

 </h:body>
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
,
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

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>
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.
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ần mềm của bạn thành các phương thức thực hiện một nhiệm vụ có thể nhận biế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">
 #{msgs.welcomeGreeting}
 <h:graphicImage library="images" name="cloudy.gif"/>

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">

 #{msgs.findAPlace}
 <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>
 <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ục Thà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">

 #{msgs.findAPlace}
 <ui:include src="addressForm.xhtml"> <ui:include src="logoutIcon.xhtml">
 </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.
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ách nà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:
 ... <util:login.../> ...
Và để sử dụng thành phần
icon (biểu tượng), bạn sẽ làm thế
này:
 ... <util:icon.../> ...
Cuối cùng, bạn sử dụng thành phần địa điểm như thế này:
 ... <places:place.../> ...
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
 <util:icon actionMethod="#{sourceViewer.showSource}" image="#{resource['images:disk-icon.jpg']}"/> ...
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
 <util:icon actionMethod="#{places.logout}" image="#{resource['images:back-arrow.jpg']}"/> ...
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"   <composite:interface> <composite:attribute name="image"/> <composite:attribute name="actionMethod" method-signature="java.lang.String action()"/> </composite:interface>  <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>
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"  <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>
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">  <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> ...
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">   <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>  <composite:implementation> <h:form id="form" prependId="false">
 #{cc.attrs.loginPrompt}
 <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>
 <h:commandButton id="loginButton" value="#{cc.attrs.loginButtonText}" action="#{cc.attrs.loginAction}"/>
 </h:form>
 <h:messages layout="table"/>
 </composite:implementation>
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">   <composite:interface> <composite:attribute name="location" required="true"/> </composite:interface>  <composite:implementation>
 <places:map title="Map"/> <places:weather title="Weather"/>
 </composite:implementation>
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">   <composite:interface> <composite:attribute name="title"/> </composite:interface>  <composite:implementation>

 <h:outputText value="#{cc.attrs.title}" style="color: blue"/>
 <h:panelGrid columns="1"> <h:panelGroup>
  <h:outputText value="#{cc.parent.attrs.location.streetAddress}, "/>  <h:outputText value=" #{cc.parent.attrs.location.city}" /> <h:outputText value="#{cc.parent.attrs.location.state}"/>

 </h:panelGroup> <h:panelGrid columns="2">
 #{msgs.zoomPrompt}
 <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>
 </composite:implementation>
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">   <composite:interface> <composite:attribute name="title"/> </composite:interface>  <composite:implementation>

 <h:outputText value="#{cc.attrs.title}" style="color: blue"/>

 <h:outputText style="font-size: 12px;" value="#{cc.parent.attrs.location.weather}" escape="false"/>

 </composite:implementation>
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
place bằ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.
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.
Tải về
Tài nguyên
Học tập
- Trang chủ JSF: Tìm thêm tài nguyên về phát triển với JSF.
- "Facelets vừa như in với JSF" (Richard Hightower, developerWorks, 02.2006) và "Lập trình Facelets nâng cao" (Richard Hightower, developerWorks, 02006): Tìm hiểu thêm về các đặc tính của Facelets.
- Lập trình viên thực dụng (Andy Hunt and Dave Thomas, The Pragmatic Bookshelf, 2001): Hunt và Thomas đã giới thiệu nguyên tắc DRY trong cuốn sách này.
- Các mẫu hình thực tế tốt nhất của Smalltalk (Kent Beck, Prentice Hall, 1996): Tìm hiểu thêm về mẫu hình Phương thức phức hợp.
- Blog của Roger Kitain: Roger Kitain và Ed Burns cùng đứng đầu nhóm đặc tả cho JSF 2.0.
- Blog của Jim Driscoll: Bạn sẽ tìm thấy nhiều mục có liên quan đến JSF 2.
- Blog của Ryan Lubke: Ryan Lubke làm việc về triển khai thực hiện tham chiếu JSF 2.
- Vùng công nghệ Java của developerWorks: Tìm hàng trăm bài viết về mọi khía cạnh về lập trình Java.
Lấy sản phẩm và công nghệ
- JSF: Tải về JSF 2.0.
Thảo luận
- "Truy cập công khai đến các cuộc thảo luận JSF 2.0 JSR-314-EG hiện đã có sẵn" (Ed Burns's Blog, java.net, 03.2009): Tìm hiểu cách đăng ký vào danh sách gửi thư của nhóm chuyên gia JSF2.
- Xem các blog của developerWorks và dành tâm trí cho cộng đồng My developerWorks.
Bình luận
-
Vùng dữ liệu trên developerWorks
Khám phá các bài viết xoay quanh lĩnh vực dữ liệu, Quản lý hệ thống thông tin
-
Vùng mã nguồn mở trên developerWorks
Xem các bài viết về HTML, CSS, JavaScript,...
-
Điện toán đám mây
Tìm hiểu về điện toán đám mây

markdown:
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.
## 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](#resources)), nói rõ: Mỗi một mảnh kiến thức phải được biểu diễn duy 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](http://www.ibm.com/developerworks/vn/library/j-jsf2fu1/index.html), 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](http://www.ibm.com/developerworks/vn/library/j-jsf2fu1/index.html), 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
![ Khung nhìn ứng dụng các địa điểm: Đăng nhập, xem mã nguồn và các địa điểm](three-views-a.jpg)
![ ](three-views-b.jpg)
![ ](three-views-c.jpg)
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](#fig1):
##### 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">  <h:head> <title> <
ui:insertname="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"/>
 < ui:insertname="heading"> #{msgs.placesHeading} </ui:insert>

 < ui:insertname="menuLeft"/>

 < ui:insertname="content"/>

 < ui:insertname="menuRight"> <ui:include src="/sections/shared/sourceViewer.xhtml"/> </ui:insert>

 </h:body>
Khuôn mẫu trong
[Liệt kê 1](#listing1) 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
,
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

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](#listing1) 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](#listing1), 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:definename="menuLeft"> <ui:include src="/sections/login/menuLeft.xhtml"/> </ui:define> < ui:definename="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](#fig1)):
##### 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:definename="content"> <ui:include src="/sections/showSource/content.xhtml"/> </ui:define> < ui:definename=" menuLeft"> <ui:include src="/sections/showSource/menuLeft.xhtml"/> </ui:define> < ui:definename="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](#listing1), 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](#fig1)):
##### 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:definename="menuLeft"> <ui:include src="/sections/places/menuLeft.xhtml"/> </ui:define> < ui:definename="content"> <ui:include src="/sections/places/content.xhtml"/> </ui:define> </ui:composition>
Chú ý các nét giống nhau trong các Liệt kê
[2](#listing2), [3](#listing3) và [4](#listing4). 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](#listing2), [3](#listing3) và [4](#listing4) 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.
## 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](#resources)): Hãy chia phần mềm của bạn thành các phương thức thực hiện một nhiệm vụ có thể nhận biế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](http://www.ibm.com/developerworks/java/library/j-eaed4.html)" 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
![ Trình đơn bên trái của khung nhìn đăng nhập](places-login-left-menu.jpg)
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">
 #{msgs.welcomeGreeting}
 <h:graphicImage library="images" name="cloudy.gif"/>

Tài liệu đánh dấu siêu văn bản trong
[Liệt kê 5](#listing5) 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
![ Trình đơn bên trái của khung nhìn các địa điểm](places-menu-left.jpg)
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">

 #{msgs.findAPlace}
 <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>
 <util:icon
image="#{resource['images:back.jpg']}" actionMethod="#{places.logout}" style="border: thin solid lightBlue"/> </ui:composition> [Liệt kê 6](#listing6) 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ục [Thành phần biểu tượng](#simpleComposite) (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](#fig3) 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 ](#listing6)— 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](#listing7)
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">

 #{msgs.findAPlace}
 <ui:include src="
addressForm.xhtml"> <ui:include src=" logoutIcon.xhtml">
 </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
![ Các khung nhìn của ứng dụng các địa điểm](places-pages-and-compositions.jpg)
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.
## 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ách nà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](#templates)
(Facelets templating), xử lý tài nguyên (đã thảo luận trong [Phần 1](http://www.ibm.com/developerworks/vn/library/j-jsf2fu1/index.html)) 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
![ Các thành phần của ứng dụng các địa điểm](component-files.jpg)
Để 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:
 ... < util:login.../> ...
Và để sử dụng thành phần
icon (biểu tượng), bạn sẽ làm thế
này:
 ... < util:icon.../> ...
Cuối cùng, bạn sử dụng thành phần địa điểm như thế này:
 ... < places:place.../> ...
### 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
![ back arrow](back-arrow.jpg)
![ disk icon](disk-icon.jpg)
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](#fig6), 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
 <util:icon
actionMethod="#{ sourceViewer.showSource}" image="#{resource[' images:disk-icon.jpg']}"/> ...
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
 <util:icon
actionMethod="#{ places.logout}" image="#{resource['images: back-arrow.jpg']}"/> ...
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"   <
composite:interface> < composite:attributename="image"/> < composite:attributename="actionMethod" method-signature="java.lang.String action()"/> </composite:interface>  < 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>
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](#listing13) 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. để 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. (
*ATTRIBUTE_NAME*}
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](#listing13) 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"  <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>
Trong
[Liệt kê 14](#listing14), 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
![ Các thành phần login của ứng dụng địa điểm](login-component.jpg)
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">  < util:loginloginPrompt="#{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> ...  [Liệt kê 15](#listing15) 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">   <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>  <composite:implementation> <h:form id="form"prependId="false">
 #{cc.attrs.loginPrompt}
 <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>
 <h:commandButton id="loginButton"value="#{cc.attrs.loginButtonText}" action="#{cc.attrs.loginAction}"/>
 </h:form>
 <h:messages layout="table"/>
 </composite:implementation>
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](#listing16) 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](#listing17) 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
![ Thành phần place](place.jpg)
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">   <composite:interface> <composite:attribute name="location" required="true"/> </composite:interface>  <composite:implementation>
 <places:map title="Map"/> <places:weather title="Weather"/>
 </composite:implementation>
Trong
[Liệt kê 19](#listing19), 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">   <composite:interface>
<composite:attribute name="title"/></composite:interface>  <composite:implementation>

 <h:outputText value=" #{cc.attrs.title}" style="color: blue"/>
 <h:panelGrid columns="1"> <h:panelGroup>
  <h:outputText value="#{cc. parent.attrs.location.streetAddress}, "/>  <h:outputText value=" #{cc. parent.attrs.location.city}" /> <h:outputText value="#{cc. parent.attrs.location.state}"/>

 </h:panelGroup> <h:panelGrid columns="2">
 #{msgs.zoomPrompt}
 <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>
 </composite:implementation>
Hãy chú ý việc sử dụng biểu thức
#{cc.parent.attrs.location. trong
*ATTRIBUTE_NAME*} [Liệt kê 20](#listing20). 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](#listing19), 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">   <composite:interface>
<composite:attribute name="title"/></composite:interface>  <composite:implementation>

 <h:outputText value="#{cc.attrs.title}"style="color: blue"/>

 <h:outputText style="font-size: 12px;" value="#{cc. parent.attrs.location.weather}" escape="false"/>

 </composite:implementation>
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](http://www.ibm.com/developerworks/vn/library/j-jsf2fu1/index.html) để 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](#listing19) 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
place bằ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.
## 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.
## Tải về
|Mô tả||Tên||Kích thước|
|Source code for the examples|
## Tài nguyên
### Học tập
[Trang chủ JSF](https://javaserverfaces.dev.java.net/): Tìm thêm tài nguyên về phát triển với JSF.
- "
[Facelets vừa như in với JSF](http://www.ibm.com/developerworks/java/library/j-facelets/?S_TACT=105AGY75)" (Richard Hightower, developerWorks, 02.2006) và " [Lập trình Facelets nâng cao](http://www.ibm.com/developerworks/java/library/j-facelets2.html?S_TACT=105AGY75)" (Richard Hightower, developerWorks, 02006): Tìm hiểu thêm về các đặc tính của Facelets. [(Andy Hunt and Dave Thomas, The Pragmatic Bookshelf, 2001): Hunt và Thomas đã giới thiệu nguyên tắc DRY trong cuốn sách này.](http://www.pragprog.com/titles/tpp/the-pragmatic-programmer) *Lập trình viên thực dụng* [(Kent Beck, Prentice Hall, 1996): Tìm hiểu thêm về mẫu hình Phương thức phức hợp.](http://www.amazon.com/malltalk-Best-Practice-Patterns-Kent/dp/013476904X) *Các mẫu hình thực tế tốt nhất của Smalltalk* [Blog của Roger Kitain](http://weblogs.java.net/blog/rogerk/): Roger Kitain và Ed Burns cùng đứng đầu nhóm đặc tả cho JSF 2.0. [Blog của Jim Driscoll](http://weblogs.java.net/blog/driscoll/): Bạn sẽ tìm thấy nhiều mục có liên quan đến JSF 2. [Blog của Ryan Lubke](http://blogs.sun.com/rlubke): Ryan Lubke làm việc về triển khai thực hiện tham chiếu JSF 2. [Vùng công nghệ Java của developerWorks](http://www.ibm.com/developerworks/java?S_TACT=105AGY75): Tìm hàng trăm bài viết về mọi khía cạnh về lập trình Java.
### Lấy sản phẩm và công nghệ
[JSF](https://javaserverfaces.dev.java.net/servlets/ProjectDocumentList): Tải về JSF 2.0.
### Thảo luận
- "
[Truy cập công khai đến các cuộc thảo luận JSF 2.0 JSR-314-EG hiện đã có sẵn](http://weblogs.java.net/blog/edburns/archive/2009/03/response_to_a_c.html)" (Ed Burns's Blog, java.net, 03.2009): Tìm hiểu cách đăng ký vào danh sách gửi thư của nhóm chuyên gia JSF2.
- Xem các
[blog của developerWorks](http://www.ibm.com/developerworks/blogs/?S_TACT=105AGY75)và dành tâm trí cho [cộng đồng My developerWorks](http://www.ibm.com/developerworks/community?S_TACT=105AGY75).
## Bình luận
[Vùng dữ liệu trên developerWorks](http://www.ibm.com/developerworks/vn/views/data/libraryview.jsp)
Khám phá các bài viết xoay quanh lĩnh vực dữ liệu, Quản lý hệ thống thông tin
[Vùng mã nguồn mở trên developerWorks](http://www.ibm.com/developerworks/vn/views/opensource/libraryview.jsp)
Xem các bài viết về HTML, CSS, JavaScript,...
[Điện toán đám mây](http://www.ibm.com/developerworks/vn/views/cloud/libraryview.jsp)
Tìm hiểu về điện toán đám mây

Content-Type: text/html; charset=UTF-8

Content-Language: en-US

Cneonction: close

X-Pad: avoid browser bug

Vary: Accept-Encoding


text:
Giá: Liên hệ
Cây Tùng Mini - Mã số: CTU3832 do các nghệ nhân lành nghề tại làng nghề truyền thống Hải Minh ( huyện Hải Hậu, tỉnh Nam Định ) sản xuất và hoàn thiện.
Điện thoại liên hệ : 0918 653 838
E-mail : mnhm@mynghehaiminh.vn
Trân trọng cảm ơn và chúc quý khách PHÚ QÚY THỌ KHANG NINH !
CÔNG TY CỔ PHẦN MỸ NGHỆ HẢI MINH

markdown:
Giá: Liên hệ
Cây Tùng Mini - Mã số: CTU3832 do các nghệ nhân lành nghề tại làng nghề truyền thống Hải Minh ( huyện Hải Hậu, tỉnh Nam Định ) sản xuất và hoàn thiện.
** Điện thoại liên hệ : 0918 653 838** ** E-mail : mnhm@mynghehaiminh.vn
**
**Trân trọng cảm ơn và chúc quý khách PHÚ QÚY THỌ KHANG NINH !** **CÔNG TY CỔ PHẦN MỸ NGHỆ HẢI MINH**

WARC-Type: response

Content-Type: application/http; msgtype=response

WARC-Truncated: length

Content-Encoding: gzip

Connection: close

Content-Type: text/html; charset=utf-8

Cache-Control: private, no-cache, no-store, proxy-revalidate, no-transform

Pragma: no-cache


text:
+ Trả lời bài viết
Hiện kết quả từ 1 tới 5 của 5
-
18.10.2012 #1GAY VIỆT NAM
- Tham gia ngày
- 25.09.2011
- Bài gửi
- 2
Tìm người bú cu ở rạch giá, kiên Giang
mình là gay kín , muốn tìm 1 top,trai thẳng càng tốt để quan hệ kín đáo với điều kiện cao trên m7,da trắng sạch sẽ.Các bạn nếu thích chơi kín đáo có thể liên hệ với mình qua yahoo [email protected]
Chủ đề tương tự:
-
28.11.2012 #2phuoc_lee GAY
tim ban rach gia
co gj lien lac 0946 288 355
-
16.12.2012 #3CHƯA ĐĂNG KÝ GAY
:)
ban de sdt lai di minh se goi
-
22.12.2012 #4CHƯA ĐĂNG KÝ GAY
xuzu
Tim ban 26t k can dep trai.hag to la dc.chung thuy.sdt0984758627
-
14.08.2014 #5ChuaDangKyThanhVien GAY
hang 17cm dc ko 0919034421
Lời nhắn từ diễn đàn
Thread Information
Users Browsing this Thread
There are currently 1 users browsing this thread. (0 members and 1 guests)

markdown:
[+ Trả lời bài viết](traloi2014@.php?s=23391587d11f629a66be55adadbf2e12&p=770905&noquote=1)
Hiện kết quả từ 1 tới 5 của 5
-
18.10.2012
[#1](showthread.php?171685-Tìm-người-bú-cu-ở-rạch-giá-kiên-Giang&s=23391587d11f629a66be55adadbf2e12&p=506054#post506054)
GAY VIỆT NAM
- Tham gia ngày
- 25.09.2011
- Bài gửi
- 2
Tìm người bú cu ở rạch giá, kiên Giang
mình là gay kín , muốn tìm 1 top,trai thẳng càng tốt để quan hệ kín đáo với điều kiện cao trên m7,da trắng sạch sẽ.Các bạn nếu thích chơi kín đáo có thể liên hệ với mình qua yahoo
[[email protected]](/cdn-cgi/l/email-protection#701205130503051f1e171c111d300911181f1f5e131f1d)
Chủ đề tương tự:
-
28.11.2012
[#2](showthread.php?171685-Tìm-người-bú-cu-ở-rạch-giá-kiên-Giang&s=23391587d11f629a66be55adadbf2e12&p=526511#post526511)phuoc_lee GAY
tim ban rach gia
co gj lien lac 0946 288 355
-
16.12.2012
[#3](showthread.php?171685-Tìm-người-bú-cu-ở-rạch-giá-kiên-Giang&s=23391587d11f629a66be55adadbf2e12&p=540023#post540023)CHƯA ĐĂNG KÝ GAY
:)
ban de sdt lai di minh se goi
-
22.12.2012
[#4](showthread.php?171685-Tìm-người-bú-cu-ở-rạch-giá-kiên-Giang&s=23391587d11f629a66be55adadbf2e12&p=544327#post544327)CHƯA ĐĂNG KÝ GAY
xuzu
Tim ban 26t k can dep trai.hag to la dc.chung thuy.sdt0984758627
-
14.08.2014
[#5](showthread.php?171685-Tìm-người-bú-cu-ở-rạch-giá-kiên-Giang&s=23391587d11f629a66be55adadbf2e12&p=770905#post770905)ChuaDangKyThanhVien GAY
hang 17cm dc ko 0919034421
#### Lời nhắn từ diễn đàn
#### Thread Information
##### Users Browsing this Thread
There are currently 1 users browsing this thread. (0 members and 1 guests)
#### Khách tìm thấy bài viết này là nhờ những từ khóa sau:
## kien giang tim ban trai quan he,
**tim ban trai rạch gia quan he**, **tim ban quan he kin đao rạch gia**

Set-Cookie: bb_lastactivity=0; expires=Sat, 19-Sep-2015 13:49:50 GMT; path=/diendan/

Cache-Control: private

Pragma: private

Server: cloudflare-nginx


text:
Xem Phim Thiện Ác Quái
Bộ Phim Thiện Ác Quái – The Good The Bad The Weird
Ba chàng cao bồi điển trai của Hàn Quốc rượt đuổi nhau trên vùng sa mạc Mãn Châu (Manchuria – Đông bắc Trung Quốc) để tranh giành bản đồ kho báu.
Để có được những cảnh quay hoành tráng, đẹp mắt với những sa mạc hoang vu, những màn đọ súng ấn tượng, đoàn làm phim Thiện, Ác, Quái đã phải làm việc cật lực trong hai năm và quay tại nhiều nước: Hàn Quốc, Trung Quốc, Hong Kong, Mông Cổ, Nhật Bản, Prague (Cộng hòa Czech), Mỹ…
Bộ phim gay cấn ngay từ những phút đầu tiên với cảnh cướp bóc và đấu súng đẫm máu trên xe lửa. Những tên cướp khét tiếng vô tình gặp nhau tại đây, gây nên một vụ hỗn chiến. ‘Kẻ cướp xe lửa’ Yoon Tae Go đánh cắp được tấm bản đồ kho báu từ một thương gia Trung Quốc. Anh ta không ngờ rằng, vì tấm bản đồ này mà rất nhiều băng đảng sống chết rượt đuổi theo anh đến tận cùng.
Lúc đó ở châu Á, Hàn Quốc bị Nhật Bản đô hộ. Nhiều người dân đã tới vùng thảo nguyên hoang dã Manchuria, giáp ranh giữa Mông Cổ và Trung Quốc để lánh nạn. Để tồn tại trong môi trường đầy khó khăn, một số người trở thành những tên cướp, kiếm sống tại vùng sa mạc cằn cỗi này.
Tấm bản đồ dẫn đến kho báu từ đời nhà Thanh chính là mối liên kết cho sự hội ngộ của tất cả các băng cướp và phe phái. Mọi chuyện bắt đầu khi tên trộm kỳ quặc Yoon Tae Go – biệt danh Quái (Song Kang Ho đóng) vô tình có được tấm bản đồ. Chang Yi – Ác (Lee Byung Hun) được thuê lấy lại báu vật này. Park Dowon – Thiện (Jung Woo Sung), người săn tội phạm cũng lần theo dấu vết để truy đuổi hai kẻ trên. Ba nhân vật lao vào một cuộc săn đuổi băng qua sa mạc.
Những tên đô hộ Nhật Bản đánh hơi được đây là con đường để hoàn thành tham vọng thống trị châu Á. Trong khi đó, quân cảm tử của Hàn Quốc cũng không bỏ qua cơ hội tìm được nguồn tài chính hỗ trợ cho nhiệm vụ của họ. Băng cướp ở bộ tộc vùng Mãn Châu cũng ao ước có được kho báu. Tất cả cùng dấn thân vào cuộc tìm kiếm và truy sát đẫm máu.
Cũng giống như bộ phim Trộm Báu Vật (Once Upon A Time in Corea), kho báu không phải là mấu chốt cuối cùng mà các nhà làm phim hướng đến. Tuy nhiên, so với Trộm Báu Vật, kết thúc của phim Thiệc, Ác, Quái có phần kịch tính và bi thảm hơn.
Vượt khỏi mô-típ của những bộ phim cao bồi thường thấy, Thiện, Ác, Quái không chia các nhân vật ra làm hai tuyến đối lập. Ba nhân vật chính trong phim đại diện cho ba loại người: Thiện (The Good) – Ác (The Bad) – Quái (The Weird). Mỗi người một mục đích, có một cách sống khác nhau. Nhưng khi đã bị cuốn vào vòng xoáy của cuộc chiến tranh giành báu vật, những khái niệm về Thiện – Ác – Quái dường như không còn là bất biến.
Dowon, cùng với chiếc mũ cao bồi, chiếc súng trường và tài nghệ bách phát bách trúng và là khắc tinh của Chang Yi và Tae Go. Có lẽ Dowon là dạng nhân vật anh hùng – một anh hùng như bao phim cao bồi khác trong hoàn cảnh loạn lạc và phức tạp. Với Dowon, cuộc đời là những cuộc rượt đuổi, bắt và bị bắt. Anh là tay súng cừ khôi nhất ở Mãn Châu, có nhiệm vụ truy bắt Park Chang Yi (The Bad) và Yoon Tae Go (The Weird) để lĩnh thưởng. Thế nhưng, càng rượt đuổi, anh lại rơi vào vòng xoáy của cuộc tranh giành bản đồ kho báu. Trớ trêu thay, cuối cùng Dowon lại bước vào cuộc đấu súng một mất một còn với hai nhân vật này. Có thể vì Chang Yi là “kẻ xấu” như lời Dowon nói, nhưng cũng có thể mục đích của anh là vì tiền.
Trong khi đó, Yoon Tea Go là một tên trộm của vùng sa mạc Mãn Châu và là đối tượng “săn bắt” của Dowon. Vô tình trộm được tấm bản đồ kho báu, Yoon Teago trở thành mục tiêu số một của Chang Yi và quân đội Nhật Bản. Trong cuộc chiến tranh giành bản đồ, có lúc Tea Go và Dowon đã đứng về một phía nhưng định mệnh cuối cùng đã đưa cả hai vào cuộc chiến một mất một còn, cùng với Chang Yi. Dù đeo đuổi mục tiêu kho báu đến cùng, Tea Go vẫn chỉ có một ước mơ bình dị là mua được một mảnh đất để xây nhà, nuôi bò, nuôi ngựa… Tea Go không bất chấp tất cả để đạt được mục đích của mình cũng không có tham vọng là ‘một người giỏi nhất’, nhưng anh phải bước vào cuộc đọ súng với Chang Yi và Dowon, chỉ vì anh là huyền thoại “Finger Chopper” – người đã cắt ngón tay của Chang Yi.
Lý giải về các nhân vật trong phim, đạo diễn phim chia sẻ: “Khán giả có thể dễ dàng gán cho từng nhân vật trong phim tính từ “thiện”, “ác” hay “quái”. Nhưng giữa bối cảnh hỗn độn của thời loạn lạc trong phim, mỗi người đều có lúc thế này hay thế khác. Tôi cảm thấy hài lòng khi ba nam diễn viên chính của phim đều đạt được thần khí của nhân vật. Họ diễn xuất rất tuyệt vời. Không còn một chút gì phong cách cổ điển của phim Hàn Quốc mà thay vào đó, cả ba đã tạo cho mình một lối diễn rất Viễn Tây”.
Ba tài tử Lee Byung Hun, Song Kang Ho, Jung Woo Sung đã diễn thật những pha mạo hiểm, không dùng đến cascadeur. Tài tử Song Kang Ho kể lại: “Có lúc tôi tiếp tục quay mà không nhận ra rằng tay mình đã gãy. Cảnh quay cưỡi ngựa rất nguy hiểm vì đó là những con ngựa đua”. Trong một cảnh chạy đuổi theo đoàn tàu trên một ngọn đồi có không khí rất loãng, Kang Ho mang theo bình oxy để thở và để… chạy. Anh đã phải chạy ở độ cao 2.000 m so với mực nước biển. Một cảnh khác, ngôi sao này đã phải nhảy từ một chiếc xe máy lên xe jeep. Những cảnh bị ngựa kéo lê trên đường, những cảnh bắn súng, đánh nhau đã khiến các diễn viên bị thương không kém gì trong trận thật. Cả người quay phim cũng bị thương khi bị ngã từ tấm ván khiêng chạy để quay cảnh đấu súng trên tàu. Nhiều người cho biết, tóc đạo diễn Kim đã bạc đi nhiều hơn khi quay bộ phim này. “Ba chúng tôi đã phải cầu nguyện để có những cánh quay dễ dàng hơn”, Song Kang Ho kể lại.
Trong vai diễn này, Song Kang Ho với sự hài hước, lạc quan và những màn võ thuật ấn tượng đã chứng minh anh là sự lựa chọn hợp lý nhất. Kang Ho từng nổi tiếng trong bộ phim Quái vật sông Hàn. Anh cũng là diễn viên Hàn Quốc hai lần được bước lên thảm đỏ LHP Cannes với Secret Sunshine (2007) và Thiện, Ác, Quái (2008).
Bộ phim cũng đánh dấu sự bứt phá của tài tử hàng đầu Hàn Quốc, Lee Byung Hun. Với vai Chang Yi, Lee Byung Hun đã phá vỡ hình tượng “người đàn ông tuyệt vời” của mình suốt 17 năm qua. Những ai từng yêu mến Byung Hun qua các vai diễn hiền lành trong những bộ phim tình cảm như: Một Cho Tất Cả, Những Ngày Tươi Đẹp, Hoa Hướng Dương… chắc chắn sẽ sốc khi thấy anh hóa thân vào vai The Bad. Sau bộ phim, nhiều người đã nói rằng nhân vật kẻ Ác làm cho đôi mắt của Lee Byung Hun trở nên lạnh lùng, đáng sợ. Lee Byung Hun đã diễn xuất thần với đôi mắt sắc lạnh và khuôn mặt biểu cảm, ẩn chứa sự tàn bạo của một kẻ quyết chiến đến cùng chỉ để khẳng định là một người giỏi nhất.
Với vẻ ngoài đẹp trai, cuốn hút người đối diện ngay từ cái nhìn đầu tiên, tài tử Jung Woo Sung lại là lựa chọn tốt nhất cho vai Park Dowon (The Good). Để đạt được thành công trong những vai diễn gai góc, Woo Sung đã liều mạng với vai diễn của mình. Trong Thiện, Ác, Quái, Jung Woo Sung thường xuyên diễn những cảnh “bay lượn”, giao đấu trên không, cả những màn phải nhảy trên đoàn tàu lửa đang lăn bánh. Anh từng được đạo diễn Ngô Vũ Sâm (John Woo) mời vào vai Triệu Tử Long trong phim Đại chiến Xích Bích vì giỏi tiếng Anh và tiếng Trung, nhưng anh đã không được chấp nhận. Tuy nhiên, trong thời gian này, Jung Woo Sung lại có cơ hội tỏa sáng trong bộ phim bom tấn quốc nội Thiện, Ác, Quái. Tới đây, Jung Woo Sung sẽ nhận vai chính trong dự án truyền hình hợp tác Hàn – Nhật mang tên Người Đi Săn Thành Phố (2009).
Thiện, Ác, Quái mô phỏng theo một trong những bộ phim cao bồi xuất sắc nhất mọi thời đại: The Good, The Bad and The Ugly (1966 – đạo diễn Sergio Leone). Tuy nhiên đạo diễn Hàn Quốc đã biến tác phẩm này thành một bộ phim cao bồi kiểu phương Đông và giành được thành công vang dội. Phim cuốn hút người xem từ những cảnh đầu tiên cho tới khi kết thúc với sự hồi hộp trước những màn đấu súng, nhào lộn trên không và cảnh rượt đuổi hoành tráng trên sa mạc. Những màn cận cảnh, đặc biệt hướng vào đôi mắt nhân vật và sự phối hợp hài hòa của âm nhạc chính là điểm nhấn, tạo nên dư âm không dễ phai mờ của phim. Thiện, Ác, Quái đã gây ấn tượng mạnh mẽ trong buổi chiếu ra mắt tại LHP Cannes vào tháng 5 và được các nhà phê bình dành cho những lời đánh giá đẹp đẽ nhất.
Khi công chiếu vào tháng 7 tại Hàn Quốc, bộ phim đã giành vị trí số một trên bảng xếp hạng doanh thu tại đất nước này. Tổng cộng sau 11 ngày công chiếu, bộ phim đã đạt mốc 4,13 triệu khán giả và thu về 26 triệu USD. Cho đến nay, tổng số khán giả của Thiện, Ác, Quái đạt 6,3 triệu lượt. Tác phẩm này đã vượt qua bộ phim hài ăn khách cuối năm 2006 là Sắc Đẹp Ngàn Cân (200 Pound Beauty) để xếp vị trí thứ 10 Top phim ăn khách nhất lịch sử điện ảnh Hàn Quốc.
Incoming search terms:
- xem phim thien ac quai
- một cho tất cả phim hàn quốc
- phim thien ac quai
- xnxx người và ngựa
- phim quai thu sa mac
- xem phim thien ac va quai
- xem phim thien ac quai hd
- bá»™ ba thiá»‡n Ã¡c quÃ¡i
- thien ac quay phim han quoc
- xem phim thien ac qua
- phim chan mac thien sa
- watch phim thien ac quai
- xem online phim thien duong tren sa mac
- xem phim bo jong tien
- xương phim trung quoc cuoc chien giành báo vật

markdown:
# Xem Phim Thiện Ác Quái
Bộ Phim
**Thiện Ác Quái – The Good The Bad The Weird**
Ba chàng cao bồi điển trai của Hàn Quốc rượt đuổi nhau trên vùng sa mạc Mãn Châu (Manchuria – Đông bắc Trung Quốc) để tranh giành bản đồ kho báu.
Để có được những cảnh quay hoành tráng, đẹp mắt với những sa mạc hoang vu, những màn đọ súng ấn tượng, đoàn làm phim Thiện, Ác, Quái đã phải làm việc cật lực trong hai năm và quay tại nhiều nước: Hàn Quốc, Trung Quốc, Hong Kong, Mông Cổ, Nhật Bản, Prague (Cộng hòa Czech), Mỹ…
Bộ phim gay cấn ngay từ những phút đầu tiên với cảnh cướp bóc và đấu súng đẫm máu trên xe lửa. Những tên cướp khét tiếng vô tình gặp nhau tại đây, gây nên một vụ hỗn chiến. ‘Kẻ cướp xe lửa’ Yoon Tae Go đánh cắp được tấm bản đồ kho báu từ một thương gia Trung Quốc. Anh ta không ngờ rằng, vì tấm bản đồ này mà rất nhiều băng đảng sống chết rượt đuổi theo anh đến tận cùng.
Lúc đó ở châu Á, Hàn Quốc bị Nhật Bản đô hộ. Nhiều người dân đã tới vùng thảo nguyên hoang dã Manchuria, giáp ranh giữa Mông Cổ và Trung Quốc để lánh nạn. Để tồn tại trong môi trường đầy khó khăn, một số người trở thành những tên cướp, kiếm sống tại vùng sa mạc cằn cỗi này.
Tấm bản đồ dẫn đến kho báu từ đời nhà Thanh chính là mối liên kết cho sự hội ngộ của tất cả các băng cướp và phe phái. Mọi chuyện bắt đầu khi tên trộm kỳ quặc Yoon Tae Go – biệt danh Quái (Song Kang Ho đóng) vô tình có được tấm bản đồ. Chang Yi – Ác (Lee Byung Hun) được thuê lấy lại báu vật này. Park Dowon – Thiện (Jung Woo Sung), người săn tội phạm cũng lần theo dấu vết để truy đuổi hai kẻ trên. Ba nhân vật lao vào một cuộc săn đuổi băng qua sa mạc.
Những tên đô hộ Nhật Bản đánh hơi được đây là con đường để hoàn thành tham vọng thống trị châu Á. Trong khi đó, quân cảm tử của Hàn Quốc cũng không bỏ qua cơ hội tìm được nguồn tài chính hỗ trợ cho nhiệm vụ của họ. Băng cướp ở bộ tộc vùng Mãn Châu cũng ao ước có được kho báu. Tất cả cùng dấn thân vào cuộc tìm kiếm và truy sát đẫm máu.
Cũng giống như bộ phim Trộm Báu Vật (Once Upon A Time in Corea), kho báu không phải là mấu chốt cuối cùng mà các nhà làm phim hướng đến. Tuy nhiên, so với Trộm Báu Vật, kết thúc của phim Thiệc, Ác, Quái có phần kịch tính và bi thảm hơn.
Vượt khỏi mô-típ của những bộ phim cao bồi thường thấy, Thiện, Ác, Quái không chia các nhân vật ra làm hai tuyến đối lập. Ba nhân vật chính trong phim đại diện cho ba loại người: Thiện (The Good) – Ác (The Bad) – Quái (The Weird). Mỗi người một mục đích, có một cách sống khác nhau. Nhưng khi đã bị cuốn vào vòng xoáy của cuộc
[chiến tranh](http://www.sharephim.net/tag/chien-tranh/) giành báu vật, những khái niệm về Thiện – Ác – Quái dường như không còn là bất biến.
Dowon, cùng với chiếc mũ cao bồi, chiếc súng trường và tài nghệ bách phát bách trúng và là khắc tinh của Chang Yi và Tae Go. Có lẽ Dowon là dạng nhân vật anh hùng – một anh hùng như bao phim cao bồi khác trong hoàn cảnh loạn lạc và phức tạp. Với Dowon, cuộc đời là những cuộc rượt đuổi, bắt và bị bắt. Anh là tay súng cừ khôi nhất ở Mãn Châu, có nhiệm vụ truy bắt Park Chang Yi (The Bad) và Yoon Tae Go (The Weird) để lĩnh thưởng. Thế nhưng, càng rượt đuổi, anh lại rơi vào vòng xoáy của cuộc tranh giành bản đồ kho báu. Trớ trêu thay, cuối cùng Dowon lại bước vào cuộc đấu súng một mất một còn với hai nhân vật này. Có thể vì Chang Yi là “kẻ xấu” như lời Dowon nói, nhưng cũng có thể mục đích của anh là vì tiền.
Trong khi đó, Yoon Tea Go là một tên trộm của vùng sa mạc Mãn Châu và là đối tượng “săn bắt” của Dowon. Vô tình trộm được tấm bản đồ kho báu, Yoon Teago trở thành mục tiêu số một của Chang Yi và quân đội Nhật Bản. Trong cuộc chiến tranh giành bản đồ, có lúc Tea Go và Dowon đã đứng về một phía nhưng định mệnh cuối cùng đã đưa cả hai vào cuộc chiến một mất một còn, cùng với Chang Yi. Dù đeo đuổi mục tiêu kho báu đến cùng, Tea Go vẫn chỉ có một ước mơ bình dị là mua được một mảnh đất để xây nhà, nuôi bò, nuôi ngựa… Tea Go không bất chấp tất cả để đạt được mục đích của mình cũng không có tham vọng là ‘một người giỏi nhất’, nhưng anh phải bước vào cuộc đọ súng với Chang Yi và Dowon, chỉ vì anh là huyền thoại “Finger Chopper” – người đã cắt ngón tay của Chang Yi.
Lý giải về các nhân vật trong phim, đạo diễn phim chia sẻ: “Khán giả có thể dễ dàng gán cho từng nhân vật trong phim tính từ “thiện”, “ác” hay “quái”. Nhưng giữa bối cảnh hỗn độn của thời loạn lạc trong phim, mỗi người đều có lúc thế này hay thế khác. Tôi cảm thấy hài lòng khi ba nam diễn viên chính của phim đều đạt được thần khí của nhân vật. Họ diễn xuất rất tuyệt vời. Không còn một chút gì phong cách cổ điển của phim Hàn Quốc mà thay vào đó, cả ba đã tạo cho mình một lối diễn rất Viễn Tây”.
Ba tài tử Lee Byung Hun, Song Kang Ho, Jung Woo Sung đã diễn thật những pha mạo hiểm, không dùng đến cascadeur. Tài tử Song Kang Ho kể lại: “Có lúc tôi tiếp tục quay mà không nhận ra rằng tay mình đã gãy. Cảnh quay cưỡi ngựa rất nguy hiểm vì đó là những con ngựa đua”. Trong một cảnh chạy đuổi theo đoàn tàu trên một ngọn đồi có không khí rất loãng, Kang Ho mang theo bình oxy để thở và để… chạy. Anh đã phải chạy ở độ cao 2.000 m so với mực nước biển. Một cảnh khác, ngôi sao này đã phải nhảy từ một chiếc xe máy lên xe jeep. Những cảnh bị ngựa kéo lê trên đường, những cảnh bắn súng, đánh nhau đã khiến các diễn viên bị thương không kém gì trong trận thật. Cả người quay phim cũng bị thương khi bị ngã từ tấm ván khiêng chạy để quay cảnh đấu súng trên tàu. Nhiều người cho biết, tóc đạo diễn Kim đã bạc đi nhiều hơn khi quay bộ phim này. “Ba chúng tôi đã phải cầu nguyện để có những cánh quay dễ dàng hơn”, Song Kang Ho kể lại.
Trong vai diễn này, Song Kang Ho với sự
[hài hước](http://www.sharephim.net/tag/hai-huoc/), lạc quan và những màn võ thuật ấn tượng đã chứng minh anh là sự lựa chọn hợp lý nhất. Kang Ho từng nổi tiếng trong bộ phim [Quái vật sông Hàn](http://www.sharephim.net/quai-vat-song-han/). Anh cũng là diễn viên Hàn Quốc hai lần được bước lên thảm đỏ LHP Cannes với Secret Sunshine (2007) và Thiện, Ác, Quái (2008).
Bộ phim cũng đánh dấu sự bứt phá của tài tử hàng đầu Hàn Quốc, Lee Byung Hun. Với vai Chang Yi, Lee Byung Hun đã phá vỡ hình tượng “người đàn ông tuyệt vời” của mình suốt 17 năm qua. Những ai từng yêu mến Byung Hun qua các vai diễn hiền lành trong những bộ
[phim tình cảm](http://www.sharephim.net/tag/phim-tinh-cam/) như: Một Cho Tất Cả, Những Ngày Tươi Đẹp, [Hoa Hướng Dương](http://www.sharephim.net/hoa-huong-duong/)… chắc chắn sẽ sốc khi thấy anh hóa thân vào vai The Bad. Sau bộ phim, nhiều người đã nói rằng nhân vật kẻ Ác làm cho đôi mắt của Lee Byung Hun trở nên lạnh lùng, đáng sợ. Lee Byung Hun đã diễn xuất thần với đôi mắt sắc lạnh và khuôn mặt biểu cảm, ẩn chứa sự tàn bạo của một kẻ quyết chiến đến cùng chỉ để khẳng định là một người giỏi nhất.
Với vẻ ngoài đẹp trai, cuốn hút người đối diện ngay từ cái nhìn đầu tiên, tài tử Jung Woo Sung lại là lựa chọn tốt nhất cho vai Park Dowon (The Good). Để đạt được thành công trong những vai diễn gai góc, Woo Sung đã liều mạng với vai diễn của mình. Trong Thiện, Ác, Quái, Jung Woo Sung thường xuyên diễn những cảnh “bay lượn”, giao đấu trên không, cả những màn phải nhảy trên đoàn tàu lửa đang lăn bánh. Anh từng được đạo diễn Ngô Vũ Sâm (John Woo) mời vào vai Triệu Tử Long trong phim Đại chiến Xích Bích vì giỏi tiếng Anh và tiếng Trung, nhưng anh đã không được chấp nhận. Tuy nhiên, trong thời gian này, Jung Woo Sung lại có cơ hội tỏa sáng trong bộ phim bom tấn quốc nội Thiện, Ác, Quái. Tới đây, Jung Woo Sung sẽ nhận vai chính trong dự án truyền hình hợp tác Hàn – Nhật mang tên Người Đi Săn Thành Phố (2009).
Thiện, Ác, Quái mô phỏng theo một trong những bộ phim cao bồi xuất sắc nhất mọi thời đại: The Good, The Bad and The Ugly (1966 – đạo diễn Sergio Leone). Tuy nhiên đạo diễn Hàn Quốc đã biến tác phẩm này thành một bộ phim cao bồi kiểu phương Đông và giành được thành công vang dội. Phim cuốn hút người xem từ những cảnh đầu tiên cho tới khi kết thúc với sự hồi hộp trước những màn đấu súng, nhào lộn trên không và cảnh rượt đuổi hoành tráng trên sa mạc. Những màn cận cảnh, đặc biệt hướng vào đôi mắt nhân vật và sự phối hợp hài hòa của âm nhạc chính là điểm nhấn, tạo nên dư âm không dễ phai mờ của phim. Thiện, Ác, Quái đã gây ấn tượng mạnh mẽ trong buổi chiếu ra mắt tại LHP Cannes vào tháng 5 và được các nhà phê bình dành cho những lời đánh giá đẹp đẽ nhất.
Khi công chiếu vào tháng 7 tại Hàn Quốc, bộ phim đã giành vị trí số một trên bảng xếp hạng doanh thu tại đất nước này. Tổng cộng sau 11 ngày công chiếu, bộ phim đã đạt mốc 4,13 triệu khán giả và thu về 26 triệu USD. Cho đến nay, tổng số khán giả của Thiện, Ác, Quái đạt 6,3 triệu lượt. Tác phẩm này đã vượt qua bộ phim hài ăn khách cuối năm 2006 là Sắc Đẹp Ngàn Cân (200 Pound Beauty) để xếp vị trí thứ 10 Top phim ăn khách nhất lịch sử điện ảnh Hàn Quốc.
#### Incoming search terms:
[xem phim thien ac quai](http://www.sharephim.net/xem-phim-thien-ac-quai/) [một cho tất cả phim hàn quốc](http://www.sharephim.net/xem-phim-thien-ac-quai/) [phim thien ac quai](http://www.sharephim.net/xem-phim-thien-ac-quai/) [xnxx người và ngựa](http://www.sharephim.net/xem-phim-thien-ac-quai/) [phim quai thu sa mac](http://www.sharephim.net/xem-phim-thien-ac-quai/) [xem phim thien ac va quai](http://www.sharephim.net/xem-phim-thien-ac-quai/) [xem phim thien ac quai hd](http://www.sharephim.net/xem-phim-thien-ac-quai/) [bá»™ ba thiá»‡n Ã¡c quÃ¡i](http://www.sharephim.net/xem-phim-thien-ac-quai/) [thien ac quay phim han quoc](http://www.sharephim.net/xem-phim-thien-ac-quai/) [xem phim thien ac qua](http://www.sharephim.net/xem-phim-thien-ac-quai/) [phim chan mac thien sa](http://www.sharephim.net/xem-phim-thien-ac-quai/) [watch phim thien ac quai](http://www.sharephim.net/xem-phim-thien-ac-quai/) [xem online phim thien duong tren sa mac](http://www.sharephim.net/xem-phim-thien-ac-quai/) [xem phim bo jong tien](http://www.sharephim.net/xem-phim-thien-ac-quai/) [xương phim trung quoc cuoc chien giành báo vật](http://www.sharephim.net/xem-phim-thien-ac-quai/)