SpringMVC中的注解式控制器(一)——请求映射规则
2018-12-19 13:54 张智清 阅读(950) 评论(0) 编辑 收藏 举报旧版的通过继承Controller接口的实现方式已经不被推荐了,从Spring2.5开始采用注解方式的控制器(如@Controller、@RequestMapping、@RequestParam、@ModelAttribute等)。
注解方式的控制器
Spring2.5需要通过处理器映射DefaultAnnotationHandlerMapping和处理器适配器AnnotationMethodHandlerAdapter来开启支持@Controller和@RequestMapping注解的处理器。
@Controller:修饰class,用于标识是处理器类,创建处理http请求的对象
@RequestMapping:请求到处理器功能方法的映射规则;
@RequestParam:请求参数到处理器功能处理方法的方法参数上的绑定;
@ModelAttribute:请求参数到命令对象的绑定;
@SessionAttributes:用于声明session级别存储的属性,放置在处理器类上,通常列出模型属性(如@ModelAttribute)对应的名称,则这些属性会透明的保存到session中;
@InitBinder:自定义数据绑定注册支持,用于将请求参数转换到命令对象属性的对应类型;
Spring3.0引入RESTful架构风格支持(通过@PathVariable注解和一些其他特性支持),且又引入了更多的注解支持:
@CookieValue:cookie数据到处理器功能处理方法的方法参数上的绑定;
@RequestHeader:请求头(header)数据到处理器功能处理方法的方法参数上的绑定;
@RequestBody:请求的body体的绑定(通过HttpMessageConverter进行类型转换);
@ResponseBody:处理器功能处理方法的返回值作为响应体(通过HttpMessageConverter进行类型转换);
@ResponseStatus:定义处理器功能处理方法/异常处理器返回的状态码和原因;
@ExceptionHandler:注解式声明异常处理器;
@PathVariable:请求URI中的模板变量部分到处理器功能处理方法的方法参数上的绑定,从而支持RESTful架构风格的URI;
Spring3.1使用新的HandlerMapping和HandlerAdapter来支持@Controller和@RequestMapping注解处理器。
新的@Contoller和@RequestMapping注解支持类:处理器映射RequestMappingHandlerMapping和处理器适配器RequestMappingHandlerAdapter组合来代替Spring2.5开始的处理器映射DefaultAnnotationHandlerMapping和处理器适配器AnnotationMethodHandlerAdapter,提供更多的扩展点。
根据HTTP/1.1协议要求,Http请求信息包含六部分信息:
-
请求方法,如GET或POST;
-
URL, 请求的地址信息;
-
协议及版本;
-
请求头信息(包括Cookie信息);
-
回车换行(CRLF);
-
请求内容区(即请求的内容或数据),如表单提交的参数数据、URL请求参数等
其1、2、4、6一般是可变的,所以请求的映射可以分为如下几种:
URL路径映射:使用URL映射请求到处理器的功能处理方法;value
-
普通URL路径映射,@RequestMapping(value={"/test1", "/user/create"}):多个URL路径可以映射到同一个处理器的功能处理方法。
-
URI模板模式映射,@RequestMapping(value="/users/{userId}"):{×××}占位符, 请求的URL可以是 “/users/123456”或“/users/abcd”,通过@PathVariable可以提取URI模板模式中的{×××}中的×××变量。@RequestMapping(value="/users/{userId}/create"):这样也是可以的,请求的URL可以是“/users/123/create”。@RequestMapping(value="/users/{userId}/topics/{topicId}"):这请求的URL可以是“/users/123/topics/123”。
-
Ant风格的URL路径映射
-
正则表达式风格的URL路径映射,格式为{变量名:正则表达式}
-
组合使用是“或”的关系
请求方法映射限定:如限定功能处理方法只处理GET请求;method
<strong>//省略import @Controller @RequestMapping("/customers/**") //①处理器的通用映射前缀 public class RequestMethodController { @RequestMapping(value="/create", method = RequestMethod.GET)//②类级别的@RequestMapping窄化 public String showForm() { System.out.println("===============GET"); return "customer/create"; } @RequestMapping(value="/create", method = RequestMethod.POST)//③类级别的@RequestMapping窄化 public String submit() { System.out.println("================POST"); return "redirect:/success"; } }</strong>
组合使用是“或”的关系
<strong>@RequestMapping(value="/methodOr", method = {RequestMethod.POST, RequestMethod.GET}):即请求方法可以是 GET 或 POST。</strong>
请求参数映射限定:如限定只处理包含“abc”请求参数的请求;params
-
请求数据中有指定参数名
//省略import @Controller @RequestMapping("/parameter1") //①处理器的通用映射前缀 public class RequestParameterController1 { //②进行类级别的@RequestMapping窄化 @RequestMapping(params="create", method=RequestMethod.GET) public String showForm() { System.out.println("===============showForm"); return "parameter/create"; } //③进行类级别的@RequestMapping窄化 @RequestMapping(params="create", method=RequestMethod.POST) public String submit() { System.out.println("================submit"); return "redirect:/success"; } }
常见的CRUD(增删改查)我们可以使用如下请求参数名来表达:
◇(create请求参数名 且 GET请求方法) 新增页面展示、(create请求参数名 且 POST请求方法)新增提交;
◇(update请求参数名 且 GET请求方法) 新增页面展示、(update请求参数名 且 POST请求方法)新增提交;
◇(delete请求参数名 且 GET请求方法) 新增页面展示、(delete请求参数名 且 POST请求方法)新增提交;
◇(query请求参数名 且 GET请求方法) 新增页面展示、(query请求参数名 且 POST请求方法) 新增提交;
◇(list请求参数名 且 GET请求方法) 列表页面展示;
◇(view请求参数名 且 GET请求方法) 查看单条记录页面展示。
-
请求数据中没有指定参数名
//请求参数不包含 create参数名 @RequestMapping(params="!create", method=RequestMethod.GET)//进行类级别的@RequestMapping窄化
-
请求数据中指定参数名=值
//省略import @Controller @RequestMapping("/parameter2") //①处理器的通用映射前缀 public class RequestParameterController2 { //②进行类级别的@RequestMapping窄化 @RequestMapping(params="submitFlag=create", method=RequestMethod.GET) public String showForm() { System.out.println("===============showForm"); return "parameter/create"; } //③进行类级别的@RequestMapping窄化 @RequestMapping(params="submitFlag=create", method=RequestMethod.POST) public String submit() { System.out.println("===============submit"); return "redirect:/success"; } }
常见的CRUD(增删改查)我们可以使用如下请求参数名来表达:
◇(submitFlag=create请求参数名 且 GET请求方法) 新增页面展示、(submitFlag=create请求参数名 且 POST请求方法) 新增提交;
◇(submitFlag=update请求参数名 且 GET请求方法) 新增页面展示、(submitFlag=update请求参数名 且 POST请求方法) 新增提交;
◇(submitFlag=delete请求参数名 且 GET请求方法) 新增页面展示、(submitFlag=delete请求参数名 且 POST请求方法) 新增提交;
◇(submitFlag=query请求参数名 且 GET请求方法) 新增页面展示、(submitFlag=query请求参数名 且 POST请求方法) 新增提交;
◇(submitFlag=list请求参数名 且 GET请求方法) 列表页面展示;
◇(submitFlag=view请求参数名 且 GET请求方法) 查看单条记录页面展示。
-
请求数据中指定参数名!=值
//请求参数submitFlag 不等于 create @RequestMapping(params="submitFlag!=create", method=RequestMethod.GET)
-
组合使用是“且”的关系
@RequestMapping(params={"test1", "test2=create"}) //②进行类级别的@RequestMapping窄化
表示请求中的有“test1”参数名 且 有“test2=create”参数即可匹配,
请求头映射限定:如限定只处理“Accept=application/json”的请求。headers
-
请求头数据中有指定参数名
@RequestMapping(value="/header/test1", headers = "Accept"):表示请求的URL必须为“/header/test1” 且 请求头中必须有Accept参数才能匹配。
-
请求头数据中没有指定参数名
@RequestMapping(value="/header/test2", headers = "!abc"):表示请求的URL必须为“/header/test2” 且 请求头中必须没有abc参数才能匹配。
-
请求头数据中指定参数名=值
@RequestMapping(value="/header/test3", headers = "Content-Type=application/json"):表示请求的URL必须为“/header/test3” 且 请求头中必须有“Content-Type=application/json”参数即可匹配
-
请求头数据中指定参数名!=值
@RequestMapping(value="/header/test7", headers = "Accept!=text/vnd.wap.wml"):表示请求的URL必须为“/header/test7” 且 请求头中必须有“Accept”参数但值不等于“text/vnd.wap.wml”即可匹配。
-
组合使用是“且”的关系
@RequestMapping(value="/header/test8", headers = {"Accept!=text/vnd.wap.wml","abc=123"}):表示请求的URL必须为“/header/test8” 且 请求头中必须有“Accept”参数但值不等于“text/vnd.wap.wml”且 请求中必须有参数“abc=123”即可匹配。
Spring3.1开始支持消费者限定、生产者限定,而且必须使用如下HandlerMapping和HandlerAdapter才支持:
<!--Spring3.1开始的注解 HandlerMapping --> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/> <!--Spring3.1开始的注解 HandlerAdapter --> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
一、功能处理方法是消费者 consumes:指定处理请求的提交内容类型Content-Type
@RequestMapping(value = "/consumes", consumes = {"application/json"}):此处使用consumes来指定功能处理方法能消费的媒体类型,其通过请求头的“Content-Type”来判断。
此种方式相对使用@RequestMapping的“headers = "Content-Type=application/json"”更能表明你的目的。
二、功能处理方法是生产者 produces:其作用就是指定返回值类型
@RequestMapping(value = "/produces", produces = "application/json"):表示将功能处理方法将生产json格式的数据,此时根据请求头中的Accept进行匹配,如请求头“Accept:application/json”时即可匹配; @RequestMapping(value = "/produces", produces = "application/xml"):表示将功能处理方法将生产xml格式的数据,此时根据请求头中的Accept进行匹配,如请求头“Accept:application/xml”时即可匹配。
此种方式相对使用@RequestMapping的“headers = "Accept=application/json"”更能表明你的目的。实际意义:在开发数据接口时,尤其调用方和开发者分属不同地方,沟通不便,通过request请求accept和produces="application/json"的配合能很好的限定数据返回格式,确保万无一失。
当你有如下Accept头:
①Accept:text/html,application/xml,application/json
将按照如下顺序进行produces的匹配 ①text/html ②application/xml ③application/json
②Accept:application/xml;q=0.5,application/json;q=0.9,text/html
将按照如下顺序进行produces的匹配 ①text/html ②application/json ③application/xml
q参数为媒体类型的质量因子,越大则优先权越高(从0到1)
③Accept:*/*,text/*,text/html
将按照如下顺序进行produces的匹配 ①text/html ②text/* ③*/*
即匹配规则为:最明确的优先匹配。
三、窄化时是覆盖,而非继承
如类级别的映射为 @RequestMapping(value="/narrow", produces="text/html"),方法级别的为@RequestMapping(produces="application/xml"),此时方法级别的映射将覆盖类级别的,因此请求头“Accept:application/xml”是成功的,而“text/html”将报406错误码,表示不支持的请求媒体类型。
只有生产者/消费者 模式 是 覆盖,其他的使用方法是继承,如headers、params等都是继承。
四、组合使用是“或”的关系
@RequestMapping(produces={"text/html", "application/json"}) :将匹配“Accept:text/html”或“Accept:application/json”。
问题:
消费的数据,如JSON数据、XML数据都是由我们读取请求的InputStream并根据需要自己转换为相应的模型数据,比较麻烦;
生产的数据,如JSON数据、XML数据都是由我们自己先把模型数据转换为json/xml等数据,然后输出响应流,也是比较麻烦的。
Spring提供了一组注解(@RequestBody、@ResponseBody)和一组转换类(HttpMessageConverter)来完成我们遇到的问题。
Spring4新注解
@RestController
:Spring4之后加入的注解,原来在@Controller
中返回json需要@ResponseBody
来配合,如果直接用@RestController
替代@Controller
就不需要再配置@ResponseBody
,默认返回json格式。@RequestMapping
:配置url映射