venerdì 30 aprile 2010

Interceptor in Struts 2


Gli Interceptor in struts2 sono, come dice il loro nome, degli intercettatori.
Essi infatti si pongono in uno stato intemedio fra il filtro di struts2 che fa da dispatcher e le varie action. Il loro scopo è quello di permettere di eseguire delle operazioni prima dell'esecuzione di un metodo di una Action e/o modificarne il suo esito. Solitamente si utilizzano per operazioni comuni e trasversali nell'appliccativo. Diciamo curano un aspetto della web-application, infatti la loro logica, se avete usato tale tecnologia, si avvicina molto all'AOP.



Di interceptor se ne possono definire quanti ce ne servono. Alcuni sono già presenti di default in struts2 come quello che si occupa della validazione o quello del settaggio dei valori postati dal browser in una action. Ma posssiamo anche definirne dei custom secondo le nostre necessità.

Dato che ce ne possono essere + di uno anzi ce ne sempre più di uno (altrimenti struts2 non funziona) essi devono essere definiti in degli 'stack' in modo da definirne l'ordine di esecuzione. Vi faccio uno schizzo e provo a commentarlo:

Arriva una richiesta da parte dell'utente di eseguire una determinata action. Il filtro agisce sulla chiamata quindi lancia un ActionInvocation il quale all'interno contiene la action da eseguire e altre info. L'evento ActionInvocation viene intercettato dal primo interceptor dello stack definito nello struts.xml come stack per quella action (possono essere personalizzati per action).
Quindi quest'ultimo esegue le sue operazioni sull'oggetto ActionInvocation e lo propaga.
Lo intercetta il secondo e così via.
Finiti gli interceptor viene eseguito il metodo della action richiesto. Il risultato (di tipo String) viene
di nuovo intercettato dagli interceptor in modo inverso per poi ritornare al filtro.

Dicevo che è molto importante l'ordine in un cui vengono definiti gli interceptor nello stack. Facciamo finta che il terzo Interceptor sia quello che sia occupa del settaggio dei parametri (passati in post dal browser dopo l'esecuzione del submit di un form) come attributi della action, e il secondo Interceptor quello della validazione. La validazione non funziona o meglio non passa poiché trova tutti gli attributi vuoti e quindi non li valida. Tutto questo poichè l'interceptor che si occupa di settarli viene eseguito dopo di quello della validazione.

Gli interceptor e lo stack di default sono definiti nello struts.xml e ogni package contiene la loro definizione.

Possono essere definiti + stack per lo stesso package e ogni action può fare riferimento a quello che gli serve o a quello di default.

Passiamo alla pratica continuando ad estendere la nostra applicazione “struts2tutorial”. Introduciamo una funzionalità: l'autenticazione. Un interceptor che creeremo si occuperà di verificare se l'utente è autenticato affinché possa eseguire una action definita protetta. Per definirla protetta useremo lo struts.xml (vedremo come) e introdurremo un form di login che ci consentirà di autenticarci sulla homepage. Se l'utente è autenticato quest'ultimo non sarà visualizzato, ma solo il suo username.
Un utente sarà autenticato quando è presente nella sessione, e per autenticarsi deve inserire username e password uguali.

Iniziamo col definire lo stack base cioè quello che abbiamo utilizzato inconsciamente fin'ora, in realta ci basta copiarlo da quello definito nello struts-default.xml (che se ricordate ne estendevamo il package).

Quindi aprite il file struts-default.xml che trovate nella root del jar struts-core.<versione>.jar
E copiate questo:

<interceptor-stack name="defaultStack">
<interceptor-ref name="exception"/>
<interceptor-ref name="alias"/>
<interceptor-ref name="servletConfig"/>
<interceptor-ref name="i18n"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="chain"/>
<interceptor-ref name="debugging"/>
<interceptor-ref name="scopedModelDriven"/>
<interceptor-ref name="modelDriven"/>
<interceptor-ref name="fileUpload"/>
<interceptor-ref name="checkbox"/>
<interceptor-ref name="multiselect"/>
<interceptor-ref name="staticParams"/>
<interceptor-ref name="actionMappingParams"/>
<interceptor-ref name="params">
<param name="excludeParams">dojo..*,^struts..*</param>
</interceptor-ref>
<interceptor-ref name="conversionError"/>
<interceptor-ref name="validation">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
<interceptor-ref name="workflow">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
</interceptor-stack>

