Spring MVC - Résolution de la vue
Bonjour,
Je débute en Spring (et en java :D) 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:
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:
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:
1 2 3
|
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<% response.sendRedirect("index.do"); %> |
ensuite le "IndexController" ...
Code:
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:
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:
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:
<% response.sendRedirect("form/item.do"); %>
et que mon deuxième controller est défini comme suit :
Code:
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:
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:
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:
<% response.sendRedirect("index2.do"); %>
et que je configure le controller "IndexController" commme suit :
Code:
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:
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:
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 ...