1.1跟踪Spring MVC的请求

每当用户在Web浏览器中点击链接或提交表单的时候,请求就开始工作了。对请求的工作描述就像是快递投送员。与邮局投递员或FedEx投送员一样,请求会将信息从一个地方带到另一个地方。请求是一个十分繁忙的家伙。从离开浏览器开始到获取响应返回,它会经历好多站,在每站都会留下一些信息同时也会带上其他信息。图5.1展示了请求使用Spring MVC所经历的所有站点。

  在请求离开浏览器时 ,会带有用户所请求内容的信息,至少会包含请求的URL。但是还可能带有其他的信息,例如用户提交的表单信息。请求旅程的第一站是Spring的DispatcherServlet。与大多数基于Java的Web框架一样,Spring MVC所有的请求都会通过一个前端控制器(front controller)Servlet。前端控制器是常用的Web应用程序模式,在这里一个单实例的Servlet将请求委托给应用程序的其他组件来执行实际的处理。在Spring MVC中,DispatcherServlet就是前端控制器。DispatcherServlet的任务是将请求发送给Spring MVC控制器(controller)。控制器是一个用于处理请求的Spring组件。在典型的应用程序中可能会有多个控制器,DispatcherServlet需要知道应该将请求发送给哪个控制器。所以DispatcherServlet以会查

  询一个或多个处理器映射(handler mapping) 来确定请求的下一站在哪里。处理器映射会根据请求所携带的URL信息来进行决策。一旦选择了合适的控制器,DispatcherServlet会将请求发送给选中的控制器 。到了控制器,请求会卸下其负载(用户提交的信息)并耐心等待控制器处理这些信息。(实际上,设计良好的控制器本身只处理很少甚至不处理工作,而是将业务逻辑委托给一个或多个服务对象进行处理。)

  控制器在完成逻辑处理后,通常会产生一些信息,这些信息需要返回给用户并在浏览器上显示。这些信息被称为模型(model)。不过仅仅给用户返回原始的信息是不够的——这些信息需要以用户友好的方式进行格式化,一般会是HTML。所以,信息需要发送给一个视图(view),通常会是JSP。控制器所做的最后一件事就是将模型数据打包,并且标示出用于渲染输出的视图名。它接下来会将请求连同模型和视图名发送回DispatcherServlet 。这样,控制器就不会与特定的视图相耦合,传递给DispatcherServlet的视图名并不直接表示某个特定的JSP。实际上,它甚至并不能确定视图就是JSP。相反,它仅仅传递了一个逻辑名称,这个名字将会用来查找产生结果的真正视图。DispatcherServlet将会使用视图解析器(view resolver)来将逻辑视图名匹配为一个特定的视图实现,它可能是也可能不是JSP。

  既然DispatcherServlet已经知道由哪个视图渲染结果,那请求的任务基本上也就完成了。它的最后一站是视图的实现(可能是JSP) ,在这里它交付模型数据。请求的任务就完成了。视图将使用模型数据渲染输出,这个输出会通过响应对象传递给客户端(不会像听上去那样硬编码) 。可以看到,请求要经过很多的步骤,最终才能形成返回给客户端的响应。大多数的步骤都是在Spring框架内部完成的,也就是图5.1所示的组件中。尽管本章的主要内容都关注于如何编写控制器,但在此之前

我们首先看一下如何搭建Spring MVC的基础组件。

1.2搭建Spring MVC

配置DispatcherServlet

DispatcherServlet是Spring MVC的核心。在这里请求会第一次接触到框架,它要负责将请求路由到其他的组件之中。按照传统的方式,像DispatcherServlet这样的Servlet会配置在web.xml文件中,这个文件会放到应用的WAR包里面。当然,这是配置DispatcherServlet的方法之一。但是,借助于Servlet 3规范和Spring 3.1的功能增强,这种方式已经不是唯一的方案了,这也不是我们本章所使用的配置方法。我们会使用Java将DispatcherServlet配置在Servlet容器中,而不会再使用web.xml文件。如下的程序清单展示了所需的Java类

Spring MVC配置的替代方案

在web.xml中声明DispatcherServlet

