Цель
Приобщиться к портальным технологиям, исследовать возможности, которые дает спецификация JSR286План работ
1. Создать проект2. Создать настройки портлета, вывести их на страницу портала
3. Сохранить настройки, проверять настройки валидатором
4. Создать режим просмотра, зависящий от настроек портлета
5. Генерировать и обрабатывать события в рамках одного портлетного приложения.
Я уже писал раньше о том, как активно развивается спецификация JSR286, как Sun один за одним клепает версии порталов, пичкая их разными вкусностями. После выхода в свободное плавание GlassFish, являющегося прямым родственником Sun Java system Server, стоит ожидать, что свободному сообществу отдадут ветку портала, который, как я писал раньше, сейчас мало чем уступает порталу от IBM. Надо внимательно присмотреться к портлетам и тем бонусам, которые появляются при их использовании. О ложках дёгтя тоже збаыать не будем.
Описание приложения
В портлетном приложении есть два портлета: SearchPortlet и DetailsPortlet. С помощью первого портлета пользователь ищет сотрудников, на втором портлете пользователь просматривает результаты.
Для того, чтобы добиться похожего результата, создайте проект
File -> New project -> Web -> Web Application с названием HRPortletExample.
В качестве сервера выберите OpenPortal Portlet Container 2.0, зарегистрированный ранее (см. мои предыдущие статьи). Выберите поддержку Portlet Support, создайте портлет с именем класса SearchPortlet.
Не забудьте поместить портлет в указанный на схеме пакет.
И так, у нас есть портлетное приложение и портлет-пустышка. Теперь займемся другими вещами.
Инфраструктура проекта
Класс Person
Создаем класс ru.habr.utils.Person. Этот класс будет отвечать за сотрудника.package ru.habr.utils;
import java.io.Serializable;
public class Person implements Comparable<Person>, Serializable{
private int id;
private String name;
private String surname;
private String department;
private String rank;
public Person(){
}
public Person(int id, String… data){
//TO-DO insert length check to avoid ArrayIndexOutOfBoundsException
this.id = id;
this.name = data[0];
this.surname = data[1];
this.department = data[2];
this.rank = data[3];
}
@Override
public String toString(){
StringBuilder sb = new StringBuilder();
sb.append(name).append(" ").
append(surname).append(" ::: ").
append(department).append(" ::: ").
append(rank);
return sb.toString();
}
public String getFullString(){
StringBuilder sb= new StringBuilder();
sb.append(name).append(surname).append(department).append(rank);
return sb.toString();
}
public String getTokenizedRepersentation(){
StringBuilder sb = new StringBuilder();
sb.append(this.id).append(":");
sb.append(this.name).append(":");
sb.append(this.surname).append(":");
sb.append(this.department).append(":");
sb.append(this.rank);
return sb.toString();
}
public static Person restorePersonFromTokenizedRepresentation( String tokenizedRepresentation){
Person person = null;
String[] dataStr = tokenizedRepresentation.split(":");
if(dataStr.length==5){
person = new Person();
person.setId(Integer.valueOf(dataStr[0]));
person.setName(dataStr[1]);
person.setSurname(dataStr[2]);
person.setDepartment(dataStr[3]);
person.setRank(dataStr[4]);
}
return person;
}
@Override
public int hashCode(){
return department.hashCode();
}
@Override
public boolean equals(Object obj){
boolean isEqual = false;
if(obj instanceof Person){
if( this.getId() == ((Person)obj).getId() ){
isEqual = true;
}
}
return isEqual;
}
public int compareTo(Person inputPerson) {
return surname.compareTo(inputPerson.getSurname());
}
//...
}
Вместо //... вставляем геттеры и сеттеры для полей класса.
Метод public String getFullString() понадобится для поиска сотрудников, а метод public String getTokenizedRepersentation() и public static Person restorePersonFromTokenizedRepresentation( String tokenizedRepresentation) понадобится для удобного хранения экземпляра класса в виде строки. Для чего нужен такой экстравагантный способ, я объясню ниже. Если уважаемые читатели подскажут, как от него избавиться, я буду безмерно благодарен.
Обратите внимание, что класс описывает методы интерфейса Comparable (чтобы сотрудников можно было сортировать), и помечен интерфейсом — маркером Serializable, для того, чтобы сотрудник мог сериализоваться.
Сортировка пригодится для вывода списка сотрудников на странице, а сериализация нужна для передачи найденного сотрудника от одного портлета другому через события.
Класс UtilClass
Этот класс читает файл с сотрудниками, создает экземпляры класса Person и засовывает и в Map, где ключ — id сотрудника, а значение — сам сотрудник.Детали вы рассмотрите в исходниках, покажу только метод, осуществляющий поиск:
public ArrayList<Person> searchForPerson(String searchString){
ArrayList<Person> resultList = null;
if(searchString == null || searchString.trim().replace(" ", "").length()<1){
return null;
}else{
resultList = new ArrayList<Person>();
searchString = searchString.trim().replace(" ", "");
for(Person p: mapWithPersons.values()){
if(p.getFullString().toLowerCase().contains(searchString.toLowerCase())){
resultList.add(p);
}
}
}
return resultList;
}
Все просто, плоско и параллельно — сотрудник вытягивается в строку и далее осуществляется поиск по совпадению части строки сотрудника и символов, введенных пользователем. Короче, суть не в поиске, едем дальше.
Портлет SearchPortlet
На этом портлете будет строка для поиска и кнопка найти. Для демонстрации режима редактирования, добавим возможность вывода полного списка сотрудников в режиме просмотра. Выглядеть это будет следующим образом:Добавление настроек в portlet.xml
Настройки портлета прописываются в portlet.xml, давайте его посмотрим и пропишем их:<portlet>
<description>SearchPortlet</description>
<portlet-name>SearchPortlet</portlet-name>
<display-name>SearchPortlet</display-name>
<portlet-class>ru.habr.portlet.SearchPortlet</portlet-class>
<expiration-cache>0</expiration-cache>
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>VIEW</portlet-mode>
<portlet-mode>EDIT</portlet-mode>
<portlet-mode>HELP</portlet-mode>
</supports>
<resource-bundle>ru.habr.portlet.messages</resource-bundle>
<portlet-info>
<title>SearchPortlet</title>
<short-title>SearchPortlet</short-title>
</portlet-info>
<portlet-preferences>
<preference>
<name>showPersonsList</name>
<value>false</value>
</preference>
</portlet-preferences>
</portlet>
В секции <portlet-preferences> указываются имена настроек (чтобы к ним можно было обращаться) и значения по умолчанию. И то и другое хранится в виде строки, соответственно неизбежны ошибки ввода. Для проверки корректности устанавливаемых настроек применяются валидаторы. О них мы поговорим в следующий раз.
Редактирование метода doEdit в портлете SearchPortlet
Переходим в класс SearchPortlet, ищем метод doEdit, отвечающий отображение режима настройки портлета:@Override
public void doEdit(RenderRequest request,RenderResponse response) throws PortletException,IOException {
//transfer preference value to jsp
String prefValue = request.getPreferences().getValue(PREF_SHOWPERSONS,"");
request.setAttribute(PREF_SHOWPERSONS, prefValue);
response.setContentType(«text/html»);
PortletRequestDispatcher dispatcher =
getPortletContext().getRequestDispatcher("/WEB-INF/jsp/SearchPortlet_edit.jsp");
dispatcher.include(request, response);
}
К текущим настройкам портлета можно обратиться через request.getPreferences().getValue(PREF_SHOWPERSONS,"")
PREF_SHOWPERSONS — статическое поле класса, хранящее имя настройки showPersonsList.
Если внимательно почитать , то видно, что настройки рекомендуется передавать на jsp в виде атрибутов, хотя на самой jsp можно точно так же обратиться к настройкам через renderRequest.getPreferences().getValue(PREF_SHOWPERSONS,"") Зачем это делать — непонятно.
SearchPortlet_edit.jsp
Выглядит так:<%@page contentType=«text/html»%>
<%@page pageEncoding=«UTF-8»%>
<%@page import=«javax.portlet.*»%>
<%@ page import=«javax.portlet.*»%>
<%@ page import=«ru.habr.portlet.SearchPortlet»%>
<%@ taglib uri=«java.sun.com/portlet_2_0» prefix=«portlet»%>
<portlet:defineObjects />
<%boolean showPersonList = Boolean.valueOf((String)renderRequest.getAttribute(SearchPortlet.PREF_SHOWPERSONS));%>
<H4>Редактирование портлета «Поиск сотрудников».</H4>
<form method=«post» action="<portlet:actionURL/>">
Отображать список сотрудников на странице?<br>
<select name="<%=SearchPortlet.PREF_SHOWPERSONS%>">
<option value=«true» <%= showPersonList? «SELECTED» : "" %> >Да</option>
<option value=«false» <%= !showPersonList? «SELECTED» : "" %> >Нет</option>
</select>
<input type=«submit» value=«Сохранить»>
</form>
Вытаскиваем значение атрибута, отображаем значение, ждем нажатия на кнопку. Сам режим редактирования выглядит так:
URL для формы генерируется на этапе компиляции jsp при помощи тэга actionURL.
Как сохранить новые настройки и что происходит при нажатии на кнопку «Сохранить» я расскажу в следующей серии!
* This source code was highlighted with Source Code Highlighter.