Spring从2.5版本开始引入注解,用户可以使用@Controller,@RequestMapping,@RequestParam,@ModelAttribute 等类似这样的注解。到目前为止,Spring的版本虽然发生了很大的变化,但注解的特性却一直延续下来,并不断扩展,让广大的开发者的工作变得更轻松。这都离不开Annotation的强大作用,本次重点讲解SpringMVC4中的常用注解。
org.springframework.steretype.Controller注解类型用于指示Spring类的实例是一个控制器,使用@Controller注解的类不需要继承特定的父类或者实现特定的接口,相对之前的版本实现Controller接口变得更加简单。而且Controller接口的实现类只能处理一个单一请求动作,而@Controller注解的控制器可以支持同事处理多个请求动作,更加灵活。
@Controller用于标记一个类,使用它标记的类就是一个SpringMVC Controller对象,即一个控制器类。Spring使用扫描机制查找应用程序中基于注解的控制器类。分发处理器会扫描使用了该注解的类的方法,并检测该方法是否使用了@RequestMapping注解,而使用@ RequestMapping注解的方法才是真正处理请求的处理器。为了保证Spring能找到控制器,需要完成两件事情:
在SpringMVC的配置文件的头文件中引入spring-context.
使用
应该将所有控制器类都放在基本包下,并指定扫描该包,即org.fkit.controller, 而不应该指定扫描org.fkit包,以免SpringMVC扫描了无关的包。
示例:@Controller注解的使用
新建一个项目ControllerTest,加入所需要的jar文件,新建HelloWorldController类:
代码如下:
package org.fkit.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class HelloWorldController {
@RequestMapping("/helloWorld")
public String helloWorld(Model model) {
model.addAttribute("message", "Hello World!");
return "helloWorld";
}
}
HelloWorldController是一个基于@Controller注解的控制器,@RequestMapping注释用来映射一个请求,value="/helloWorld"表示请求由helloWorld方法进行处理。helloWorld方法接收一个org.springframework.ui.Model类型的参数,本例在model中添加了一个名为"message"的字符串对象,该对象可以在返回的视图当中通过request对象获取。最后,方法返回一个字符串"helloWorld"作为视图名称。
新建springmvc-config.xml:
内容如下:
/WEB-INF/content/
.jsp
由于使用了注解类型,因此不需要再在配置文件中XML描述Bean。
此外,还需要在wen.xml文件中配置SpringMVC的前端控制器DispatcherServlet,因为每次配置基本一致,故此处不在赘述,以及在WEB-INF 下新建content目录,新建helloWorld.jsp,jsp内容可参考之前博文中配置内容自行配置。
3.测试
部署ConntrollerTest这个Web应用,在浏览器输入URL来测试应用:
http://localhost:8080/ControllerTest/helloWorld.
若看到以下界面,表示SpringMVC访问成功。
SpringMVC中用于参数绑定的注解有很多,都在org.springframework.web.bind.annotation包中,根据它们处理的request的不同内容部分可以分为四类(主要讲解常用类型)。
开发者需要在控制器内部为每一个请求动作开发相应的处理方法。org.springframework.web.bind.annotation.RequestMapping注解类型指示Spring用哪一个类或方法来处理请求动作,该注解可用于类或方法。(@RequestMapping虽然也在org.springframework.web.bind.annotation下面,但是严格来说,它并不属于参数绑定注解)。
@RequestMapping可以用来注释一个控制器类,在这种情况下,所有方法都将映射为相对于类级别的请求,表示该控制器处理的所有请求都被映射到value属性所指示的路径下。示例代码如下:
@Controller
@RequestMapping(value="/user")
public class UserController {
@RequestMapping(value="register")
public String register(){
return "register";
}
@RequestMapping(value="/login")
public String login(){
return "login";
}
}
由于UserController类中加了value="/user"的@RequestMapping注解,因此所有相关路径都要加上"/user",此时方法被映射到如下请求URL:
http://localhost:8080/user/register
http://localhost:8080/user/login
使用@RequestMapping注解可指定如表所示的属性。
属性 | 类型 | 是否必要 | 说明 |
value | String[] | 否 | 用于将指定请求的实际地址映射到方法上 |
name | String | 否 | 给映射地址一个别名 |
method | RequestMethod[] | 否 | 映射指定请求的方法类型,包括GET,POST,HEAD,OPTIONS,PUT,PATCH,DELETE,TARCE |
consumes | String[] | 否 | 指定处理请求的提交内容类型(Content-Type),l例如application/josn,text/html等 |
produces | String[] | 否 | 指定返回的内容类型,返回的内容类型必须是request请求头(Accept)中所包含的类型 |
params | String[] | 否 | 指定request中必须包含某些指定的header值,才能让该方法处理请求 |
Path | String[] | 否 | z在Servlet环境中只有:uri路径映射(例如:"/myPath.do")。也支持如ant的基于路径模式(例如“/myPath/*,”)。在方法层面上,支持相对路径(例如edit.do“”) |
@RequestMapping注解支持的常用属性示例如下。
@RequestMapping用来映射一个请求和一个方法。可以用@RequestMapping注释一个方法或类。
一个采用@RequestMapping注释的方法将成为一个请求处理方法,例如:
@RequestMapping(value="/hello")
public ModelAndView hello(){
return ...;
}
该示例使用@RequestMapping注释的value属性将URL映射到方法上。在这个例子中,将hello映射到hello方法上,使用如下url访问应用时将由hello方法进行处理。
http;//localhost:8080/context/hello
由于value属性是@RequestMapping注释的默认属性,因此,如果只有唯一的属性,则可以省略属性名,即如下两个标注含义相同。
@RequestMapping(value="/hello")
@RequestMapping("/hello")
但如果有超过一个属性,就必须写上value属性名称。
value属性的值也可以是一个空字符串,此时该方法被映射到如下请求URL:
http://localhost:8080/context
2.method属性
该属性用来指示该方法仅仅处理哪些HTTP请求方式。
@RequestMapping(value="/hello",method=RequestMethod.POST)
以上代码method=RequestMethod.POST表示该方法只支持POST请求。
也可以同时支持多个HTTP请求方式。如:
@RequestMapping(value="/hello", method={RequestMethod.POST,RequestMethod.GET})
如果没有指定method属性值,则请求处理方法可以处理任意的HTTP请求方式。
3.consumes属性
该属性指定处理请求的提交内容类型(Content-Type)。
@RequestMapping(value="/hello",method=RequestMethod.POST, consumes="application/json")
表示方法仅处理request Content-Type为"application/json"类型的请求。
4.produces属性
该属性指定返回的内容类型,返回的内容类型必须是request请求头(Accept)中所包含的类型。
@RequestMapping(value="/hello",method=RequestMethod.POST, produces="application/json")
方法仅处理request请求中Accept头中包含了"application/json"的请求,同时指明了返回的内容类型为application/json。
5.params属性
该属性指定request中必须包含某些参数值时,才让方法处理。
@RequestMapping(value="/hello",method=RequestMethod.POST,params="myParam=myValue")
方法仅处理其中名为"myParam",值为"myValue"的请求。
6.headers属性
该属性指定request中必须包含某些指定的header值时,才让该方法处理请求。
@RequestMapping(value="/hello",method=RequestMethod.POST, headers="Referer=http://www.fkit.org/")
方法仅处理request的header中包含了指定"Referer"请求头和对应值为"htttp://www.fkit.org/"的请求。
每个请求处理方法可以有多个不同类型的参数。
如果需要访问HttpServletReuquest对象,则可以添加HttpServletRequest作为参数,Spring会将对象正确地传递给方法:
@RequestMapping(value="/login")
public String login(HttpServletReqquest request){
return "login";
}
如果需要访问HttpSession对象,则可以添加HttpSession作为参数,Spring会将对象正确地传递给方法:
@RequestMapping(value="/login")
public String login(HttpSession session){
return "login";
}
下面是可以在请求处理方法中出现的参数类型:
其中最重要的是org.springframework.ui.Model类型。这不是ServletApI类型,而是一个Spring MVC类型,其中包含了Map对象用来存储数据。如果方法中添加了Model参数,则每次调用请求处理方法时,SpringMVC都会创建Model对象,并将其作为参数传递给方法。
每个请求处理方法可以返回以下类型的返回结果。
在请求处理方法可出现和返回的参数类型中,最重要的就是Model和ModelAndView了。对于MVC框架,控制器(controller)执行业务逻辑,用于产生模型数据(Model),而视图(view)则用于渲染模型数据。
如何将模型数据传递给视图是SpringMVC框架的一项重要工作,SpringMVC提供了多种途径输出模型数据,如:
下面将重点介绍Model,ModelMap以及ModelAndView, @ModelAttribute 和@SessionAttributes放到后面介绍。
1. Model 和 ModelMap
SpringMVC在内部使用了一个org.springframework.ui.Model接口存储模型数据,它的功能类似java.util.Map接口,但是比Map易于使用。org.springframework.ui.ModelMap接口实现了Map接口。
SpringMVC在调用处理方法之前会创建一个隐含的模型对象,作为模型数据的存储容器。如果处理方法的参数为Model或ModelMap类型,则SpringMVC会将隐含模型的引用传递给这些参数。在处理方法内部,开发者就可以通过这个参数对象访问模型中的所有数据,也可以向模型中添加新的属性数据。
在处理方法中,Model和ModelMap对象都可以使用如下方法添加模型数据:
示例: Model 和 ModelMap 使用
@Controller
public class UserlController{
//@ModelAttribute修饰的方法会于login调用,该方法用于接收前台jsp页面传入的参数
@ModelAttribute
public void userModel(String loginname,String password,Model model){
logger.info("ulserModel");
//创建User对象存储jsp页面传入的参数
User user= new User();
user.setLoginname(loginname);
user.setPassword(password);
//将User对象添加到Model当中
model.addAttribute("user",user);
}
@RequestMapping(value="/login1")
public String login(Model model){
logger.info("login");
//从Model当中取出之前存入的名为user的对象
User user= (User) model.asMap().get("user");
System.out.println(user);
//设置user对象的usernam属性
user.setUsername("测试");
return "result1";
}
}
@ModelAttribute修饰的userModel方法会于login调用,它把请求参数值赋给对应变量,可以向方法中的Model添加对象,前提是要在方法签名中加入一个Model类型的参数。
@Controller
public class User2lController{
private static final Log logger= LogFactory.getLog(UserlController.clas);
//@ModelAttribute修饰的方法会于login调用,该方法用于接收前台jsp页面传入的参数
@ModelAttribute
public void userMode2(String loginname,String password,ModelMap modelMap){
logger.info("ulserModel");
//创建User对象存储jsp页面传入的参数
User user= new User();
user.setLoginname(loginname);
user.setPassword(password);
//将User对象添加到Model当中
modelMap.addAttribute("user",user);
}
@RequestMapping(value="/login2")
public String login2(ModelMap modelMap){
logger.info("login");
//从Model当中取出之前存入的名为user的对象
User user= (User) modelMap.get("user");
System.out.println(user);
//设置user对象的usernam属性
user.setUsername("测试");
return "result2";
}
}
User2Controller和UserController的代码功能基本一致,只是存储对象由Model改成了ModelMap.
2. ModelAndVIew
控制器处理方法的返回值如果是ModelAndView,则其既包含模型数据信息,也包含视图信息,这样SpringMVC将使用包含的视图对模型数据进行渲染。可以简单地将模型数据看成一个Map
在处理方法中可以使用ModelAndView对象的如下方法添加模型数据:
addObject(String attributeName, Object attributeValue);
可以通过如下方法设置视图:
setViewName(String viewName)
示例 :ModelAndView 的使用
@Controller
public class User3lController{
private static final Log logger= LogFactory.getLog(UserlController.clas);
//@ModelAttribute修饰的方法会于login调用,该方法用于接收前台jsp页面传入的参数
@ModelAttribute
public void userMode3(String loginname,String password,ModelAndView mv){
logger.info("ulserMode3");
//创建User对象存储jsp页面传入的参数
User user= new User();
user.setLoginname(loginname);
user.setPassword(password);
//将User对象添加到Model当中
mv.addObject("user",user);
}
@RequestMapping(value="/login3")
public ModelAndView login3(ModelAndView mv){
logger.info("login3");
//从Model当中取出之前存入的名为user的对象
User user= (User) mv.getModel().get("user");
System.out.println(user);
//设置user对象的usernam属性
user.setUsername("测试");
mv.setViewName("result3");
return mv;
}
}
User3Controller和UserControlller的代码功能基本一致,只是存储对象改成了ModelAndView 。