代码改变世界

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

2018-12-19 13:54 by 张智清, 阅读(955) 阅读, 推荐(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使用新的HandlerMappingHandlerAdapter来支持@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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<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>

 

组合使用是“或”的关系

 

1
<strong>@RequestMapping(value="/methodOr", method = {RequestMethod.POST, RequestMethod.GET}):即请求方法可以是 GET 或 POST。</strong>

 

请求参数映射限定:如限定只处理包含“abc”请求参数的请求;params

  • 请求数据中有指定参数名

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    //省略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请求方法) 查看单条记录页面展示。

  • 请求数据中没有指定参数名

 

1
2
//请求参数不包含 create参数名
@RequestMapping(params="!create", method=RequestMethod.GET)//进行类级别的@RequestMapping窄化

 

  • 请求数据中指定参数名=值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    //省略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请求方法) 查看单条记录页面展示。

  • 请求数据中指定参数名!=值

1
2
//请求参数submitFlag 不等于 create
@RequestMapping(params="submitFlag!=create", method=RequestMethod.GET)  
  • 组合使用是“且”的关系

1
@RequestMapping(params={"test1""test2=create"})  //②进行类级别的@RequestMapping窄化

    表示请求中的有“test1”参数名 且 有“test2=create”参数即可匹配,

请求头映射限定:如限定只处理“Accept=application/json”的请求。headers

  • 请求头数据中有指定参数名

1
2
@RequestMapping(value="/header/test1", headers = "Accept"):表示请求的URL必须为“/header/test1”
且 请求头中必须有Accept参数才能匹配。
  • 请求头数据中没有指定参数名

1
2
@RequestMapping(value="/header/test2", headers = "!abc"):表示请求的URL必须为“/header/test2”
且 请求头中必须没有abc参数才能匹配。
  • 请求头数据中指定参数名=值

1
@RequestMapping(value="/header/test3", headers = "Content-Type=application/json"):表示请求的URL必须为“/header/test3” 且 请求头中必须有“Content-Type=application/json”参数即可匹配
  • 请求头数据中指定参数名!=值

1
@RequestMapping(value="/header/test7", headers = "Accept!=text/vnd.wap.wml"):表示请求的URL必须为“/header/test7” 且 请求头中必须有“Accept”参数但值不等于“text/vnd.wap.wml”即可匹配。
  • 组合使用是“且”的关系

1
@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才支持:

1
2
3
4
<!--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

1
@RequestMapping(value = "/consumes", consumes = {"application/json"}):此处使用consumes来指定功能处理方法能消费的媒体类型,其通过请求头的“Content-Type”来判断。

此种方式相对使用@RequestMapping的“headers = "Content-Type=application/json"”更能表明你的目的。

二、功能处理方法是生产者 produces:其作用就是指定返回值类型

1
2
@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等都是继承。

四、组合使用是“或”的关系

1
@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映射

 

模拟器报Installation error: INSTALL_FAILED_CONTAINER_ERROR解决方法

2014-04-11 10:49 by 张智清, 阅读(18192) 阅读, 推荐(1) 推荐, 收藏, 编辑
摘要:当我部署一个Eclipse中的项目时,提示Installation error: INSTALL_FAILED_CONTAINER_ERROR,通过在网上上查找解决放啊按得知,我把项目的默认安装位置设置成了优先安装到外置存储,只要把它改成自动就行了解决方案:找到项目下AndroidManifest.xml文件中的manifest标签,里面有个属性是android:installLocation的属性,我之前为了节约手机的内存空间把值设置成了preferExternal,只要改成auto就可以了。之前是android:installLocation="preferExternal&qu 阅读全文

解决INSTALL_FAILED_INSUFFICIENT_STORAGE调试错误的解决

2014-04-10 21:59 by 张智清, 阅读(3269) 阅读, 推荐(0) 推荐, 收藏, 编辑
摘要:由于程序安装包较大,在模拟器上安装时经常出现INSTALL_FAILED_INSUFFICIENT_STORAGE提示。后在网上搜索,找到解决方法如下:<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.andrewsmith.android.darkness" android:installLocation="preferExternal"在android工程的manifest文件根节点加入上面最后一句即可解决。 阅读全文

现在Cocos2d-X v3.x若模拟器调试必须OpenGL ES2

2014-04-10 21:57 by 张智清, 阅读(408) 阅读, 推荐(0) 推荐, 收藏, 编辑
摘要:Android模拟器如何获取支持运行OpenGL ES 21、编辑模拟器,添加‘GPU Emulation’项。2、找到configurationInfo.reqGlEsVersion >= 0×20000代码,在后面添加|| Build.FINGERPRINT.startsWith(“generic”)语句。 阅读全文

Mac OS X环境变量设置

2014-04-08 10:57 by 张智清, 阅读(572) 阅读, 推荐(0) 推荐, 收藏, 编辑
摘要:之前的一博客空间到期没有备份,丢失了一些资料。以下仅仅通过搜素引擎找回的一些东东!一、首先要知道Mac OS X是什么样的Shell,使用命令echo $SHELL如果输出的是:csh或者tcsh,则就是C Shell。如果输出的是:bash, sh, zsh, 则可能就是Bourne Shell的一个变种。Mac OS X 10.2之前默认的是C Shell,10.3之后默认的是Bourne Shell。二、如果是Bourne Shell可以把要添加的环境变量添加到你主目录下面的.profile或者.bash_profile文件中。三、如果是C Shell同上,只是编辑的文件名为 .cshr 阅读全文

配置Cocos2d-x + Android + Eclipse + Windows的开发环境心酸历程

2014-04-08 10:54 by 张智清, 阅读(252) 阅读, 推荐(0) 推荐, 收藏, 编辑
摘要:之前的一博客空间到期没有备份,丢失了一些资料。以下仅仅通过搜素引擎找回的一些东东!配置Cocos2d-x + Android + Eclipse + Windows的开发环境真得是个心酸历程,绝对没有Mac OSX下轻松自如。详细步骤可查看:http://blog.csdn.net/bboyfeiyu/article/details/8995325 阅读全文

Cocos2D-X中针对CocosBuilder的解析器CCBReader

2014-04-08 09:54 by 张智清, 阅读(6260) 阅读, 推荐(0) 推荐, 收藏, 编辑
摘要:之前的一博客空间到期没有备份,丢失了一些资料。以下仅仅通过搜素引擎找回的一些东东!首先知道Cocos2D项目: 在Cocos2D项目中加载ccb文件:在加载CocosBuilder的文件 前,CocosBuilder文档或者ccb文件需要以一种压缩的二进制各式发布——即ccbi文件。一旦被发布为ccbi文件,则只需要一行代码即可简 单地加载到具体的Cocos2D工程项目中(前提保证已经将CCBReader.h和CCBReader.m文件添加到项目中):CCBReader *ccbReader = new cocos2d::extension::CCBReader(ccNodeLoaderLib 阅读全文

XCode5添加新建类模板(Cocos2dx Template Class for Scene or Layer)

2014-04-04 21:15 by 张智清, 阅读(1559) 阅读, 推荐(0) 推荐, 收藏, 编辑
摘要:怎么添加xcode类模板? 1、打开Xcode的类模板目录地址:/Applications/Xcode.app/Contents/Developer/Library/Xcode/Templates/File Templates 2、打开里面C and C++文件,就会看到Xcode的cpp类模板文件。复制一个C++ Class.xctemplate文件夹,取名:2dx Scene Class.xctemplate,放在C and C++目录下。 3、修改TemplateInfo.plist(主要修改创建文件时候的描述介绍) 打开2dx Scene Class.xctemplate/TemplateInfo.plist, 修改Description的值为:A C++ class for Cocos2d-x Scene。 4、修改___FILEBASENAME___.h 打开2dx Scene Class.xctemplate/___FILEBASENAME___.h,修改成以下内容: 阅读全文

话说神奇的content="IE=edge,chrome=1"的meta标签内容

2013-10-19 10:27 by 张智清, 阅读(31847) 阅读, 推荐(5) 推荐, 收藏, 编辑
摘要:这是个是IE8的专用标记,用来指定IE8浏览器去模拟某个特定版本的IE浏览器的渲染方式(比如人见人烦的IE6),以此来解决部分兼容问题,例如模拟IE7的具体方式如下:但令我好奇的是,此处这个标记后面竟然出现了chrome这样的值,难道IE也可以模拟chrome了?迅速搜索了一下,才明白原来不是微软增强了IE,而是谷歌做了个外挂:Google Chrome Frame(谷歌内嵌浏览器框架GCF)。这个插件可以让用户的IE浏览器外不变,但用户在浏览网页时,实际上使用的是Google Chrome浏览器内核,而且支持IE6、7、8等多个版本的IE浏览器,谷歌这个墙角挖的真给力!而上文提到的那个met 阅读全文

(转)检测到在集成的托管管道模式下不适用的ASP.NET 设置

2013-10-08 11:18 by 张智清, 阅读(1752) 阅读, 推荐(0) 推荐, 收藏, 编辑
摘要:我们将ASP.NET程序从IIS6移植到IIS7,可能运行提示以下错误:HTTP 错误 500.23 - Internal Server Error检测到在集成的托管管道模式下不适用的 ASP.NET 设置。为什么会出现以上错误? 在IIS7的应用程序池有两种模式,一种是“集成模式”,一种是“经典模式”。 经典模式 则是我们以前习惯的IIS 6 的方式。 如果使用集成模式,那么对自定义的httpModules 和 httpHandlers 就要修改配置文件,需要将他们转移到和节里去。两种解决方法: 第一种方法:配置应用程序池 在IIS7上配置应用程序池,并且将程序池的模式改为“经典”... 阅读全文
点击右上角即可分享
微信分享提示