Използване на JavaServer Faces с ajax jsf – Поглед отвътре



Дата27.03.2017
Размер83.68 Kb.
#17885

Използване на JavaServer Faces с AJAX

JSF – Поглед отвътре

Въведение


Един от компонентите на Java 2 Enterprise Edition е JavaServer Faces технологията. Това е фреймуърк за разработване на уеб приложения базиран на JSP и Java Servlets технологиите. Едно от главните преимущества е, че позволява ясно разграничение на презентационата част и бизнес логиката в приложението.

Пример за JSF приложение


Ще демонстрираме съвсем просто JSF приложение, приемащо име за параметър и след натискане на бутона “Hello” се зарежда страница с надпис Hello с подаденото име.

Повечето JSF приложения започват с включването на двете библиотеки с готови компоненти:



<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>

<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>

Следва описанието на самата страница започващо със стандартните тагове <html> и <body>. Ето как се дефинира формата, в която се попълва името:





value="#{personBean.name}" required="true"/>





Интересното тук е израза value="#{personBean.name}". personBean e дефиниран по следния начин във файла faces-config.xml (конфигурационния файл на JSF приложението):



personBean

com.ceco.jsf.PersonBean

session



Класът com.ceco.jsf.PersonBean – тривиален Java Bean с пропърти name.

Съответно дефинираме навигацията между страниците и в добавяме в страницата с резултата следния таг:





По този начин се изписва стойността на свойството name на bean-а personBean, което свойство е попълнено от предната страница.

Демонстрация

Добавяне на автоматични подсказки чрез AJAX - Servlet


В случай, че не знаем на кого искаме да кажем Hello, добавянето на автоматични подсказки към полето за въвеждане на име ще ни улесни.

За да добавим това са ни нужни основно 2 неща: клиентска част – javascript код, който изпраща асинхронни заявки и обработва резултата, сървърна част – java код, който обработва заявките и връща отговор.


Клиентска част


Добавяме в страницата с полето за името следния код:



Създаваме попъп меню за полето, в което се въвежда името:


И добавяме action listeners:



Функцията doCompletion(...) изпраща заявка по следния начин:

function doCompletion(...) {

...

var url = "AjaxServlet?key=" + escape(target.value);

...

req.onreadystatechange = processRequest;

req.open("GET", url, true);

req.send(null);

}

Функцията processRequest(...) обработва резултата по следния начин:

function parseMessages(...) {

...

var items = req.responseXML.getElementsByTagName("items")[0];

for (loop = 0; loop < items.childNodes.length; loop++) {

var item = items.childNodes[loop];

appendItem(menu, item.childNodes[0].nodeValue);

}

}

Където appendItem добавя нова подсказка към попъп менюто.

Сървърна част


Създаваме сървлет AjaxServlet, който ще обработва заявките. Извличаме параметъра на заявката и определяме съвпаденията:

public void doGet(...) {

...

String key = (String) request.getParameter("key");

namesBean.getMatches(null, key, result);

...

}

Съставяме отговор на заявката:

public void doGet(...) {

...

sb.append("");

Iterator it = items.iterator();

while (it.hasNext()) {

sb.append("");

sb.append(it.next().toString());

sb.append("");

}

sb.append("");

...

}

И я изпращаме на клиента:

public void doGet(...) {

...

response.setContentType("text/xml");

response.setHeader("Cache-Control", "no-cache");

response.getWriter().write(sb.toString());

...

}

Добавяме във файла web.xml секция с която заявяваме, че заявките с URL /AjaxServlet ще се обработват от сървлета, който току-що написахме:



Ajax Faces Servlet

com.ceco.jsf.AjaxServlet





Ajax Faces Servlet

/AjaxServlet


Демонстрация

Добавяне на автоматични подсказки чрез AJAX – PhaseListener


Трябва да се добави картинката от слайдовете

Вторият начин за добавянето на автоматични подсказки е чрез използване на PhaseListener. Всяко JSF приложение има жизнен цикъл, който се състои от няколко фази (например осъществяванеto на връзка с managed-beans, обработване на дефинираните в страницата валидации, т.н.). Чрез собствен PhaseListener ние можем да проследим жизнения цикъл на приложението и в частност, можем да прихванем всяка заявка в неговия контекста. Необходими са следните промени в примера:


Клиентска част


Просто сменяме URL-а на заявката, за да я изпратим в контекста на приложението:

var url = "faces/ajax?&key=" + escape(target.value);

Сървърна част


Създаваме клас AjaxListener по следния начин:

