Spring MVC体系简介

Spring MVC体系概述

体系结构
  1. 客户端发出一个Http请求,web应用服务器接收到这个请求。如果匹配DispatcherServlet的请求映射路径(在web.xml中指定),则web容器将该请求转交给DispatcherServlet处理。

  2. DispatcherSerovlet接收到这个请求后,将根据请求的信息(包括URL,HTTP方法,请求报文头,请求参数,Cokie等)及HandlerMapping的配置找到处理请求的处理器(Handler)。可将HandlerMapping看作路由控制器,将Handler看做目标主机。值得注意的是,在SpringMVC中并没有定义一个Handler接口,实际上,任何一个Object都可以作为请求处理器。

  3. 当DispatcherServlet根据HandlerMapping得到对应当前请求的Handler后,通过HandlerAdapter对handler进行封装,再以统一的适配器接口调用Handler。HandlerAdapter是SpringMVC的框架级接口,顾名思义,HandlerAdapter是一个适配器,它用统一的接口对各种Handler方法进行调用

  4. 处理器完成业务逻辑的处理之后将返回一个ModelAndView给DispatcherServlet,ModelAndView包含了视图逻辑名和模型数据信息。

  5. ModelAndView包含的是“视图逻辑名”而非真正的视图对象,DispatcherServlet借由ViewResolver完成逻辑视图名到真实视图对象的解析工作。

  6. 得到真实的视图对象View后,DispatcherServlet就使用这个View对象对ModelAndView中的模型数据进行视图渲染。

  7. 最终客户端得到的响应消息可能是一个普通的HTML页面,也可能是一个XML或JSON串,甚至是一张图片或一个PDF文档等不同媒体形式。

DispatcherServlet内部逻辑

    initStrategies()方法将在WebApplicationContext初始化后自动执行,此时Spring上下文中的Bean已经初始化完毕。该方法的工作原理是:通过反射机制查找并装配Spring容器中用户显示自定义的组件Bean,如果找不到,则装配默认的组件实例。

    Spring MVC定义了一套默认的组件实现类,也就是说,即使在Spring容器中没有显示定义组件bean,DispatcherServlet也会装配好一套可用的默认组件。在Spring-webmvc-4.x.jar包的org/springframework/web/servlet类路径下拥有一个DispatcherServlet.propertiesp配置文件,该文件指定了DispatcherServlet所使用的默认组件。

    如果希望采用非默认的组件,则只需要在Spring配置文件中配置自定义的组件Bean即可。Spring MVC一旦发现上下文中有用户自定义的组件,就不会使用默认的组件。



    有些组件最多允许存在一个实例,如MutlipartResolver,LocaleResolver等;而另一些组件允许存在多个实例,如HandlerMapping,HandlerAdapter等。同一类型的组件如果存在多个,可通过order属性确定优先级迅速,值越小优先级越高。

注: 标注了Spring MVC通过@Controller注解的类使其成为一个可处理Http请求的控制器(使用<context:component-scan/>扫描相应的类包),DispatcherServlet使用DefaultAnnotationHandlerMapping查找负责处理对应请求的处理器。

注解驱动的控制器

使用@RequestMapping映射请求

    @RequestMapping使用value指定请求URL,在类定义处指定的URL相对于Web应用的部署路径,而在方法定义处指定的URL则相对于类定义处指定的URL。

    @RequestMapping不但支持标准的URL,还支持Ant风格(?、*和**字符)和带{XXX}占位符的URL。例如:

  • /user/*/create,匹配/user/aa/create,/user/bb/create
  • /user/**/create,匹配/user/create,/user/aa/create,/user/aa/bb/create
  • /user/create?,匹配/user/createaa,/user/createbb
  • /user/{userId},匹配/user/123,/user/456
  • /company/{companyId}/user/{userId}/detail,匹配/company/123/user/456/detail

    通过@PathVariable可以将URL中的占位符参数绑定到控制器方法入参中。如@PathVariable("userId")。

通过请求参数,请求方法或请求头进行映射

    @RequestMapping的value,method,params及headersf分别表示请求URL,请求方法,请求参数及报文头的映射条件,它们之间是与的关系,联合使用多个条件项可让请求映射更加精细化。


  • "params1": 表示请求必须包含名为params1的请求参数
  • "!params1": 表示请求不能包含名为params1的请求参数
  • "params1!=value1": 表示请求必须包含名为params1的请求参数,但其值不能为value1
  • {"params1=value1","param2"}: 表示请求必须包含名为params1和params2的两个请求参数,且params1必须为value1
