Controller也就是我们常说的控制器,负责处理由DispatcherServler分发的用户请求,将请求数据处理后封装成ModelAndView返回。
@Controller这个注解就是用来标记控制器的,被它标记的类就是控制器。Controller通过@RequestMapping来定义URL和其方法之间的映射。
分发处理器将会扫描使用了@Controller注解的类中用@RequestMapping 注解的方法,直到找到具体处理URL请求的方法。
<bean class="com.xx.controller.MyController"/>
<context:component-scan base-package="com.xx.controller">context:component-scan>
一般我们采用第二种方式,把所有的控制器放在一个或者几个包下,一并扫描,在这之前,你需要配置SpringMVC的注解驱动(这么写不需要再配置处理器映射器和处理器适配器):
<mvc:annotation-driven />
@RequestMapping是一个用来处理请求地址映射的注解(将请求映射到对应的控制器方法中),可以用在类或者方法中。
用类上表示类中的所有响应请求的方法都是以该地址作为父路径,那么要想访问该控制器下的方法,都要加上这个路径。
用在方法上则表示这个方法用来专门处理该地址的请求。
- 普通值。比如
@RequestMapping(value="/test")
- 支持RESTful风格(将请求参数传递在url地址中)。比如
@RequestMapping(value="/test/{t_id}/{t_name}")
,t_id和t_name可以当做变量用@PathVariable注解来提取。(下面介绍)- 支持ant风格。
?
匹配任何单字符,*
匹配0或者任意数量的字符**
匹配0或者更多的目录。比如@RequestMapping(value="/test/t_*")
- 支持正则表达式。比如
@RequestMapping(value="/test/{t_id:a-z0-9+}")
。同样可以通过@PathVariable提取t_id。- 支持多路径访问。比如
@RequestMapping(value={"/test","/test2","test3"})
。那么/test,/test2,test3都会映射到该方法上。
比如
@RequestMapping(value="/test",method={RequestMethod.GET,RequestMethod.POST})
比如
@RequestMapping(value="/test",params="user=001")
,http://localhost:8080/test?user=001 那么才能访问到(名和值都要匹配)。
比如
@RequestMapping(value="/test",headers="Referer=http://www.admin.com/")
。
那么请求的URL必须为"/test"且请求头必须有包含“Referer”的请求头和对应值为http://www.admin.com/的请求。
例如
@RequestMapping(value = "/test", method = RequestMethod.POST, consumes="application/json")
方法仅处理request Content-Type为“application/json”类型的请求。
例如
@RequestMapping(value = "/test", method = RequestMethod.POST, produces="application/json")
方法仅处理request请求中Accept头中包含了"application/json"的请求,同时暗示了返回的内容类型为application/json;
根据处理的Request的不同内容部分分为四类:
处理requet uri 部分的注解: @PathVariable;
处理request header部分的注解: @RequestHeader, @CookieValue;
处理request body部分的注解:@RequestParam, @RequestBody;
处理attribute类型是注解: @SessionAttributes, @ModelAttribute;
@PathVariable注解的位置是方法参数。
@PathVariable这个注解用来将请求URL中的模板变量映射到处理方法的参数上。
示例:
@RequestMapping(value="/users/{user}/password/{password}")
public void test(
@PathVariable(value="user"))String user,
@PathVariable(value="password")String password){
// TODO
System.out.prinlln("user:"+user);
System.out.println("passord"+password);
}
比如url为/users/admin/password/12345那么会自动将其与test方法中用@PathVariable注解的同名参数绑定,也就是说,方法中变量user和password的值就是admin和12345。
@ReuqestHeader和@CookieValue这两个注解的位置都是在方法参数上。前者用来将Request请求的header部分的值绑定到方法的参数上。
比如:
这是一个Request 的header部分:
Host:localhost:8080
Accept:text/html,application/xhtml+xml,application/xml;q=0.9
Accept-Language:fr,en-gb;q=0.7,en;q=0.3
Accept-Encoding:gzip,deflate
Accept-Charset:ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive:300
@RequestMapping("/testHeader")
public void testHeader(
@RequestHeader("Host")String host,
@RequestHeader("Accept")String accept){
// TODO
}
通过这种方式,可以将header部分的值绑定到方法的参数对象上。
@CookieValue可以把Request Header部分中cookie的值绑定到方法的参数上:
例如有如下的cookie值:status=online
@RequestMapping("/testCookie")
public void testCookie(@CookieValue("status")String status){
// TODO
}
将status的值绑定到参数上。
@RequestParam注解的位置:方法参数上。
这个注解用于在SpringMVC后台控制层获取参数(简单类型),@RequestParam注解会通过request.getParameter(" ")将获取的Stirng直接与方法参数绑定(String–>简单类型的转换有ConversionService配置的转换器来完成)。因为使用request.getParameter()方式获取参数,所以可以处理get 方式中queryString的值,也可以处理post方式中 body data的值。也可以用来解决请求参数的名称和controller方法的参数名称不一致时的参数绑定问题。
它有四个个常用的属性:
@ResponseBody表示该方法的返回结果直接写入HTTP response body中,一般在异步获取数据时使用(AJAX),在使用@RequestMapping路径后,返回值通常解析为跳转路径,加上@ResponseBody后返回结果不会别解析为跳转路径,而是直接写入HTTP response body中。常用在异步获取json数据,加上@ResponseBody后,会将返回结果对象解析为json数据返回。
@RequestMapping("/responseBody")
@ResponseBody
public User responseBody(){
User user = new User();
user.setId(2);
user.setUsername("lisi");
user.setPassword("123456");
return user;//{"id":2,"username":"lisi","password":"123456"}
}
这个方法会在执行结束后自动以responseBody为逻辑视图名返回view。你可以自己建一个真实视图,页面上就会显示{“id”:2,“username”:“lisi”,“password”:“123456”}。
@RequestBody用于将前天发送过来的固定格式的数据(xml,json等)封装成对应的JavaBean对象,封装使用的HandlerAdapter 默认配置的HttpMessageConverter,它负责将数据解析然后封装到形参对象上。该注解通常用来处理Content-Type(不是application/x-www-form-urlencoded编码的内容,例如application/json,application/xml等)
/**
* @RequestBody User user是用来把请求的json数据格式自动的转成实体类对象
*/
@RequestMapping("/requestBody")
public String requestBody(@RequestBody User user, Model model) {
model.addAttribute("user", user);
return "forward:index.jsp";
}
当@ModelAttribute注释在方法参数上时,会将该参数对象添加到Model中。
当@ModelAttribute注释在方法上时,该方法就变成了非请求处理方法:该Controller的所有方法在调用前,都会先执行该方法。
被@ModelAttribute注释的方法表示这个方法的目的是增加一个或多个模型(model)属性。这个方法和别@RequestMapping注释的方法一样同样支持@RequestParam参数,但是不能直接被请求映射。
一个Controller可以有多个@ModelAttribute方法,这些方法都会在@RequestMapping方法被调用之前先执行。
@Controller
public class TestController {
@ModelAttribute
public void populateModel(@RequestParam(value="user") String user, Model model) {
model.addAttribute("user", user);
}
@RequestMapping(value = "/login")
public String login() {
return "login";
}
}
本例中,在获取了/login的请求后,populateModel()方法会在login()方法执行前执行,并把请求参数(/login/username=“xxx”)加到model属性(user)中。那么在login方法执行后会返回视图名login和populateModel创建好的model。
2. 返回具体类的方法
@ModelAttribute
public User getUser(String username){
if(username!=null && !username.equals("admin")){
return userService.getUserInfo(username);
}
return null;
}
这种情况下,model的属性的名称没有指定,它有返回类型隐含表示,比如这个方法返回User类型,那么这个model属性名称就是user,值为方法的返回值。
当然,你也可以自己指定属性名:
@ModelAttribute(value="user")
public User getUser(String username){
if(username!=null && !username.equals("admin")){
return userService.getUserInfo(username);
}
return null;
}
ModelAtrribute注释的方法参数表示应从模型model中取得,如果model中没有找到,那么这个参数就会先被实例化加入到model中。若在model中找到了它,请求参数名称和model属性字段相匹配就会自动填充。这个机制对于表单提交数据表单到对象属性上很有效。
用来通过名称对应,把相应名称的值绑定到注解的参数bean上;要绑定的值来源于:
A) @SessionAttributes 启用的attribute 对象上;
B) @ModelAttribute 用于方法上时指定的model对象;
C) 上述两种情况都没有时,new一个需要绑定的bean对象,然后把request中按名称对应的方式把值绑定到bean中。
@RequestMapping("/test")
public String getUser(@ModelAtrribute("user") User user){
user.setUsername="xxx";
user.setPassword="xxx";
return "login";
}
本例中,首先查询 @SessionAttributes有无绑定的user对象,不存在则去查询model中是否绑定了user对象,二者都没就会先调用User的构造方法创建一个user,当请求路径的请求参数或者提交的表单与user的属性名(username|password)匹配时,就会自动将其值绑定到user对象中。比如请求路径为http://localhost/springmvc_001/login.htm?username="xxx"?password="xxx"
,user对象中的属性username和password将会被设置为xxx。
我们一般用@ModelAttribute来注解参数,某种程度上@ModelAttribute和@RequestParam功能相似,不同的是@RequestParam用于绑定单个参数值,而@ModelAttribute注解可以绑定所有名称匹配的,此外它自动将绑定后的数据添加到模型中,无形中也给我们提供了便利。
实际上,Model中的属性作用域是request级别的,也就是说,只是当前请求有效。如果希望在多个请求中共享ModelMap中的属性,必须将其舒心转存到session中,这样Model中的属性才能跨请求访问。
简而言之,@SessionAttributes是添加在controller的类名上。@SessionAttributes注解作用,是将model中的数据再向session中存一份以便跨请求访问。
@Controller
@SessionAttributes("username")
public class myController {
//将Model属性名为username的属性放到Session属性列表中,以便这个属性可以跨请求访问
//在该controller中的方法中往model存入属性为username的键值对时会自动的往session中存一份
//那么你就可以在下一次访问(session有效期内)中用session.getAtrribute("username")取到
}
当然你也可以指定多个属性,比如@SessionAttributes(value={"username","password"})
。此外,@SessionAttributes 还可以通过类型指定属性,比如@SessionAttribute(types=User.class)
,类型同样可以有多个。
SessionAttribute可以获取session(HttpSession以及@SessionAttributes)中的数据。
@SessionAttributes需要清除时,使用
SessionStatus.setComplete();
来清除。注意,它只清除@SessionAttributes的session,不会清除HttpSession的数据。故如用户身份验证对象的session一般不用它来实现,还是用session.setAttribute等传统的方式实现。如果你想清空未使用注解方式保存的session数据,使用session.invalidate();
它清空的是HttpSession中的数据。
看个@SessionAttribute和session清空的案例:
@RequestMapping("/testGetSessionAttribute")
public String testGetSessionAttribute(
@SessionAttribute(name = "user") User user,
@SessionAttribute(name = "valide_code") String valide_code,
HttpSession session,
SessionStatus sessionStatus) {
// 清空session,只会清空未使用注解方式保存的session数据
// session.invalidate();
// 清空session的方法,清空使用@SessionAttributes保存的数据
sessionStatus.setComplete();
// System.out.println("user_name:"+user.getUsername());
// System.out.println("pass_word:"+user.getPassword());
System.out.println("valide_code:" + valide_code);
return "forward:session_attr.jsp";
}