public class AjaxListener implements PhaseListener {

И имплементираме съответните методи.

public PhaseId getPhaseId() {

return PhaseId.RESTORE_VIEW;

}

Метода getPhaseId() показва, че AjaxListener се интересува само от фазата Restore View: това е първата фаза от жизнения цикъл и се влиза в нея, когато FacesServlet подаде направената от клиента заявка.

За да разграничим заявката направена чрез AJAX от другите заявки, правим филтриране в метода afterPhase(...)



public void afterPhase(PhaseEvent event) {

String rootId = event.getFacesContext().getViewRoot().getViewId();

if (rootId.indexOf(AJAX_VIEW_ID) != -1) {

handleAjaxRequest(event);

}

}

В метода handleAjaxRequest(event); извършваме същите процедури както в метода doGet(...) на AjaxServlet. Не трябва да забравяме да извикаме метода event.getFacesContext().responseComplete();, който прекратява жизнения цикъл на приложението.

Накрая регистрираме AjaxListener във файла faces-config.xml по следния начин:






com.ceco.jsf.AjaxListener



Демонстрация

Сравнение между двата подхода


Двата подхода са приблизително еднакви по отношение на сложност и производителност, но решението с PhaseListener е по-стилно – свързано е с цикъла на JSF приложението и може лесно да се възползва от преимуществата, които дава това. При решението с PhaseListener не се налага на модифицирате web.xml.

Добавяне на автоматични подсказки чрез AJAX – Custom component


Горните два начина имат някои недостатъци:

Решенията не са преизползваеми между приложенията. За всяко приложение се налага да се пише срвлет или phase listener и JavaScript файл.

JSF предлага модел за разработка на приложения, където автор на страница и апликейшън разработчика могат да работят независимо един от друг. С горните два подхода тези функции се нарушават, защото авторът на страницата трябва да се грижи за JavaScript-а и за AJAX заявките към сървърната компонента, което значи, че той трябва малко или много да е запознат със сървърната част от приложението.

Тези недостатъци се избягват с помощта на потребителска компонента. JSF предостаея лесен начин за изграждането на такива компоненти, и за разработчика става много лесно да добави AJAX функционалност.


Изготване на потребителската компонента


Потребителската компонента отговаря за следните неща:

Рендерира HTML презентацията на компонентата

Грижи се за добавянето на връзка към JavaScript файла в HTML сраницата както и за предоставянето на този файл на клиента

Грижи се за обработката на AJAX заявките

Без да се спираме подробно на построяването на потребителски компоненти с JSF правим следните неща:

Дефинираме собствен таг с атрибути (чрез XML описание и чрез налседяване на класа UIComponentTag)

Имплементираме HTML рендерер

Имплементираме PhaseListener

Имплементираме сървърна компонента наследяваща компонентата HtmlInputText

Рендериране HTML презентацията на компонентата


Тук трябва да се погрижим HTML репрезентацията на нашата компонента да съдържа атрибути позволяващи да комуникира със сървърната част чрез AJAX.

Това става в метода getEndTextToRender(...). Добавяме дефиницията на попъп менюто по следния начин:



protected void getEndTextToRender(...) throws IOException {

...

writer.startElement("div", component);

writer.writeAttribute("id", "menu-popup0", null);



...

writer.writeAttribute("class", "popupFrame", null);

writer.endElement("div");

...

}

Изключваме подсказките на браузъра и добавяме в дефиницията на полето JavaScript функциите, които ще бъдат извикани при настъпване на съответното събитие:

protected void getEndTextToRender(...) throws IOException {

...

writer.writeAttribute("autocomplete", "off", null);

...

writer.writeAttribute("onkeyup", "doCompletion(...)", null);

...

}

Рендериране на JavaScript файла


Добавяме в HTML рендерера връзка към JavaScript файла, но трябва да се погрижим тази връзка да присъства само един път на страница (ако използваме две полета с автоматични подсказки на 1 страница не са ни нужни две връзки към JavaScript файла):

protected void getEndTextToRender(...) throws IOException {

...

renderScriptOnce(writer, component, context);

...

}

Където renderScriptOnce(...):

private void renderScriptOnce(...) {

Map requestMap = context.getExternalContext().getRequestMap();

Boolean scriptRendered = (Boolean)requestMap.get(RENDERED_SCRIPT_KEY);
if (scriptRendered == Boolean.TRUE) {

return;

}

requestMap.put(RENDERED_SCRIPT_KEY, Boolean.TRUE);

...

}

Клиента получава HTML кода, генериран от нашия рендерър. Връзката към JavaScript файла е следната:



Това кара браузъра да потърси този файл, и тази заявка обработваме в нашия PhaseListener по следния начин:

public void afterPhase(PhaseEvent event) { String rootId = event.getFacesContext().getViewRoot().getViewId(); if (rootId.endsWith("ajax-textfield.js")) { handleResourceRequest(event, "script.js", "text/javascript"); } ...

Метода handleResourceRequest(...) изпраща на клиента съответния файл

Обработка на AJAX заявките


Обработката на заявките се прави по аналогичен на предишния пример начин.

Демонстрация (комплираме и пакетираме в jar файл)

Използване на потребителската компонента


Използваме за база предишния пример. Просто добавяме в JSP страницата нашате потребителска компонента:

<%@ taglib uri="http://java.sun.com/ajaxC/txt" prefix="ajaxC" %> ... completionMethod="#{namesBean.getMatches}" value="#{personBean.name}" required="true" onchoose="function(item) { return chooseName(item); }" />

Където namesBean e managed bean добавен в faces-config.xml и предоставя метода getMatches, която се използва за определянето на съдържанието на подсказката. (#{namesBean.getMatches} се свързва към Java обекта от класа NamesBean в метода afterPhaze на PhazeLister-а в потребителската компонента).

Виждаме как не се налага да боравим с JavaScript, а само да предоставим метод, от който се изжличат специфичните за приложението подсказки.6

Демонстрация

Библиотеки с готови AJAX enabled компоненти

WebStudio

AjaxFaces

Exadel Visual Component Platform




Сподели с приятели:




©obuch.info 2024
отнасят до администрацията

    Начална страница