15. října 2007

Vytváření JSP EL funkcí

JSP EL používám často a sem tam se mi stane, že bych potřeboval použít vlastní funkci. J2EE specifikace nabízí velmi elegantní řešení, jak si rychle takovou funkci vytvořit.
Pozn. Přijde mi, že je to v tutoriálu J2EE trochu zapadlé, tak proto jsem se rozhodl o tom napsat dnešní článek.

Originální popis se nachází zde v tutoriálu J2EE.

Pro demonstraci postupu jsem si vybral funkci, která mi řekne, zda je/není daný prvek v kolekci.

Vytvoření funkce

package cz.anect.mis.web.tags;

import java.util.Collection;

/**
* This class encapsulates handy funcions for using in JSP EL.
*
* Functions must be defined in /WEB-INF/functions.tld.
*
* @author pjuza@anect.com
*/
public class Functions {

/**
* Method returns true if specified object is contained in
* input collection.
* @param col Input collection for searching
* @param obj Searched object
* @return returns true if specified object is contained in input collection.
*/
public static boolean inCollection(Collection col, Object obj) {
if (col == null || obj == null)
return false;

return col.contains(obj);
}
}

Snad jediné omezení je, že funkce musí být statická a veřejná (public).

Definice funkce pomocí TLD

<?xml version="1.0" encoding="UTF-8" ?>

<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee web-jsptaglibrary_2_0.xsd"
version="2.0">
<description>A tag library that defines my custom functions.</description>
<tlib-version>1.0</tlib-version>
<short-name>FunctionTagLibrary</short-name>
<uri>/FunctionLibrary</uri>

<function>
<name>inCollection</name>
<function-class>cz.anect.mis.web.tags.Functions</function-class>
<function-signature>boolean inCollection(java.util.Collection, java.lang.Object)</function-signature>
</function>
</taglib>


Použití funkce

Nejdříve musíme TLD standardně nadeklarovat před vlastním použitím na stránce:
<%@ taglib uri="/WEB-INF/tld/functions.tld" prefix="myfn" %>

A nyní můžeme bez problémů danou funkci použít:

<c:forEach var="kw" items="${keywords}">
<c:if test='${not myfn:inCollection(search.basicKeyWordIds, kw.id)}'>
<option value="<c:out value="${kw.id}"/>"><c:out value="${kw.value}"/></option>
</c:if>
</c:forEach>

6 komentářů:

Anonymní řekl(a)...

Pěkné. Ačkoliv mi připadá EL v JSP trošku zbytečný - proč používat další jazyk, když už tam je Java, kde si tu statickou metodu můžeš zavolat taky. Zajímavější je ale použití EL v facelets, kde je to dělano podobně.

Petr Jůza řekl(a)...

Já jsem dost proti tomu, aby se Java kód používat v prezentační vrstvě. Tam dle mého názoru nemá co dělat. Prezentační vrstva má sloužit pouze k zobrazení dat a k získání dat od uživatele.

Anonymní řekl(a)...

pouzivani javy v jsp nakonec vede k neprehlednosti, mnohem lepsi je pouzivat EL

Petr Jůza řekl(a)...

Já bych řekl, že nepřehlednost je to nejmenší z pohledu dané aplikace. Jako hlavní problémy pak vidím v tom, že se špatně aplikace škáluje (viděl jsem dokonce použití EJB přímo v JSP stránkách), že nemohu efektivně refaktorovat a reagovat na změny zákazníka, že nemohu vytvářet více druhů klientů (nejenom webový klient) atd.

Anonymní řekl(a)...

nedalo by se toto resit take pomoci beanu (jsp:useBean) ?

Anonymní řekl(a)...

Ano, Java by se v prezentační vrstvě používat neměla=> neměli by se používat JSP - myšlenka EL je v tom, aby člověk který neumí Javu, dokázal psát prezentační vrstvu. Ale myslím si, že realita je taková, že momentálně píšou prezentašní vrstvu Java programátoři. Samozřejmě jsem nemyslel aby se v prezentační vrstvě objevovala logika, ale to co se dá napsat v EL se dá i napsat v Java. Takle se velice často mixuje EL a Java na jedné stránce, což je podle mě špatně. Proto si myslím, že když chce někdo používat EL, tak rovnou ať použije Facelets, nebo jiný podobný framework.