Trong các ứng dụng thông thường, việc liệt kê tất cả các phần tử (bản ghi) là một việc rất hay gặp. Trong trường hợp, nếu số lượng bản ghi nhiều và tràn hết màn hình thì ta sẽ có nhu cầu phân trang.
Liferay có tiện ích search container rất hữu ích cho chúng ta khi thực hiện công việc như trên. Trong bài này, mình sẽ giới thiệu chi tiết cách sử dụng search container.
Bài toán: Vì mình chưa giới thiệu cách kết nối và lấy dữ liệu từ cơ sở dữ liệu nên hướng dẫn này các dữ liệu sẽ được tạo giả trong một file .class nào đó. Sau này, khi làm quen với cơ sử dữ liệu rồi ta sẽ kết hợp lại để được ví dụ gần sát với thực thế hơn. Bài toán ở đây rất đơn giản, chúng ta liệt kê một danh sách các sinh viên (Student), trong màn hình này, chúng ta cho phép tìm kiếm theo tên, giới tính,...
Trước hết hãy tạo một project mới tên là Search Tutorial nhé (cách tạo project ở đây). Bây giờ chúng ta sẽ đi tạo 4 lớp gồm: Student, StudentSearchContainer, StudentSearchTerms và StudentDisplayTerms, chúng ta sẽ lần lượt tạo từng lớp và giải thích xem chúng để làm gì nhé.
Lớp Student: Lớp này được gọi là model (trong mô hình MVC), ta sẽ tạo mới một package có tên là model (đường dẫn đầy đủ là: com.blogspot.chingovan.tutorial.model và bạn biết cách tạo package rồi chứ?) Lớp này được sử dụng để biểu diễn thông tin của một đối tượng (Student). Nội dung của nó như sau:
Bây giờ, viết lớp StudentDisplayTerms kế thừa từ DisplayTerms thì ta vẫn nguyễn được các trường trên đồng thời ta bổ xung thêm ba trường mới là code, name và gender. Tùy thuộc vào việc chúng ta tìm kiếm thì thì chúng ta sẽ thêm các trường phù hợp.
Trong hàm dựng, các điều kiện chúng ta mới đưa vào sẽ được lấy tự request chuyển xuống từ lệnh tìm kiếm của chúng ta. Còn các trường mặc định của DisplayTerms sẽ được tự động gán kết quả từ request. Ví dụ, ta có: code = ParamUtil.getString(portletRequest, "code"); có nghĩa là trên màn hình jsp sẽ phải truyền xuống một biến có tên là code.
Thông thường, *DisplayTerms có ý nghĩa đúng như cái tên của nó sẽ được phục vị để hiện thị các điều kiện tìm kiếm. Tức là khi bạn nhập vào ô name nội dung là "Nam" chẳng hạn, bạn nhấn tìm kiếm sau một hồi tìm kiếm trên màn hình hiện ra kết quả nhưng ô name vẫn giữ nguyên chữ "Nam". Về kỹ thuật mình sẽ nói sau, bây giờ chúng ta xem xét lớp StudentSearchTerms xem nó có ý nghĩa gì và dùng vào hoàn cảnh nào nhé.
Ta thấy, StudentSearchTerms kế thừa từ StudentDisplayTerms, chúng ta chỉ sửa hàm dựng một chút. Ở ví dụ này không có các tham số đặc biệt vì vậy chúng ta sẽ thấy StudentSearchTerms không có bất kỳ mở rộng nào so với StudentDisplayTerms. Tuy nhiên, ở các form tìm kiếm phức tạp, chẳng hạn tìm kiếm theo ngày/tháng/năm thì dữ liệu chuyển xuống chỉ là các con số, ta phải tổng hợp lại thành kiểu Date thì lúc này mới có nhiều khác biệt giữa hai lớp này.
Lớp StudentSearchContainer: Lớp này được kế thừa từ lớp SearchContainer có chứa các thông tin số lượng các bản ghi trên một trang, thông điệp khi không tìm thấy kết quả, tiêu đề của các cột, sắp xếp dữ liệu theo cột (post sau sẽ nói chi tiết hơn về sắp xếp). Code của lớp này như sau:
Ta thấy, lớp này có một hàm dựng gồm hai tham số là PortletRequest và PortletURL tham số thứ nhất chứa các dữ liệu mà ta gửi xuống khi nhấn vào nút "Tìm kiếm", các điều kiện lọc như theo code, name và gender sẽ được lấy từ các thẻ input đấy vào PortletRequest, StudentDisplayTerms và StudentSearchTerms sẽ lấy các dữ liệu này. Trong hàm dựng này, chúng ta gọi hàm dựng của lớp cha với các tham số gồm PortletRequest, StudentSearchTerms, StudentDisplayTerms, tên biến lưu trữ chỉ số bản ghi, số lượng bản ghi / trang, PortletURL, tiêu đề của các cột, thông điệp khi không có kết quả phù hợp với điều kiện tìm kiếm.
Sau khi tạo xong các lớp trên, ta sẽ quay lại với các file jsp. Các file nay sẽ sử dụng các lớp mà chúng ta đã viết để lọc dữ liệu và hiển thị lên màn hình.
File view.jsp: Ta xem nội dung của file view.jsp như sau:
Trong file này ta lưu ý một số thẻ như sau:
Lớp Student: Lớp này được gọi là model (trong mô hình MVC), ta sẽ tạo mới một package có tên là model (đường dẫn đầy đủ là: com.blogspot.chingovan.tutorial.model và bạn biết cách tạo package rồi chứ?) Lớp này được sử dụng để biểu diễn thông tin của một đối tượng (Student). Nội dung của nó như sau:
Như bạn thấy đấy, lớp Student chỉ là một POJO bình thường đúng không.
Lớp StudentDisplayTerms: Lớp này sẽ chứa các tham số phục vụ cho việc lọc dữ liệu. Ta tạo mới một package là com.blogspot.chingovan.tutorial.search và tạo lớp StudentDisplayTerms trong package vừa tạo và nó có nội dung như sau:
Ta thấy, lớp StudentDisplayTerms được kế thừa từ lớp DisplayTerms (bạn có thể xem API của DisplayTerms tại đây). Ta đi giải thích một chút về lớp DisplayTerms, lớp này có các trường gồm keywords , advancedSearch và andOperator trong đó, keywords là các điều kiện trong trường hợp tổng quát, advancedSearch = true nếu chúng ta cho phép tìm kiếm nâng cao, andOperator cho biết ta sử dụng phép toán AND hay OR cho các điều kiện tìm kiếm.Lớp StudentDisplayTerms: Lớp này sẽ chứa các tham số phục vụ cho việc lọc dữ liệu. Ta tạo mới một package là com.blogspot.chingovan.tutorial.search và tạo lớp StudentDisplayTerms trong package vừa tạo và nó có nội dung như sau:
Bây giờ, viết lớp StudentDisplayTerms kế thừa từ DisplayTerms thì ta vẫn nguyễn được các trường trên đồng thời ta bổ xung thêm ba trường mới là code, name và gender. Tùy thuộc vào việc chúng ta tìm kiếm thì thì chúng ta sẽ thêm các trường phù hợp.
Trong hàm dựng, các điều kiện chúng ta mới đưa vào sẽ được lấy tự request chuyển xuống từ lệnh tìm kiếm của chúng ta. Còn các trường mặc định của DisplayTerms sẽ được tự động gán kết quả từ request. Ví dụ, ta có: code = ParamUtil.getString(portletRequest, "code"); có nghĩa là trên màn hình jsp sẽ phải truyền xuống một biến có tên là code.
Thông thường, *DisplayTerms có ý nghĩa đúng như cái tên của nó sẽ được phục vị để hiện thị các điều kiện tìm kiếm. Tức là khi bạn nhập vào ô name nội dung là "Nam" chẳng hạn, bạn nhấn tìm kiếm sau một hồi tìm kiếm trên màn hình hiện ra kết quả nhưng ô name vẫn giữ nguyên chữ "Nam". Về kỹ thuật mình sẽ nói sau, bây giờ chúng ta xem xét lớp StudentSearchTerms xem nó có ý nghĩa gì và dùng vào hoàn cảnh nào nhé.
Ta thấy, StudentSearchTerms kế thừa từ StudentDisplayTerms, chúng ta chỉ sửa hàm dựng một chút. Ở ví dụ này không có các tham số đặc biệt vì vậy chúng ta sẽ thấy StudentSearchTerms không có bất kỳ mở rộng nào so với StudentDisplayTerms. Tuy nhiên, ở các form tìm kiếm phức tạp, chẳng hạn tìm kiếm theo ngày/tháng/năm thì dữ liệu chuyển xuống chỉ là các con số, ta phải tổng hợp lại thành kiểu Date thì lúc này mới có nhiều khác biệt giữa hai lớp này.
Lớp StudentSearchContainer: Lớp này được kế thừa từ lớp SearchContainer có chứa các thông tin số lượng các bản ghi trên một trang, thông điệp khi không tìm thấy kết quả, tiêu đề của các cột, sắp xếp dữ liệu theo cột (post sau sẽ nói chi tiết hơn về sắp xếp). Code của lớp này như sau:
Ta thấy, lớp này có một hàm dựng gồm hai tham số là PortletRequest và PortletURL tham số thứ nhất chứa các dữ liệu mà ta gửi xuống khi nhấn vào nút "Tìm kiếm", các điều kiện lọc như theo code, name và gender sẽ được lấy từ các thẻ input đấy vào PortletRequest, StudentDisplayTerms và StudentSearchTerms sẽ lấy các dữ liệu này. Trong hàm dựng này, chúng ta gọi hàm dựng của lớp cha với các tham số gồm PortletRequest, StudentSearchTerms, StudentDisplayTerms, tên biến lưu trữ chỉ số bản ghi, số lượng bản ghi / trang, PortletURL, tiêu đề của các cột, thông điệp khi không có kết quả phù hợp với điều kiện tìm kiếm.
Sau khi tạo xong các lớp trên, ta sẽ quay lại với các file jsp. Các file nay sẽ sử dụng các lớp mà chúng ta đã viết để lọc dữ liệu và hiển thị lên màn hình.
File view.jsp: Ta xem nội dung của file view.jsp như sau:
Trong file này ta lưu ý một số thẻ như sau:
- Thẻ liferay-ui:search-container: là thẻ chứa root chứa tất cả các nội dung gồm điều kiện tìm kiếm, danh sách các bản ghi. Ta thấy có một thuộc tính có nội dung như sau: searchContainer="<%= studentSearchContainer %>" thuộc tính có giá trị là một object của lớp SearchContainer, ngoài ra còn nhiều thuộc tính khác ta sẽ tìm hiểu sau.
- Thẻ liferay-ui:search-container-results: thẻ này có hai thuộc tính là results và total, results chứa danh sách kết quả tìm kiếm được của một trang (từ start đến end) và total là số lượng kết quả tối đa.
- Thẻ liferay-ui:search-container-row: thể hiện nội dung sẽ được hiển thị trên mỗi dòng kết quả, có hai thuộc tính cần quan tâm là className và modelVar, className chính là đường dẫn đầy đủ đến tên lớp của các phần tử trong danh sách kết quả của thẻ liferay-ui:search-container-results và modelVar là tên biến do chúng ta tự đặt. Về cơ bản, chúng ta hãy coi thẻ này thể hiện cho một vòng lặp khi ta xét tất cả các kết quả được trả về.
- Thẻ liferay-ui:search-container-column-text: thẻ này nằm trong thẻ liferay-ui:search-container-row thể hiện cho một cột của một vòng lặp. Thẻ này có một vài thuộc tính như: property, name, value, ... Trong trường hợp các thuộc tính của kết quả trả về không cần phải xử lý như thuộc tính code, name hay address thì ta có thể hiển thị ngay lên màn hình và giá trị của thuộc tính này tương ứng với tên của một thuộc tính trong lớp Student. Còn trường hợp cần phải xử lý trước khi hiện thị ta sẽ sử dụng thuộc tính value, ví dụ thuộc tính gender cho giá trị true và false nếu để hai giá trị này thì người dùng không hiểu được vì vậy ta cần phải sử lý trước. Thuộc tính name được sử dụng để hiện thị tên cột tương ứng.
- Thẻ liferay-ui:search-iterator: thẻ này có ý nghĩa như là một vòng lặp theo các kết quả trả về.
Bây giờ chúng ta deploy portlet này vào portal và kết quả sẽ như sau:
Liệt kê tất cả các kết quả |
Lưu ý: trong file view.jsp ta thấy có lớp DemoStudentUtil, lớp này chỉ để cung cấp dữ liệu cho chúng ta. Sau này, khi làm quen với việc có kết nối với cơ sở dữ liệu thì chúng ta sẽ lấy dữ liệu từ service lên. Còn trong trường hợp này chỉ mang tính chất minh hoạt.
Hiện tại, ta đã hiện thị tất cả các dữ liệu lên màn hình rồi. Nhưng ta chưa cho phép tìm kiếm. Bây giờ chúng ta sẽ bổ xung thêm phần tìm kiếm vào nhé. Muốn tìm kiếm được thì ta phải thêm file view.jsp một form chứa nội dung tìm kiếm.
Nội dung của file view.jsp sau khi chính sửa như sau:
Ta thấy, chỉ có 3 chỉnh chỗ chỉnh sửa mà thôi:
- Dòng số 6: thêm biến String portletURLString = portletURL.toString();
- Dòng số 10: thêm vào thẻ <aui:form action="<%= portletURLString %>" method="post" name="fm"> mục đích của thẻ aui:form cho phép chúng ta tạo ra một form để nhập dữ liệu để lọc.
- Dòng số 13: <liferay-ui:search-form page="/html/searchtutorial/search.jsp" servletContext="<%= application %>" /> mục đích của dòng này là liên kết đến file search.jsp sẽ là đoạn code bố trí các thành phần giúp chúng ta nhập dữ liệu để lọc.
Nội dung của file search.jsp như sau:
Ta để ý một số điểm trong file search.jsp sau:
- Dòng số 6: nhằm mục đích lấy object từ file view.jsp sang.
- Các dòng 12, 15 và 19: là các thành phần cho phép chúng ta nhập dữ liệu để lọc. Ta lưu ý, các dòng này có thuộc tính name có giá trị tương ứng với các thuộc tính trong file StudentDisplayTerms. Chúng ta phải làm điều này, vì sau khi nhấn vào nút search màn hình sẽ gữi nguyên lại điều kiện lọc mà chúng ta vừa tìm.
Tìm kiếm với điều kiện |
Sau khi xong xuôi, ta deploy code và portal và refresh lại màn hình. Bây giờ bạn nhập điều kiện lọc vào. Ví dụ, code = "00", Name = "Anh" và Gender=Nam (giá trị 1) thì ta sẽ lọc được tất cả các sinh viên có mã chứa chuỗi "00", tên có chuỗi "Anh" và có giới tính là "Nam"
Đây là một hướng dẫn rất cơ bản cho những người mới bắt đầu với Liferay, nếu bạn có chút ít kinh nghiệm thì rõ ràng còn rất nhiều các tham số cần tùy chỉnh nữa. Tuy nhiên, ta dừng ở đây đã vì hướng dẫn quá dài chỉ làm người đọc rối trí mà thôi. Các bài sau ta sẽ đi phân tích các thành phần liên quan đến SearchContainer và kết hợp với việc lấy dữ liệu từ cơ sở dữ liệu thay vì dữ liệu tạm thời như trong hướng dẫn này.
Thành thật mà nói, SearchContainer giúp ích rất nhiều cho lập trình viên, bạn sẽ không tốn nhiều thời gian để trình bày một danh sách kể quả trên màn hình và sử dụng SearchContainer sẽ tạo ra sự thống nhất trong ứng dụng nhiều người viết thay vì mỗi người viết theo một kiểu riêng của mình. Bạn sẽ không thất vọng khi đầu tư thời gian tìm hiểu nó đâu (tin mình đi).
Bạn có thể tải về code đầy đủ tại đây.
Bạn có thể tải về code đầy đủ tại đây.
Không có nhận xét nào:
Đăng nhận xét