1、第 17 章 基于注解的控制器0117.1 Spring MVC 常用注解02030417.2 在 Spring MVC 中处理模型数据17.3 基于注解的控制器示例 117.4 基于注解的控制器示例 2本章导读从从 Spring 2.5 开始引入注解,使用注解的方式开始引入注解,使用注解的方式可以减少可以减少 XML 的配置,也提供了自动装配的功的配置,也提供了自动装配的功能,使得开发工作变得更为轻松,这实际上是能,使得开发工作变得更为轻松,这实际上是“约定优于配置约定优于配置”的开发原则。的开发原则。0117.1 Spring MVC 常用注解使用基于注解的控制器有以下两个优点:使用基于注
2、解的控制器有以下两个优点:(1)一个使用基于注解的控制器可以处理多个动作一个使用基于注解的控制器可以处理多个动作,而一个实现,而一个实现了了 Controller 接口的控制器只能处理一个动作。这就允许将相关的接口的控制器只能处理一个动作。这就允许将相关的操作操作写在同一个控制器类中写在同一个控制器类中,从而减少应用程序中类的数量。,从而减少应用程序中类的数量。(2)基于注解的控制器的请求映射不需要存储在配置文件中。使)基于注解的控制器的请求映射不需要存储在配置文件中。使用用 RequestMapping 注解类型注解类型,可以对一个方法进行请求处理。,可以对一个方法进行请求处理。0117.1
3、 Spring MVC 常用注解org.springframework.stereotype.Controller 注解类型用于指示注解类型用于指示 Spring 类的实例是一个控制器,类的实例是一个控制器,其注解形式是其注解形式是 Controller,Spring MVC 使使用扫描机制查找应用程序中所有基于注解的控制器类(使用用扫描机制查找应用程序中所有基于注解的控制器类(使用Controller 标记的类)。分发处理器会扫描使用了该注解的类的方法,标记的类)。分发处理器会扫描使用了该注解的类的方法,并检测该方法是否使用了并检测该方法是否使用了 RequestMapping 注解,而使用
4、注解,而使用 RequestMapping 注解的方法才是真正处理请求的处理器。注解的方法才是真正处理请求的处理器。为了保证为了保证 Spring 能找到你的控制器,需要在能找到你的控制器,需要在 Spring MVC 的配置文件的配置文件中添加相应的扫描配置信息。中添加相应的扫描配置信息。17.1.1 Controller 和 RequestMapping0117.1 Spring MVC 常用注解RequestMapping 注解可以在控制器类的级别和(或)控制器类中的注解可以在控制器类的级别和(或)控制器类中的方法的级别上使用。在类的级别上的注解会将一个特定请求或者请求方法的级别上使用。
5、在类的级别上的注解会将一个特定请求或者请求模式映射到一个控制器之上。之后还可以另外添加方法级别的注解来模式映射到一个控制器之上。之后还可以另外添加方法级别的注解来进一步指定到处理方法的映射关系。进一步指定到处理方法的映射关系。17.1.1 Controller 和 RequestMapping0117.1 Spring MVC 常用注解 Spring MVC 还定义了处理器的拦截器,当启动还定义了处理器的拦截器,当启动 Spring MVC 的时候,的时候,Spring MVC 就会就会解析解析 Controller 中的中的 RequestMapping 的配置的配置,再结合所配置的拦截器,
6、这样它就会组成多个拦截器和一个控制器的再结合所配置的拦截器,这样它就会组成多个拦截器和一个控制器的形式,存放到一个形式,存放到一个 HandlerMapping 中去。中去。当请求来到服务器,首先是通过请求信息找到对应的当请求来到服务器,首先是通过请求信息找到对应的 HandlerMapping,进而可以找到对应的拦截器和处理器,这样就能够运行对应的控制器进而可以找到对应的拦截器和处理器,这样就能够运行对应的控制器和拦截器。和拦截器。17.1.1 Controller 和 RequestMapping0117.1 Spring MVC 常用注解 将依赖注入到将依赖注入到 Spring MVC
7、控制器的最简单方法是通过注解控制器的最简单方法是通过注解 Autowired 到字段(属性)或方法到字段(属性)或方法。Autowired 注解类型属于注解类型属于 org.springframework.beans.factory.annotation 包。包。被定位于实现业务逻辑功能的被定位于实现业务逻辑功能的 Service,为了能被作为依赖注入,为了能被作为依赖注入,类必类必须要声明为须要声明为 Service,该类型是,该类型是 org.springframework.stereotype 的成的成员员。Service 注解类型指示类是一个服务。注解类型指示类是一个服务。此外,在此外
8、,在 Spring MVC 配置文件中,还需要添加自动扫描控制器配置文件中,还需要添加自动扫描控制器(Contoller)所在的包以及服务()所在的包以及服务(Service)所在的包的代码。)所在的包的代码。17.1.2 Autowired 和 Service0117.1 Spring MVC 常用注解 RequestParam 用于将请求参数区数据映射到功能处理方法的参数上。用于将请求参数区数据映射到功能处理方法的参数上。例如下面的示例代码:例如下面的示例代码:17.1.3 RequestParam 和 PathVariable 这里这里 RequestParam 注解可以用来提取请求参数
9、区数据名为注解可以用来提取请求参数区数据名为“num”的的 String 类型的参数,并将之作为输入参数传给类型的参数,并将之作为输入参数传给 number。0117.1 Spring MVC 常用注解 这里请求参数区数据可以是这里请求参数区数据可以是 URL 请求中的参数,也可以是提交表单中请求中的参数,也可以是提交表单中的参数。例如针对前一种可假设的参数。例如针对前一种可假设 URL 请求如下:请求如下:http:/localhost:8080/context/accounts/show?num=168针对后一种可假设提交表单如下:针对后一种可假设提交表单如下:17.1.3 Request
10、Param 和 PathVariable0117.1 Spring MVC 常用注解 PathVariable 可以用来映射可以用来映射 URL 中的占位符中的占位符到目标方法的参数中。到目标方法的参数中。例如有以下的代码:例如有以下的代码:17.1.3 RequestParam 和 PathVariable 如请求的如请求的 URL 为为“控制器控制器URL/users/123/topics/456”,则自动将,则自动将 URL 中模板变量中模板变量 userId 和和 topicId 绑定到通过绑定到通过 PathVariable 注解的同注解的同名参数上,即入参后名参数上,即入参后 us
11、erId=123、topicId=456。0117.1 Spring MVC 常用注解 考虑浏览器和服务器之间的交互。当用户第考虑浏览器和服务器之间的交互。当用户第 1 次访问服务器时,服务次访问服务器时,服务器会在响应消息中增加器会在响应消息中增加 Set-Cookie 头字段,将用户信息以头字段,将用户信息以 Cookie 的形的形式发送给浏览器。一旦用户浏览器接受了服务器发送的式发送给浏览器。一旦用户浏览器接受了服务器发送的 Cookie 信息,信息,就会将它保存在浏览器的缓冲区中。这样,当浏览器后续访问该服务就会将它保存在浏览器的缓冲区中。这样,当浏览器后续访问该服务器时,都会在请求信
12、息中将用户信息以器时,都会在请求信息中将用户信息以 Cookie 的形式发送给的形式发送给 Web 服务服务器,从而使服务器端分辨出当前请求是由哪个用户发出的。器,从而使服务器端分辨出当前请求是由哪个用户发出的。使用使用 Cookie 注解可以将请求的注解可以将请求的 Cookie 数据映射到功能处理方法的参数据映射到功能处理方法的参数上。数上。17.1.4 CookieValue 和 RequestHeader0117.1 Spring MVC 常用注解org.springframework.web.bind.annotation.RequestHeader 注解类型用注解类型用于将请求的头
13、信息区数据映射到功能处理方法的参数上。于将请求的头信息区数据映射到功能处理方法的参数上。在控制器的方法参数中使用在控制器的方法参数中使用 RequestHeader 注解,能够从注解,能够从 Http 请求请求头中提取指定的某个请求头,可以说等价于头中提取指定的某个请求头,可以说等价于 HttpServletRequest.getHeader(String)。17.1.4 CookieValue 和 RequestHeader0217.2 在 Spring MVC 中处理模型数据ModelAndView 有一个类型为有一个类型为 ModelMap 的的属性属性 model,而,而 ModelM
14、ap 继承了继承了 LinkedHashMap,因此可,因此可以存放各种键值对。以存放各种键值对。为了进一步定义数据模型功能,为了进一步定义数据模型功能,Spring 还创还创建了类建了类 ExtendedModelMap,这个类实现了,这个类实现了数据模型定义的数据模型定义的 Model 接口,如图接口,如图17-1所示,所示,并且还在此基础上派生了关于数据绑定的类并且还在此基础上派生了关于数据绑定的类 BindingAwareModelMap。17.2.1 数据模型0217.2 在 Spring MVC 中处理模型数据在控制器的方法中,可以把在控制器的方法中,可以把 ModelAndVie
15、w、Model、ModelMap 作为作为参数。在参数。在 Spring MVC 运行的时候,运行的时候,会自动初始化它们会自动初始化它们,因此可以选择,因此可以选择 ModelMap 或者或者 Model 作为数据模型。事实上作为数据模型。事实上 Spring MVC 创建的是一创建的是一个个 BindingAwareModelMap 实例。实例。ModelAndView 初始化后,初始化后,model 属性为空,当调用它增加数据模型的属性为空,当调用它增加数据模型的方法后,会自动创建一个方法后,会自动创建一个 ModelMap 实例,用以保存数据模型。实例,用以保存数据模型。17.2.1
16、数据模型0217.2 在 Spring MVC 中处理模型数据Spring MVC 提供了以下几种途径输出模型数据:提供了以下几种途径输出模型数据:17.2.1 数据模型0217.2 在 Spring MVC 中处理模型数据可将控制器处理方法的返回值设为可将控制器处理方法的返回值设为 ModelAndView,ModelAndView 中既可存放视图信息,也可存放模型数据信中既可存放视图信息,也可存放模型数据信息。息。SpringMVC 会把会把 ModelAndView 的的 model 中数据放入中数据放入到到 request 域对象中。域对象中。17.2.2 ModelAndView02
17、17.2 在 Spring MVC 中处理模型数据Spring MVC 在调用方法前会创建一个在调用方法前会创建一个隐含的模型对象隐含的模型对象作为模型数据作为模型数据的存储容器(事实上这个隐含的模型对象是一个的存储容器(事实上这个隐含的模型对象是一个 BindingAwareModelMap 类型的对象,通过后面的例子我们可以验类型的对象,通过后面的例子我们可以验证),如果方法的入参为证),如果方法的入参为 Map、Model 或者或者 ModelMap 类型,类型,Spring MVC 会将隐含模型的引用传递给这些入参(因为会将隐含模型的引用传递给这些入参(因为 BindingAwareM
18、odelMap 继承或实现了继承或实现了 Map、Model 或者或者 ModelMap)。在方法体内,开发者可以通过这个入参对象访问到模)。在方法体内,开发者可以通过这个入参对象访问到模型中的所有数据,也可以向模型中添加新的属性数据,型中的所有数据,也可以向模型中添加新的属性数据,Spring MVC 也会把也会把 Map 中数据放入到中数据放入到 request 域对象中。域对象中。17.2.3 Map 及 Model0217.2 在 Spring MVC 中处理模型数据上面介绍的两种方式,上面介绍的两种方式,Spring MVC 都是将数据存放在都是将数据存放在 request 域对象域
19、对象中,若希望在多个请求之间共用某个模型属性数据,则可以在控制器中,若希望在多个请求之间共用某个模型属性数据,则可以在控制器类上标注一个类上标注一个 SessionAttributes 注解(该注解只能放在类的上面,注解(该注解只能放在类的上面,而不能修饰放方法),而不能修饰放方法),Spring MVC将把模型中对应的属性暂存到将把模型中对应的属性暂存到 HttpSession 中。中。SessionAttributes 除了可以通过属性名指定需要放到会话中的属性外,除了可以通过属性名指定需要放到会话中的属性外,还可以还可以通过模型属性的对象类型指定通过模型属性的对象类型指定哪些模型属性需要
20、放到会话中。哪些模型属性需要放到会话中。17.2.4 SessionAttributes0217.2 在 Spring MVC 中处理模型数据Spring MVC 在每次调用请求处理方法时,都会创建在每次调用请求处理方法时,都会创建 Model 类型的一个实例。若打算使用该实例,则可以在方类型的一个实例。若打算使用该实例,则可以在方法中添加一个法中添加一个 Model 类型的参数。除此之外,我们还可以类型的参数。除此之外,我们还可以使用在方法中添加使用在方法中添加org.springframework.web.bind.annotation.ModelAttribute注解类型将请求参数绑定到
21、注解类型将请求参数绑定到 Model 对象。对象。17.2.5 ModelAttribute0217.2 在 Spring MVC 中处理模型数据ModelAttribute 注解只支持一个属性注解只支持一个属性 value,类型为,类型为String,表示绑定的属性名称。,表示绑定的属性名称。可以用可以用 ModelAttribute 来注解方法参数或方法。来注解方法参数或方法。带带 ModelAttribute 注解的方法(请求方法),会将其输注解的方法(请求方法),会将其输入的或创建的参数对象添加到入的或创建的参数对象添加到 Model 对象中(若方法中没对象中(若方法中没有显式地增加)
22、。有显式地增加)。17.2.5 ModelAttribute0217.2 在 Spring MVC 中处理模型数据ModelAttribute 还可以标注一个非请求的处理方法还可以标注一个非请求的处理方法。被。被 ModelAttribute 注解的方法,会在每次调用该控制器类的请求处理注解的方法,会在每次调用该控制器类的请求处理方法时被调用。方法时被调用。Spring MVC会在调用请求处理方法之前调用带有会在调用请求处理方法之前调用带有 ModelAttribute 注注解的方法。带解的方法。带 ModelAttribute 注解的方法可以返回一个对象或一个注解的方法可以返回一个对象或一个
23、 void 类型。如果返回一个对象,则返回对象会自动添加到类型。如果返回一个对象,则返回对象会自动添加到 Model中;中;若方法返回若方法返回 void,则还必须添加一个,则还必须添加一个 Model 类型的参数,并自行将实类型的参数,并自行将实例添加到例添加到 Model 中。中。17.2.5 ModelAttribute0317.3 基于注解的控制器示例 1本示例着是对前面章节中本示例着是对前面章节中SpringMVC_Basic_Demo2 工程的改写。工程的改写。由于使用由于使用注解类型注解类型来开发,一个控制器类可以来开发,一个控制器类可以包含多个请求处理方法包含多个请求处理方法。
24、原本在。原本在 SpringMVC_Basic_Demo2 工程中的两个控制工程中的两个控制器器 AddBookController 和和 SaveBookController,这里这里用一个控制器替代用一个控制器替代 就可以了,这个控制就可以了,这个控制器是器是 BookController。而控制器。而控制器 BookController 包含了两个请求方法,其请求包含了两个请求方法,其请求映射分别是映射分别是/book_add 和和/book_save。0417.4 基于注解的控制器示例 2本示例着重说明:本示例着重说明:如何使用如何使用 Autowired 和和 Service 进行依
25、赖注入;进行依赖注入;Spring 如何通过如何通过 Flash 属性进属性进行重定向传值;行重定向传值;PathVariable 使用;使用;Spring 组件自动扫描机制。组件自动扫描机制。本章小结本章主要介绍了本章主要介绍了 Spring MVC 中的一些常用注解的使用,这中的一些常用注解的使用,这里包括里包括 Controller 和和 RequestMapping、Autowired 和和 Service、RequestParam 和和 PathVariable、CookieValue 和和 RequestHeader、SessionAttributes 和和 ModelAttribute、Resource 和和 Qualifier、Repository 和和 Component,以及,以及 Spring MVC 中如何处理模型数据和中如何处理模型数据和重定向等内容。重定向等内容。