xmlns:
xsi="http:
//www.w3.org/2001/XMLSchema-instance"
xsi:
schemaLocation="
version="2.5">
SpringAnnotationMVCSample
--Spring服务层的配置文件-->
contextConfigLocation
classpath:
applicationContext.xml
--Spring容器启动监听器-->
org.springframework.web.context.ContextLoaderListener
--SpringMVC的Servlet,它将加载WEB-INF/annomvc-servlet.xml的
配置文件,以启动SpringMVC模块-->
annomvc
org.springframework.web.servlet.DispatcherServlet
2
annomvc
*.do
web.xml中定义了一个名为annomvc的SpringMVC模块,按照SpringMVC的契约,需要在WEB-INF/annomvc-servlet.xml配置文件中定义SpringMVC模块的具体配置。
annomvc-servlet.xml的配置内容如下所示:
清单3.annomvc-servlet.xml
xmlversion="1.0"encoding="UTF-8"?
>
xmlns="http:
//www.springframework.org/schema/beans"
xmlns:
xsi="http:
//www.w3.org/2001/XMLSchema-instance"
xmlns:
p="http:
//www.springframework.org/schema/p"
xmlns:
context="http:
//www.springframework.org/schema/context"
xsi:
schemaLocation="http:
//www.springframework.org/schema/beans
http:
//www.springframework.org/schema/beans/spring-beans-2.5.xsd
http:
//www.springframework.org/schema/context
http:
//www.springframework.org/schema/context/spring-context-2.5.xsd">
--①:
对web包中的所有类进行扫描,以完成Bean创建和自动依赖注入的功能-->
component-scanbase-package="com.baobaotao.web"/>
--②:
启动SpringMVC的注解功能,完成请求和注解POJO的映射-->
AnnotationMethodHandlerAdapter"/>
--③:
对模型视图名称的解析,即在模型视图名称添加前后缀-->
p:
prefix="/WEB-INF/jsp/"p:
suffix=".jsp"/>
因为Spring所有功能都在Bean的基础上演化而来,所以必须事先将Controller变成Bean,这是通过在类中标注@Controller并在annomvc-servlet.xml中启用组件扫描机制来完成的,如①所示。
在②处,配置了一个AnnotationMethodHandlerAdapter,它负责根据Bean中的SpringMVC注解对Bean进行加工处理,使这些Bean变成控制器并映射特定的URL请求。
而③处的工作是定义模型视图名称的解析规则,这里我们使用了Spring2.5的特殊命名空间,即p命名空间,它将原先需要通过元素配置的内容转化为属性配置,在一定程度上简化了的配置。
启动Tomcat,发送http:
//localhost/forum.doURL请求,BbtForumController的listAllBoard()方法将响应这个请求,并转向WEB-INF/jsp/listBoard.jsp的视图页面。
回页首
让一个Controller处理多个URL请求
在低版本的SpringMVC中,我们可以通过继承MultiActionController让一个Controller处理多个URL请求。
使用@RequestMapping注解后,这个功能更加容易实现了。
请看下面的代码:
清单3.每个请求处理参数对应一个URL
packagecom.baobaotao.web;
importcom.baobaotao.service.BbtForumService;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.stereotype.Controller;
importorg.springframework.web.bind.annotation.RequestMapping;
@Controller
publicclassBbtForumController{
@Autowired
privateBbtForumServicebbtForumService;
@RequestMapping("/listAllBoard.do")//<——①
publicStringlistAllBoard(){
bbtForumService.getAllBoard();
System.out.println("calllistAllBoardmethod.");
return"listBoard";
}
@RequestMapping("/listBoardTopic.do")//<——②
publicStringlistBoardTopic(inttopicId){
bbtForumService.getBoardTopics(topicId);
System.out.println("calllistBoardTopicmethod.");
return"listTopic";
}
}
在这里,我们分别在①和②处为listAllBoard()和listBoardTopic()方法标注了@RequestMapping注解,分别指定这两个方法处理的URL请求,这相当于将BbtForumController改造为MultiActionController。
这样/listAllBoard.do的URL请求将由listAllBoard()负责处理,而/listBoardTopic.do?
topicId=1的URL请求则由listBoardTopic()方法处理。
对于处理多个URL请求的Controller来说,我们倾向于通过一个URL参数指定Controller处理方法的名称(如method=listAllBoard),而非直接通过不同的URL指定Controller的处理方法。
使用@RequestMapping注解很容易实现这个常用的需求。
来看下面的代码:
清单4.一个Controller对应一个URL,由请求参数决定请求处理方法
packagecom.baobaotao.web;
importcom.baobaotao.service.BbtForumService;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.stereotype.Controller;
importorg.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/bbtForum.do")//<——①指定控制器对应URL请求
publicclassBbtForumController{
@Autowired
privateBbtForumServicebbtForumService;
//<——②如果URL请求中包括"method=listAllBoard"的参数,由本方法进行处理
@RequestMapping(params="method=listAllBoard")
publicStringlistAllBoard(){
bbtForumService.getAllBoard();
System.out.println("calllistAllBoardmethod.");
return"listBoard";
}
//<——③如果URL请求中包括"method=listBoardTopic"的参数,由本方法进行处理
@RequestMapping(params="method=listBoardTopic")
publicStringlistBoardTopic(inttopicId){
bbtForumService.getBoardTopics(topicId);
System.out.println("calllistBoardTopicmethod.");
return"listTopic";
}
}
在类定义处标注的@RequestMapping让BbtForumController处理所有包含/bbtForum.do的URL请求,而BbtForumController中的请求处理方法对URL请求的分流规则在②和③处定义分流规则按照URL的method请求参数确定。
所以分别在类定义处和方法定义处使用@RequestMapping注解,就可以很容易通过URL参数指定Controller的处理方法了。
@RequestMapping注解中除了params属性外,还有一个常用的属性是method,它可以让Controller方法处理特定HTTP请求方式的请求,如让一个方法处理HTTPGET请求,而另一个方法处理HTTPPOST请求,如下所示:
清单4.让请求处理方法处理特定的HTTP请求方法
packagecom.baobaotao.web;
importcom.baobaotao.service.BbtForumService;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.stereotype.Controller;
importorg.springframework.web.bind.annotation.RequestMapping;
importorg.springframework.web.bind.annotation.RequestMethod;
@Controller
@RequestMapping("/bbtForum.do")
publicclassBbtForumController{
@RequestMapping(params="method=createTopic",method=RequestMethod.POST)
publicStringcreateTopic(){
System.out.println("callcreateTopicmethod.");
return"createTopic";
}
}
这样只有当/bbtForum.do?
method=createTopic请求以HTTPPOST方式提交时,createTopic()方法才会进行处理。
回页首
处理方法入参如何绑定URL参数
按契约绑定
Controller的方法标注了@RequestMapping注解后,它就能处理特定的URL请求。
我们不禁要问:
请求处理方法入参是如何绑定URL参数的呢?
在回答这个问题之前先来看下面的代码:
清单5.按参数名匹配进行绑定
@RequestMapping(params="method=listBoardTopic")
//<——①topicId入参是如何绑定URL请求参数的?
publicStringlistBoardTopic(inttopicId){
bbtForumService.getBoardTopics(topicId);
System.out.println("calllistBoardTopicmethod.");
return"listTopic";
}
当我们发送http:
//localhost//bbtForum.do?
method=listBoardTopic&topicId=10的URL请求时,Spring不但让listBoardTopic()方法处理这个请求,而且还将topicId请求参数在类型转换后绑定到listBoardTopic()方法的topicId入参上。
而listBoardTopic()方法的返回类型是String,它将被解析为逻辑视图的名称。
也就是说Spring在如何给处理方法入参自动赋值以及如何将处理方法返回值转化为ModelAndView中的过程中存在一套潜在的规则,不熟悉这个规则就不可能很好地开发基于注解的请求处理方法,因此了解这个潜在规则无疑成为理解SpringMVC框架基于注解功能的核心问题。
我们不妨从最常见的开始说起:
请求处理方法入参的类型可以是Java基本数据类型或String类型,这时方法入参按参数名匹配的原则绑定到URL请求参数,同时还自动完成String类型的URL请求参数到请求处理方法参数类型的转换。
下面给出几个例子:
∙listBoardTopic(intt