visto che ve lo trovate aperto scrutatelo un pochino così capite come è organizzato, quali sono gli interceptor e gli stack già definiti e come si definiscono. Per sapere cosa fanno vi rimando alla documentazione ufficiale.
Quella che vedete è la definizione di uno stack. Notate come l' “actionMappingParams” sta prima dello stack di validazione.
Restando sulla validazione ricordate nel post dedicato che dicevo che per default salta il metodo input? Come potete vedere accade perché viene passato come parametro all'interceptor che si occupa della validazione e che ovviamente ora possiamo aggiustare come vogliamo.

Dopo aver copiato aprite lo struts.xml del progetto e create il tag

<interceptors>

</interceptors>

all'interno incollate lo stack e cambiategli il nome da defaultStack a turorialStack dato che dobbiamo personalizzarlo.

Quindi definiamolo come nuovo stack di default per tutte le action, inserendo la seguente definizione XML dopo la chiusura del tag interceptors:

<default-interceptor-ref name="tutorialStack" />



Ecco lo struts momentaneo:

<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name="struts.objectFactory" value="spring" />



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




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


<interceptors>
<interceptor-stack name="tutorialStack">
<interceptor-ref name="exception" />
<interceptor-ref name="alias" />
<interceptor-ref name="servletConfig" />
<interceptor-ref name="i18n" />
<interceptor-ref name="prepare" />
<interceptor-ref name="chain" />
<interceptor-ref name="debugging" />
<interceptor-ref name="scopedModelDriven" />
<interceptor-ref name="modelDriven" />
<interceptor-ref name="fileUpload" />
<interceptor-ref name="checkbox" />
<interceptor-ref name="multiselect" />
<interceptor-ref name="staticParams" />
<interceptor-ref name="actionMappingParams" />
<interceptor-ref name="params">
<param name="excludeParams">dojo..*,^struts..*</param>
</interceptor-ref>
<interceptor-ref name="conversionError" />
<interceptor-ref name="validation">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
<interceptor-ref name="workflow">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
</interceptor-stack>
</interceptors>

<default-interceptor-ref name="tutorialStack" />

<action name="concatena_*" method="{1}" class="concatenaAction">
<result name="input" type="tiles">concatena</result>
<result name="submit" type="tiles">concatena</result>
</action>

<action name="testvalidazione_*" method="{1}" class="testValidazioneAction">
<result name="input" type="tiles">testValidazione</result>
<result name="submit" type="tiles">testValidazione</result>
</action>
</package>

</struts>


Come avete intuito gli stack non possono estendere altri stack come i package, quindi vanno ridefiniti per intero. Ereditiamo invece la definizione di ogni singolo interceptor (lo vediamo fra poco come si definiscono).

Suggerisco di testare l'applicazione in modo da vedere se tutto è rimasto come prima.

Nella maggior parte dei casi nelle applicazioni web o portali, la gestione dell'utente autenticato è trasversale all'applicativo e a tal motivo creiamo una action di base che ci fornisce l'utente autenticato quando necessario:

/**
*
*/
package com.blogspot.piergiuseppe82.struts2intro.action;

import java.util.Map;

import org.apache.struts2.dispatcher.SessionMap;
import org.apache.struts2.interceptor.SessionAware;

import com.opensymphony.xwork2.ActionSupport;

/**
* @author placava
*
*/
@SuppressWarnings("serial")
public abstract class AbstractBaseAction extends ActionSupport implements SessionAware{
private SessionMap<String, Object> session;
protected static final String USER_TUTORIAL = "USER_TUTORIAL";

public String getUtenteTuorial() {
try{
return (String)session.get(USER_TUTORIAL);
}catch (Exception e) {
return null;
}
}

@Override
public void setSession(Map<String, Object> arg0) {
session = (SessionMap<String, Object>)arg0;

}

public SessionMap<String, Object> getSession() {
return session;
}


}


Notate che abbiamo esteso ActionSupport dato che essa dovrà essere estesa da tutte le action. In oltre notate l'interfaccia che implementa:SessionAware. Tale interfaccia ci permette di farci dare da struts2 la sessione http creata dal server. Per fare ciò ci obbliga a implementare il metodo setSession(Map<String, Object> arg0).
Quindi il metodo getUtenteTutorial() che si occupa di fornirci l'utente in sessione.

