Trong hai post trước đây (service builder và search container) cho phép chúng ta tương tác với dữ liệu và tương tác với giao diện. Trong post này mình sẽ kết hợp cả hai công việc riêng rẽ ở hai post trên vào thành một. Có nghĩa là ứng dụng của chúng ta sẽ lấy dữ liệu từ cơ sở dữ liệu hiển thị lên màn hình nhờ search container và chúng ta có thể dùng các tham số của search container để lọc các bản ghi phù hợp. Bây giờ các ứng dụng ta viết ra sát với thực tế rồi đấy.
Giới thiệu
Trong post này, chúng ta sẽ sử dụng lại code của hai post trước (bạn vui lòng đọc lại kỹ nhé, mã nguồn tưng ứng của 2 post trên service builder và search container). Lúc này, ta tạo một portlet mới có tên là combine-portlet. Bạn copy file service.xml trong project service builder và các file (StudentSearchContainer, StudentDisplayTerms, StudentSearchTerms) nhưng nhớ đổi tên package cho đúng nhé.
Cài đặt
Đầu tiên, ta tạo lớp portlet như sau:
Tiếp theo ta sẽ chép file service.xml như đã nói ở trên vào thư mục WEB-INFO:
Tuy nhiên so với bài trước ta chỉ thay đổi một chút đó là thuộc tính package-path và namespace việc thay đổi này thực chất chỉ để các lớp được sinh ra nằm trong các gói có tên hợp lý mà thôi.
Bây giờ chúng ta thực hiện builder service thôi (click chuột phải vào tên project >> Liferay >> Build Services, chờ đợi 1 lúc nhé). Vậy là bước xây dựng dữ liệu đã xong rồi. Tiếp theo ta xây dựng phần search container. Phần này ta cần phải sao chép ba file *.java tương ứng.
Lớp đầu tiên là StudentDisplayTerms:
Lớp thứ hai là StudentSearchTerms:
Lớp thứ ba là StudentSearchContainer:
Ba lớp trên có thay đổi chút ít về package và import nhưng nội dung vẫn giữ như cũ. Như vậy, 2 thành phần chính đã có rồi, giờ ta sẽ viết đoạn mã jsp. Chẳng cần suy nghĩ gì nhiều, chúng ta sẽ sử dụng lại các đoạn được viết từ post trước (gồm 3 file là init.jsp, view.jsp và search.jsp) chúng ta sẽ thay đổi đường dẫn và import cho phù hợp. Hãy copy 3 file trên vào thư mục docroot/html/combine. Nội dung của 3 file lần lượt như sau:
File init.jsp (chứa các import, ...):
File search.jsp (chứa các điều kiện tìm kiếm):
File view.jsp (chứa phần search container):
Ta thấy, trong file view.jsp có 2 dòng 16 và 17 là ta gọi service để lấy danh sách Student từ cơ sở dữ liệu và số lượng bản ghi (service builder tự động sinh các phương thức này cho chúng ta, thật TIỆN LỢI đúng không?). Bây giờ hãy deploy portlet vào hệ thống và kéo portlet trên giao diện ta sẽ thấy kết quả như sau:
Hiển thị các bản ghi được lấy từ cơ sở dữ liệu |
Như vậy là ta đã lấy được dữ liệu từ dưới cơ sở dữ liệu và hiển thị lên màn hình một cách đẹp dễ. Lúc này, ta thử các thao tác search xem sao? Bạn nhập mã muốn tìm, tên và giới tính rồi nhấn vào nút Search có chuyện gì xảy ra không? Không hề, vẫn là tất cả các bản ghi. Vậy làm sao chúng ta có thể lấy được các bản ghi phù hợp với điều kiện search của chúng ta?
Nếu bây giờ ta sửa chương trình thì phải sửa ở đâu? Tất nhiên là phần nào lấy dữ liệu rồi. Chính xác là dòng 16 và 17 trong file view.jsp. Nhưng sửa thế nào bây giờ? Liệu service builder có hỗ trợ chúng ta được gì hay không? Với điều kiện như trên ta sẽ có hai kịch bản là:
Nếu bây giờ ta sửa chương trình thì phải sửa ở đâu? Tất nhiên là phần nào lấy dữ liệu rồi. Chính xác là dòng 16 và 17 trong file view.jsp. Nhưng sửa thế nào bây giờ? Liệu service builder có hỗ trợ chúng ta được gì hay không? Với điều kiện như trên ta sẽ có hai kịch bản là:
- Lọc theo mã và tên (tức là không phụ thuộc vào giới tính)
- Lọc theo mã, tên và cả giới tính.
Với kịch bản 1 ta chỉ quan tâm đến hai trường là code và fullName, bạn mở file service.xml và thêm vào đoạn sau:
<finder name="C_F" return-type="Collection">
<finder-column name="code" comparator="LIKE" />
<finder-column name="fullName" comparator="LIKE" />
</finder>
Với kịch bản 2 ta quan tâm đến ba trường gồm code, fullName và gender, ta tiếp tục thêm đoạn mã sau vào file service.xml:
<finder name="C_F_G" return-type="Collection">
<finder-column name="code" comparator="LIKE" />
<finder-column name="fullName" comparator="LIKE" />
<finder-column name="gender" comparator="=" />
</finder>
Nội dung của file service.xml lúc này sẽ như sau:
Ta thấy có hai thẻ finder được thêm vào, thẻ này để làm gì? Trước hết bạn hãy build lại project đã nhé (chú ý: mỗi khi thay đổi file service.xml đều cần phải build lại). Build xong ta có thấy gì thay đổi không? Chẳng có gì thay đổi đúng không? Thực ra là có đây, Liferay sẽ tự động sinh ra các phương thứ findByC_F và findByC_F_G trong lớp Persistence.
Như vậy, làm thế nào để ta có thể gọi các phương thức được sinh ra ở trên? Thức tế, ta không gọi được trực tiếp các phương thức trên thông qua các lớp Persistence mà phải gọi qua service. Nhưng Liferay không sinh tự đông các phương thức, chính vì vậy ta cần phải viết các phương thức thực hiện nghiệm vụ của chúng ta dựa trên các phương thức được sinh tự động bởi Liferay. Vậy chúng ta cần phải viết các phương thức của chúng ta ở chỗ nào?
Như vậy, làm thế nào để ta có thể gọi các phương thức được sinh ra ở trên? Thức tế, ta không gọi được trực tiếp các phương thức trên thông qua các lớp Persistence mà phải gọi qua service. Nhưng Liferay không sinh tự đông các phương thức, chính vì vậy ta cần phải viết các phương thức thực hiện nghiệm vụ của chúng ta dựa trên các phương thức được sinh tự động bởi Liferay. Vậy chúng ta cần phải viết các phương thức của chúng ta ở chỗ nào?
Trong file service.xml có thuộc tính package-path= "com.blogspot.chingovan.tutorial.combine" như vậy, bạn sẽ mở các lớp trong package com.blogspot.chingovan.tutorial.combine.service.impl, ta thấy có hai lớp StudentLocalServiceImpl và StudentSearviceImpl, đây chính là nơi để chúng ta viết các phương thức thực hiện nghiệp vụ của chương trình. Bạn hãy mở lớp StudentLocalServiceImpl ra. Nội dung ban đầu sẽ như sau:
Ta thấy ngay chỗ ta cần viết các phương thức của mình. Vì chúng ta đang viết hàm để lấy dữ liệu với các tham số là các điều kiện tìm kiếm. Chính vì thế ta sẽ viết phương thức tên là search với các tham số code, fullName, gender, start, end trong đó start và end dùng để phân trang và phương thức
count với các tham số là code, fullName, gender như sau:
Ta thấy ngay chỗ ta cần viết các phương thức của mình. Vì chúng ta đang viết hàm để lấy dữ liệu với các tham số là các điều kiện tìm kiếm. Chính vì thế ta sẽ viết phương thức tên là search với các tham số code, fullName, gender, start, end trong đó start và end dùng để phân trang và phương thức
count với các tham số là code, fullName, gender như sau:
Sau khi viết xong các phương thức này ta sẽ thực hiện build service. Mục đích của việc build khi ta sửa nội dung của các lớp *Impl là để sinh các phương thức trong các lớp *Util tương ứng. Sau khi build xong, ta sửa hai dòng 16 và 17 trong file view.jsp, ngoài ra mình còn thêm một lệnh ở dòng 8 nữa, nội dung đầy đủ như sau:
Bây giờ deploy portlet, rồi refresh lại màn hình, gõ điều kiện tìm kiếm của bạn và nhấn nút "Search", kết quả sẽ trả lại những bản ghi phù hợp với nội dung mà ta yêu cầu.
Kết luận
Post này thực sự rất dài, tuy nhiên, nếu để ý kĩ ta thấy nó được kết hợp của hai post trước đó mà thôi. Việc viết thêm các phương thức nào, thêm các finder nào trong file service.xml là tùy thuộc vào nghiệp vụ chương trình của bạn, có thể là tìm theo ngày sinh chẳng hạn. Bài này là một ví dụ rất đầy đủ và gần với thực tế nhất. Hãy tham khảo nó nhé, code đầy đủ ở đây.
Cho e hỏi là khi nhấn nút search thì ko hiện gì cũng ko lỗi gì thì bị sao
Trả lờiXóaThanks for your visiting,
XóaBạn xem có thêm vào cuối (trước thẻ đóng dòng chưa, có thẻ này thì dữ liệu mới hiển thị lên được.
Good luck!
tức là data trong DB thì đã hiện lên rồi, nhưng khi nhập dữ liệu vào các ô để search thì ko đc
XóaHi,
XóaCó một số điểm cần lưu ý:
1. search-container phải được đặt trong 1 form
2. các điều kiện search phải đảm bảo để trả ra kết quả. Bạn xem phương thức search ở trong file https://github.com/programmerit/liferay-tutorial/blob/master/combine-portlet/docroot/WEB-INF/src/com/blogspot/chingovan/tutorial/combine/service/impl/StudentLocalServiceImpl.java đối với các điều kiện lọc là chuỗi phải thêm các dấu "%" vào đầu và cuối, các số thực phải lọc trong khoảng,...
3. Bạn hãy gửi portlet của bạn để mình xem kĩ hơn và có câu trả lời chính xác nhất. Email của mình là chingovan@gmail.com
Rgrd!
Cho mình hỏi là headerNames và orderableHeaderNames trong StudentSearchContainer dùng để làm gì vậy
Trả lờiXóa