转载

SpringMVC中的注解式控制器(一)——请求映射规则

旧版的通过继承Controller接口的实现方式已经不被推荐了,从Spring2.5开始 采用注解方式的控制器 (如@Controller、@RequestMapping、@RequestParam、@ModelAttribute等)。

注解方式的控制器

需要通过处理器映射 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请求信息包含六部分信息:

  1. 请求方法,如GET或POST;

  2. URL, 请求的地址信息;

  3. 协议及版本;

  4. 请求头信息(包括Cookie信息);

  5. 回车换行(CRLF);

  6. 请求内容区(即请求的内容或数据),如表单提交的参数数据、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映射
原文  http://www.cnblogs.com/lovecode/articles/10142785.html
正文到此结束
Loading...