Học liferay qua ví dụ: Sử dụng Custom query để implement service

Học liferay qua ví dụ: Sử dụng Custom query để implement service

Như đã đề cập ở phần trên, mặc định service-builder chỉ tạo ra các method cơ bản, nếu muốn có các method để phục vụ cho các xử lý nghiệp vụ phức tạp hơn thì ta phải tạo ra nó. Phần này sẽ hướng dẫn chúng ta cách thêm các method vào các class mà service-builder đã tạo ra. Chúng ta sẽ tìm hiểu điều này qua ví dụ sau.
Ví dụ portlet của bạn cần chức năng để tìm kiếm product. User sẽ input keyword và click button search, sau đó kết quả tương ứng sẽ hiểu thị. Việc trước tiên chúng ta sẽ làm là implement service để thực hiện việc search này. (Phạm vi của ví dụ này không hướng dẫn cách tạo portlet để search product mà chỉ hướng dẫn cách hiện thực service. Việc tạo portlet với chức năng search xin dành cho bạn đọc)

Để thực hiện việc này, chúng ta cần làm các bước sau.

B1: Khởi tạo class finder, bổ sung service.

Ở package persistence, Tạo 1 class có tên ProductFinderImpl (<tên class> = <entity name> +
FinderImpl). Ở Class này, tạo 2 method rỗng là searchByNameOrDescription và
countByNameOrDescription (Tên method thì đặt tùy ý). Nội dung các method như sau:

1
2
3
4
5
6
7
8
9
10
11
12

package vn.softech.web.dng67.service.persistence;
import java.util.List;
import vn.softech.web.dng67.model.Product;
import com.liferay.portal.kernel.exception.SystemException;
public class ProductFinderImpl {
             public List<Product> searchByNameOrDescription (String keyword, int start, int end) throws SystemException {
                     return null;
              }
       public long countByNameOrDescription (String keyword) throws SystemException {
              return 0;
       }
}

Open file ProductLocalServiceImpl.java bổ sung 2 method searchByNameOrDescription và countByNameOrDescription (Tên method thì đặt tùy ý). Nội dung các method như sau:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package vn.softech.web.dng67.service.impl;
import java.util.List;
import com.liferay.portal.kernel.exception.SystemException;
import com.liferay.portal.kernel.util.OrderByComparator;
import vn.softech.web.dng67.model.Product;
import vn.softech.web.dng67.service.base.ProductLocalServiceBaseImpl;
public class ProductLocalServiceImpl extends ProductLocalServiceBaseImpl {
       public List<Product> getProducts (int start, int end, OrderByComparator orderByComparator ) throws SystemException {
              return this.productPersistence.findAll(start, end, orderByComparator);
       }
       public List<Product> searchByNameOrDescription (String keyword, int start, int end) throws SystemException {
              return null;
       }
       public long countByNameOrDescription (String keyword) throws SystemException {
              return 0;
       }
}

Để Portlet có thể sử dụng các method này thì chúng ta thực hiện re-build service bằng cách run ant build-service như ở bước tạo service 1 lần nữa. Mục đích của việc này là để service-builder tạo interface ProductFinder và bổ sung 2 method mới thêm vào ở ProductLocalServiceImpl vào interface ProductLocalService và class ProductLocalServiceImplUtil để chúng ta sử dụng ở portlet. Class ProductFinderImpl là hiện thực của interface ProductFinder (ở class ProductFinderImpl bổ sung thêm ở khai báo class đoạn code “implements ProductFinder”)

B2: Implement finder và service

Ở bước trên chúng ta chỉ tạo ra các method rỗng (không thực hiện gì cả). Ở bước này, chúng ta sẽ implement cho nó (bổ sung code).

a) Implement Finder

Finder cũng giống như các persistence khác là nó thực hiện việc tương tác với DB. Phần này sẽ hướng dẫn cách sử dụng Custom query để thực hiện truy vấn dữ liệu. Hãy thực hiện theo các bước sau đề cập dưới đây.
+ Ở thư mục src của project, tạo folder custom-sql. Sau đó tạo file default.xml trong folder vừa tạo. Cấu trúc folder và Nội dung file default.xml như sau:


