In der aktuellen Revision #52 ist eine neue Klasse RadioListTag hinzugekommen. Diese stellt eine einfache, abstrakte Basisklasse für Tags dar, die zur Ausgabe von Auswahllisten genutzt werden kann.
Die Auswahllisten sind oftmals gleichartig strukturiert: Man hat eine Liste von Einträgen, von denen man genau einen aussuchen soll. Damit die Liste nicht zu aufgebläht wird, werden die Informationen "versteckt". Erst bei einem Klick auf den Listeneintrag werden sie angezeigt.
Der RadioListTag nimmt einem nun eine Menge Arbeit ab. Um einen eigenen Listen-Tag zu erstellen, leitet man einfach eine eigene Klasse von ihm ab:
import java.util.Iterator;
import java.util.Set;
import users.UserManager;
import housemanagement.WebPortal;
import housemanagement.tags.RadioListTag;
import housemanagement.users.PortalUser;
public class PrintUsers extends RadioListTag {
private static final long serialVersionUID = 1L;
private Set<String> userNames;
private Iterator<String> it;
private PortalUser currentUser;
public PrintUsers() {
super();
userNames = UserManager.getGlobalUM().getUserNames();
it = userNames.iterator();
}
public void beginNext() {
currentUser = (PortalUser) UserManager.getGlobalUM().getUser(it.next());
}
public String currentBody() {
Object args[] = { currentUser.getProfile().getFirstName(),
currentUser.getProfile().getName(),
currentUser.isDeleted() };
return WebPortal.getMessageResource("hm.tags.rlt.printusers.body", args);
}
public String currentId() {
return currentUser.getName();
}
public String currentTitle() {
return currentUser.getName();
}
public Boolean hasNext() {
return it.hasNext();
}
}
Den Konstruktor sollte man nutzen, um sich bspw. einen Iterator für die Liste zu holen, deren Inhalt man ausgeben will.
Wichtig sind dann die restlichen Methoden:
hasNext() wird aufgerufen um nachzufragen, ob weitere Items auszugeben sind. Hier bestenfalls den Rückgabewert des Iterators zurückgeben.
beginNext() sollte dann dazu genutzt werden, um den nächsten auszugebenden Eintrag zwischenzuspeichern.
Die Methode currentId() sollte die ID des aktuellen Items ausgeben, hier also bestenfalls item.getName() aufrufen, da diese Methode bereits einzigartige Werte liefern sollte. currentTitle gibt den Wert zurück, der später in der Liste dann auftaucht. Im Beispiel wird hier ebenfalls die ID ausgegeben, allerdings bietet es sich an, hier noch ein paar zusätzliche Infos mit auszugeben.
Schließlich gibt es noch currentBody(). Diese Methode sollte die Inhalte zurückgeben, die dann im aufklappbaren Abschnitt auftauchen. Im Beispiel wird hier noch ein schöner Kunstgriff verwendet. Und zwar findet sich der Inhalt schon vorformatiert in der MessageResources:
hm.tags.rlt.printusers.body=\
<table>\
<tr>\
<td align="left">\
Vorname:\
</td>\
<td align="left">\
{0}\
</td>\
</tr>\
<tr>\
<td align="left">\
Nachname:\
</td>\
<td align="left">\
{1}\
</td>\
</tr>\
<tr>\
<td align="left">\
Gelöscht:\
</td>\
<td align="left">\
{2}\
</td>\
</tr>\
</table>
Im Tag selbst wird nun die statische Methode WebPortal.getMessageResources() genutzt, um den entsprechenden Eintrag auszulesen. Dabei wird eine Liste mit Inhalten übergeben, die dann entsprechend an den Stellen {0} - {2} eingesetzt werden.
Um den eigens erstellten Tag dann nutzen zu können, einfach folgendes in die Datei WEB-INF/tlds/housemanagement.tld eintragen:
<name>PrintUsers</name>
<tag-class>housemanagement.administration.tags.PrintUsers</tag-class>
<body-content>empty</body-content>
</tag>
Danach kann man den Tag einfach in einer JSP nuzten:
<%@ taglib uri="/tags/struts-html" prefix="html" %>
<%@ taglib uri="/tags/struts-logic" prefix="logic" %>
<%@ taglib uri="/tags/webpoint" prefix="wp" %>
<%@ taglib uri="/tags/housemanagement" prefix="hm" %>
<h1>
<bean:message key="housemanagement.admin.viewusers.caption"/>
</h1>
<html:form action="/ViewUsersAction">
<hm:PrintUsers/>
<table>
<tr>
<td align="center">
<html:submit property="method">
<bean:message key="housemanagement.admin.viewusers.resetpassword.caption"/>
</html:submit>
</td>
<td align="center">
<html:submit property="method">
<bean:message key="housemanagement.admin.viewusers.deleteuser.caption"/>
</html:submit>
</td>
</tr>
</table>
</html:form>
UPDTAE
In der neuesten Revision gibt es eine neue Datei TagResources.properties. Diese sollte dazu genutzt werden, die Tag-Grundgerüste abzulegen. Damit bleibt die eigentliche Message-Resources weiterhin sauber während wir Java- und HTML-Code ebenfalls trennen können.
Außerdem sollte in der TagResources kein übersetzbarer Text mehr sein! Sprich: Bezeichnungen, die übersetzt werden sollten ebenfalls durch Platzhalter ersetzen, eine Übersetzung in der MessageResources einfügen und durch die Tag-Klasse die Einträge aus der MessageResources auslesen und in das Gerüst aus der TagResources einfügen lassen.
UPDATE #2
So, weitere Neuigkeiten:
Daten dürfen nicht im Konstruktor des Tags initialisiert werden. Warum? Anscheinend gibt es immer genau eine Instanz des Tags, die dann im Speicher gehalten (zumindest aber kurz gecached) wird. D.h. z.B. auf obiges Beispiel bezogen:
Nachdem der Tag zwar anfangs zu funktionieren scheint, wird er bei wiederholtem Aufruf keine Benutzer mehr darstellen! Der Grund ist, das eben intern noch der alte Iterator verwendet wird, der zwischenzeitlich aber nur noch "false" beim Aufruf von getNext() zurückliefert. Damit wird auch nichts mehr dargestellt.
Um das ganze zu umgehen, gibt es nun eine weitere abstrakte Methode, die implementiert werden muss: initializeData().
Einfach die benötigten Daten statt im Konstruktor in dieser Methode initialisieren und fertig ;)
