林炳文Evankaka原创作品。转载请注明出处http://blog.csdn.net/evankaka
Spring2.5引入注解式处理器支持,通过@Controller和@RequestMapping注解定义我们的处理器类。并且提供了一组强大的注解需要通过处理器映射DefaultAnnotationHandlerMapping和处理器适配器AnnotationMethodHandlerAdapter来开启支持@Controller和@RequestMapping注解的处理器。
@Controller:用于标识是处理器类;
@RequestMapping:请求到处理器功能方法的映射规则;
@RequestParam:请求参数到处理器功能处理方法的方法参数上的绑定;
@ModelAttribute:请求参数到命令对象的绑定;
@InitBinder:自定义数据绑定注册支持,用于将请求参数转换到命令对象属性的对应类型;
一、视图返回
1、返回String对象
- @RequestMapping(value ="/index")//相对于根目录的路径
- public String test(ModelMap model) {
- model.addAttribute("message", "调用FirstController的test方法");
- return "index";//指定页面要跳转的view视图路径
- }
@RequestMapping(value ="/index")//相对于根目录的路径
public String test(ModelMap model) {
model.addAttribute("message", "调用FirstController的test方法");
return "index";//指定页面要跳转的view视图路径
}
直接返回视图的名称,结果:
2、返回ModelAndView对象
- @RequestMapping("/index1")
- public ModelAndView test2() {
- ModelAndView modelAndView = new ModelAndView();
- ///modelAndView.setView(new RedirectView("index1"));
- modelAndView.setViewName("index1");//指定页面要跳转的view视图路径
- modelAndView.addObject("message", "调用FirstController的test1方法");//第二个参数:指定了要项前台传递的参数,在前台可以这样取值 ${sp_ids }
- return modelAndView;
- }
@RequestMapping("/index1")
public ModelAndView test2() {
ModelAndView modelAndView = new ModelAndView();
///modelAndView.setView(new RedirectView("index1"));
modelAndView.setViewName("index1");//指定页面要跳转的view视图路径
modelAndView.addObject("message", "调用FirstController的test1方法");//第二个参数:指定了要项前台传递的参数,在前台可以这样取值 ${sp_ids }
return modelAndView;
}
结果:
其中
- modelAndView.setViewName("index1");
modelAndView.setViewName("index1");
也可以写成:
- modelAndView.setView(new RedirectView("index1"));
modelAndView.setView(new RedirectView("index1"));
ModelAndView()
这个构造方法构造出来的ModelAndView不能直接使用,应为它没有指定view,也没有绑定对应的model对象。当然,model对象不是必须的,但是view确实必须的。
用这个构造方法构造的实例主要用来在以后往其中加view设置和model对象。
给ModelAndView
实例设置view的方法有两
个:setViewName(String viewName) 和 setView(View view)。前者是使用view
name,后者是使用预先构造好的View对象。其中前者比较常用。事实上View是一个接口,而不是一个可以构造的具体类,我们只能通过其他途径来获取
View的实例。对于view
name,它既可以是jsp的名字,也可以是tiles定义的名字,取决于使用的ViewNameResolver如何理解这个view name。
如何获取View的实例以后再研究。
而对应如何给ModelAndView
实例设置model则比较复杂。有三个方法可以使用:
- addObject(Object modelObject)
- addObject(String modelName, Object modelObject)
- addAllObjects(Map modelMap)
addObject(Object modelObject)
addObject(String modelName, Object modelObject)
addAllObjects(Map modelMap)
二、@RequestMapping
对于各种注解而言,排第一的当然是“@Controller”,表明某类是一个controller。“@RequestMapping”请求路径映射,如果标注在某个controller的类级别上,则表明访问此类路径下的方法都要加上其配置的路径;最常用是标注在方法上,表明哪个具体的方法来接受处理某次请求。
@RequestMapping 参数说明
- value
- 定义处理方法的请求的 URL 地址。
- method
- 定义处理方法的 http method 类型,如 GET、POST 等。
- params
- 定义请求的 URL 中必须包含的参数。
- headers
- 定义请求中 Request Headers 必须包含的参数
2.1 拦截路径设置
(1) 方法上的拦截
- @Controller
- public class FirstController {
- @RequestMapping(value ="/index")//相对于根目录的路径
- public String test(ModelMap model) {
- model.addAttribute("message", "调用FirstController的test方法");
- return "index";//指定页面要跳转的view视图路径
- }
- }
@Controller
public class FirstController {
@RequestMapping(value ="/index")//相对于根目录的路径
public String test(ModelMap model) {
model.addAttribute("message", "调用FirstController的test方法");
return "index";//指定页面要跳转的view视图路径
}
}
表示拦截:http://localhost:8080/SpringMVCLearningChapter2
/index1
(2)类上的拦截
- @Controller
- @RequestMapping("/user")
- public class SecondController {
- @RequestMapping(value ="/index")
- public String test(ModelMap model) {
- model.addAttribute("message", "调用SecondController 的test方法");
- return "index";//指定页面要跳转的view视图路径
- }
- @RequestMapping("/index1")
- public ModelAndView test2() {
- ModelAndView modelAndView = new ModelAndView();
- ///modelAndView.setView(new RedirectView("index1"));
- modelAndView.setViewName("index1");//指定页面要跳转的view视图路径
- modelAndView.addObject("message", "调用SecondController 的test1方法");//第二个参数:指定了要项前台传递的参数,在前台可以这样取值 ${sp_ids }
- return modelAndView;
- }
- }
@Controller
@RequestMapping("/user")
public class SecondController {
@RequestMapping(value ="/index")
public String test(ModelMap model) {
model.addAttribute("message", "调用SecondController 的test方法");
return "index";//指定页面要跳转的view视图路径
}
@RequestMapping("/index1")
public ModelAndView test2() {
ModelAndView modelAndView = new ModelAndView();
///modelAndView.setView(new RedirectView("index1"));
modelAndView.setViewName("index1");//指定页面要跳转的view视图路径
modelAndView.addObject("message", "调用SecondController 的test1方法");//第二个参数:指定了要项前台传递的参数,在前台可以这样取值 ${sp_ids }
return modelAndView;
}
}
表示拦截:http://localhost:8080/SpringMVCLearningChapter2/
user/index
和http://localhost:8080/SpringMVCLearningChapter2/user/index1
即拦截:根目录/user/index和根目录/user/index1
- 普通URL路径映射
@RequestMapping(value={"/login.do","/user/login.do"}):多个URL路径可以映射到同一个处理器的功能处理方法。
- URL模板模式映射
@RequestMapping(value="/users/{userId}"):{xxx}占位符,请求的URL可以是"/users/123456"或"/users/abcd"。
@RequestMapping(value="/users/{userId}/login.do"):这样也是可以的,请求的URL可以是"/users/123/login.do"。
@RequestMapping(value="/users/{userId}/channel/{channelId}"):这样也是可以的,请求的URL可以是"/users/123/channel/456"。
- Ant风格的URL路径映射
@RequestMapping(value="/users/**"):可以匹配"/users/abc/abc"。
@RequestMapping(value="/model?"):可匹配"/model1"或"/modela" ,但不匹配"/model"或"/modelaa";
@RequestMapping(value="/model*"):可匹配"/modelabc"或"/model",但不匹配"/modelabc/abc";
@RequestMapping(value="/model/*"):可匹配"/model/abc",但不匹配"/modelabc";
@RequestMapping(value="/model/**/{modelId}"):可匹配"/model/abc/abc/123”或"/model/123",
也就是Ant风格和URI模板变量风格可混用;
- 正则表达式风格的URL路径映射
从Spring3.0开始支持正则表达式风格的URL路径映射,格式为{变量名:正则表达式}
@RequestMapping(value="/login/{userId://d+}.do"):可以匹配
"/login/123.do",但不能匹配"/login/abc.do",这样可以设计更加严格的规则。
- 组合使用是"或"的关系
如@RequestMapping(value={"/login.do","/user/login.do"})组合使用是或的关系,即"/login.do"或
"/user/login.do"请求URL路径都可以映射到@RequestMapping指定的功能处理方法。
2、param参数
如果想给一个页面设置传递的参数,可以写成如下:
- @Controller
- @RequestMapping("/third")
- public class ThirdController {
- @RequestMapping(value ="/index",params="name")//要求传递参数name,浏览器中输入name后,控制器会自动把参数传递给test中的name
- public String test(ModelMap model,String name) {
- model.addAttribute("message", name);
- return "index";
- }
- }
因为它要求你一定要传递一个name参数,所以得这样写:
当然,这里也可以把需要的参数注解到方法的参数上去
- @RequestMapping(value ="/index")//要求传递参数name,浏览器中输入name后,控制器会自动把参数传递给test中的name
- public String test(ModelMap model,@RequestParam("name")String name) {
- model.addAttribute("message", name);
- return "index";
- }
@RequestMapping(value ="/index")//要求传递参数name,浏览器中输入name后,控制器会自动把参数传递给test中的name
public String test(ModelMap model,@RequestParam("name")String name) {
model.addAttribute("message", name);
return "index";
}
效果和上面和一样的。这时如果还是想访问http://localhost:8080/SpringMVCLearningChapter2/third/index,把required=false加上
- @RequestMapping(value ="/index")
- public String test(ModelMap model,@RequestParam(value="name",required=false)String name) {
- model.addAttribute("message", name);
- return "index";
- }
- @RequestMapping(value ="/index1",method = RequestMethod.GET,params="name")
- public ModelAndView test2() {
- ModelAndView modelAndView = new ModelAndView();
- ///modelAndView.setView(new RedirectView("index1"));
- modelAndView.setViewName("index1");//指定页面要跳转的view视图路径
- modelAndView.addObject("message", "调用SecondController 的test1方法");//第二个参数:指定了要项前台传递的参数,在前台可以这样取值 ${sp_ids }
- return modelAndView;
- }
@RequestMapping(value ="/index1",method = RequestMethod.GET,params="name")
public ModelAndView test2() {
ModelAndView modelAndView = new ModelAndView();
///modelAndView.setView(new RedirectView("index1"));
modelAndView.setViewName("index1");//指定页面要跳转的view视图路径
modelAndView.addObject("message", "调用SecondController 的test1方法");//第二个参数:指定了要项前台传递的参数,在前台可以这样取值 ${sp_ids }
return modelAndView;
}
表明只能通过GET来访问,或要POST,改成
- method = RequestMethod.POST
@RequestMapping(headers)
headers 的作用也是用于细化映射。只有当请求的 Request Headers 中包含与 heanders 值相匹配的参数,处理方法才会被调用。
@RequestMapping(value = "/specify", headers = "accept=text/*")
public String specify(){
return "example_specify_page";
}
请求的 Request Headers 中 Accept 的值必须匹配 text/* ( 如 text/html ),方法才会被调用。
三、其它常用注解
handler method 参数绑定常用的注解,我们根据他们处理的Request的不同内容部分分为四类:(主要讲解常用类型)
A、处理requet uri 部分(这里指uri template中variable,不含queryString部分)的注解: @PathVariable;
B、处理request header部分的注解: @RequestHeader, @CookieValue;
C、处理request body部分的注解:@RequestParam, @RequestBody;
D、处理attribute类型是注解: @SessionAttributes, @ModelAttribute;1、 @PathVariable
当使用@RequestMapping URI template 样式映射时, 即 /fourth/{num}, 这时的num可通过 @Pathvariable注解绑定它传过来的值到方法的参数上。
示例代码:
- @Controller
- @RequestMapping("/fourth/{num}")
- public class FourthController {
- @RequestMapping(value ="/index/{string}")
- public String test(ModelMap model,@PathVariable("num") int num,@PathVariable("string") String string) {
- model.addAttribute("message", "num="+String.valueOf(num)+" string="+string);
- return "index";
- }
- }
@Controller
@RequestMapping("/fourth/{num}")
public class FourthController {
@RequestMapping(value ="/index/{string}")
public String test(ModelMap model,@PathVariable("num") int num,@PathVariable("string") String string) {
model.addAttribute("message", "num="+String.valueOf(num)+" string="+string);
return "index";
}
}
浏览器输入:http://localhost:8080/SpringMVCLearningChapter2/fourth/1234/index/linbingwen
上面代码把URI template 中变量num的值和string的值,绑定到方法的参数上。若方法参数名称和需要绑定的uri template中变量名称不一致,需要在@PathVariable("num")指定uri template中的名称。
2、 @RequestHeader、@CookieValue
@RequestHeader 注解,可以把Request请求header部分的值绑定到方法的参数上。
- @RequestMapping(value = "six/index4")
- public String getHello(@RequestHeader ("host") String hostName,
- @RequestHeader ("Accept") String acceptType,
- @RequestHeader ("Accept-Language") String acceptLang,
- @RequestHeader ("Accept-Encoding") String acceptEnc,
- @RequestHeader ("Cookie") String cookie,
- @RequestHeader ("User-Agent") String userAgent)
- {
- System.out.println("Host : " + hostName);
- System.out.println("Accept : " + acceptType);
- System.out.println("Accept Language : " + acceptLang);
- System.out.println("Accept Encoding : " + acceptEnc);
- System.out.println("Cookie : " + cookie);
- System.out.println("User-Agent : " + userAgent);
- return "index4";
- }
@RequestMapping(value = "six/index4")
public String getHello(@RequestHeader ("host") String hostName,
@RequestHeader ("Accept") String acceptType,
@RequestHeader ("Accept-Language") String acceptLang,
@RequestHeader ("Accept-Encoding") String acceptEnc,
@RequestHeader ("Cookie") String cookie,
@RequestHeader ("User-Agent") String userAgent)
{
System.out.println("Host : " + hostName);
System.out.println("Accept : " + acceptType);
System.out.println("Accept Language : " + acceptLang);
System.out.println("Accept Encoding : " + acceptEnc);
System.out.println("Cookie : " + cookie);
System.out.println("User-Agent : " + userAgent);
return "index4";
}
运行后输入:http://localhost:8080/SpringMVCLearningChapter2/six/index4
运行结果:
注:@RequestHeader 与@RequestParam 一样也有3个参数,其含义与的@RequestParam 参数含义相同。
@CookieValue 可以把Request header中关于cookie的值绑定到方法的参数上。
参数绑定的代码:
- @RequestMapping("six/index3")
- public String test3(Model model,@CookieValue(value="JSESSIONID", defaultValue="") String jsessionId) {
- model.addAttribute("jsessionId", jsessionId);
- return "index3";
- }
- <%@ page language="java" contentType="text/html; charset=gb2312"
- pageEncoding="gb2312"%>
- <!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=gb2312">
- <title>Insert title here</title>
- </head>
- <body>
- 采用String返回视图jsessionId=:${jsessionId}
- </body>
- </html>
<%@ page language="java" contentType="text/html; charset=gb2312"
pageEncoding="gb2312"%>
<!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=gb2312">
<title>Insert title here</title>
</head>
<body>
采用String返回视图jsessionId=:${jsessionId}
</body>
</html>
结果:
即把JSESSIONID的值绑定到参数cookie上
注:@CookieValue 与@RequestParam 一样也有3个参数,其含义与的@RequestParam 参数含义相同
3、@RequestParam, @RequestBody
@RequestParam
A) 常用来处理简单类型的绑定,通过Request.getParameter() 获取的String可直接转换为简单类型的情况( String--> 简单类型的转换操作由ConversionService配置的转换器来完成);因为使用request.getParameter()方式获取参数,所以可以处理get 方式中queryString的值,也可以处理post方式中 body data的值;
B)用来处理Content-Type: 为 application/x-www-form-urlencoded编码的内容,提交方式GET、POST;
C) 该注解有两个属性: value、required; value用来指定要传入值的id名称,required用来指示参数是否必须绑定;@RequestBody
该注解常用来处理Content-Type: 不是application/x-www-form-urlencoded
编码的内容,例如application/json, application/xml等;
它是通过使用HandlerAdapter 配置的HttpMessageConverters
来解析post data body,然后绑定到相应的bean上的。
因为配置有FormHttpMessageConverter,所以也可以用来处理 application/x-www-form-urlencoded
的内容,处理完的结果放在一个MultiValueMap<String, String>里,这种情况在某些特殊需求下使用,详情查看FormHttpMessageConverter api;
示例代码:
- @RequestMapping(value = "/something", method = RequestMethod.PUT)
- public void handle(@RequestBody String body, Writer writer) throws IOException {
- writer.write(body);
- }
4、@SessionAttributes, @ModelAttribute
@SessionAttributes:
该注解用来绑定HttpSession中的attribute对象的值,便于在方法中的参数里使用。
该注解有value、types两个属性,可以通过名字和类型指定要使用的attribute 对象;
示例代码:
- @Controller
- @RequestMapping("/editPet.do")
- @SessionAttributes("pet")
- public class EditPetForm {
- // ...
- }
@ModelAttribute
该注解有两个用法,一个是用于方法上,一个是用于参数上;
用于方法上时: 通常用来在处理@RequestMapping之前,为请求绑定需要从后台查询的model;
用于参数上时: 用来通过名称对应,把相应名称的值绑定到注解的参数bean上;要绑定的值来源于:
A) @SessionAttributes 启用的attribute 对象上;
B) @ModelAttribute 用于方法上时指定的model对象;
C) 上述两种情况都没有时,new一个需要绑定的bean对象,然后把request中按名称对应的方式把值绑定到bean中。
用到方法上@ModelAttribute的示例代码:
- @ModelAttribute("string1")
- public String preRun() {
- System.out.println("Test Pre-Run");
- String string="linbingwen";
- return string;
- }
@ModelAttribute("string1")
public String preRun() {
System.out.println("Test Pre-Run");
String string="linbingwen";
return string;
}
这种方式实际的效果就是在调用@RequestMapping的方法之前,为request对象的model里put(“string1”, string);
JSP中可以这样来获取
- <%@ page language="java" contentType="text/html; charset=gb2312"
- pageEncoding="gb2312"%>
- <!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=gb2312">
- <title>Insert title here</title>
- </head>
- <body>
- < 通过@ModelAttribute类方法传递参数:<br/>
- 方法一取出"{string1}":${string1}<br/>
- <%String string1=(String)request.getAttribute("string1");%>
- 方法二取出"request.getAttribute":<%=string1 %><br/>
- </body>
- </html>
它会在每次访问网页前调用:
输入http://localhost:8080/SpringMVCLearningChapter2/six/index2,总共刷新了4次
用在参数上的@ModelAttribute示例代码:
- @RequestMapping(value ="six/index2")//相对于根目录的路径
- public String test(@ModelAttribute("str") String str) {
- return "index2";//指定页面要跳转的view视图路径
- }
@RequestMapping(value ="six/index2")//相对于根目录的路径
public String test(@ModelAttribute("str") String str) {
return "index2";//指定页面要跳转的view视图路径
}
其实就是相相当于把参数传递到request中去,所以JSP中可以这样获取参数
- <%@ page language="java" contentType="text/html; charset=gb2312"
- pageEncoding="gb2312"%>
- <!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=gb2312">
- <title>Insert title here</title>
- </head>
- <body>
- ==========================================================<br/>
- 通过@ModelAttribute方法上参数传递参数:
- <%String str=(String)request.getParameter("str");%>
- "request.getAttribute":<%=str%><br/>
- </body>
- </html>
<%@ page language="java" contentType="text/html; charset=gb2312"
pageEncoding="gb2312"%>
<!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=gb2312">
<title>Insert title here</title>
</head>
<body>
==========================================================<br/>
通过@ModelAttribute方法上参数传递参数:
<%String str=(String)request.getParameter("str");%>
"request.getAttribute":<%=str%><br/>
</body>
</html>
运行结果:
5、ResponseBody
用来输出响应,如
- @ResponseBody
- @RequestMapping(value="/index/{imageld}")//相对于根目录的路径
- public byte[] test2(@PathVariable("imageld") String str) {
- System.out.println(str);
- Resource resource= new ClassPathResource("/image.jpg");
- byte[] data = null;
- try {
- data = FileCopyUtils.copyToByteArray(resource.getInputStream());
- } catch (IOException e) {
- e.printStackTrace();
- }
- return data;//指定页面要跳转的view视图路径
- }
@ResponseBody
@RequestMapping(value="/index/{imageld}")//相对于根目录的路径
public byte[] test2(@PathVariable("imageld") String str) {
System.out.println(str);
Resource resource= new ClassPathResource("/image.jpg");
byte[] data = null;
try {
data = FileCopyUtils.copyToByteArray(resource.getInputStream());
} catch (IOException e) {
e.printStackTrace();
}
return data;//指定页面要跳转的view视图路径
}
输入:http://localhost:8080/SpringMVCLearningChapter2_1/index/imgd
四、补充讲解
问题: 在不给定注解的情况下,参数是怎样绑定的?
通过分析AnnotationMethodHandlerAdapter和RequestMappingHandlerAdapter的源代码发现,方法的参数在不给定参数的情况下:
若要绑定的对象时简单类型: 调用@RequestParam来处理的。
若要绑定的对象时复杂类型: 调用@ModelAttribute来处理的。
这里的简单类型指Java的原始类型(boolean, int 等)、原始类型对象(Boolean, Int等)、String、Date等ConversionService里可以直接String转换成目标对象的类型;
林炳文Evankaka原创作品。转载请注明出处http://blog.csdn.net/evankaka