Archiv pro štítek: Rich Faces

JSF – použití AJAXu s frameworkem Rich Faces


Cílem tohoto článku je ukázat, jak snadno můžeme používat AJAX s webovými frameworky Java Server Faces a Rich Faces.

AJAX (Asynchronous Javascript and XML) je technologie, pomocí které měníme obsah webové stránky bez nutnosti jejího opětovného načtení. Tento způsob obnovy dat na stránce je rychlejší, šetrnější k serverovému výkonu a uživatelsky příjemnější než způsob, při kterém znovu načítáme celou stránku.

V aplikaci kterou nyní vyvíjíme jsme se rozhodli technologii AJAX používat. Prezentační vrstvu programujeme ve frameworku JSF 1.2 (neřešme proč nepoužíváme JSF 2.0, kde je podpora AJAXu lepší). Společně se standardními komponentami, které JSF mají, používáme komponenty Rich Faces.

Rich Faces je knihovna, která obsahuje velké množstní hotových grafických komponent a dále pak komponenty, které „za nás“ implementují Ajaxové volání mezi klientem a serverem. Tato funkcionalita výrazně urychluje vývoj a je jednoduchá na naučení. Jednoduchost použití budu demostrovat na příkladu, který bude řešit následující úkol:

Vytvořte webovou stránku, na které zobrazte 2 tabulky se jmény sportů. V tabulce A bude seznam všech sportů, které bude možné přidat do tabulky B. Přidání se provede kliknutím na odkaz „Pridat“, tzn. že po jeho stisknutí se jméno přidá do tabulky B a odebere z tabulky A. V tabulce B bude tedy seznam vybraných sportů a bude možné sport odebrat. Odebrání se provede kliknutím na odkaz „Odebrat“, tzn. že po jeho stisknutí se název přidá do tabulky A a odebre z tabulky B. Navíc se po každé akci zobrazí v info panelu pod tabulkami informace o naposledy provedené akci.

Nejprve si vytvoříme tzv. JSF Managed Beanu (pro jednoduchost se data načítají přímo v konstruktoru a nepoužívají se konstanty za texty):

package eu.bcvsolutions.ui.bean;

import java.util.ArrayList;
import java.util.List;

public class TestBean {

	private List selectedSports;
	private List allSports;
	private String sport;
	private String infoMessage;
	
	public TestBean() {
		selectedSports = new ArrayList();
		allSports = new ArrayList();
		
		allSports.add("Fotbal");
		allSports.add("Basketbal");
		allSports.add("Hokej");
		allSports.add("Formule");
		allSports.add("Tenis");
	}
	
	public String addToSelectedSports() {
		selectedSports.add(sport);
		allSports.remove(sport);
		setupAddActionToInfoMessage();
		return null;
	}
	
	public String removeFromSelectedSports() {
		selectedSports.remove(sport);
		allSports.add(sport);
		setupRemoveActionToInfoMessage();
		return null;
	}

	public List getSelectedSports() {
		return selectedSports;
	}

	private void setupAddActionToInfoMessage() {
		String message = "Uspesne jste pridali uzivatele %s";
		infoMessage = String.format(message, sport);
	}
	
	private void setupRemoveActionToInfoMessage() {
		String message = "Uspesne jste odebrali uzivatele %s";
		infoMessage = String.format(message, sport);
	}
	
	public void setSelectedSports(List selectedSports) {
		this.selectedSports= selectedSports;
	}

	public List getSllSports() {
		return allSports;
	}

	public void setSllSports(List allSports) {
		this.allSports= allSports;
	}

	public String getSport() {
		return sport;
	}

	public void setSport(String sport) {
		this.sport= sport;
	}

	public String getInfoMessage() {
		return infoMessage;
	}

	public void setInfoMessage(String infoMessage) {
		this.infoMessage = infoMessage;
	}
}

V této ukázce je nastaven scope na hodnotu „page“. Nastavení scope provádím v souboru components.xml (používám navíc interační framework Seam), pokud používáte „čisté“ JSF, nastavíte scope ve faces-config.xml.

Kód beany je vcelku jasný – beana udržuje informace o všech názvech, o vybraných názvech, o vybraném sportu, je zde umístěn text informačního panelu a obsluhují se události po stisknutí tlačítek.

Dále vytvoříme následující xhtml stránku:

