Bonjour,

Je débute en Spring (et en java ) et après avoir lu un certains nombres de chapitre du livre "Spring par la pratique 2.5 et 3.0", je me suis dit qu'il était temps de passer à la pratique, justement.

J'ai donc lancé Netbeans 7 et créé un nouveau projet web avec spring MVC.

J'ai modifié le dispatcher-servlet par défaut ( faisant office de contexte spring ) pour "activer" la prise en compte des annotations ( afin de pouvoir configurer les controllers directement ).

J'ai créé un package "web.views" hebergeant deux pages JSP ( "index.jsp" et "itemForm.jsp" ).

J'ai également créé un package "web.controllers" contenant deux Controllers ( "IndexController" et "ItemFormController" )

Lorsque je compile le projet la page "redirect.jsp" est appelée ( car configurée comme "welcome-file" dans le web.xml ). Cette page redirige vers l'URL "index.do".

Le controller "IndexController" intercepte la requete et redirige vers la page "index.jsp" ... Ca marche !
et si dans le controller je précise que la vue de "retour" est "itemForm" ... ca marche encore... formidable.

Voici le code de tout ce que je viens de raconter :

d'abord le web.xml : ( rien de spéciale ici si ce n'est le welcome-file et le "pattern url" associé à la servlet "dispatcher"

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
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
35
36
37
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/applicationContext.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!--  facultatif (comportement par défaut) voir page 189 -->
        <init-param> 
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/dispatcher-servlet.xml</param-value>
        </init-param>
        <init-param>
            <param-name>debug</param-name>
            <param-value>0</param-value>
        </init-param>
        <load-on-startup>2</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>
    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
    <welcome-file-list>
        <welcome-file>redirect.jsp</welcome-file>
    </welcome-file-list>
</web-app>
ensuite la configuration du contexte spring ( = dispatcher-servlet.xml ) ( je passe la déclaration des schémas xsd et tout le tralala )

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
 
{...}
    <mvc:annotation-driven/>
    <context:component-scan base-package="web.controllers" />
 
    <bean id="viewResolver"
          class="org.springframework.web.servlet.view.InternalResourceViewResolver"
          p:prefix="/WEB-INF/classes/web/views/"
          p:suffix=".jsp" />
ensuite le redirect.jsp ...

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
 
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<% response.sendRedirect("index.do"); %>
ensuite le "IndexController" ...

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 
{...}
@Controller
public class IndexController
{
 
    @RequestMapping("index.do")
    public ModelAndView index(HttpServletRequest request, HttpServletResponse response) throws Exception
    {
        Map<String, Object> model = new HashMap<String, Object>();
        ItemBean itemBean = new ItemBean();
        itemBean.setFname("John");
        itemBean.setLname("Doe");
        model.put("itemBean", itemBean);
        return new ModelAndView("itemForm", model);
    }
}
le petit "ItemBean" qui va bien :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
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
 
public class ItemBean
{
    private String _fname;
    private String _lname;
 
    public String getFname()
    {
        return _fname;
    }
 
    public void setFname(String fname)
    {
        this._fname = fname;
    }
 
    public String getLname()
    {
        return _lname;
    }
 
    public void setLname(String lname)
    {
        this._lname = lname;
    }
 
}
enfin "index.jsp" :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jstl/core_rt" %>
<%@taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt_rt" %>
<!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>Welcome to Spring Web MVC project </title>
    </head>
 
    <body>
        <p>
            <c:out value="${itemBean.fname}"/>, <c:out value="${itemBean.lname}"/><br/>
        </p>
    </body>
</html>
Bref tout marche bien, on notera que mon controller retourne un objet de type ModelAndView précisant en premier paramètre un string représentant l'identifiant de la vue, et en 2ème une Map contenant le model utilisé par la vue.

Là où ça coince ... c'est que j'ai un deuxième controller ... qui s'appel "ItemFormController"
et si je change dans le "redirect.jsp" la redirection comme ci-dessous :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
<% response.sendRedirect("form/item.do"); %>
et que mon deuxième controller est défini comme suit :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 
@Controller
public class ItemFormController
{
 
    @RequestMapping("form/item.do")
    public ModelAndView index(HttpServletRequest request, HttpServletResponse response) throws Exception
    {
        Map<String, Object> model = new HashMap<String, Object>();
        ItemBean itemBean = new ItemBean();
        itemBean.setFname("John");
        itemBean.setLname("Doe");
        model.put("itemBean", itemBean);
        ModelAndView mav = new ModelAndView("index",model);
        return mav;
    }
}
Et bien ca me retourne systématiquement une erreur 404 :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
 
HTTP Status 404 -
 
type Status report
 
message
 
descriptionThe requested resource () is not available.
GlassFish Server Open Source Edition 3.1

Alors que le controller fait clairement la même chose que le premier ... la seule différence étant l'annotation @RequestMapping qui "écoute" sur "form/item.do";

J'ai vérifié avec le debugger et je passe bien dans le controller ...

Enfin dernier bémol, si je change le controller de la manière suivante :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 
@Controller
public class ItemFormController
{
 
    @RequestMapping("form/item.do")
    public String index(HttpServletRequest request, HttpServletResponse response) throws Exception
    {
        Map<String, Object> model = new HashMap<String, Object>();
        ItemBean itemBean = new ItemBean();
        itemBean.setFname("John");
        itemBean.setLname("Doe");
        model.put("itemBean", itemBean);
        ModelAndView mav = new ModelAndView("index",model);
        //return mav;
        return "index";
    }
}
C'est à dire que le controller retourne non plus un objet de type "ModelAndView" mais un "String", la vue est correctement affichée... (même si le model est vide)

Dernier détails ( bein oui avant c'était un bémol :p ) : Si je configure la page "redirect.jsp" comme suit :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
<% response.sendRedirect("index2.do"); %>
et que je configure le controller "IndexController" commme suit :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
 
@Controller
public class IndexController
{
 
    @RequestMapping("index2.do")
    public ModelAndView index(HttpServletRequest request, HttpServletResponse response) throws Exception
    {
     {...}
ca marche ... (la vue est bien affichée )

par contre si je configure le controller "IndexController" comme çà :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
 
@Controller
public class IndexController
{
 
    @RequestMapping("index3.do")
    public ModelAndView index(HttpServletRequest request, HttpServletResponse response) throws Exception
    {
     {...}
et le controller "ItemFormController" comme ça :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
 
@Controller
public class ItemFormController
{
 
    @RequestMapping("index2.do")
    public ModelAndView index(HttpServletRequest request, HttpServletResponse response) throws Exception
    {
      {...}
afin que la redirection soit prise en charge par le controller "ItemFormController" ... et bien ça ne marche pas ( erreur 404 )... ( bien sur le code dans les deux controllers est identique, et donc la même vue est ciblée)

Alors j'ai juste une question : WTF ?

D'après les cas de figures exposés ci-dessus :
- ça ne peut pas venir de la valeur de l'annotation @RequestParam puisque j'ai tester la même valeur ( "index2.do" ) dans les deux controllers et ça ne marche pas qu'avec le deuxième controller...
- ça peut venir du ModelAndView qui fait de la mer** en interne mais c'est tellement bateau comme truc que ce bug devrait être connu et j'ai rien trouvé sur le sujet sur google.


Dernière question : Si vous n'utilisez pas les "ModelAndView", vous utilisez quoi à la place pour transmettre le model à la vue ?


Merci de m'avoir lu et merci d'éclairer ma lanterne ...