在典型的Spring MVC应用中,我们会需要DispatcherServlet和Context-LoaderListener。AbstractAnnotationConfigDispatcherServletInitializer会自动注册它们,但是如果需要在web.xml中注册的话,那就需要我们自己来完成这项任务了。如下是一个基本的web.xml文件,它按照传统的方式搭建了DispatcherServlet和ContextLoaderListener。

在web.xml中搭建Spring MVC

ContextLoaderListener和DispatcherServlet各自都会加载一个Spring应用上下文。上下文参数contextConfigLocation指定了一个XML文件的地址,这个文件定义了根应用上下文,它会被ContextLoaderListener加载。如程序清单7.3所示,根上下文会从“/WEB-INF/spring/root-context.xml”中加载bean定义。DispatcherServlet会根据Servlet的名字找到一个文件,并基于该文件加载应用上下文。在程序清单7.3中,Servlet的名字是appServlet,因此DispatcherServlet会从“/WEB-INF/appServlet-context.xml”文件中加载其应用上下文。

如果你希望指定DispatcherServlet配置文件的位置的话,那么可以在Servlet上指定一个contextConfigLocation初始化参数。例如,如下的配置中,DispatcherServlet会从“/WEB-INF/spring/appServlet/servlet-context.xml”加载它的bean:

1.3处理multipart形式的数据

multipart格式的数据会将一个表单拆分为多个部分(part),每个部分对应一个输入域。在一般的表单输入域中,它所对应的部分中会放置文本型数据,但是如果上传文件的话,它所对应的部分可以是二进制,下面展现了multipart的请求体:

尽管multipart请求看起来很复杂,但在Spring MVC中处理它们却很容易。在编写控制器方法处理文件上传之前,我们必须要配置一个multipart解析器,通过它来告诉DispatcherServlet该如何读取multipart请求。

配置multipart解析器

DispatcherServlet并没有实现任何解析multipart请求数据的功能。它将该任务委托给了Spring中MultipartResolver策略接口的实现,通过这个实现类来解析multipart请求中的内容。从Spring 3.1开始,Spring内置了两个MultipartResolver的实现供我们选择:CommonsMultipartResolver:使用Jakarta CommonsFileUpload解析multipart请求;StandardServletMultipartResolver:依赖于Servlet 3.0对multipart请求的支持(始于Spring 3.1)。一般来讲,在这两者之间,StandardServletMultipartResolver可能会是优选的方案。它使用Servlet所提供的功能支持,并不需要依赖任何其他的项目。如果我们需要将应用部署到Servlet 3.0之前的容器中,或者还没有使用Spring 3.1或更高版本,那么可能就需要CommonsMultipartResolver了。

1.4跨重定向请求传递数据

在处理完POST请求后,通常来讲一个最佳实践就是执行一下重定向。除了其他的一些因素外,这样做能够防止用户点击浏览器的刷新按钮或后退箭头时,客户端重新执行危险的POST请求。在第5章,在控制器方法返回的视图名称中,我们借助了“redirect:”前缀的力量。当控制器方法返回的String值以“redirect:”开头的话,那么这个String不是用来查找视图的,而是用来指导浏览器进行重定向的路径。我们可以回头看一下程序清单5.17,可以看到processRegistration()方法返回的“redirect:String”如下所示:

“redirect:”前缀能够让重定向功能变得非常简单。你可能会想Spring很难再让重定向功能变得更简单了。但是,请稍等:Spring为重定向功能还提供了一些其他的辅助功能。具体来讲,正在发起重定向功能的方法该如何发送数据给重定向的目标方法呢?一般来讲,当一个处理器方法完成之后,该方法所指定的模型数据将会复制到请求中,并作为请求中的属性,请求会转发(forward)到视图上进行渲染。因为控制器方法和视图所处理的是同一个请求,所以在转发的过程中,请求属性能够得以保存。但是,如图7.1所示,当控制器的结果是重定向的话,原始的请求就结束了,并且会发起一个新的GET请求。原始请求中所带有的模型数据也就随着请求一起消亡了。在新的请求属性中,没有任何的模型数据,这个请求必须要自己计算数据。

显然,对于重定向来说,模型并不能用来传递数据。但是我们也有一些其他方案,能够从发起重定向的方法传递数据给处理重定向方法中:

1.使用URL模板以路径变量和/或查询参数的形式传递数据;
2.通过flash属性发送数据。

