XVII. Exemple 15 - Intégration Struts 2 / Spring▲
Dans l'exemple précédent, nous n'avions pas de données de portée Application partagées par toutes les requêtes de tous les utilisateurs. Nous en montrons un exemple ici. Pour le mettre en oeuvre, nous utilisons le framework Spring [http://www.springsource.org/]. Spring est un outil de très grande valeur. Nous n'en montrons dans cet exemple qu'une infime partie. Un exemple ultérieur l'utilisera plus intensivement.
Le but de cette application est d'afficher des données de portée Application.
XVII-A. Le projet Netbeans▲
Le projet Netbeans de l'application est le suivant :
- en [1] :
- [web.xml] qui configure l'application web va évoluer vis à vis de ce qu'il était dans les versions précédentes
- [applicationContext.xml] est le fichier de configuration de Spring
- en [2] : la vue [Context.jsp] qui affichera les données de portée Application
- en [3] :
- le fichier des messages [messages.properties]
- le fichier de configuration principal de Struts [struts.xml]. Va évoluer vis à vis des applications précédentes.
- en [4] :
- l'action Struts [Action1.java]
- la classe [Config.java] qui va mémoriser les données de portée application
- le fichier de configuration secondaire de Struts [example.xml]
- en [5] : la bibliothèque Struts 2
- en [6] :
- les archives nécessaires à Spring [spring-core, spring-context, spring-beans, spring-web, commons-logging]
- l'archive du plugin Spring pour Struts 2. Permet l'intégration de Spring avec Struts 2 [struts2-spring-plugin]
Vis à vis des versions précédentes :
- il faut rajouter des archives au projet
- modifier les fichiers [web.xml] et [struts.xml]
XVII-B. Configuration▲
XVII-B-1. Le fichier [web.xml]▲
Le fichier [web.xml] évolue comme suit :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
<?
xml
version="1.0"
encoding="UTF-8"?
>
<
web-app
id
=
"
WebApp_9
"
version
=
"
2.4
"
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
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd
"
>
<
display-name
>
Exemple 14<
/
display-name
>
<
filter
>
<
filter-name
>
struts2<
/
filter-name
>
<
filter-class
>
org.apache.struts2.dispatcher.FilterDispatcher<
/
filter-class
>
<
/
filter
>
<
filter-mapping
>
<
filter-name
>
struts2<
/
filter-name
>
<
url-pattern
>
/*<
/
url-pattern
>
<
/
filter-mapping
>
<
listener
>
<
listener-class
>
org.springframework.web.context.ContextLoaderListener<
/
listener-class
>
<
/
listener
>
<
/
web-app
>
La modification a lieu lignes 12-14. Un listener est ajouté à l'application web. Lorsque l'application web va être lancée, la classe implémentant ce listener va être instanciée. C'est une classe de Spring. Cette classe va exploiter le fichier [WEB-INF/applicationContext.xml]. Celui-ci est le suivant :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
<?
xml
version="1.0"
encoding="UTF-8"?
>
<
beans
xmlns
=
"
http://www.springframework.org/schema/beans
"
xmlns
:
xsi
=
"
http://www.w3.org/2001/XMLSchema-instance
"
xmlns
:
tx
=
"
http://www.springframework.org/schema/tx
"
xsi
:
schemaLocation
=
"
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
"
>
<!--
configuration
des
beans
de
portée
application
-->
<
bean
id
=
"
config
"
class
=
"
example.Config
"
>
<
property
name
=
"
nbMaxUsers
"
value
=
"
10
"
/
>
<
/
bean
>
<
/
beans
>
- le fichier de configuration de Spring a la balise racine <beans> (lignes 2 et 11). On pourrait traduire beans par objets. Spring va instancier tous les objet (bean) trouvés dans ce fichier de configuration. Il ne le fait qu'une fois, lorsque le listener Spring est lancé au démarrage de l'application web.
- lignes 7-9 : définissent un bean nommé config (id). Le bean config est associé à la classe (class) [example.Config]. Spring va instancier cette classe.
- ligne 8 : définit une propriété de la classe [example.Config]. Spring va appeler la méthode [example.Config].setNbMaxUsers(10). Il faut donc que la méthode setNbMaxUsers existe dans la classe. Celle-ci est la suivante :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
package
example;
public
class
Config {
private
int
nbMaxUsers;
public
int
getNbMaxUsers
(
) {
return
nbMaxUsers;
}
public
void
setNbMaxUsers
(
int
nbMaxUsers) {
this
.nbMaxUsers =
nbMaxUsers;
}
}
Cette classe ne définit qu'un champ nbMaxUsers avec ses get et set. Si on a bien suivi ce qui a été dit, au démarrage de l'application web, une instance de la classe [Config] est instanciée avec la valeur 10 pour son champ nbMaxUsers. Nous n'avons défini qu'un unique champ mais c'est suffisant pour notre démonstration. Nous voulons montrer que ce champ, qui pourrait représenter un nombre maximal d'utilisateurs, est une donnée de portée Application accessible à toutes les actions. C'est ce que nous montrerons avec l'action [Action1].
XVII-B-2. Le fichier [struts.xml]▲
Le fichier de configuration principal de Struts est le suivant :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
<?
xml
version="1.0"
encoding="UTF-8"
?
>
<!
DOCTYPE
struts
PUBLIC
"
-//Apache
Software
Foundation//DTD
Struts
Configuration
2.0//EN
"
"
http://struts.apache.org/dtds/struts-2.0.dtd
"
>
<
struts
>
<!--
internationalisation
-->
<
constant
name
=
"
struts.custom.i18n.resources
"
value
=
"
messages
"
/
>
<!--
intégration
Spring
-->
<
constant
name
=
"
struts.objectFactory.spring.autoWire
"
value
=
"
name
"
/
>
<
include
file
=
"
example/example.xml
"
/
>
<
package
name
=
"
default
"
namespace
=
"
/
"
extends
=
"
struts-default
"
>
<
default-action-ref
name
=
"
index
"
/
>
<
action
name
=
"
index
"
>
<
result
type
=
"
redirectAction
"
>
<
param
name
=
"
actionName
"
>
Action1<
/
param
>
<
param
name
=
"
namespace
"
>
/example<
/
param
>
<
/
result
>
<
/
action
>
<
/
package
>
<
/
struts
>
Seule la ligne 10 est différente des versions précédentes de ce fichier. Elle définit une constante Struts. Les objets instanciés par Spring peuvent être injectés dans d'autres objets. C'est le fondement même de Spring. Ici une référence sur l'objet de type [Config] créé par Spring va pouvoir être injecté dans des objets Struts. C'est là qu'intervient le plugin Spring pour Struts 2 qui assure l'intégration de Spring par Struts.
La ligne 10 indique que l'injection d'objets Spring dans un objet Struts se fera de façon automatique (autowire) par nom (value). Revenons au fichier de configuration [applicationContext.xml] :
2.
3.
4.
<!--
configuration
des
beans
de
portée
application
-->
<
bean
id
=
"
config
"
class
=
"
example.Config
"
>
<
property
name
=
"
nbMaxUsers
"
value
=
"
10
"
/
>
<
/
bean
>
Ce que Struts 2 appelle le nom du bean est en fait l'id. Donc ici, le bean de type [Config] instancié a pour nom config.
L'action [Action1.java] est la suivante :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
package
example;
import
com.opensymphony.xwork2.ActionSupport;
...
public
class
Action1 extends
ActionSupport implements
SessionAware, RequestAware, ParameterAware {
//
constructeur
sans
paramètre
public
Action1
(
) {
}
//
Session,
Request,
Parametres
private
Map<
String, Object>
session;
private
Map<
String, Object>
request;
private
Map<
String, String[]>
parameters;
private
Config config;
@
Override
public
String execute
(
) {
....
//
requête
request.put
(
"
nbMaxUsers
"
, config.getNbMaxUsers
(
));
//
affichage
page
JSP
return
SUCCESS;
}
...
public
Config getConfig
(
) {
return
config;
}
public
void
setConfig
(
Config config) {
this
.config =
config;
}
}
L'action [Action1] est identique à ce qu'elle était dans l'application précédente aux détails près suivants :
- ligne 15 : un champ config a été ajouté. Parce qu'il porte le nom d'un bean instancié par Spring, ce champ recevra automatiquement une référence sur cet objet. Ainsi l'action a accès à la configuration de l'application ou plus généralemet aux données de portée Application.
- ligne 31 : Spring instanciera le champ config via sa méthode set. Elle doit donc être présente.
- ligne 21 : l'action accède aux informations de portée Application. On met le nombre maximal d'utilisateurs nbMaxUsers dans la requête afin que la vue [Context.jsp] puisse l'afficher.
XVII-B-3. Le fichier [example.xml]▲
Le fichier secondaire de configuration de Struts est identique à celui de la version précédente :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
<?
xml
version="1.0"
encoding="UTF-8"
?
>
<!
DOCTYPE
struts
PUBLIC
"
-//Apache
Software
Foundation//DTD
Struts
Configuration
2.0//EN
"
"
http://struts.apache.org/dtds/struts-2.0.dtd
"
>
<
struts
>
<
package
name
=
"
example
"
namespace
=
"
/example
"
extends
=
"
struts-default
"
>
<
action
name
=
"
Action1
"
class
=
"
example.Action1
"
>
<
result
name
=
"
success
"
>
/example/Context.jsp<
/
result
>
<
/
action
>
<
/
package
>
<
/
struts
>
XVII-C. La vue [Context.jsp]▲
La vue [Context.jsp] est la suivante :
<%@
page
contentType
=
"
text
/
html
;
charset
=
UTF
-
8
"
pageEncoding
=
"
UTF
-
8
"
%>
<%@
taglib
prefix
=
"
s
"
uri
=
"
/
struts
-
tags
"
%>
<
html
>
<
head
>
<
title
>
<
s
:
text
name
=
"
Context
.
titre
"
/
>
<
/
title
>
<
s
:
head
/
>
<
/
head
>
<
body
background
=
"
<
s
:
url
value
=
"
/
ressources
/
standard
.
jpg
"
/
>
"
>
<
h2
>
<
s
:
text
name
=
"
Context
.
message
"
/
>
<
/
h2
>
<
h3
>
<
s
:
text
name
=
"
Context
.
parameters
"
/
>
<
/
h3
>
nom : <
s
:
property
value
=
"
#
parameters
[
'
nom
'
]
"
/
>
<
br
/
>
age : <
s
:
property
value
=
"
#
parameters
[
'
age
'
]
"
/
>
<
h3
>
<
s
:
text
name
=
"
Context
.
session
"
/
>
<
/
h3
>
compteur : <
s
:
property
value
=
"
#
session
[
'
compteur
'
]
"
/
>
<
h3
>
<
s
:
text
name
=
"
Context
.
request
"
/
>
<
/
h3
>
nbMaxUsers : <
s
:
property
value
=
"
#
request
[
'
nbMaxUsers
'
]
"
/
>
<
/
body
>
<
/
html
>
XVII-D. Les tests▲
Un exemple d'exécution est le suivant :