<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
	xmlns:s="http://jboss.com/products/seam/taglib"
	xmlns:ui="http://java.sun.com/jsf/facelets"
	xmlns:f="http://java.sun.com/jsf/core"
	xmlns:h="http://java.sun.com/jsf/html" 
	xmlns:a4j="http://richfaces.org/a4j" 
	xmlns:bcv="http://www.bcvsolutions.eu/jsf" 
	xmlns:rich="http://richfaces.org/rich" 
	xmlns:c="http://java.sun.com/jstl/core" >

<html>
<head>
<title>BCV solutions s.r.o. - Ukazka pouziti technologii JSF, AJAX, Rich Faces</title>
</head>

<body>
	<a4j:form>		
	<table>
	<tbody>
	<tr>
	<td valign="top">
	  Vybrane sporty
	  <br/>
	  <rich:dataTable value="#{testBean.selectedSports}" var="sport" id="selectedTable">
									
	    <rich:column>
	      <f:facet name="header">
	         Nazev
	      </f:facet>
	      <h:outputText value="#{sport}" />
	   </rich:column>
	   <rich:column>
	      <f:facet name="header">
	        Akce
	      </f:facet>
	      <a4j:commandLink value="Odebrat" action="#{testBean.removeFromSelectedSports}"
                    reRender="selectedTable, allTable, infoMessage">
                    <f:setPropertyActionListener value="#{sport}" target="#{testBean.sport}"/>
	      </a4j:commandLink>
	    </rich:column>	
	  </rich:dataTable>
	</td>
	<td valign="top">
	  Seznam sportu
	  <br/>
	  <rich:dataTable value="#{testBean.allSports}" var="sport" id="allTable">
	    <rich:column>
	      <f:facet name="header">
	        Nazev
	      </f:facet>
	      <h:outputText value="#{sport}" />
	    </rich:column>
	    <rich:column>
	      <f:facet name="header">
	        Akce
	      </f:facet>
	      <a4j:commandLink value="Pridat" action="#{testBean.addToSelectedSports}"
                            reRender="selectedTable, allTable, infoMessage">
                  <f:setPropertyActionListener value="#{sport}" target="#{testBean.sport}"/>
	      </a4j:commandLink>
	    </rich:column>	
	  </rich:dataTable>
	</td>
	</tr>
	</tbody>
	</table>
	<h:outputText id="infoMessage" 
		value="#{testBean.infoMessage}"
		style="background-color: #ffff99"/>
	</a4j:form>
</body>
</html>

</ui:composition>

Na této stránce není vůbec nic složitého. Jediné, co stačilo udělat proto, aby se nemusela znovu přenášet všechna data a posílal se jen obsah tabulek a obsah info panelu (nyní na stránce žádný další obsah není, ale v reálné aplikaci by zajisté byl) bylo použití komponenty a4j:commandLink. Rozdílem oproti standardnímu h:commandLink je v parametru reRender. Tomu jsme předali ID komponent, jejichž obsah má být obnoven. Dále jsme místo standardní formulářové komponenty h:form použili komponentu frameworku Rich Faces a4j:form (v tomto případě by to však ani nebylo nutné).

Nyní si stručně popišme použité komponenty:

  • a4j:form

    • obdoba h:form, která řeší 2 základní nedostatky:

      • pokud je nastaven parametr ajaxSubmit na true, umožňuje komvertovat všechny „neajaxové“ volání komponent na ajaxové
      • umožňuje obnovení komponenty h:commandLink bez nutnosti obnovení celého formuláře
  • a4j:commandLink

    • obdoba h:commandLink, rozdíl je v tom, že tato komponenta generuje Ajax request a umožňuje updatovat jenom část stránky

Výsledek naší ukázky vypadá takto:

Dá se říct, že naš kód je obdobou komponenty rich:pickList. My jsme však tuto komponentu nevyužili, protože jsme potřebovali komplexnější funkcionalitu. Podobným způsobem, kterým jsme vytvářeli tyto dvě tabulky je např. možné po stisknutí zobrazit editační formulář, modální panel do kterého pomocí ajaxu dotáhneme kompletní data o sportu apod.


Vytváříte ve vaši firmě webové aplikace na platformě Java? Potřebujete navrhnout architekturu jádra aplikace či webového rozhraní? Neváhejte se obrátit na tým našich vývojářů a konzultantů.