首先,我们看一下Spring如何帮助我们通过路径变量和/或查询参数的形式传递数据。

通过URL模板进行重定向

通过路径变量和查询参数传递数据看起来非常简单。例如,在程序清单5.19中,我们以路径变量的形式传递了新创建Spitter的username。但是按照现在的写法,username的值是直接连接到重定向String上的。这能够正常运行,但是还远远不能说没有问题。当构建URL或SQL查询语句的时候,使用String连接是很危险的。

除了连接String的方式来构建重定向URL,Spring还提供了使用模板的方式来定义重定向URL。例如,在程序清单5.19中,processRegistration()方法的最后一行可以改写为如下的形式

现在,username作为占位符填充到了URL模板中,而不是直接连接到重定向String中,所以username中所有的不安全字符都会进行转义。这样会更加安全,这里允许用户输入任何想要的内容作为username,并会将其附加到路径上

除此之外,模型中所有其他的原始类型值都可以添加到URL中作为查询参数。作为样例,假设除了username以外,模型中还要包含新创建Spitter对象的id属性,那processRegistration()方法可以改写为如下的形式:

所返回的重定向String并没有太大的变化。但是,因为模型中的spitterId属性没有匹配重定向URL中的任何占位符,所以它会自动以查询参数的形式附加到重定向URL上。如果username属性的值是habuma并且spitterId属性的值是42,那么结果得到的重定向URL路径将会是“/spitter/habuma?spitterId=42”。

通过路径变量和查询参数的形式跨重定向传递数据是很简单直接的方式,但它也有一定的限制。它只能用来发送简单的值,如String和数字的值。在URL中,并没有办法发送更为复杂的值,但这正是flash属性能够提供帮助的领域。

使用flash属性

假设我们不想在重定向中发送username或ID了,而是要发送实际的Spitter对象。如果我们只发送ID的话,那么处理重定向的方法还需要从数据库中查找才能得到Spitter对象。但是,在重定向之前,我们其实已经得到了Spitter对象。为什么不将其发送给处理重定向的方法,并将其展现出来呢

实际上,Spring也认为将跨重定向存活的数据放到会话中是一个很不错的方式。但是,Spring认为我们并不需要管理这些数据,相反,Spring提供了将数据发送为flash属性(flash attribute)的功能。按照定义,flash属性会一直携带这些数据直到下一次请求,然后才会消失。

Spring提供了通过RedirectAttributes设置flash属性的方法,这是Spring 3.1引入的Model的一个子接口。RedirectAttributes提供了Model的所有功能,除此之外,还有几个方法是用来设置flash属性的。具体来讲,RedirectAttributes提供了一组addFlashAttribute()方法来添加flash属性。重新看一下processRegistration()方法,我们可以使用addFlashAttribute()将Spitter对象添加到模型中

在这里,我们调用了addFlashAttribute()方法,并将spitter作为key,Spitter对象作为值。另外,我们还可以不设置key参数,让key根据值的类型自行推断得出

在重定向执行之前,所有的flash属性都会复制到会话中。在重定向后,存在会话中的flash属性会被取出,并从会话转移到模型之中。处理重定向的方法就能从模型中访问Spitter对象了,就像获取其他的模型对象一样。图7.2阐述了它是如何运行的。

