Khi nào sử dụng <ui: include>, các tệp thẻ, các thành phần tổng hợp và / hoặc các thành phần tùy chỉnh?


102

Gần đây, tôi đã bắt đầu sử dụng JSF 2.0 với Khuôn mặt và cảm thấy bối rối trước các thành phần tổng hợp mới khi biết <ui:include>các kỹ thuật tạo khuôn mẫu hiện có và các kỹ thuật tạo khuôn mẫu khác được cung cấp bởi Khuôn mặt 1.x.

Sự khác biệt giữa các cách tiếp cận đó là gì? Về mặt chức năng, chúng dường như cung cấp các tệp thẻ giống nhau: <ui:param>vs <cc:attribute>, <ui:insert>+ <ui:define>vs, sử dụng lại các mẫu hiện có. Có gì ngoài cú pháp và đặc tả giao diện rõ ràng trong trường hợp các thành phần hỗn hợp không? Hiệu suất có thể khác nhau?

Câu trả lời:


176

Sự khác biệt giữa các cách tiếp cận đó là gì?

Khuôn mẫu

Sử dụng Facelet các mẫu (như trong <ui:composition>, <ui:include><ui:decorate>) nếu bạn muốn chia mảnh vỡ bố cục trang chính vào các mẫu reuseable. Ví dụ: đầu trang, menu, nội dung, chân trang, v.v.

Ví dụ:

Các tệp thẻ khuôn mặt

Sử dụng các tệp thẻ Facelet nếu bạn muốn có một nhóm các thành phần có thể sử dụng lại để ngăn chặn / giảm thiểu việc sao chép mã. Ví dụ: một nhóm các thành phần nhãn + đầu vào + thông báo. Sự khác biệt chính với các thành phần hỗn hợp là đầu ra của tệp thẻ Facelet không đại diện cho một tệp duy nhất UIComponentvà trong một số trường hợp có thể là giải pháp duy nhất khi một thành phần hỗn hợp không đủ. Nói chung, có một <ui:include>với một hoặc nhiều <ui:param>vượt qua thuộc tính bean được quản lý (và do đó không phải là giá trị mã cứng) là một tín hiệu cho thấy tệp bao gồm tốt hơn có thể là tệp thẻ.

Ví dụ:

Các thành phần tổng hợp

Sử dụng các thành phần tổng hợp nếu bạn muốn tạo một tùy chỉnh duy nhất và có thể tái sử dụng UIComponentvới một trách nhiệm duy nhất bằng cách sử dụng XML thuần túy. Một thành phần tổng hợp như vậy thường bao gồm một loạt các thành phần hiện có và / hoặc HTML và được hiển thị vật lý như một thành phần duy nhất và được cho là được ràng buộc với một thuộc tính bean duy nhất. Ví dụ: một thành phần đại diện cho một thuộc tính đơn lẻ java.util.Datebởi 3 <h:selectOneMenu>thành phần phụ thuộc hoặc một thành phần kết hợp <p:fileUpload><p:imageCropper>thành một thành phần giới <my:uploadAndCropImage>thiệu một com.example.Imagethực thể tùy chỉnh duy nhất dưới dạng thuộc tính.

Ví dụ:

Các thành phần tùy chỉnh

Sử dụng một thành phần tùy chỉnh bất cứ khi nào không thể đạt được chức năng với các tệp thẻ Facelet hoặc các thành phần tổng hợp, do thiếu hỗ trợ trong bộ thành phần chuẩn / có sẵn. Có thể tìm thấy các ví dụ ở khắp nơi trong mã nguồn của các thư viện thành phần nguồn mở như PrimeFacesOmniFaces .

Trình xử lý thẻ

Khi bạn muốn kiểm soát việc xây dựng cây thành phần JSF thay vì hiển thị đầu ra HTML, thì bạn nên sử dụng trình xử lý thẻ thay vì một thành phần.

Ví dụ:

Dự án mẫu

Dưới đây là một số dự án ví dụ sử dụng tất cả các kỹ thuật đã đề cập ở trên.


Hiệu suất có thể khác nhau?

Về mặt kỹ thuật, mối quan tâm về hiệu suất là không đáng kể. Sự lựa chọn phải được thực hiện dựa trên các yêu cầu chức năng cụ thể và mức độ trừu tượng cuối cùng, khả năng tái sử dụng và khả năng bảo trì của việc thực hiện. Mỗi cách tiếp cận đều có mục đích và hạn chế được xác định rõ ràng.