Creiamo la action che si occupa dell'autenticazione:

/**
*
*/
package com.blogspot.piergiuseppe82.struts2intro.action;

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

/**
* @author placava
*
*/
@SuppressWarnings("serial")
@Component("autenticazioneAction")
@Scope("request")
public class AutenticazioneAction extends AbstractBaseAction {

private static final String LOGIN = "login";
private static final String LOGOUT = "logout";
private static final String INDEX = "index";
private static final String LOGIN_ERROR= "loginError";

private String username;
private String password;


public String input(){
addActionError("Non hai i permessi per eseguire la funzione");
return INPUT;
}

public String index(){
addActionMessage("Clicca su una delle funzioni");
return INDEX;
}


public String login(){
if (username!=null && username.equals(password)){

getSession().put(USER_TUTORIAL, username);
addActionMessage("Ciao "+username+". Benvenuto!! ");
return LOGIN;
}else{
addActionError("Errore durante il processo di autenticazione verifica i dati inseriti");
return LOGIN_ERROR;
}
}

public String logout(){
getSession().invalidate();
addActionMessage("Log out eseguito con successo ");
return LOGOUT;
}



public String getUsername() {
return username;
}





public void setUsername(String username) {
this.username = username;
}





public String getPassword() {
return password;
}





public void setPassword(String password) {
this.password = password;
}

}



Come vedete estende la Action di base in modo da avere nell'area di validatà della classe sia l'accesso alla sessione e sia all'utente.
Allora abbiamo i metodi:
input – verrà richiamato come redirect nel caso in cui l'utente non è autenticato per accedere ad una funzione protetta.
login – sarà la destinazione come post del form di autenticazione. É deciderà se l'utente ha credenziali valida o meno. In caso di esito positivo mette lo ustente in sessione. In caso di esito negativo aggiungerà un ActionError (funziona come gli ActionMessage che già conosciamo)
logout - si occupa di invalidare la sessione.
index – dato che la homepage avrà bisogno dello username dell'utente per visualizzarlo, invece di creare un'altra action per un solo metodo ho preferito metterlo qui. Questo comporterà di non avere la index.jsp come risorsa di ingresso ma una action che definirò nello struts.xml con alias “index”. Infine i metodi accessori ai suoi attributi.

Di seguito la sua validazione AutenticazioneAction-validation.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.2//EN" "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">
<validators>
<field name="username">
<field-validator type="requiredstring" short-circuit="true">
<message><![CDATA[Devi inserire la Username.]]> </message>
</field-validator>
</field>
<field name="password">
<field-validator type="requiredstring" short-circuit="true">
<message> <![CDATA[Devi inserire la Password.]]> </message>
</field-validator>
</field>

</validators>





Prima di proseguire fate estendere a tutte le altre action dell'applicativo la AbstractBaseAction. Anche se tale passaggio è obbligatorio solo per le action che vogliamo definire siucure per una questione di logica applicativa conviene eseguirlo anche sulle action che non definiremo sicure.

Andiamo al cuore, creiamo il nostro interceptor:

/**
*
*/
package com.blogspot.piergiuseppe82.struts2intro.interceptors;

import com.blogspot.piergiuseppe82.struts2intro.action.AbstractBaseAction;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;

/**
* @author placava
*
*/
@SuppressWarnings("serial")
public class AuthenticationInterceptor extends AbstractInterceptor {
private static final String NON_AUTENTICATO = "noAutenticato";

@Override
public String intercept(ActionInvocation invocation) throws Exception {
if (invocation.getAction() instanceof AbstractBaseAction) {
AbstractBaseAction action = (AbstractBaseAction) invocation.getAction();
if(action.getUtenteTuorial()==null || "".equals(action.getUtenteTuorial())){
return NON_AUTENTICATO;
}
}else{
throw new RuntimeException("Impossibile recuperare l'utente di sessione. Action non di tipo AbstractBaseAction");
}
return invocation.invoke();
}

}

Quindi per creare un interceptor basta creare una classe concreta che estende AbstractInterceptor la quale ci obbliga a implementare il metodo “intercept(ActionInvocation invocation)”.
All'interno di tale metodo dobbiamo mettere la logica dell'interceptor.