请求处理方法签名
方法入参使用@RequestParam注解指定对应的请求参数,包含3个参数
  • value: 参数名
  • required: 是否必需,默认为true,不存在将抛出异常
  • defaultValue: 默认参数名,设置该参数时,自动将required设为false
使用@CookieValue可让处理方法入参绑定某个cookie的值,它和@RequestParam一样有3个参数
使用@RequestHeader绑定请求报文头的属性值
使用命令/表单对象绑定请求参数值
使用Servlet API对象作为入参
使用I/O对象作为入参

    Servlet的ServletRequest拥有getInputStream()和getReader()方法,可以通过它们读取请求的信息。相应的,ServletResponse拥有getOutputStream()和getReader()方法,可以通过它们输出响应信息。

使用HttpMessageConverter<T>

    HttpMessageConverter<T>是Spring的一个重要的接口,它负责将请求信息转换为一个对象(类型为T),将对象(类型为T)输出为响应信息。

    DispatcherServlet默认已经安装了RequestMappingHandleAdapter作为HandleAdapter的组件实现类,HttpMessageConverter即由RequestMappingHandleAdapter使用,将请求信息转换为对象,或将对象转换为响应信息。

HttpMessageConverter<T>的实现类




    RequestMappingHandleAdapter默认已经转配了以下HttpMessageConverter:

  1. StringHttpMessageConverter
  2. ByteArrayHttpMessageConverter
  3. SourceHttpMessageConverter
  4. AllEncompassingFormHttpMessageConverter
使用HttpMessageConverter<T>

    SpringMVC提供了两种途径使用HttpMessageConverter<T>将请求信息转换并绑定到处理方法的入参中:

  • 使用@RequestBody/@ResponseBody对处理方法进行标注
  • 使用HttpEntity<T>/ResponseEntity<T>作为处理方法的入参或返回值
1. 使用@RequestBody/@ResponseBody

    在1处,SpringMVC将根据requestBody的类型查找匹配的HttpMessageConverter,由于StringHttpMessageConverter的泛型类型对应String,所以StringHttpMessageConverter将被SpringMVC选中,用它将请求体信息进行转换并将结果绑定到requestBody入参上。

    在2处,由于方法返回值类型为byte[],所以SpringMVC根据类型匹配的查找规则将使用ByteArrayHttpMessageConverter对返回值进行处理,即将图片数据流输出到客户端。

2. 使用HttpEntity<T>/ResponseEntity<T>

    和@RequestBody/@ResponseBody类似,HttpEntity<T>不但可以访问请求和响应报文体的数据,还可以访问请求和响应报文头的数据。SpringMVC根据HttpEntity的泛型类型查找对应的HttpMessageConverter。




    在1处使用HttpEntity<String>指定入参的类型,SpringMVC分析出泛型类型为String,使用StringHttpMessageConverter将请求体类型绑定到httpEntity中,返回String类型的值座位逻辑视图名。

    在2处的处理方法返回值类型为ResponseEntity<byte[]>,SpringMVC分析出泛型类型为byte[],使用ByteArrayHttpMessageConverter输出图片数据流。

处理XML和JSON

    SpringMVC提供了几个处理XML和JSON格式的请求/响应消息的HttpMessageConverter。

  • MarshallingHttpMessageConverter:处理XML格式的请求或响应消息
  • Jaxb2RootElementHttpMessageConverter:同上,底层使用Jaxb
  • MappingJackson2HttpMessageConverter:处理JSON格式的请求或响应消息

    因此,只要在SpringMVC容器中为RequestMappingHandlerAdapter装配好相应的处理XML和JSON格式的请求/响应消息的HttpMessageConverter,并在交互中通过请求的Accept指定MIME类型,SpringMVC就可使服务端的处理方法和客户端透明的通过XML和JSON格式的消息进行通信。

    首先为RequestMappingHandleAdapter装配可处理XML和JSON格式的请求/响应消息的HttpMessageConverter


    控制器相应的方法如下:



    通过以上HTTP请求/响应报文,客户端的User对象被流化为一段对象的XML报文,同时通过报文头属性Accept和Content-Type指定接收的MIME类型和本请求的报文内容均为application/xml。

    将请求报文头属性Accept和Content-Type更改为application/json,User对象的数据以JSON格式进行传递。


©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,723评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,003评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,512评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,825评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,874评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,841评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,812评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,582评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,033评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,309评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,450评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,158评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,789评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,409评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,609评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,440评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,357评论 2 352

推荐阅读更多精彩内容