Tuy nhiên, các thành phần tổng hợp có chi phí đáng kể trong quá trình xây dựng / khôi phục chế độ xem (cụ thể: trong khi lưu / khôi phục trạng thái chế độ xem). Và, trong các phiên bản cũ hơn của Mojarra, các thành phần tổng hợp có vấn đề về hiệu suất khi gán giá trị mặc định, điều này đã được khắc phục kể từ 2.1.13. Ngoài ra, Mojarra đã bị rò rỉ bộ nhớ khi a <cc:attribute method-signature>được sử dụng cho các biểu thức phương thức, về cơ bản toàn bộ cây thành phần được tham chiếu lại trong phiên HTTP, điều này đã được khắc phục kể từ 2.1.29 / 2.2.8. Có thể bỏ qua rò rỉ bộ nhớ trong các phiên bản 2.1 cũ hơn như sau:

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

Hoặc trong các phiên bản 2.2 cũ hơn như sau:

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

Tuy nhiên, khi bạn có tương đối "nhiều" thành phần tổng hợp và bạn đã javax.faces.STATE_SAVING_METHODthiết lập client, thì hiệu suất sẽ là một vấn đề. Không lạm dụng các thành phần tổng hợp nếu bạn chỉ muốn có chức năng cơ bản đã có thể thực hiện được với một tệp bao gồm hoặc tệp thẻ đơn giản. Không sử dụng tính dễ cấu hình (đọc: không *.taglib.xmlcần tệp) như một cái cớ để thích các thành phần phức hợp hơn các tệp thẻ.

Khi sử dụng Mojarra 2.2.10 trở lên, đừng quên tắt khoảng thời gian làm mới Khuôn mặt tương đối ngắn cho chế độ sản xuất:

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

Không sử dụng cài đặt này để phát triển, nếu không, bạn phải khởi động lại toàn bộ máy chủ để phản ánh các thay đổi trong tệp Khuôn mặt! Mojarra 2.2.11 và mới hơn, và MyFaces đã được đặt mặc định -1khi javax.faces.PROJECT_STAGEkhông được đặt thành Development.


tại sao bạn muốn hiển thị 1 thành phần (thành phần tổng hợp) thay vì giả sử là 3 (tệp thẻ facelet)? Ý tôi là, vào một ngày nắng đẹp, bạn có thể cảm thấy như 1 thay vì 3 ... nhưng tôi đoán có điều gì đó khác đằng sau nó. Trong ví dụ của bạn, bạn đang mở rộng UINamingContainer ... đó có thể là một trong những lý do để sử dụng cc (vì vậy để có thể ghi đè một số chức năng triển khai jsf cụ thể)?
Toskan

2
Một tệp thẻ nên được xem như một loại bao gồm. Một thành phần tổng hợp nên được xem như một thành phần thực. Một thành phần kết hợp yêu cầu phải triển khai NamingContainer, nếu không, bạn sẽ gặp sự cố ID trùng lặp khi cùng một thành phần được sử dụng lại nhiều lần.
BalusC

@BalusC Giả sử tôi có một loạt HTML và JSF tạo một 'khối' cho phép tôi thêm hoặc xóa Địa chỉ (và tất cả các thuộc tính của nó: đường phố, số, thành phố, v.v.). Tôi cần sử dụng cùng một khối đó trong 2 hoặc 3 trang. Điều đó có nằm trong mô tả của bạn về Thành phần tổng hợp không?
RinaldoPJr

1
@Rinaldo: Tôi nghĩ rằng tôi sẽ sử dụng tệp thẻ cho tệp đó với các ID thành phần được điền động như được minh họa trong stackoverflow.com/questions/5713718/… . IMO, nếu nó có thể được thực hiện với một tệp thẻ, hãy sử dụng nó. Nếu không thể thực hiện được với tệp thẻ, hãy sử dụng kết hợp. Nếu bạn cần nhiều thành phần để thao tác một thuộc tính (không phải địa chỉ, nhưng ví dụ: tên đường + số nhà sẽ đi trong một thuộc tính), thì một thành phần hỗn hợp sẽ là giải pháp duy nhất.
BalusC

2
@Tarik: vật liệu tổng hợp có rất nhiều chi phí so với thẻ tag. Nói cách khác: hiệu suất kém. Chỉ sử dụng nó nếu bạn cần tạo một thành phần UI tùy chỉnh duy nhất dựa trên một tập hợp các thành phần hiện có có liên quan chặt chẽ. Điều này không thể được thực hiện với một tệp thẻ. Ví dụ, ZEEF.com chỉ có một tổng hợp: tải lên / tải xuống / cắt hình ảnh tất cả trong một được sử dụng trong ảnh trang ao, ảnh hồ sơ, tiêu đề khối liên kết, khối hình ảnh, v.v. Nó bị ràng buộc chỉ là một thuộc Imagetính trong đậu.
BalusC
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.