Il metodo in esempio non fa altro che verificare se la action, contenuta nell'action invocation, è effettivamente una istanza del tipo AbstractBaseAction. In caso di esito positivo richiama il suo metodo “getUtenteTutorial()”, altrimenti lancia un eccezione. In caso il metodo “getUtenteTutorial” fornisce un valore nullo o stringa vuota ritorna come result la stringa “noAutenticato” la quale, come vedrete + avanti, è mappata come global-result nello struts.xml. Quindi se tutto va ok si prosegue con l'invocazione della action (in modo da essere intercettata dagli interceptor settati come successivi).

Quindi ecco lo struts.xml completo e definitivo:

<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name="struts.objectFactory" value="spring" />



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


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



<interceptors>
<interceptor-stack name="tutorialStack">

<interceptor-ref name="exception" />
<interceptor-ref name="alias" />
<interceptor-ref name="servletConfig" />
<interceptor-ref name="i18n" />
<interceptor-ref name="prepare" />
<interceptor-ref name="chain" />
<interceptor-ref name="debugging" />
<interceptor-ref name="scopedModelDriven" />
<interceptor-ref name="modelDriven" />
<interceptor-ref name="fileUpload" />
<interceptor-ref name="checkbox" />
<interceptor-ref name="multiselect" />
<interceptor-ref name="staticParams" />
<interceptor-ref name="actionMappingParams" />
<interceptor-ref name="params">
<param name="excludeParams">dojo..*,^struts..*</param>
</interceptor-ref>
<interceptor-ref name="conversionError" />
<interceptor-ref name="validation">
<param name="excludeMethods">input,back,cancel,browse,index,logout</param>
</interceptor-ref>
<interceptor-ref name="workflow">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>

</interceptor-stack>



<interceptor-stack name="secureTutorialStack">

<interceptor-ref name="exception" />
<interceptor-ref name="alias" />
<interceptor-ref name="servletConfig" />
<interceptor-ref name="i18n" />
<interceptor-ref name="prepare" />
<interceptor-ref name="chain" />
<interceptor-ref name="debugging" />
<interceptor-ref name="scopedModelDriven" />
<interceptor-ref name="modelDriven" />
<interceptor-ref name="authenticationInterceptor" />
<interceptor-ref name="fileUpload" />
<interceptor-ref name="checkbox" />
<interceptor-ref name="multiselect" />
<interceptor-ref name="staticParams" />
<interceptor-ref name="actionMappingParams" />
<interceptor-ref name="params">
<param name="excludeParams">dojo..*,^struts..*</param>
</interceptor-ref>
<interceptor-ref name="conversionError" />
<interceptor-ref name="validation">
<param name="excludeMethods">input,back,cancel,browse,index,logout</param>
</interceptor-ref>
<interceptor-ref name="workflow">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>

</interceptor-stack>

<interceptor name="authenticationInterceptor"
class="com.blogspot.piergiuseppe82.struts2intro.interceptors.AuthenticationInterceptor" />
</interceptors>

<default-interceptor-ref name="tutorialStack" />

<global-results>
<result name="noAutenticato" type="redirectAction">
<param name="actionName">autenticazione_input</param>
</result>
</global-results>



<action name="concatena_*" method="{1}" class="concatenaAction">

<interceptor-ref name="secureTutorialStack"/>

<result name="input" type="tiles">concatena</result>
<result name="submit" type="tiles">concatena</result>
</action>

<action name="testvalidazione_*" method="{1}" class="testValidazioneAction">
<result name="input" type="tiles">testValidazione</result>
<result name="submit" type="tiles">testValidazione</result>
</action>

<action name="autenticazione_*" method="{1}" class="autenticazioneAction">
<result name="input" type="tiles">homepage</result>
<result name="login" type="tiles">homepage</result>
<result name="logout" type="tiles">homepage</result>
<result name="loginError" type="tiles">homepage</result>
</action>

<action name="index" method="index" class="autenticazioneAction">
<result name="index" type="tiles">homepage</result>
</action>
</package>

</struts>



Allora, come vedete ci stanno due stack di interceptors “tutorialStack” e “secureStackTutorial”. Sono identici tranne per il fatto che il secondo ha il nostro interceptor di autenticazione:
<interceptor-ref name="authenticationInterceptor" />

che è mappato dopo la definizione degli stack con la dicitura:

<interceptor name="authenticationInterceptor"
class="com.blogspot.piergiuseppe82.struts2intro.interceptors.AuthenticationInterceptor" />


Notate anche come ho corretto i parametri dell'interceptor di validazione in modo da non essere esguita sui metodi con nome “index” e “logout”.

Subito dopo i tag <interceptors> è definito (e deve esserlo sempre qui) quello di default. Sotto trovate il global result “noAutenticato” che è di tipo “redirectAction” ossia fa richiamare al browser (con un 302) la action con alias “autenticazione_input” dato che il form per il login stà nell'html che ne viene renderizzato dopo la sue esecuzione.

Come facciamo a definire quale action devono essere eseguite sotto autenticazione e quali no?

Semplice basta che diciamo a struts2, che la action in oggetto, non deve essere intercettata dallo stack definito come default, ma da quello definito col nome “secureTutorialStack”. Per fare ciò bisogna mettere all'interno dei tag <action ..> …..</action> la seguente definizione:

<interceptor-ref name="secureTutorialStack"/>


Se guardate lo struts.xml ho definito come sicura solo la ConcatenaAction le altre no, in modo tale che per poter accedere alla funzionalità l'utente deve essere loggato.

Da questo capite come si possono definire + stack e come ognuno di loro può essere associato a una o + action.


Ps: Ci stanno altre tecniche per definire quale action e/o persino quale metodo della action deve essere eseguito sotto autenticazione, ad esempio interfacce o annotations. Di solito uso le annotation, ho fatto l'esempio utilizzando lo struts.xml solo perchè il tema del tutorial sono gli interceptor, gli stack e i loro utilizzi.

Ora elenco gli altri files coinvolti nelle modifiche.
La index.jsp non c'è più ma c'è WebContent/frames/home.jsp che contiene il form per il login:

<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>




<div class="main">
<div class="autenticazione">
<s:if test="utenteTuorial == empity">

<s:form action="autenticazione_login" method="post">
<s:textfield name="username" label="Username" />
<s:password name="password" label="Password" />
<s:submit name="submit" value="Login"/>
</s:form>

</s:if>
<s:else>
<s:form action="autenticazione_logout" method="post">
Ciao <strong></strong><s:property value="utenteTuorial"/></strong>
<s:submit name="submit" value="Logout"/>
</s:form>
</s:else>
</div>
<a href="concatena_input.action">Prova la Concatena Action</a>
<br/><br/>
<a href="testvalidazione_input.action">Prova la Action di Validazione</a>
<br/>
<br/>
<br/>
<br/>

<br/>
<br/>
<br/>
<br/>
</div>




e nel base frame ho aggiunto il tag per gli actionError:

<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://tiles.apache.org/tags-tiles" prefix="tiles" %>
<%@ taglib prefix="s" uri="/struts-tags"%>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Pergiuseppe 82 - Java e Oltre</title>
<link rel="stylesheet" type="text/css" href="css/intro.css" media="all">
</head>
<body>
<tiles:insertAttribute name="header" flush="false"/>

<div class="content">

<tiles:insertAttribute name="frame" flush="false"/>

<div class="areaMessaggi">

<strong>AREA MESSAGGI</strong>
<s:actionmessage/>
<s:actionerror/>
<s:fielderror/>
</div>

</div>

<tiles:insertAttribute name="footer" flush="false"/>
</body>
</html>


e per ultimo il tiles.xml:

<!DOCTYPE tiles-definitions PUBLIC
"-//Apache Software Foundation//DTD Tiles Configuration 2.0//EN"
"http://tiles.apache.org/dtds/tiles-config_2_0.dtd">

<tiles-definitions>

<!-- INIZIO BASE FRAME -->

<definition name="baseFrame" template="/baseFrame/baseFrame.jsp">
<put-attribute name="header" value="/blocks/header.jsp" />
<put-attribute name="footer" value="/blocks/footer.jsp" />
</definition>

<definition name="concatena" extends="baseFrame">
<put-attribute name="frame" value="/frames/concatenaFrame.jsp" />
</definition>

<definition name="testValidazione" extends="baseFrame">
<put-attribute name="frame" value="/frames/testValidazioneFrame.jsp" />
</definition>

<definition name="homepage" extends="baseFrame">
<put-attribute name="frame" value="/frames/home.jsp" />
</definition>
</tiles-definitions>