1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version="1.0" encoding="UTF-8"?>
<custom-sql>
       <sql id="vn.softech.web.dng67.service.persistence.ProductFinder.searchByNameOrDescription">
              <![CDATA[
                     SELECT * FROM sample_product WHERE product_name LIKE ? OR description LIKE ?
              ]]>
       </sql>
       <sql id="vn.softech.web.dng67.service.persistence.ProductFinder.countByNameOrDescription">
              <![CDATA[
                     SELECT COUNT(id_product) FROM sample_product WHERE product_name LIKE ? OR description LIKE ?
              ]]>
       </sql>
    </custom-sql>

Giải thích:
File này dùng để định nghĩa các câu SQL mà chúng ta sử dụng trong project. Mỗi SQL được định nghĩa bằng tag sql và phân biệt bằng id duy nhất. (Việc đặt ID là tùy ý miễn sao duy nhất là được).
+ Tiếp theo, Open file ProductFinderImpl.java và thực hiện code cho 2 method đã đề cập như sau:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
public class ProductFinderImpl extends BasePersistenceImpl<Product> implements ProductFinder{
       public List<Product> searchByNameOrDescription(String key, int start, int end) throws SystemException {
              Session session= null;
              String sql= "";
              try {
                     //open session
                     session= openSession();
                     //set SQL by ID
           sql=CustomSQLUtil.get(ProductFinder.class.getName()+".searchByNameOrDescription");
                     SQLQuery query= session.createSQLQuery(sql);
                     query.addEntity("Product", ProductImpl.class);
                     QueryPos qPos= QueryPos.getInstance(query);
                     qPos.add("%"+ key+ "%");
                     qPos.add("%"+ key+ "%");
                     return (List<Product>) QueryUtil.list(query, getDialect(), start, end);
              }
              catch(Exception ex){
                     ex.printStackTrace();
                     throw new SystemException(ex);
              }
              finally{
                     closeSession(session);
              }
       }
      -------------------------------------------------------------------------------------------------------------------------
       public long countByNameOrDescription(String key) throws SystemException{
              Session session= null;
              String sql= "";
              try{
                     //open session
                     session= openSession();
                     //set SQL by ID
                     sql=CustomSQLUtil.get(ProductFinder.class.getName()+".countByNameOrDescription");
                     SQLQuery query= session.createSQLQuery(sql);
                     query.addEntity("Product", ProductImpl.class);
                     QueryPos qPos= QueryPos.getInstance(query);
                     qPos.add("%"+ key + "%");
                     qPos.add("%"+ key + "%");
                     return Long.parseLong(query.uniqueResult().toString());
              }
              catch(Exception ex){
                     ex.printStackTrace();
                     throw new SystemException(ex);
              }
              finally{
                     closeSession(session);
              }
       }
}

Giải thích:

Các method ở Finder sẽ đọc câu SQL được đính nghĩa ở default.xml để sử dụng (xem line 28, 53). Đối số truyền cho method get ở line 28 phải có nội dung giống với ID của SQL định nghĩa ở line 3 của file default.xml. Đối tượng QueryPos thực hiện thiết lập tham số cho các dấu hỏi (?) trong SQL. Line 30 thực hiện chuyển đổi các kết quả tìm được thành các đối tượng kiểu Product. Nếu không thực hiện addEntity thì mặc định kết quả query có kiểu mảng 2 chiều [][].

+ Tiếp theo, Open file ProductLocalServiceImpl.java và thực hiện code cho 2 method đã đề cập như sau:

1
2
3
4
5
6
7
public List<Product> searchByNameOrDescription(String key, int start, int end) throws SystemException{
              return productFinder.searchByNameOrDescription(key, start, end);
       }
       public long countByNameOrDescription(String key) throws SystemException{
              return productFinder.countByNameOrDescription(key);
       }

Class Service chỉ thực hiện việc gọi Finder thông qua biến nội bộ đã được khỏi tạo ở class Base Service. Đến đây thì việc implement service đã hoàn thành. Việc còn lại là sử dụng nó ở portlet để thực hiện việc tìm kiếm product. Bài sau sẽ hướng dẫn áp dung custom-sql để tìm kiếm product.

No comments:

Post a Comment