Spring MVC起步的更多相关文章

  1. Spring MVC 起步

    跟踪Spring MVC的请求 在请求离开浏览器时①,会带有用户所请求内容的信息,至少会包含请求的URL. 请求旅程的第一站是Spring的DispatcherServlet.与大多数基于Java的W ...

  2. spring in action 5.1 小结 spring mvc起步

    0 配置 DispatcherServlet 是 spring mvc的核心,常规配置方法可以查看之前博客.springMVC简单例子 在此使用servlet 3 规范和 spring3.1 功能增强 ...

  3. Spring学习笔记 7.1 Spring MVC起步

    7.1.1 跟踪Spring MVC的请求请求首先到达DispatcherServlet(DispatcherServlet是Spring MVC中的前端控制器):DispatcherServlet的 ...

  4. Spring MVC起步(一)

    下图展示了请求使用Spring MVC所经历的所有站点. 在请求离开浏览器时1,会带有用户请求内容的信息,至少会包含请求的URL.但是还可能包含其他的信息,如用户提交的表单. DispatcherSe ...

  5. 一、Spring MVC起步——IntelliJ IDEA 搭建Spring MVC环境(手把手搭建)

    本机环境: JDK 1.7 IntelliJ IDEA 2017.2 1.新建项目 Create New Project ​ 选择Spring MVC ​ 填写项目名和项目存放位置 ​ 然后点击Fin ...

  6. SSM(spring mvc+spring+mybatis)学习路径——2-1、spring MVC入门

    目录 2-1 Spring MVC起步 一.回顾Servlet 二.SpringMVC简介 三.搭建SpringMVC第一个案例 四.简单流程及配置 五.使用注解开发Controller 六.参数绑定 ...

  7. Spring Boot起步依赖:定制starter

    在定制我们自己的起步依赖--xxx.spring.boot.starter之前,我们先了解下什么是Spring Boot起步依赖. 起步依赖,是Spring Boot带给我们的一项重要的便利.要理解S ...

  8. 如何用Java类配置Spring MVC(不通过web.xml和XML方式)

    DispatcherServlet是Spring MVC的核心,按照传统方式, 需要把它配置到web.xml中. 我个人比较不喜欢XML配置方式, XML看起来太累, 冗长繁琐. 还好借助于Servl ...

  9. Spring MVC重定向和转发以及异常处理

    SpringMVC核心技术---转发和重定向 当处理器对请求处理完毕后,向其他资源进行跳转时,有两种跳转方式:请求转发与重定向.而根据要跳转的资源类型,又可分为两类:跳转到页面与跳转到其他处理器.对于 ...

随机推荐

  1. learn Linux sed command

    learn Linux sed command 一.参考文档: . sed命令详解 http://qifuguang.me/2015/09/21/sed%E5%91%BD%E4%BB%A4%E8%AF ...

  2. js之购物车案例

      这里主要提供思路: 一共两个页面通过原生来实现,我们需要对cookie进行封装. 在商品列表页,我们将点击添加的商品放入一个对象中,而后将该对象放入数组中,一个对象可以说就是一个商品.在购物车页面 ...

  3. php 配置上传大文件

    打开php.ini,首先找到file_uploads = on ;是否允许通过HTTP上传文件的开关.默认为ON即是开upload_tmp_dir ;文件上传至服务器上存储临时文件的地方,如果没指定就 ...

  4. 关于Mybatis将查询结果中添加常量列并返回

    引言 在使用mybatis的时候,查询一个集合返回给前台页面,在有的时候,我们会添加一个常量字段到对象或者集合中,来标识这个对象属于的类型等等情况,当前台进行再次请求的时候携带此变量进行请求. 但是: ...

  5. 如何向map和reduce脚本传递参数,加载文件和目录

    本文主要讲解三个问题:       1 使用Java编写MapReduce程序时,如何向map.reduce函数传递参数.       2 使用Streaming编写MapReduce程序(C/C++ ...

  6. 2017-2018-2 20165222实验四《Android程序设计》实验报告

    Android Stuidio的安装测试: 参考<Java和Android开发学习指南(第二版)(EPUBIT,Java for Android 2nd)>第二十四章: - 参考http: ...

  7. LOJ3044. 「ZJOI2019」Minimax 搜索

    LOJ3044. 「ZJOI2019」Minimax 搜索 https://loj.ac/problem/3044 分析: 假设\(w(1)=W\),那么使得这个值变化只会有两三种可能,比\(W\)小 ...

  8. simulink pi的方法产生锁相环

    pi方法就是比例积分方法,关于pi方法介绍参考http://www.elecfans.com/dianzichangshi/20120909287851.html 锁相环pi方法原理参考http:// ...

  9. .OPF文件剖析

    OPF文档是epub电子书的核心文件,且是一个标准的XML文件,依据OPF规范,主要由五个部分组成: 1.<metadata>,元数据信息,由两个子元素组成: <dc-metadat ...

  10. kong 了解

      Kong 是在客户端和(微)服务间转发API通信的API网关,通过插件扩展功能.Kong 有两个主要组件: Kong Server :基于nginx  的服务器,用来接收 API 请求. Apac ...