Il progetto eclipse con i files completi e che non ho menzionato lo trovate QUI.

10 commenti:

  1. Ciao. ho provato il tuo esempio, ma non funziona!
    Non riesce a trovare la risorsa...(hai tolto la index,jsp ) e sembra che non trovi l'action della "index".

    Cosa posso fare per farla funzionare?

    Grazie
    Luca

    RispondiElimina
  2. La index.jsp non c'è più ma c'è WebContent/frames/home.jsp che contiene il form per il login

    cmq devo verificare per la action.... è da tempo che non tocco il progetto e struts2 in generale.... il tempo di recuperarlo e rispondo!!!

    RispondiElimina
  3. Si avevo visto la home.jsp!

    Ho notato che nel web.xml hai inserito:


    index.action


    e a quanto pare non trova la risorsa...

    Grazie

    Ciao

    RispondiElimina
  4. Ciao,

    ti ringrazio per questo post e per la dritta inerente l'implementazione della BaseAction.
    Non ho capito però come richiamare il metodo getUtenteTutorial da una delle mie pagine JSP. Supponi che in un paio di pagine JSP io abbia la necessità di mostrare i dati delle'utente loggato (per es. username, nome, cognome, etc.) rappresentato da un opportuno oggetto User creato in fase di login. A questo punto il metodo getUtenteTutorial restituirebbe un oggetto di tipo User. Ma come faccio a utilizzarlo dentro la mia pagina JSP? Grazie anticipatamente

    RispondiElimina
  5. Ciao....

    Come fare lo dovresti capire seguendo gli altri tutorial su struts2 che ho postato....

    Comunque proprio come dici tu invece di restituire una semplice stringa restituisci una instanza di un possibile oggetto User un semplice pojo (cioè un oggetto semplice con attributi privati e metodi accessori... fra i quali nome, cogn... ecc).. dopo di che ad esempio nella home.jsp al posto di

    </strong><s:property value="utenteTuorial"/></strong>

    scrivi

    </strong><s:property value="utenteTuorial.nome"/></strong>

    se vuoi visualizzare il nome....

    Semplice no?

    PS: Ti ricordo che la action che esegui la hai come root nel context della pagina....
    Quindi richiamando utenteTuorial.nome come value-expression è come se avessi scritto

    autenticazioneAction.getUtenteTuorial().getNome();

    forse questo ti aiuta a capire meglio..
    ;)

    RispondiElimina
  6. Ciao,
    ti ringrazio per la tua risposta che mi è stata molto utile. Ho ancora qualche dubbio per quando riguarda la fase di logout.
    Andando a verificare dalla webapp "manager" di tomcat, quando si esegue il logout viene, diciamo così, eliminato l'utente dalla sessione ma non viene invalidata veramente la sessione. Ciò comporta il mantenimento sul server di sessioni "vuote". Come posso invalidare le sessioni alla "vecchia maniera", ovvero con session.invalidate() (con session che è un oggetto Session) in modo da eliminare effettivamente le sessioni "vuote"? Spero di essere stato chiaro nella mia esposizione. Grazie ancora per il tuo tempo

    RispondiElimina
  7. fai implementare l'interfaccia ServletRequestAware alla action che si dovrà occupare di invalidare la sessione..

    e quando ti serve chiami il metodo getServletRequest().getSession(true).invalidate();

    ormai è da tanto che non uso struts però penso che questo funzioni.... cmq se non ti è chiaro provo a spiegarmi meglio

    RispondiElimina
  8. ma ti risulta questo comportamento, a mio modo di vedere, anomalo del metodo invalidate()?
    Poi...
    "ormai è da tanto che non uso struts"...ora cosa usi? JSF?
    Grazie ancora

    RispondiElimina
  9. hai provato il metodo che ti ho detto?
    In pratica fornisce la request (j2ee standard) gestita dall'application server e da li recuperi la sessione per invalidarla... cioè tagli fuori stuts2 dal processo di invalidazione.. se non funziona questo vuol dire che è l'application server a non funzionare. e non so come aiutarti. cmq dato che fai session(true) sicuro ne crea una nuova...

    Si sto usando jsf 2.0

    Cmq

    RispondiElimina
  10. Complimenti davvero per i tuoi articoli molto chiari e ben fatti.
    PS: Anche io sono alla ricerca della index.action :)

    RispondiElimina