Struts2: I namespace

Un piccolo esempio su come lavorare con i namespace in Struts 2.

Cosa sono i namespaces in Struts2

I namespaces non sono altro, detto in parole povere, che gruppi nei quali vengono suddivise le actions. Action con lo stesso nome possono appartenere a namespaces diversi e avere comportamenti diversi. All’atto pratico, considerando l’url del browser, corrispondono al prefisso (o alle serie di prefissi) dell’action stessa.

Supponiamo di avere una applicazione web che si chiami “namespaces”. Eseguito il deploy, per esempio sotto Tomcat, di namespaces.war, ottenete:

http://localhost:8080/namespaces/index.action

La parte dell’url in grassetto: /index.action è così composta:

  • Il namespace “/” (che viene spesso chiamato “root”)
  • L’action “index.action”

Analogamente, nell’URL:

http://localhost:8080/namespaces/futurama/personaggi.action

abbiamo:

  • Il namespace “/futurama”
  • L’action “personaggi.action”

Esiste un namespace fittizio, che è il namespace di default, indicato con “”. Quando viene chiamata una action all’interno di un determinato namespace, e questa non esiste, viene controllato il default e se lì è definita una action con quel nome questa viene eseguita.

Si può anche definire (in questo esempio l’ho fatto) il namespace root, relativo al “/”. Questo è il namespace di riferimento quando una action viene chiamata a livello del context path. Come per gli altri namespace, se l’action chiamata non esiste, viene cercata nel default.

Una nota importante. Questo meccanismo di “rollback” alla ricerca di action perdute non va di namespace in namespace. Se una action non viene trovata nel namespace indicato viene sempre cercata direttamente nel default. Quindi, se l’action /topolinia/personaggi/pippo.action non viene trovata qui, non viene cercata in /topolinia/pippo.action, ma direttamente in /pippo.action.

Come si definiscono i namespaces

La definizione, nel file struts.xml è molto semplice.
Il namespace default si dichiara non dichiarandolo (?), in questo modo:

<package name="default" extends="struts-default">

	[...]
	<result-types>
		[... Un elenco di result type ...]
	</result-types>

	// Una serie di action...
	<action name="login">
		[...]
	</action>

</package>

Ovvero dichiarando un package senza specificare il namespace. Tutte le action all’interno di questo package sono disponibili in tutti i namespace, se non presenti negli stessi.

Il namespace “/” (root) si può dichiarare in questo modo:

<package name="root" namespace="/" extends="default">

	<default-action-ref name="index" />

	<action name="index">
		[...]
	</action>

	<action name="sitemap">
		[...]
	</action>

</package>

Le action dichiarate qui sono visibili solo al primo livello, subito dopo il context path.

In maniera analoga si possono definire tutti i namespaces necessari alla nostra applicazione web. Qui per esempio viene definito il namespace /topolinia, con le action /topolinia/index, /topolinia/pippo e /topolinia/pluto

<package name="topolinia" namespace="/topolinia" extends="default">

	<default-action-ref name="index" />

	<action name="index">
		<result type="tiles" name="success">tiles.topolinia</result>
	</action>

	<action name="pippo">
		<result type="tiles" name="success">tiles.topolinia.pippo</result>
	</action>

	<action name="pluto">
		<result type="tiles" name="success">tiles.topolinia.pluto</result>
	</action>

</package>

Richiamare una action all’interno da una .jsp

Utilizzando i tag di struts è possibile definire una url ad una action specificando il relativo namespace, in questo modo:

<%@ taglib prefix="s" uri="/struts-tags" %>

<s:url action="pippo" var="pippo" namespace="/topolinia" ></s:url>

Vai alla pagina di <a href="<s:property value="#pippo"/>">Pippo</a>

Il progetto di esempio

In questo esempio sono definiti tre namespaces (oltre al default), e contiene una navigazione di base per passare sia ad action dello stesso namespace che ad action di altri namespace.

Questo lo struts.xml:

<struts>

	<constant name="struts.devMode" value="true" />

	<constant name="struts.action.extension" value=","/>	

	<package name="default" extends="struts-default">

		<result-types>
			<result-type name="tiles" 
			class="org.apache.struts2.views.tiles.TilesResult" />
		</result-types>

		<action name="login">
			<result type="tiles" name="success">tiles.login</result>
		</action>

	</package>

	<package name="root" namespace="/" extends="default">

		<default-action-ref name="index" />

		<action name="index">
			<result type="tiles" name="success">siteLayout</result>
		</action>

		<action name="sitemap">
			<result type="tiles" name="success">tiles.sitemap</result>
		</action>

	</package>

	<package name="topolinia" namespace="/topolinia" extends="default">

		<default-action-ref name="index" />

		<action name="index">
			<result type="tiles" name="success">tiles.topolinia</result>
		</action>

		<action name="pippo">
			<result type="tiles" 
			name="success">tiles.topolinia.pippo</result>
		</action>

		<action name="pluto">
			<result type="tiles" 
			name="success">tiles.topolinia.pluto</result>
		</action>

	</package>

	<package name="futurama" namespace="/futurama" extends="default">

		<default-action-ref name="index" />

		<action name="index">
			<result type="tiles" name="success">tiles.futurama</result>
		</action>

		<action name="personaggi">
			<result type="tiles" 
			name="success">tiles.futurama.personaggi</result>
		</action>

		<action name="trama">
			<result type="tiles" 
			name="success">tiles.futurama.trama</result>
		</action>

	</package>

</struts>

Come template per le viste utilizzo tiles2.

Nella pagina sitemap è configurato il Config Browser Plugin, che mostra il dettaglio dei namespaces e delle action associate.

Potete scaricare (temporaneamente, in attesa che sia su github) l’esempio da qua.