TRƯỜNG ĐẠI HỌC BÁCH KHOA HÀ NỘI
VIỆN CÔNG NGHỆ THÔNG TIN VÀ TRUYỀN THỒNG
o0o
BÀI TẬP LỚN
CÔNG NGHỆ WEB VÀ DỊCH VỤ TRỰC TRUYẾN
Đề tài: Phát triển portlet mới cho người dùng
Giảng viên hướng dẫn: Thầy Tạ Tuấn Anh
Nhóm thực hiện: Nhóm 04 - HTTT K52
Sinh viên thực hiện: Dương Mạnh Linh 20071697
Mai Ngọc Dương 20070009
Nguyễn Văn Minh 20071970
Vũ Văn Thiện 20072737
Lê Quang Vịnh 20073503
Đỗ Như Linh 20071700
Lớp HTTT – K52
Hà Nội – Tháng 11/2011
1 | Page
Mục Lục
Phần 1: Tổng quan về portlet 3
1. Nhắc lại về Liferay portal 3
1.1 Khái niệm về portlet 4
1.2 Phân loại 5
1.2.1 JavaServer Page portlet (JSP portlet) 6
1.2.2 Strusts portlet 6
1.2.3 JavaServer Faces portlet (JSF portlet) 6
1.2.4 Vaadin portlet 6
1.2.5 Spring MVC portlet 7
1.3 Hoạt động của portlet trong Liferay portal 7
1.4 Truyền dữ liệu giữa các phase 8
Phần 2: Tìm hiểu về JSP portlet và Vaadin portlet 10
2.1 JSP portlet 10
2.1.1 Cấu trúc 10
2.1.2 Mô hình MVC trong JSP portlet 14
2.1.3 Một vài đặc điểm của JSP portlet 14
2.2 Vaadin portlet 14
2.2.1 Cấu trúc Vaadin portlet 16
2.2.2 Hoạt động của Vaadin portlet 17
2.2.3 Một vài đặc điểm của Vaadin portlet 17
Phần 3: Thực hành – Hướng dẫn phát triển portlet 18
3. Cài đặt môi trường phát triển portlet 18
3.1 JSP portlet 19
3.1.1 First-portlet 19
3.1.2 MyGreeting-portlet (simple) 20
3.1.3 MyGreeting-portlet1 (Advance) 23
3.1.4 Greeting-Session-Portlet 25
3.1.5 Ajax portlet 27
3.1.6 Report portlet 32
3.2 Vaadin portlet 34
2 | Page
3.2.1 FirstVaadin portlet
3.2.2 NotifyVaadin portlet
3.2.3 Login portlet
3.2.4 Vaadin-portlet mode
3.3 Project example
Phần 4: Một số vấn đề tham khảo
4. Các tags phổ biến trong portlet
4.1 Tùy chỉnh portlet trên giao diện
4.2 Các quy ước chuẩn về code
Phần 5: Phân công công việc
Phần 6: Kết luận
Phần 7: Tài liệu tham khảo
Phần 1: Tổng quan về portlet
1. Nhắc lại về Liferay portal
3 | Page
Portal là: Cổng thông tin điện tử tích hợp là điểm truy cập tập trung
và duy nhất, tích hợp các kênh thông tin, các dịch vụ và ứng dụng, phân
phối tới người sử dụng thông qua một phương thức thống nhất và đơn
giản trên nền tảng Web.
Có nhiều loại cổng thông tin khác nhau cung cấp nhiều loại dịch vụ và ứng
dụng khác nhau, tuy nhiên chúng đều phải có 1 số tính năng cơ bản như:
- Khả năng cá nhân hóa (Personalization)
- Tích hợp nhiều loại thông tin (Content aggregation)
- Xuất bản thông tin (Content syndication)
- Hỗ trợ nhiều môi trường hiển thị thông tin (Multidevice support)
- Khả năng đăng nhập một lần (Single Sidn on – SSO)
- Quản trị portal (Portal administrator)
- Quản trị người dùng (Portal user management)
Chính các tính năng này là điểm phân biệt giữa một website bình thường,
một ứng dụng quản trị nội dung (CMS) hay một ứng dụng chạy trên nền tảng
web (Web application) với một cổng thông tin. Khái niệm này hiện nay vẫn
còn bị nhầm lẫn bởi rất nhiều người.
Portal có các tính năng giúp người quản trị thu thập, quản lý nhiều
nguồn thông tin khác nhau, từ đó phân phối chúng dưới dạng các dịch vụ
cho từng người dùng khác nhau tuỳ thuộc vào nhóm quyền, vào nhu cầu
cũng như mục đích của người dùng đó. Portal thực hiện việc này hết sức
linh động, từ những công việc như tìm xem và đặt mua sách trong một kho
hàng trực tuyến, xem và thay đổi thông tin về sinh viên và giáo viên trên
các ứng dụng quản lý giảng dạy, đến việc đăng và chia sẻ các thông tin, tài
nguyên, bài viết trên các diễn dàn hay cung cấp việc truy cập thống nhất và
thuận lợi đến các thông tin nội bộ trong một website của công ty Portal
như một cổng vào vạn năng cho người dùng tìm kiếm thông tin và tác
nghiệp một cách thuận lợi và dễ dàng
Khái niệm Portal đã xuất hiện từ khá lâu, trải qua một quá trình dài phát
triển và hoàn thiện. Liferay portal hiện đang là giải pháp cổng thông tin với mã
nguồn mở toàn diện và phổ biến nhất hiện nay.
1.1 Khái niệm về portlet
Portlet là một web application nhỏ chạy trong portal. Nó là phần quan
trọng nhất của bất kì cổng thông tin nào, bởi vì nó chứa các chức năng
thực tế của portal, cụ thể hóa các chức năng đó thành giao diện tương tác
với người dùng. Mọi hoạt động trên portal được thực hiện thông qua các
4 | Page
portlet. Nói một cách khác, portlet chính là trái tim của portal.
H1. Hình ảnh về portlet tren portal (các vùng được khoanh)
Mỗi portlet chỉ là một phần nhỏ của trang web, một trang có thể bao
gồm nhiều portlet. Nó được biên dịch ra thành một đoạn mã HTML trong
cả trang web, vì thế, trong một portlet không bao gồm các tag như <html>,
<head> hay <body>. Portal sẽ kết hợp các đoạn mã HTML đó từ nhiều
portlet và gộp thành một trang web hoàn chỉnh.
Nội dung sản sinh bởi 1 portlet cũng đuợc gọi là 1 fragment. Một
fragment là 1 phần các ngôn ngữ đánh dấu (như HTML, XHTML, WML)
tuân thủ nghiêm ngạt các luật và có thể được kết hợp với các fragments
khác tạo nên 1 tài liệu hoàn chỉnh. Nội dung của một portlet thông thường
được tích hợp với nội dung của các portlet khác để hình thành nên trang
cổng điện tử. Chu kỳ sống của 1 portlet được quản lý bởi portlet container.
Portlet container là thành phần quản lý các portlet của portal, nó chịu
trách nhiệm quản lý, thiết lập, cung cấp tài nguyên, quản lý chu trình sống
của portlet. Portlet container nhận các yêu cầu từ cổng điện tử và thực
thi các yêu cầu đó trên các portlet mà nó quản lý. Portlet container không
chịu trách nhiệm kết hợp nội dung sản sinh bởi các portlet, trách nhiệm
đó thuộc về portal. Một cách khác, có thể coi portlet container là một trạm
trung giam điều phối các hoạt động của portlet và portal.
1.2 Phân loại
Portlet cũng có nhiều loại khác nhau và đều được Liferay portal hỗ trợ. Một số
loại portlet phổ biến có thể kể đến như:
5 | Page
o
JavaServer Page (JSP) portlets
o
Struts portlets
o
JavaServer Faces (JSF) portlets
o
Vaadin portlets
o
Spring Model–View–Controller (MVC) portlets
1.2.1 JavaServer Page portlet (JSP portlet)
Đây là loại portlet đơn giản nhất trong Liferay. Phần core xử lý được
viết bằng java. Các nhà phát triển có thể dễ dàng hiểu và phát triển được
các JSP portlet bởi cấu trúc, cách thức xử lý cũng như logic của JSP portlet
là khá đơn giản và dễ hiểu.
Trong Liferay plugin SQK đã có chế độ tự động sinh các portlet theo
dạng JSP portlet, coi như đây mà loại portlet mặc định
1.2.2 Strusts portlet
Strusts portlet được thiết kế theo mô hình MVC dựa trên nền tảng của
Struts Portlet Framework. Strust portlet là một trong những công nghệ
hoàn chỉnh nhất của portlet tuy nhiên việc phát triển nó là khó khăn hơn.
Chúng ta có thể tải Struts portlet và Struts 2.0 portlet trên trang download
của Liferay
1.2.3 JavaServer Faces portlet (JSF portlet)
Portlet được xây dựng trên nền tảng của Java Server Faces APIs của
SUN. Đây là công nghệ tiêu chuẩn để xây dựng giao diện người dùng phía
máy chủ, được thiết kế để giúp cho các nhà thiết kế giao diện web dễ dàng
hơn.
Trên giao diện download của Liferay, ta có thể lấy được các WAR file
cho cả JSF 1.1 và JSF 1.2 Portlet
1.2.4 Vaadin portlet
Vaadin portlet là portlet mới nhất được hỗ trợ trong Liferay portal mặc
dù chúng ta có thể chạy các phiên bản cũ bằng cách cài đặt thủ công thông
qua các file thư viện mở của Vaadin.
Vaadin portlet có một đặc điểm khá là thú vị bởi chúng ta viết Vaadin
portlet hoàn toàn ở phía server, chúng ta không cần lo ngại về HTML,
CSS, về Javascript hay sự tương thích với trình duyệt bởi nó hoàn toàn
được xử lý từ bên trong. Vaadin portlet được phát triển dựa trên Vaadin
Framework.
6 | Page
1.2.5 Spring MVC portlet
Liferay portal cũng hỗ trợ Spring MVC portlet. Spring MVC portlet nổi
tiếng với khía cạnh lập trình định hướng. Được phát triển dựa trên Spring
Web Flow (SWF), Spring Framework – đây là giải pháp tốt nhất cho việc
quản lý dòng chảy trong ứng dụng web. Cụ thể nó cho phép chúng ta chụp
các dòng sự kiện như một module khép kín và có thể tái sử dụng cho các
tình huống khác nhau. Và như vậy, nó là lý tưởng cho việc xây dựng các
module ứng dụng web cho phép các nhà quản lý dễ dàng quản lý các giao
dịch mà không cần quan tâm đến các vấn đề xử lý ở mức độ thấp.
1.3 Hoạt động của portlet trong Liferay portal
Một điểm đặc thù của portlet đó là nó cần tới 2 bước để hiển thị. Nó khác
biệt với rất nhiều người phát triển servlet hay những người quen sử dụng
các ngôn ngữ thông dụng nhu PHP, Python hay Ruby…
Lý do cho việc phải sử dụng đến 2 phases là do portlet không phải là một
trang HTML hoàn chỉnh, nó chỉ là một phần nhỏ trong cả trang. Trang tin
được tạo ra bằng cách gọi một hoặc một số portlet và điền các mã HTML bổ
sung cho chúng để có được một trang HTML hoàn chỉnh.
Tuy nhiên,việc này cũng đem lại một vài rắc rối. Ta có thể hình dung quá
trình hoạt động của portet và portal như sau:
Khi người dùng tương tác với trang web, chẳng hạn như bấm vào 1
link trong 1 portlet cụ thể nào đó. Tất nhiên là cổng thông tin phải có trách
nhiệm xử lý sự kiện đó và trả lại kết quả cho portlet. Sau đó nó phải làm
nhiệm vụ hiển thị cả trang web bao gồm portlet vừa tác động( nội dung
của portlet này có thể đã thay đổi ), đồng thời nó phải hiện thị nội dung của
cả các portlet khác. Việc này là cần thiết bởi các portlet này mặc dù người
dùng không tương tác đến nhưng nội dung của nó vẫn có thể bị thay đổi
bởi hành động vừa rồi của người dùng. Vậy làm thế nào để cổng thông tin
hiển thị được nội dung của các portlet khác khi không có bất kì tác động
nào đến chúng?
Chúng ta hình dung một kịch bản: Chúng ta có một trang bán hàng với
2 portlet, một navigation-portlet (portlet cho các hình thức vận chuyển
hàng) và shopping-portlet. Người dùng thao tác với trang như sau:
-
Người dùng vào trang bán hàng.
-
Click vào một button trong shopping-portlet để mua hàng. Lúc này,
tài khoản và giỏ hàng của người dùng đó sẽ tự động được cập nhật
và bắt đầu một quá trình để vận chuyển sản phẩm cần mua. Sau khi
7 | Page
hoạt động này, cổng thông tin sẽ gọi đến navigation-portlet với giao
diện mặc định của nó.
-
Người dùng bấm vào 1 link trong navigation-portlet để chọn kiểu
vận chuyển. Nội dung của portlet được thay đổi. Sau đó cổng thông
tin cũng phải hiển thị lại nội dung của shopping-portlet, và do đó
nó lặp lại hành động cuối của người dùng là click vào nút mua hàng
một quá trình mua hàng được lặp lại dẫn đến một quá trình vận
chuyển mới … Và để portlet có được nội dung của nó, nó cần phải
yêu cầu lại tới portal. Việc này còn có thể lặp lại nhiều lần nữa (ít
nhất là cho tới khi tài khoản người dùng đến giới hạn)
Ta có thể thấy, rõ ràng là kịch bản trên là không đúng. Để ngăn chặn tình
huống này, các đặc điểm kỹ thuật của portlet định nghĩa 2 giai đoạn cho
mọi yêu cầu của portlet để cho phép cổng thông tin có thể phân biệt được
một hành động nào là đang được thực hiện (tất nhiên là không nên lặp lại)
và nội dung được sinh ra:
-
Action phase: Giai đoạn này chỉ có thể được thực hiện tại 1 portlet
tại 1 thời điểm và thường là kết quả của việc tương tác giữa người
dùng với trang web. Trong giai đoạn này, các portlet có thể thay đổi
trạng thái của nó. Nó cũng được đề nghị rằng có thể thực hiện các
tác động như thay đổi CSDL hay các hoạt động mà không cần lặp đi
lặp lại
-
Render phase: Giai đoạn này luôn luôn áp dụng cho tất cả các portlet
trong trang bao gồm portlet vừa tác động và cả các portlet khác. Nó
được thực thi khi có 1 tác động nào đó làm thay đổi đến nội dung
của cả trang. Có một điểm quan trọng là trong một trang, thứ tự
render các portlet là không xác định. Nếu cần thiết cho viện này,
Liferay có một mở rộng là render-weight trong liferay-portlet.xml
nhưng muốn sử dụng thì người dùng phải tự thêm vào. Các portlet
có render-weight cao hơn sẽ được render trước
1.4 Truyền dữ liệu giữa các phase
Như đã trình bày, portlet hoạt động trên 2 phase chính. Vậy làm cách nào mà
dữ liệu hay các thông tin được truyền từ phase sang phase kia?
Có 2 cách mà ta có thể làm để truyền dữ liệu từ action phase vào render
phase.
8 | Page
-
Thứ nhất, ta có thể truyền qua các biến. Trong lúc thực hiện
processAction ta có thể truyền thêm một tham số mới cho bước
render:
actionResponse.setRenderParameter("parameter-name", "value");
Trong render phase (file jsp) giá trị này có thể đọc và sử dụng như
một biến bình thường:
renderRequest.getParameter("parameter-name");
(*) Chú ý
Khi gọi một actionURL, các tham số truyền chỉ có thể đọc ở
giai đoạn action phase (trong phương thức proceessAction).
Để có thể truyền tham số cho bước render phase ta phải
lấy chúng từ actionRequest và sau đó sử dụng phương thức
setRenderParamater cho mỗi tham số cần.
Một chú ý quan trọng là các biến RenderParamater sẽ được
portal ghi nhớ cho tới khi chính các portlet đó được gọi với tham
số khác. Do đó trường hợp người dùng sử dụng portlet này và
tạo ra các tham số, sau đó người dùng tiếp tục tác động đến các
portlet khác, và mỗi lần trang được nạp lại, portal sẽ render lại
portlet của chúng ta và sử dụng ngay các tham số được thiết lập.
Điều này có nghĩa là thông báo của chúng ta (giả sử đó là thông
báo “Save successfuly” trong ví dụ trên) nó sẽ được hiện ra ngay
cả khi không phải chúng ta bấm Save.
-
Phương pháp thứ 2 là ta có thể sử dụng đó là sử dụng session. Trên
thực tế phương pháp này tốt hơn so với phương pháp trên. Nó
không chỉ truyền tham số cho một portlet mà tất cả các portlet đều
có thể lấy được. Có thể mọi người đã quen với cách này khi lập trình
với các ngôn ngữ khác. Để thực hiện việc này, ta sử dụng thêm lớp
SesionMessage được liferay cung cấp. Cụ thể ta sẽ trình bày trong
phần (9) Greeting-Sesion-portlet
9 | Page
Phần 2: Tìm hiểu về JSP portlet và Vaadin portlet
2.1 JSP portlet
2.1.1 Cấu trúc
Trong Eclipse Liferay IDE, portlet mặc định khi tạo project là JSP
portlet, và được xây dựng dựa trên mô hình chuẩn theo MVCPortlet
Framework. Nó đã ẩn đi rất nhiều phần xử lý phức tạp phía dưới portlet và
giúp cho người phát triển có thể dễ dàng nắm bắt được cấu trúc, cách xây
dựng và xử lý portlet mà không cần quan tâm quá nhiều đến cách xử lý bên
trong.
Nhìn qua 1 portlet sẽ gồm 3 phần chính:
Java source
Configuration file
Client-side file (.jsp, .css, .js, images, …)
Khi sử dụng Liferay Plugin SDK để tạo portlet, cấu trúc cơ bản của thư mục
chứa có dạng như sau :
Folder Structure:
H2. Portlet Structure
-
Phần Java source được chứa trong thư mục docroot/WEB-INF/src
10 | Page
-
Các file cấu hình được chứa trong thư mục docroot/WEB-INF dưới
dạng các file .xml.
o
liferay-display.xml: tập tin mô tả category mà portlet được
chứa (cụ thể ở đây là category Sample mà ta đã nói khi Add
portlet vào portal), đồng thời khai báo id các portlet được
chứa trong cùng project.
o
liferay-portlet.xml: Tập tin mô tả một số tùy chọn của
portlet khi được cài đặt trên Liferay portal. Chẳng hạn như
name, display name, khai báo java class, các thư mục chứa
css, js… Ta cũng có thể thấy, trong 1 project có thể chứa nhiều
portlet. Các portlet được khai báo lần lượt và id của nó được
đặt trong file liferay-display.xml
o
liferay-plugin-package.properties: Tập tin mô tả một số
đặc điểm của portlet.
o
portlet.xml: Tập tin mô tả cấu hình cụ thể của từng portlet.
Là một người mới bắt đầu vào việc tìm hiểu portlet, chúng ta
sẽ tập trung vào tập tin này bởi nó cho ta một cái nhìn gần và
rõ ràng hơn về cấu hình tùy chọn của 1 portlet
-
Các file phía client như .jsp, .css, javascript, image … chứa trong
docroot
Để có 1 hình dung cụ thể, rõ ràng hơn về các cấu hình cho 1 portlet, ta sẽ đi
vào xem xét cụ thể một số file
Portlet.xml
<portlet-app
version="2.0"
xmlns=" />app_2_0.xsd"
xmlns:xsi=" />xsi:schemaLocation=" />portlet-app_2_0.xsd />portlet-app_2_0.xsd"
>
<portlet>
<portlet-name>MyGreeting</portlet-name>
<display-name>MyGreeting</display-name>
<portlet-class>
com.liferay.util.bridges.mvc.MVCPortlet
</portlet-class>
<init-param>
<name>view-jsp</name>
11 | Page
<value>/view.jsp</value>
</init-param>
<expiration-cache>0</expiration-cache>
<supports>
<mime-type>text/html</mime-type>
</supports>
<portlet-info>
<title>MyGreeting</title>
<short-title>MyGreeting</short-title>
<keywords>MyGreeting</keywords>
</portlet-info>
<security-role-ref>
<role-name>administrator</role-name>
</security-role-ref>
<security-role-ref>
<role-name>guest</role-name>
</security-role-ref>
<security-role-ref>
<role-name>power-user</role-name>
</security-role-ref>
<security-role-ref>
<role-name>user</role-name>
</security-role-ref>
</portlet>
</portlet-app>
o
portlet-name : Portlet-name khai báo tên của portlet. Mỗi portlet-
name là duy nhất trong một portal. Nó cũng có ý nghĩa tương tự như
id của portlet trong Liferay portal.
o
display-name : Khai báo tên được hiển thị của portlet trên trang
web. Display-name không cần thiết phải là duy nhất.
o
portlet-class: khai báo class java có trách nhiệm xử lý các thao tác
trên portlet.
o
init-param: chứa một cặp tên/giá trị như là một tham số khởi tạo
của portlet. Ở đây nó khai báo file hiển thị của portlet là view.jsp.
o
expiration-cache: Tham số này chỉ ra thời gian lưu trữ của portlet
trong bộ nhớ đệm. Nếu để giá trị là -1 có nghĩa là không bao giờ hết.
o
support: chỉ ra loại định dạng dữ liệu được hỗ trợ: mime-type. Đồng
thời nó cũng khai báo các “portlet-mode” để hỗ trợ cho các loại nội
dung đặc biệt. Tất cả các poortlet phải hỗ chợ cho “view mode”. Khái
niệm “portlet-mode” được định nghĩa bởi các đặc tả của portlet.
o
portlet-info: định nghĩa các thông tin của portlet.
12 | Page
o
Security-role-ref: chứa thông tin về các đối tượng được phép truy
cập vào. Cụ thể trong liferay nó chỉ ra tên các đối tượng được truy
cập vào portlet.
Liferay-portlet.xml
File chứa các thông tin bổ sung cho portlet, đó là các tùy chọn nâng cao
cho các portlet java chuẩn được install trong Liferay. Theo mặc định,
file chứa các nội dung cụ thể sau:
<liferay-portlet-app>
<portlet>
<portlet-name>MyGreeting</portlet-name>
<icon>/icon.png</icon>
<instanceable>true</instanceable>
<header-portlet-css>/css/main.css</header-portlet-css>
<footer-portlet-javascript>/js/main.js</footer-portlet-
javascript>
<css-class-wrapper>MyGreeting-portlet</css-class-
wrapper>
</portlet>
<role-mapper>
<role-name>administrator</role-name>
<role-link>Administrator</role-link>
</role-mapper>
<role-mapper>
<role-name>guest</role-name>
<role-link>Guest</role-link>
</role-mapper>
<role-mapper>
<role-name>power-user</role-name>
<role-link>Power User</role-link>
</role-mapper>
<role-mapper>
<role-name>user</role-name>
<role-link>User</role-link>
</role-mapper>
</liferay-portlet-app>
o
Portlet-name:chứa tên của portlet, nó phải giống với portlet-name
trong portlet.xml
o
Icon: đường dẫn đến file icon cho portlet
13 | Page
o
Instanceable: thuộc tính chỉ ra khả năng có thể có nhiều portlet
giống nhau trên cùng 1 trang hay không (true – có thể, false - không)
o
Header-portlet-css, footer-portlet-javascript: đường dẫn đến file .css
và .js tương ứng
Chúng ta đã nắm được cơ bản về cấu trúc portlet và thông qua việc
phân tích cụ thể 2 file cấu hình ta đã nắm được các thuộc tính tùy chọn
quan trọng của một portlet. Từ đó ta đã có một hình dung rõ ràng và cụ
thể hơn về một portlet.
2.1.2 Mô hình MVC trong JSP portlet
Như đã biết, JSP portlet được viết theo mô hình chuẩn của
MVCPortlet Framework.
- Model (M in MVC): là các file mã java có mục đích chính là quản lý và
truy cập dữ liệu. Nó được gọi tới bởi các Controller và thực hiện các yêu
cầu đó rồi trả kết quả về cho Controller triệu gọi. Hiện tại MVCPortlet
Framework cung cấp 2 lớp ActionProcessor và RenderProcessor để thực
thi mọi hoạt động với cơ sở dữ liệu.
- View (V in MVC): Có nhiệm vụ trình bày nội dung trên portal. Nó
sử dụng mộ công nghệ phổ biến là JSP. Về mặt kĩ thuật, ta có thể
bao gồm cả các dữ liệu đã được trình bay ra dưới mã HTML hoặc
của servlet khác. Các trang JSP có thể tận dụng tất cả các hàm có sẵn
theo chuẩn của JSP, tuy nhiên nó cũng có thể sử dụng các hàm cung
cấp bởi các portlet API. Ví dụ như, các tham số yêu cầu không phải
thu được từ những đối tượng “request” có sẵn trong trang JSP mà là
từ đối tượng RenderRequest có sẵn hoặc một thư viện API được sử
dụng “javax.portlet.renderRequest” hoặc bằng các tab để định nghĩa
“renderRequest”.
- Controller (C in MVC): Chứa trong các file mã java có nhiệm vụ xử
lý tất cả các “processAction” và các yêu cầu “render”. Trong cả 2
phương pháp, controller cùng xử lý như nhau, và được phân biệt dựa
trên một tham số yêu cầu là “request_type” được cung cấp trong lớp
“portlet.mvcportlet.core.RenderProcessor”
2.1.3 Một vài đặc điểm của JSP portlet
- JSP portlet là portlet được sử dụng rộng rãi nhất bởi nó dễ dàng phát
triển, mã code dễ hiểu và logic xử lý dễ hình dung
- JSP portlet được sử dụng làm portlet mặc định trong một số IDE phát
triển Liferay portal
2.2 Vaadin portlet
14 | Page
Vaadin là một môi trường phát triển web rất thú vị. Ý tưởng chính của
Vaadin là lập trình ở phí server, nó cho phép chùng ta không cần để ý
nhiều đến các trang web hay giao diện người dùng. Trong lập trình web
truyền thống, ta có thể sẽ mất nhiều thời gian để đi học tập các công nghệ
web mới, các công nghệ truy lỗi với các ngôn ngữ phía client như HTML,
Javasctip…trong khi với Vaadin, ta chỉ cần tập trung vào phần xử lý logic
của các ứng dụng. Với mô hình máy chủ theo định hướng lập trình, Vaadin
sẽ quản lý các giao diện người dùng trong trình duyệt và sử dụng AJAX để
làm cầu nối liên lạc giữa trình duyệt và server. Thêm vào đó, Vaadin giúp
chúng ta tránh được 1 vấn dề khá đau đầu là việc tương thích với trình
duyệt.
Kiến trúc của Vaadin
Phần cốt lõi của nó là dựa các thư viện javascript, nó được thiết kế để cho
việc tạo, bảo trì một cách dễ dàng các giao diện người dùng trên web.
Bởi vì HTML, javascript và các công nghệ phía trình duyệt khác là vô hình
đối với các ứng dụng logic, vì thế ta có thể coi trình duyệt chỉ như là một
client-platform. Một client hiển thị giao diện người dùng và giao tiếp với
các sự kiện gửi người sử dụng gửi đến server ở mức độ thấp. Việc điều
khiển logic của giao diện người dùng được chạy như một “Java web server”
cùng với các ứng dụng logic khác.
Ngược lại, công nghệ client-server bình thường cần phải có rất nhiều ứng
dụng khác để liên lạc giữa client và server. Vì thế, về cơ bản loại bỏ lớp giao
diện người dùng trong kiến trúc phần mềm là một phương pháp tiếp cận
rất hiệu quả
15 | Page
2.2.1 Cấu trúc Vaadin portlet
Hình ảnh cấu trúc Vaadin portlet:
H3. Vaadin portlet
Như ta có thể thấy, Vaadin portlet không hề có các file ở phía client (
các file jsp)
Các file portlet.xml, liferay-portlet.xml tương tự như ở portlet
Liferay. Có một chút chú ý ở phần <support>. Vaadin hỗ trợ chúng ra
xem ở 3 mode là view, edit, help
16 | Page
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>view</portlet-mode>
<! <portlet-mode>edit</portlet-mode> >
<! <portlet-mode>help</portlet-mode> >
</supports>
File quan trọng nhất là các file chứa mã code .java trong Java
Resource/src
Rất nhiều thư viện được tích hợp để tương thích với mọi trình duyệt phổ
biến
2.2.2 Hoạt động của Vaadin portlet
Một điểm khác biệt của Vaadin portlet là nó hoàn toàn viết ở phía
server, nên hoạt động của nó cũng có một ít sự khác biệt. Có thể hình
dung, việc viết Vaadin portlet hoàn toàn giống như việc phát triển các
phần mềm dạng winform. Người lập trình không cần quan tâm tới các
bước « render » ra trinfg duyệt, nó được thực hiện bởi vaadin framework
trên server.
Vaadin portlet được cấu thành bởi 1 cửa sổ chính (mainWindow), các
thành phần khác được coi như các component và được mainWindow
quản lý. Các component luôn có cơ chế lắng nghe hoạt động, bất kì
tương tác nào của người dùng sẽ được thu nhận thông qua các sự kiện và
chuyển về server để xử lý.
Có thể lấy ví dụ về 1 component Button luôn lắng nghe sự kiện « click »
Bất cứ khi nào người dùng « click » vào button đó đều phát sinh một sự
kiện là « buttonClick » và được sercer xử lý.
mainWindow.addComponent(
new Button("What is the time?",
new Button.ClickListener() {
public void buttonClick(ClickEvent event) {
mainWindow.showNotification(
"The time is " + new Date());
}
}));
Việc hiển thị thông báo ra màn hình như nào ta không cần quan tâm bởi
nó đã được framework qui định.
2.2.3 Một vài đặc điểm của Vaadin portlet
17 | Page
- Vaadin portlet hoàn toàn được viết từ phía Server: tức là nó chỉ bao gồm
các file chứa mã .java và cái file .xml cấu hình
- Chúng ta không cần quan tâm tới việc sử dụng HTML, CSS hay
javascript
- Vaadin portlet phù hợp với các web mà có yêu cầu cao về xử lý logic
mà không nặng về mặt hình thức.
Phần 3: Thực hành – Hướng dẫn phát triển portlet
3. Cài đặt môi trường phát triển portlet
a. Các gói cài đặt
Download 3 gói cài đặt chính tại trang chủ của Liferay ( địa chỉ: http://
www.liferay.com/ )
-
Liferay Portal Community Edition Bundled with Tomcat
(hiện tại đang sử dụng phiên bản liferay-portal-tomcat-6.0.6-
20110225)
( />6.0.6/liferay-portal-tomcat-6.0.6-20110225.zip/download )
-
Eclipse Indigo + Liferay IDE v1.3.1 (Windows 32-bit)
( />1.3.1/eclipse_Liferay_IDE_1.3.1_v201108302303-win32.zip/
download )
-
Plugins SDK (hiện tại đang sử dụng phiên bản liferay-plugins-sdk-
6.0.6-20110225)
( />6.0.6/liferay-plugins-sdk-6.0.6-20110225.zip/download )
b. Cấu hình môi trường
Việc cấu hình bao gồm các bước:
-
Install plug-in SDK vào Eclipse: Plugin SDK là một bộ công cụ nhỏ
rất hữu ích được cung cấp bởi Liferay. Nó cung cấp nền tảng để phát
triển tất cả các bổ sung cho Liferay portal như portlet, theme, hook,
template …
18 | Page
-
Cài đặt môi trường Eclipse IDE: Được xây dựng trên nền tảng của
Eclipse và được tích hợp đầy đủ các tính năng, các thư viện tiện ích
của Liferay. Eclipse cung cấp môi trường đầy đủ để phát triển các
plugin cho Liferay porttal một cách dễ dàng nhất.
-
Sau khi cài đặt và cấu hình môi trường xong, kích hoạt server. Mặc
định của Tomcat là chạy localhost tại địa chỉ http://localhost:8080 .
Nếu các bước cấu hình đúng, một giao diện “Wellcome to
Liferay” sẽ được hiện ra. Tài khoản mặc định của hệ thống là
/test , ta có thể đăng nhập với tài khoản này để
test và thực hiện các chức năng của administrator
H4. Liferay Wellcome
Chi tiết cách cài đặt và cấu hình được trình bày cụ thể trong phần phụ lục
“Hướng dẫn cài đặt chi tiết”.
3.1 JSP portlet
3.1.1 First-portlet
H5. Demo first-portlet
19 | Page
Portlet này là portlet được tạo ra bằng Eclipse, ta chưa hề can thiệp bất cứ j vào
phần code. Nhìn qua portlet để nhận xét:
- Portlet chỉ có 1 file view.jsp, nội dung đơn giản là câu thông báo “This
is …”
<%@ taglib uri=" prefix="portlet" %>
<portlet:defineObjects />
This is the <b>FirstProject</b> portlet.
- Nội dung portlet không có gì đáng kể, ta chỉ nhìn qua để biết cấu trúc 1
JSP portlet và chuẩn bị cho bước phát triển tiếp theo
3.1.2 MyGreeting-portlet (simple)
Thay vì chỉ hiển thị một câu thông báo có sẵn “This is …” trong file
view.jsp, ta cùng làm một portlet với nhiệm vụ khó hơn, đó là hiển thị ra một
lời chào mừng và cho phép người dùng có thể sửa nó:
H6. MyGreeting-portlet
Đây là phần code đã được sửa trong file view.jsp :
<%@ taglib uri="
prefix="portlet" %>
<%@ page import="javax.portlet.PortletPreferences"
%>
<portlet:defineObjects />
20 | Page
<%
PortletPreferences prefs =
renderRequest.getPreferences();
String greeting = (String)prefs.getValue(
"greeting", "Hello! Welcome to our portal.");
%>
<p><%= greeting %></p>
<portlet:renderURL var="editGreetingURL">
<portlet:param name="jspPage" value="/edit.jsp"
/>
</portlet:renderURL>
<p><a href="<%= editGreetingURL %>">Edit greeting</
a></p>
Và chúng ta tạo thêm một file edit.jsp với nội dung:
<%@ taglib uri="
prefix="portlet" %>
<%@ taglib uri="
prefix="aui" %> <%@ page
import="javax.portlet.PortletPreferences" %>
<portlet:defineObjects />
<%
PortletPreferences prefs =
renderRequest.getPreferences();
String greeting =
renderRequest.getParameter("greeting");
if (greeting != null) {
prefs.setValue("greeting", greeting);
prefs.store();
%>
<p>Greeting saved successfully!</p>
<%
}
%>
<%
greeting = (String)prefs.getValue(
"greeting", "Hello! Welcome to our portal.");
%>
<portlet:renderURL var="editGreetingURL">
<portlet:param name="jspPage" value="/edit.jsp"
/>
</portlet:renderURL>
<aui:form action="<%= editGreetingURL %>"
method="post">
21 | Page
<aui:input label="greeting" name="greeting"
type="text" value="<%= greeting %>" />
<aui:button type="submit" />
</aui:form>
<portlet:renderURL var="viewGreetingURL">
<portlet:param name="jspPage" value="/
view.jsp" />
</portlet:renderURL>
<p><a href="<%= viewGreetingURL %>">Back</a></p>
Để ý sự khác biệt giữa portlet này và portlet đầu tiên:
- Đầu tiên, nó khai báo mội biến String greeting = “Hello. Wellcome …”
và cho nó hiển thị ra trinh duyệt
- Sau đó, sử dụng <portlet:renderURL> để link đến trang edit.jsp cho
phép sửa đổi nội dung:
<portlet:renderURL var="editGreetingURL">
<portlet:param name="jspPage" value="/edit.jsp" />
</portlet:renderURL>
<p><a href="<%= editGreetingURL %>">Edit greeting</a></p>
- File edit.jsp có một vài hàm xử lý bao gồm 1 form cho phép người dùng
thay đổi nội dung lời chào, và Save nó lại. Các thao tác được thực hiện
thông qua đối tượng renderRequest và PortletReferences
Ta có thể có 1 vài nhận xét quan trọng về portlet này:
Việc liên kết giữa 2 trang được sử dụng bởi tag
<portlet:renderURL>, nó được định nghĩa trong thư viện
. Tag này chỉ có duy nhất 1
tham số là tên 1 trang jsp, và nó được MVCPortlet sử dụng để
xác định trang web sẽ trả lại kết quả cho mỗi yêu cầu. Chúng ta
luôn luôn phải định nghĩa taglib <%@ taglib uri="http://
java.sun.com/portlet_2_0" prefix="portlet" %> để có
thể sử dụng. Hạn chế này tồn tại bởi vì portlet không thật sự là
cả một trang mà chỉ là một phần của trang web, vì thế URL luôn
phải chỉ đến đúng portlet mà nó chịu trách nhiệm xử lý. Portal sẽ
chịu trách nhiệm giải thích tablib với vừa đủ những thông tin mà
portlet cần sử dụng.
Trong file edit.jsp, có sử dụng tablib AUI đây là một phần của thư
viện Alloy UI. Alloy UI là một thu viện hỗ trợ giúp đơn giản các
mã code cần thiết cho việc tạo một form.
22 | Page
Một tab khác được sử dụng là <portlet:defineObjects /
>. Việc định nghĩa tab này giúp ta có thể chèn vào jsp một tập
hợp các biến ẩn rất hữu ích cho việc phát triển portlet như
renderRequest, portletConfig, portletPreference, …
3.1.3 MyGreeting-portlet1 (Advance)
Trong các ví dụ trên, chúng ta mới chỉ thao tác ở mức View và chưa có j
xử lý ở các mức bên trong, xử lý các file core .java
Ở ví dụ này, chúng ta sẽ làm quen với việc đó.
Giữ nguyên mà trong file view.jsp, file edit.jsp được thay đổi với nội
dung như sau:
<%@ taglib uri="
prefix="portlet" %>
<%@ taglib uri="
prefix="aui" %>
<%@ page
import="com.liferay.portal.kernel.util.ParamUtil" %>
<%@ page
import="com.liferay.portal.kernel.util.Validator" %>
<%@ page import="javax.portlet.PortletPreferences" %>
<portlet:defineObjects />
<%
PortletPreferences prefs =
renderRequest.getPreferences();
String greeting = (String)prefs.getValue(
"greeting", "Hello! Welcome to our portal.");
%>
<portlet:actionURL var="editGreetingURL">
<portlet:param name="jspPage" value="/edit.jsp" /
>
</portlet:actionURL>
<aui:form action="<%= editGreetingURL %>"
method="post">
<aui:input label="greeting" name="greeting"
type="text" value="<%= greeting %>" />
<aui:button type="submit" />
</aui:form>
23 | Page
<portlet:renderURL var="viewGreetingURL">
<portlet:param name="jspPage" value="/view.jsp" /
>
</portlet:renderURL>
<p><a href="<%= viewGreetingURL %>">Back</a></p>
Để ý thì ta có thể thấy, sự khác biệt ở đây nằm ở tag
<portlet:actionURL>, ví dụ trên chúng ta sử dụng <portlet:renderURL>
Trên thực tế, còn 1 tag nữa là <portlet:resourceURL>. Sự khác biệt của các
tag URL như sau :
-
renderURL : đây là loại URL mà chúng ta vẫn dùng, nó dùng để gọi 1
portlet mà chỉ dùng bước render. Chúng ta sẽ không can thiệp được
vào phần action phase.
-
actionURL : loại URL này khai báo cho portlet biết cách để thực thi
action phase trước khi render portlet vào trong trang.
-
resourceURL : loại URL này dùng để lấy images, XML, JSON … hay
bất khì dạng dữ liệu khác. Nó rất tiện ích để tạo các yêu cầu AJAX lên
server. Điểm khác biệt của loại URL này là ta toàn quyền xử lý dữ
liệu gửi phản hồi.
Tiếp theo, tạo file MyGreeting.java trong thư mục docroot/WEB-INF/src với
nội dung:
package com.test;
import java.io.IOException;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.PortletException;
import javax.portlet.PortletPreferences;
import com.liferay.util.bridges.mvc.MVCPortlet;
public class Mygreeting extends MVCPortlet {
@Override
public void processAction(
ActionRequest actionRequest, ActionResponse
actionResponse)
throws IOException, PortletException {
24 | Page
PortletPreferences prefs =
actionRequest.getPreferences();
String greeting =
actionRequest.getParameter("greeting");
if (greeting != null) {
prefs.setValue("greeting", greeting);
prefs.store();
}
super.processAction(actionRequest, actionResponse);
}
}
Mặc định để xử lý các request từ client thông qua actionURL là processAction,
ở đây chúng ta cần @Override nó để xử lý theo ý muốn.
Deloy lại portlet và quan sát kết quả.
Nhận xét:
-
Sự khác biệt ở đây so với portlet trước là sau khi bấm “Save” nó sẽ
tự động quay trở lại trang view.jsp với lời chào đã được thay đổi –
khác với trường hợp trước ta phải bấm “Back” đê quay lại xem kết
quả. Giải thích cho việc này là vì trong ví dụ trước ta chỉ dùng bước
render nên chúng ta không can thiệp được vào quá trình xử lý của
portal nên cần một thao tác khác để quay lại.
-
Các ví dụ từ trước đến giờ luôn được thực hiện theo dạng “request -
response”. Vậy làm thế nào để có thể portal không chỉ chả về các kết
quả mà client yêu cầu mà còn chứa cả các thông tin khác nữa? Chúng
ta cần một bước xử lý để có thể truyền biến từ action phase sang
render phase. Chẳng hạn như một câu thông báo ”Thông tin đã được
thay đổi thành công!”.
3.1.4 Greeting-Session-Portlet
Như đã trình bày, có 2 cách để truyền biến từ action phase và render phase
và cũng đã có ví dụ để nói rằng cách sử dụng session sẽ có hiệu quả hơn. Vì thế
trong demo này, chúng ta sẽ sử dụng session để truyền biến từ action tới render
phase.
Viết lại class Greeting.java và thêm dòng:
25 | Page