SpringMVC精讲

SpringMVC4
框架技术

SpringMVC4 框架技术讲义
第1章 SpringMVC 概述

回顾 MVC 架构模式

Model2-MVC(掌握)

Model2 加入了 Servlet, 分离了 Model1 中 jsp 控制业务逻辑的部分。 这里 Servlet 充当控制器,管理者的角色,负责管理用户的请求,Servlet 根据请求的内容调用适合的 JavaBean,在
JavaBean 中访问 DB 存取数据,计算处理数据。Servlet 把根据处理结果选择合适的 jsp 显示
JavaBean 的数据。呈现给用户。请求处理完毕。

MVC 架构和三层架构的联系与区别(了解)

三层架构
UI: 界面层(User Interface layer)
BLL: 业务逻辑层(Business Logic Layer)
DAL:数据访问层(Data Access Layer)

MVC 架构
M 即 Model(模型层),主要负责出来业务逻辑以及数据库的交互
V 即 View( 视 图 层 ), 主 要 用 于 显 示 数 据 和 提 交 表 单C 即 Controller(控制器),主要是接收请求,调用 Model 处理请求,并控制请求转发

三层架构与 MVC 的联系:
都是三层,分层的目的是解耦合,按职责划分层次。各层功能独立单一。易于扩展应用, 提高开发效率。

主要的区别:

  1. 三层架构适用所有的应用架构, MVC 侧重是 web 应用的使用(jsp 和 servlet 的解耦)。

  2. 三层架构中没有控制器 Controller. MVC 中有控制器层 Controller

    为什么要使用 SpringMVC(理解)

  3. 基于 MVC 架构
    基于 MVC 架构,功能分工明确。解耦合,

  4. 容易理解,上手快;使用简单。
    二步设置就可以开发一个注解的 SpringMVC 项目,SpringMVC 也是轻量级的,jar 很小。不依赖的特定的接口和类。

  5. 作 为 Spring 框 架 一 部 分 , 能 够 使 用 Spring 的 IoC 和 Aop 。 方 便 整 合
    Strtus,MyBatis,Hiberate,JPA 等其他框架。

  6. SpringMVC 强化注解的使用,在控制器,Service,Dao 都可以使用注解。方便灵活。
    使用@Controller 创建处理器对象,@Service 创建业务对象, @Autowired 或者@Resource 在控制器类中注入 Service, Service 类中注入 Dao。

    SpringMVC 简介(了解)

SpringMVC 也叫 Spring web mvc,属于表现层的框架。SpringMVC 是 Spring 框架的一部分,是在 Spring3.0 后发布的。

第一个配置式 SpringMVC 程序(掌握)

项目:primary
完成功能:用户提交一个请求,服务端处理器在接收到这个请求后,给出一条欢迎信息, 在响应页面中显示该信息。

导入 Jar 包

在创建好 web 项目后,首先要导入 Jar 包。SpringMVC 需要的基本 Jar 包,是在原 Spring 的 Jar 包基础上(四个核心 jar, 日志 jar,spring-aop.jar,spring-web.jar),增加 springmvc 框架的实现包:spring-webmvc.jar

注册中央调度器

(1) 全限定性类名

该中央调度器为一个 Servlet,名称为 DispatcherServlet。中央调度器的全限定性类名在导入的 Jar 文件 spring-webmvc-4.3.9.RELEASE.jar 的第一个包 org.springframework.web.servlet 下可找到。

(2)

在中添加的作用是,标记是否在Web 服务器(这里是Tomcat) 启动时会创建这个 Servlet 实例,即是否在 Web 服务器启动时调用执行该 Servlet 的 init()方法,而不是在真正访问时才创建。
它的值必须是一个整数。
 当值大于等于 0 时,表示容器在启动时就加载并初始化这个 servlet,数值越小,该 Servlet
的优先级就越高,其被创建的也就越早;
 当值小于 0 或者没有指定时,则表示该 Servlet 在真正被使用时才会去创建。
 当值相同时,容器会自己选择创建顺序。

(3)
对于,可以写为 / ,建议写为*.do 的形式。详见 1.4 再解。

(4) 配置文件位置与名称

注册完毕后,可直接在服务器上发布运行。此时,默认浏览器页面,及 MyEclipse 控制台均会抛出 FileNotFoundException 异常。即默认要从项目根下的 WEB-INF 目录下找名称为
Servlet 名称-servlet.xml 的配置文件。这里的“Servlet 名称”指的是注册中央调度器时
标签中指定的 Servlet 的 name 值。本例配置文件名为 springmvc-servlet.xml。
从 DispatcherServlet 类的父类的源码注释 FrameworkServlet 中也可看到相关描述:

而一般情况下,该配置文件是放在类路径下,即 src 目录下。所以,在注册中央调度器时,还需要为中央调度器设置查找 SpringMVC 配置文件路径,及文件名。
打开 DispatcherServlet 的源码,其继承自 FrameworkServlet,而该类中有一个属性
contextConfigLocation,用于设置 SpringMVC 配置文件的路径及文件名。该初始化参数的属性

就来自于这里。

创建 SpringMVC 配置文件

在工程的类路径即 src 目录下创建 SpringMVC 的配置文件 springmvc.xml。该文件名可以任意命名。而该 xml 文件的约束,则使用 Spring 配置文件最全约束。

定义处理器

该处理器需要实现 Controller 接口。

ModelAndView 类中的 addObject()方法用于向其 Model 中添加数据。Model 的底层为一个 HashMap。

Model 中的数据存储在 request 作用域中,SringMVC 默认采用转发的方式跳转到视图, 本次请求结束,模型中的数据被销毁。

注册处理器

在 springmvc.xml 中注册处理器。不过,需要注意处理器的 id 属性值为一个请求 URI。表示当客户端提交该请求时,会访问 class 指定的这个处理器。

定义目标页面

在 WEB-INF 目录下新建一个子目录 jsp,在其中新建一个 jsp 页面 show.jsp。

修改视图解析器的注册

SpringMVC 框架为了避免对于请求资源路径与扩展名上的冗余, 在视图解析器InternalResouceViewResolver 中引入了请求的前辍与后辍。而 ModelAndView 中只需给出要跳转页面的文件名即可,对于具体的文件路径与文件扩展名,视图解析器会自动完成拼接。

修改处理器


SpringMVC 执行流程(掌握)

图一:

图二:

执行流程的源代码分析,序列图:

执行流程简单分析

(1)浏览器提交请求到中央调度器
(2)中央调度器直接将请求转给处理器映射器。
(3)处理器映射器会根据请求,找到处理该请求的处理器,并将其封装为处理器执行链后返回给中央调度器。
(4)中央调度器根据处理器执行链中的处理器,找到能够执行该处理器的处理器适配器。
(5)处理器适配器调用执行处理器。
(6)处理器将处理结果及要跳转的视图封装到一个对象 ModelAndView 中,并将其返回给处理器适配器。
(7)处理器适配器直接将结果返回给中央调度器。
(8)中央调度器调用视图解析器,将 ModelAndView 中的视图名称封装为视图对象。
(9)视图解析器将封装了的视图对象返回给中央调度器
(10)中央调度器调用视图对象,让其自己进行渲染,即进行数据填充,形成响应对象。
(11)中央调度器响应浏览器。

API 简要说明

(1) DispatcherServlet (不需要程序员开发)
中央调度器,也称为前端控制器,在 MVC 架构模式中充当控制器 C,DispatcherServlet
是整个流程的控制中心,由它调用诸如处理器映射器、处理器适配器、视图解析器等其它组

件处理用户请求。中央调度器的存在降低了组件之间的耦合度。

(2) HandlerMapping (不需要程序员开发)

处理器映射器,负责根据用户请求找到相应的将要执行的 Handler,即处理器。即用于完成将用户请求映射为要处理该请求的处理器,并将处理器封装为处理器执行链传给中央调度器。

(3) HandlAdapter(不需要程序员开发)

处理器适配器,通过 HandlerAdapter 对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。中央调度器会根据不同的处理器自动为处理器选择适配器,以执行处理器。

(4) Handler (需要程序员开发),即 Controller

处理器,也称为后端控制器,在 DispatcherServlet 的控制下 Handler 调用 Service 层对具体的用户请求进行处理。由于 Handler 涉及到具体的用户业务请求,所以一般情况下需要程序员根据业务需求自己开发 Handler。

(5) ViewResolver (不需要程序员开发)

视图解析器,负责将处理结果生成 View 视图,ViewResolver 首先将逻辑视图名解析为物理视图名,即具体的页面地址,再生成 View 视图对象。最后将处理结果通过页面形式展示给用户。

(6) View (需要程序员开发 jsp 页面)

SpringMVC 框架提供了很多的 View 视图类型。一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由程序员根据业务需求开发具体的页面。

DispatcherServlet 的默认配置

第一个 SpringMVC 的程序已经可以正确运行了。但发现一个问题:在流程介绍中所述的重要的处理器映射器、处理器适配器、视图解析器等,都在哪里,不用做配置吗?
当然不是!这些内容均在 DispatcherServlet 的默认配置 DispatcherServlet.properties 文件中被定义。这个文件与 DispatcherServlet 类在一个包下,而且是当 Spring 配置文件中没有指定配置时使用的默认情况。

从上面的内容可知,这些组件的默认配置如下:

再解<url-pattern/>(掌握)

配置详解

(1) 建议写为*.do 形式

在没有特殊要求的情况下,SpringMVC 的中央调度器 DispatcherServlet 的 常使用后辍匹配方式,如写为*.do 或者 *.action, *.mvc 等。
页面都不能访问。

(2) 可以写为 /

可以写为 /,因为 DispatcherServlet 会将向静态资源的获取请求,例如.css、.js、.jpg、.png 等资源的获取请求,当作是一个普通的 Controller 请求。中央调度器会调用处理器映射器为其查找相应的处理器。当然也是找不到的,所以在这种情况下,所有的静态资源获取请求也均会报 404 错误。

项目:url-pattern。在项目 primary 基础上进行修改。
需求:在 index.jsp 页面中存在一个访问图片的链接。该项目用于演示将写为*.do 可以访问到该图片,而写为/,则无法访问。

A、 在项目中添加图片
在项目的 WebRoot 下添加一个目录 images,并在其中添加一张图片资源。

B、 修改 index 页面

C、 修改的值

保持的值为 *.do,扩展名方式,图片会正常显示。将的值修改为 / ,则图片将无法显示。

静态资源访问

的值并不是说写为/后,静态资源就无法访问了。经过一些配置后,该问题也是可以解决的。

(1) 使用mvc:default-servlet-handler/(理解)
在 Tomcat 中,有一个专门用于处理静态资源访问的 Servlet – DefaultServlet。其
为 default。可以处理各种静态资源访问请求。该 Servlet 注册在 Tomcat 服务器的 web.xml 中。在 Tomcat 安装目录/conf/web.xml。

项目:url-pattern-2。在项目 url-pattern 基础上修改。
只需要在 springmvc.xml 中添加mvc:default-servlet-handler/标签即可。
mvc:default-servlet-handler/表示使用 DefaultServletHttpRequestHandler 处理器对象。而该处理器调用了 Tomcat 的 DefaultServlet 来处理静态资源的访问请求。如果默认的 servlet 名称不是 default,需要使用属性 default-servlet-name 指定 servlet 的名称,
例如:<mvc:default-servlet-handler default-servlet-name=”servlet 名称” />

Tomcat, Jetty 默认 Servlet 的名字 – “default”
WebLogic 默认 Servlet 的名字 – “FileServlet”
WebSphere 默认 Servlet 的名字 – “SimpleFileServlet”
当然了,要想使用<mvc: …/>标签,需要引入 mvc 约束

该约束可从 Spring 帮助文档中搜索关键字 spring-mvc.xsd 即可获取:
docs/spring-framework-reference/htmlsingle/index.html

(2) 使用mvc:resources/(掌握)
项目:url-pattern-3。在项目 url-pattern 基础上修改。

在 Spring3.0.4 版本后,Spring 中定义了专门用于处理静态资源访问请求的处理器ResourceHttpRequestHandler。并且添加了mvc:resources/标签,专门用于解决静态资源无法访问问题。需要在 springmvc.xml 中添加如下形式的配置:

/images/car.png 等)。注意,后面是两个星号**。

第2章 SpringMVC 注解式开发

所谓 SpringMVC 的注解式开发是指,在代码中通过对类与方法的注解,便可完成处理器在 springmvc 容器的注册。注解式开发是重点。

第一个注解式 SpringMVC 项目

注解的项目同样需要中央调取器,视图解析器。新建项目 primary-annotation

定义处理器

在类上与方法上添加相应注解即可。
@Controller: 表 示 当 前 类 为 处 理 器 @RequestMapping:表示当前方法为处理器方法。该方法要对 value 属性所指定的 URI
进行处理与响应。被注解的方法的方法名可以随意。

ModelAndView 类中的 addObject()方法用于向其 Model 中添加数据。Model 的底层为一个 HashMap。

Model 中的数据存储在 request 作用域中,SringMVC 默认采用转发的方式跳转到视图, 本次请求结束,模型中的数据被销毁。

若有多个请求路径均可匹配该处理器方法的执行,则@RequestMapping 的 value 属性中可以写上一个数组。

注册组件扫描器

这里的组件即处理器,需要指定处理器所在基本包。

定义视图页面

在 WEB-INF 目录下新建一个子目录 jsp,在其中新建一个 jsp 页面 welcome.jsp。

@RequestMapping 定义请求规则

通过@RequestMapping 注解可以定义处理器对于请求的映射规则。该注解可以注解在方法上,也可以注解在类上,但意义是不同的。value 属性值常以“/”开始,也可不加“/”

在类上使用@RequestMapping(掌握)

@RequestMapping 的 value 属性用于定义所匹配请求的 URI。但对于注解在方法上与类上,其 value 属性所指定的 URI,意义是不同的。
一个@Controller 所注解的类中,可以定义多个处理器方法。当然,不同的处理器方法所匹配的 URI 是不同的。这些不同的 URI 被指定在注解于方法之上的@RequestMapping 的
value 属性中。但若这些请求具有相同的 URI 部分,则这些相同的 URI,可以被抽取到注解在类之上的@RequestMapping 的 value 属性中。此时的这个 URI 表示模块的名称。URI 的请求是相对于 Web 的根目录。
换个角度说,要访问处理器的指定方法,必须要在方法指定 URI 之前加上处理器类前定义的模块名称
项目:requestMapping-modelName。在 primary-annotation 基础上进行修改。
Step1:修改处理器类 MyController。
Step2:添加视图页面
在/WEB-INF/jsp 目录下添加 some.jsp 与 other.jsp 页面,删除原 welcome.jsp 页面。

对请求提交方式的定义(掌握)

对于@RequestMapping,其有一个属性 method,用于对被注解方法所处理请求的提交方式进行限制,即只有满足该 method 属性指定的提交方式的请求,才会执行该被注解方法。
Method 属性的取值为 RequestMethod 枚举常量。常用的为 RequestMethod.GET 与
RequestMethod.POST,分别表示提交方式的匹配规则为 GET 与 POST 提交。
以上处理器方法只能处理 POST 方式提交的请求。客户端浏览器常用的请求方式,及其提交方式有以下几种:

也就是说,只要指定了处理器方法匹配的请求提交方式为 POST,则相当于指定了请求发送的方式:要么使用表单请求,要么使用 AJAX 请求。其它请求方式被禁用。
当然,若不指定 method 属性,则无论是 GET 还是 POST 提交方式,均可匹配。即对于请求的提交方式无要求。

项目:requestMapping-method。在 requestMapping-modelName 基础上进行修改。

Step1:修改处理器类 MyController
Step2:修改 index 页面

对请求中携带参数的定义(掌握)

@RequestMapping 中 params 属性中定义了请求中必须携带的参数的要求。以下是几种情况的说明。
@RequestMapping(value=”/xxx.do”, params={“name”,”age”}) :要求请求中必须携带请求参数 name 与 age
@RequestMapping(value=”/xxx.do”, params={“!name”,”age”}) :要求请求中必须携带请求参数 age,但必须不能携带参数 name
@RequestMapping(value=”/xxx.do”, params={“name=zs”,”age=23”}) :要求请求中必须携带请求参数 name,且其值必须为 zs;必须携带参数 age,其其值必须为 23

项目:requestMapping-params。在 requestMapping-modelName 基础上进行修改。

处理器方法的参数

处理器方法可以包含以下四类参数,这些参数会在系统调用时由系统自动赋值,即程序员可在方法内直接使用。
 HttpServletRequest
 HttpServletResponse
 HttpSession
 请求中所携带的请求参数

逐个参数接收(掌握)

只要保证请求参数名与该请求处理方法的参数名相同即可。
项目:receiveParameters-property。在 requestMapping-method 基础上修改。
Step1:修改 index 页面

Step2:修改处理器类 MyController

Step3:添加 show 页面
在/WEB-INF/jsp 下添加 show.jsp 页面。

请求参数中文乱码问题(掌握)

对于前面所接收的请求参数,若含有中文,则会出现中文乱码问题。Spring 对于请求参数中的中文乱码问题, 给出了专门的字符集过滤器: spring-web-4.3.9.RELEASE.jar 的
org.springframework.web.filter 包下的 CharacterEncodingFilter 类。

(1) 解决方案

在 web.xml 中注册字符集过滤器,即可解决 Spring 的请求参数的中文乱码问题。不过, 最好将该过滤器注册在其它过滤器之前。因为过滤器的执行是按照其注册顺序进行的。
直接在项目 receiveParameters-property 上进行修改。

(2) 源码分析
打开 CharacterEncodingFilter 类的源码,发现有三个 set 方法。

字符集设置核心方法:

校正请求参数名@RequestParam(掌握)

所谓校正请求参数名,是指若请求 URL 所携带的参数名称与处理方法中指定的参数名不相同时,则需在处理方法参数前,添加一个注解@RequestParam(“请求参数名”),指定请 求 URL 所携带参数的名称。该注解是对处理器方法参数进行修饰的。value 属性指定请求参数的名称。

项目:receiveParameters-params。在 receiveParameters-property 基础上修改。
Step1:修改 index 页面
将表单中的参数名称修改的与原来不一样。

Step2:修改处理器类 MyController

对象参数接收(掌握)

将处理器方法的参数定义为一个对象,只要保证请求参数名与这个对象的属性同名即可。项目:receiveParameters-object。在 receiveParameters-property 基础上修改。

Step1:定义类 Student

Step2:修改处理器类 MyController

Step3:修改 show 页面

处理器方法的返回值

使用@Controller 注解的处理器的处理器方法,其返回值常用的有四种类型:
 第一种:ModelAndView
 第二种:String
 第三种:无返回值 void
 第四种:返回自定义类型对象
根据不同的情况,使用不同的返回值。

返回 ModelAndView(掌握)

若处理器方法处理完后,需要跳转到其它资源,且又要在跳转的资源间传递数据,此时处理器方法返回 ModelAndView 比较好。当然,若要返回 ModelAndView,则处理器方法中

需要定义 ModelAndView 对象。
在使用时,若该处理器方法只是进行跳转而不传递数据,或只是传递数据而并不向任何资源跳转(如对页面的 Ajax 异步响应),此时若返回 ModelAndView,则将总是有一部分多余:要么 Model 多余,要么 View 多余。即此时返回 ModelAndView 将不合适。

返回 String(理解)

处理器方法返回的字符串可以指定逻辑视图名,通过视图解析器解析可以将其转换为物理视图地址

返回内部资源逻辑视图名
若要跳转的资源为内部资源,则视图解析器可以使用 InternalResourceViewResolver 内部资源视图解析器。此时处理器方法返回的字符串就是要跳转页面的文件名去掉文件扩展名后的部分。这个字符串与视图解析器中的 prefix、suffix 相结合,即可形成要访问的 URI。
项目:returnString-viewName。在 receiveParameters-object 基础上修改。直接修改处理器类 MyController

当然,也可以直接返回资源的物理视图名。不过,此时就不需要再在视图解析器中再配置前辍与后辍了。

返回 void(了解)

对于处理器方法返回 void 的应用场景,AJAX 响应.
若处理器对请求处理后,无需跳转到其它任何资源,此时可以让处理器方法返回 void。例如,对于 AJAX 的异步请求的响应。

项目:returnVoid-ajax。在 primary-annotation 基础上进行修改。
Step1:导入 Jar 包
由于本项目中服务端向浏览器传回的是 JSON(JavaScript Object Notation,JS 对象符号) 数据,需要使用一个工具类将字符串包装为 JSON 格式,所以需要导入 JSON 的 Jar 包。
Step2:引入 jQuery 库
由于本项目要使用 jQuery 的 ajax()方法提交 AJAX 请求,所以项目中需要引入 jQuery 的库。在 WebRoot 下新建一个 Folder(文件夹),命名为 js,并将 jquery-1.11.1.js 文件放入其中。

当然,该 jQuery 库文件,需要在使用 ajax()方法的 index 页面中引入。

Step3:定义 index 页面
index 页面由两部分内容构成:一个是,用于提交 AJAX 请求;一个是

点击按钮发起请求
Step4: 定义对象 Student

Step5:修改处理器类 MyController
处理器对于 AJAX 请求中所提交的参数,可以使用逐个接收的方式,也可以以对象的方式整体接收。只要保证 AJAX 请求参数与接收的对象类型属性同名。
以逐个方式接收参数:

Step6:删除视图页面
由于是服务端直接向浏览器发回数据,所以也就无需视图页面了,所以需要删除
WEB-INF 中的 jsp 目录及其中的 show 页面。

(1) Json 介绍(理解)

JSON 的两种结构
1.“名称/值”对的集合。 例如 { name:”张三” , age : 23 }
2. 值的有序列表,它被理解为数组。例如:[{ name:”张三” , age : 23 } , { name:”李力” , age :
28 }]

在 JSON-Lib 中

常用的的 json 库: json-lib , Jackson , google 公司的 gson 和阿里巴巴的 fastjson

返回对象(掌握)

处理器方法也可以返回 Object 对象。这个 Object 可以是 Integer,String,自定义对象,
Map,List 等。但返回的对象不是作为逻辑视图出现的,而是作为直接在页面显示的数据出现的。

返回对象,需要使用@ResponseBody 注解,将转换后的 JSON 数据放入到响应体中。

(1) 环境搭建

A 、 导 入 Jar 包

由于返回 Object 数据,一般都是将数据转化为了 JSON 对象后传递给浏览器页面的。而这个由 Object 转换为 JSON,是由 Jackson 工具完成的。所以需要导入 Jackson 的相关 Jar 包。

B、 注册注解驱动

将 Object 数据转化为 JSON 数据,需要由消息转换器 HttpMessageConverter 完成。而转换器的开启,需要由mvc:annotation-driven/来完成。
SpringMVC 使用消息转换器实现请求数据和对象,处理器方法返回对象和响应输出之间的自动转换
当 Spring 容器进行初始化过程中,在mvc:annotation-driven/处创建注解驱动时,默认创建了七个 HttpMessageConverter 对象。也就是说,我们注册mvc:annotation-driven/,就是为了让容器为我们创建 HttpMessageConverter 对象。

HttpMessageConverter 接口 : HttpMessageConverter 是 Spring3.0 新添加的一个接 口, 负责将请求信息转换为一个对象(类型为 T),将对象( 类型为 T)输出为响应信息

HttpMessageConverter接口定义的方法:

boolean canRead(Class<?> clazz,MediaType mediaType): 指定转换器 可以读取的对象类型,即转换器是否可将请求信息转换为 clazz 类型的对 象, 同时指定支持 MIME 类型
(text/html,applaiction/json 等)

boolean canWrite(Class<?> clazz,MediaType mediaType):指定转换器 是否可将 clazz 类型的对象写到响应流中,响应流支持的媒体类型 在 MediaType 中定义。
LIst getSupportMediaTypes():该转换器支持的媒体类型。

T read(Class<? extends T> clazz,HttpInputMessage inputMessage): 将请求信息流转换为 T 类

型的对象。

void write(T t,MediaType contnetType,HttpOutputMessgae outputMessage):将 T 类型的对象写到响应流中,同时指定相应的媒体类 型为 contentType

加入注解驱动mvc:annotation-driven/后适配器类的 messageConverters 属性值

HttpMessageConverter 接口实现类 作用
ByteArrayHttpMessageConverter 负责读取二进制格式的数据和写出二进制格
式的数据
StringHttpMessageConverter 负责读取字符串格式的数据和写出字符串格
式的数据
ResourceHttpMessageConverter 负责读取资源文件和写出资源文件数据
SourceHttpMessageConverter 能够读 / 写 来 自 HTTP 的 请 求 与 响 应 的
javax.xml.transform.Source , 支 持 DOMSource,
SAXSource, 和 StreamSource 的 XML 格式
AllEncompassingFormHttpMessageConvert
er 负责处理表单(form)数据
Jaxb2RootElementHttpMessageConverter 使用 JAXB 负责读取和写入xml 标签格式的数

MappingJackson2HttpMessageConverter 负责读取和写入 json 格式的数据。利用
Jackson 的 ObjectMapper 读写 json 数据,操作
Object 类型数据,可读取 application/json,响
应媒体类型为 application/json

(2) 返回字符串对象

若要返回非中文字符串,将前面返回数值型数据的返回值直接修改为字符串即可。但若返 回 的 字 符 串 中 带 有 中 文 字 符 , 则 接 收 方 页 面 将 会 出 现 乱 码 。 此 时 需 要 使 用
@RequestMapping 的 produces 属性指定字符集。
produces,产品,结果,即该属性用于设置输出结果类型。
项目:returnObject-String。

直接修改处理器即可。

(3) 返回自定义类型对象

返回自定义类型对象时,不能以对象的形式直接返回给客户端浏览器,而是将对象转换为 JSON 格式的数据发送给浏览器的。
由于转换器底层使用了Jackson 转换方式将对象转换为JSON 数据,所以需要导入Jackson
的相关 Jar 包。
项目:returnObject-custom。在 returnObject-string 基础上进行修改。
Step1:定义 VO 类
Step2:修改处理器 MyController

Step3:修改 index 页面

(4) 返回 List 集合
项目:returnObject-list。在 returnObject-custom 基础上进行修改。
Step1:修改处理器 MyController

Step2:修改 index 页面

第3章 SpringMVC 核心技术

请求重定向和转发

当处理器对请求处理完毕后,向其它资源进行跳转时,有两种跳转方式:请求转发与重定向。而根据所要跳转的资源类型,又可分为两类:跳转到页面与跳转到其它处理器。
注意,对于请求转发的页面,可以是WEB-INF 中页面;而重定向的页面,是不能为WEB-INF 中页的。因为重定向相当于用户再次发出一次请求,而用户是不能直接访问 WEB-INF 中资源的。

SpringMVC 框架把原来 Servlet 中的请求转发和重定向操作进行了封装。现在可以使用简单的方式实现转发和重定向。
forward:表示转发,实现 request.getRequestDispatcher(“xx.jsp”).forward() redirect: 表示重定向,实现 response.sendRedirect(“xxx.jsp”)

forword 和 redirect 根据他们的目标,可以分为页面和其他处理器。

请求转发

处理器方法返回 ModelAndView 时,需在 setViewName()指定的视图前添加 forward:,且此时的视图不再与视图解析器一同工作,这样可以在配置了解析器时指定不同位置的视图。视图页面必须写出相对于项目根的路径。forward 操作不需要视图解析器。
处理器方法返回 String,在视图路径前面加入 forward: ,转发到视图页面。转发到其他处理器的格式:forward:xxx.do

(1) 处理器方法返回 ModelAndview 转发到视图:

(2) 处理器方法返回 String 发到视图:

(3) 转发到其他的处理器
发起请求的 jsp
处理器方法:

show.jsp

请求重定向

在处理器方法返回的视图字符串的前面添加 redirect:,则可实现重定向跳转。
当重定向到目标资源时,若需要向下传递参数值,除了可以直接通过请求 URL 携带参数,通过 HttpSession 携带参数。

(1) 处理器方法返回 ModelAndView 重定向到视图
处理器方法定义:

some.jsp 定义,使用 param 对象获取请求参数

重定向操作,使用 get 方式传递参数

(2) 处理器方法返回 String 重定向到视图
处理器方法定义:

(3) 重定向到其他处理器
处理器定义:

访问请求地址:

show.jsp 不能使用 EL 表达式 ${myname}取出数据。重定向数据没有存入到 Model
控制台输出:

异常处理(掌握)

常用的 SpringMVC 异常处理方式主要有三种:
 使用系统定义好的异常处理器 SimpleMappingExceptionResolver
 使用自定义异常处理器
 使用异常处理注解

SimpleMappingExceptionResolver 异常处理器

该方式只需要在 SpringMVC 配置文件中注册该异常处理器 Bean 即可。该 Bean 比较特殊,没有 id 属性,无需显式调用或被注入给其它,当异常发生时会自动执行该类。
项目:simpleMappingExceptionResolver。在项目 receiveParameters-property 上修改。自定义异常类
定义三个异常类:NameException、AgeException、StudentException。其中 StudentException
是另外两个异常的父类。

(1) 修 改 Controller

(2) 注册异常处理器

 exceptionMappings:Properties 类型属性,用于指定具体的不同类型的异常所对应的异常响应页面。Key 为异常类的全限定性类名,value 则为响应页面路径
 defaultErrorView:指定默认的异常响应页面。若发生的异常不是 exceptionMappings 中指定的异常,则使用默认异常响应页面。
 exceptionAttribute:捕获到的异常对象。一般异常响应页面中使用。

(3) 定义异常响应页面
在 WebRoot 下新建一个目录 errors,在其中定义三个异常响应页面。

自定义异常处理器

使用 SpringMVC 定义好的 SimpleMappingExceptionResolver 异常处理器,可以实现发生指定异常后的跳转。但若要实现在捕获到指定异常时,执行一些操作的目的,它是完成不了的。此时,就需要自定义异常处理器。
自定义异常处理器,需要实现HandlerExceptionResolver 接口,并且该类需要在SpringMVC
配置文件中进行注册。
项目:customExceptionResolver。在项目 simpleMappingExceptionResolver 上修改。

(1) 定义异常处理器

当一个类实现了 HandlerExceptionResolver 接口后,只要有异常发生,无论什么异常, 都会自动执行接口方法 resolveException()。

(2) 注册异常处理器

异常处理注解

使用注解@ExceptionHandler 可以将一个方法指定为异常处理方法。该注解只有一个可选属性 value,为一个 Class<?>数组,用于指定该注解的方法所要处理的异常类,即所要匹配的异常。
而被注解的方法,其返回值可以是 ModelAndView、String,或 void,方法名随意,方法参数可以是 Exception 及其子类对象、HttpServletRequest、HttpServletResponse 等。系统会自动为这些方法参数赋值。
对于异常处理注解的用法,也可以直接将异常处理方法注解于 Controller 之中。

不过,一般不这样使用。而是将异常处理方法专门定义在一个类中,作为全局的异常处理类。
需要使用注解@ControllerAdvice , 字面理解就是“控制器增强” ,是给控制器对象增强功能的。使用@ControllerAdvice 修饰的类中可以使用@ExceptionHandler。
当使用@RequestMapping 注解修饰的方法抛出异常时,会执行@ControllerAdvice 修饰的类中的异常处理方法。
@ControllerAdvice 是使用@Component 注解修饰的,可以context:component-scan 扫描到@ControllerAdvice 所在的类路径(包名),创建对象。
项目:annotationExceptionResolver。在项目 customExceptionResolver 上修改。

(1) 定义全局异常处理类

(2) 定义 Spring 配置文件

拦截器(掌握)

SpringMVC 中的 Interceptor 拦截器是非常重要和相当有用的,它的主要作用是拦截指定的用户请求,并进行相应的预处理与后处理。其拦截的时间点在“处理器映射器根据用户提 交的请求映射出了所要执行的处理器类,并且也找到了要执行该处理器类的处理器适配器, 在处理器适配器执行处理器之前”。当然,在处理器映射器映射出所要执行的处理器类时, 已经将拦截器与处理器组合为了一个处理器执行链,并返回给了中央调度器。

一个拦截器的执行

项目:interceptor。自定义拦截器
自定义拦截器,需要实现 HandlerInterceptor 接口。而该接口中含有三个方法:

 postHandle(request, response, Object handler, modelAndView):
该方法在处理器方法执行之后执行。处理器方法若最终未被执行,则该方法不会执行。由于该方法是在处理器方法执行完后执行,且该方法参数中包含 ModelAndView,所以该方法可以修改处理器方法的处理结果数据,且可以修改跳转方向。
 afterCompletion(request, response, Object handler, Exception ex):
当 preHandle()方法返回 true 时,会将该方法放到专门的方法栈中,等到对请求进行响应的所有工作完成之后才执行该方法。即该方法是在中央调度器渲染(数据填充)了响应页面之后执行的,此时对 ModelAndView 再操作也对响应无济于事。

拦截器中方法与处理器方法的执行顺序如下图:

换一种一表现方式,也可以这样理解:

(1) 注册拦截器

mvc:mapping/用于指定当前所注册的拦截器可以拦截的请求路径,而/**表示拦截所有请求。

(2) 修改 index 页面

(3) 修改处理器

(4) 修改 show 页面

(5) 控制台输出结果

多个拦截器的执行

项目:interceptor2。在项目 interceptor 基础上修改。

(1) 再定义一个拦截器

(2) 多个拦截器的注册与执行

(3) 控制台执行结果

当有多个拦截器时,形成拦截器链。拦截器链的执行顺序,与其注册顺序一致。需要再次强调一点的是,当某一个拦截器的 preHandle()方法返回 true 并被执行到时,会向一个专门的方法栈中放入该拦截器的 afterCompletion()方法。
多个拦截器中方法与处理器方法的执行顺序如下图:

从图中可以看出,只要有一个 preHandle()方法返回 false,则上部的执行链将被断开, 其后续的处理器方法与 postHandle()方法将无法执行。但,无论执行链执行情况怎样,只要方法栈中有方法,即执行链中只要有 preHandle()方法返回 true,就会执行方法栈中的

afterCompletion()方法。最终都会给出响应。

换一种一表现方式,也可以这样理解:

(4) 阅读源码

查看中央调度器 DispatcherServlet 的 doDispatch()方法源码:在执行处理器方法之前, 会执行处理器执行链对象 mappedHandler 的 applyPreHandle()方法。然后执行 Handler,最后执行处理器执行链对象的 applyPostHandle()方法。
applyPreHandle() 方法用于执行处理器执行链中的所有拦截器的 preHandle() 方法。
applyPreHandle()方法的返回结果取决于执行链中的每一个拦截器的 preHandle()方法。只要有一个 preHandle()方法返回 false,则其就会返回 false。然后就执行了 return;即结束了
doDispatch()方法,即该请求的处理结束。

对于处理器执行链的 applyPostHandle() 方法, 其是循环倒序执行所有拦截器的
postHandle()方法的。

那么 afterCompletion()方法是什么时候执行的呢?
在刚才的处理器执行链的 applyPreHandle() 方法中看到, 若存在任一个拦截器的
preHandle()方法返回 false,则会调用执行处理器执行链的 triggerAfterCompletion()方法,即会触发所有 afterCompletion()方法的执行。
在 doDispatch()方法中也存在一个 catch(){}语句,表示若发生异常,则会调用执行
triggerAfterCompletion()方法。

但在正常情况下,即所有的 preHandle()方法返回均为 true,且 doDispatch()方法没有异常发生的情况下,afterCompletion()方法是在视图解析器后执行的。
查看中央调度器 DispatcherServlet 的 processDispatchResult()方法源码可知,在对视图渲染过后, 会调用执行处理器执行链的 triggerAfterCompletion() 方法, 即执行所有的
afterCompletion()方法。

打开处理器执行链的 triggerAfterCompletion() 方法, 可以看到, 其对拦截器的
afterCompletion()方法的执行,也是循环倒序执行的。

权限拦截器举例

只有经过登录的用户方可访问处理器,否则,将返回“无权访问”提示。
本例的登录,由一个 JSP 页面完成。即在该页面里将用户信息放入 session 中。也就是说,只要访问过该页面,就说明登录了。没访问过,则为未登录用户。

项目:interceptor_permission。在项目 interceptor1 基础上修改。

(1) 修改 index 页面

(2) 定 义 Controller

(3) 定义 welcome 页面

(4) 定义权限拦截器
当 preHandle()方法返回 false 时,需要使用 request 或 response 对请求进行响应。

(5) 定义 fail 页面

(6) 注册权限拦截器

(7) 定义 login 页面

(8) 定义 logout 页面

(9) 项目测试
Step1:在地址栏先直接提交 system.do 请求
Step2:访问 login.jsp,进行用户登录Step3:再次提交 system.do 请求

Step4:访问 logout.jsp,进行用户退出Step5:三次提交 system.do 请求

SpringMVC 执行流程详解(掌握)


浏览器发送请求【1】

浏览器发送请求至中央调度器 DispatcherServlet.

中央调度器接收请求【2 ,3】

中央调度器 DispatcherServlet 收到请求后,首先对请求进行了一个简单判断,判断其为 简 单 请 求 , 还 是 Multipart 请 求 。 然 后 中 央 调 度 器 遍 历 每 一 个 处 理 器 映 射器
HandlerMapping,将请求交给每一个处理器映射器进行匹配。

处理器映射器对请求进行匹配【4 ,5】

处理器映射器 HandlerMapping 接收到中央调度器传递来的请求后,对请求进行解析。根据解析结果,找到与请求相对应的处理器对象,并将其包装为处理器执行链
HandlerExecutionChain 对象,返回给中央调度器。
所以处理器映射器顾名思义,就是将请求映射为处理器。

中央 调度 器接收处理器执 行链 【6 ,7 ,8】

由于处理器的种类不只一种,不同的处理器需要不同的处理器适配器 HandlerAdapter 来执行。所以中央调度器在接收到处理器映射器 HandlerMapping 发送来的处理器执行链对象 HandlerExecutionChain 后,根据处理器执行链中的处理器,查找到与之相应的处理器适配器对象 HandlerAdapter。
当然,此时中央调度器除了找到相应的处理器适配器外,还做了一个工作:执行处理器执行链中的拦截器前端方法。

处理器适配器执行处理器【9 】

中央调度器根据处理器执行链中的处理器找到相应的处理器适配器,并在执行完处理器执行链中的拦截器前端方法后,立即调用处理器适配器,让其执行处理器。

处理器被执行【10 ,11 】

处理器适配器执行处理器后,处理器将 ModelAndView 返回给处理器适配器。

处理器适配器将  ModelAndView 返回给中央调度器【12  ,13】

处理器适配器在接收到处理器返回的 ModelAndView 后,直接将 ModelAndView 返回给中央调度器。

中央调度器接收 ModelAndView 【14 ,15 】

中央调度器在接收到处理器适配器发送来的 ModelAndView 后,并不是将其作为最终的调度结果,而是首先调用执行处理器执行链中的拦截器后端方法。因为中央处理器将
ModelAndView 对象传递给了拦截器的后端方法,使后端方法可以修改 ModelAndView。处理器执行链的拦截器后端方法执行完毕后,形成最终的调度结果,所以中央调度器马
上进行调度结果的处理,对处理结果 ModelAndView 进行渲染。而这个渲染的过程,其实是中央调度器遍历所有视图解析器,并根据不同的视图类型由相应的视图解析器形成相应的视图对象的过程。

视图解析器形成视图对象【16 ,17】

视图解析器的工作很简单,将视图名称与响应目标定位对象进行绑定,形成视图对象返回给中央调度器。

中央处理器调用视图渲染方法渲染视图对象【18 ,19 】

在找到相应的视图对象后,中央处理器调用视图对象的渲染方法,真正对视图进行渲染。

视图对象进行真正渲染【20 ,21 】

这个渲染主要做了三样工作:合并数据 Model;结合视图对象中的响应目标定位对象, 准备响应对象 Response;结合合并的数据 Model 与形成的 Response 对象,形成最终的响应视图。

中央调度器对请求进行响应【22 ,23 】

在形成最终的响应视图后,中央调度器执行了收尾工作:执行处理器执行链拦截器的
afterCompletion()方法。由 afterCompletion()方法发出对请求的最终响应。

浏览器接收到响应【24 】

浏览器接收到由服务端发来的最终的响应

3.5 SpringMVC 完整执行流程图

第4章 SSM 整合开发

SSM 编程,即 SpringMVC + Spring + MyBatis 整合,是当前最为流行的 JavaEE 开发技术架构。其实SSM 整合的实质,仅仅就是将MyBatis 整合入Spring。因为SpringMVC 原本就是Spring 的一部分,不用专门整合。
SSM 整合的实现方式可分为两种:基于 XML 配置方式,基于注解方式。

搭建 SSM 开发环境(理解)

导入 Jar 包(18 个)

(1) mybatis 的 Jar 包(1 个)

(2) Spring 的 Jar 包(9 个)

(3) mybatis 与 Spring 整合 Jar 包(1 个)

(4) Jackson 的 Jar 包(3 个)

(5) 其它 Jar 包(4 个)
由于需要连接 mysql 数据库,所以导入 mysql 驱动 Jar 包。
由于连接数据库使用 Druid 数据源,所以导入 Druid 的 jar 包。

配置 web.xml

(1) 指定 Spring 配置文件的位置

注意,这里指定的 Spring 的配置文件,是整个 SSM 项目的总的容器。其中注册了数据源、
Service、Dao 的 Bean 等。这是与 SpringMVC 的中央调度器中指定的配置文件 SpringMVC.xml
是不同的。
SpringMVC.xml 中存放的仅仅是用于 SpringMVC 的“四器”注册,及 SpringMVC 相关 Bean
的注册,只是 SSM 项目中的一部分。
当然,也可以将这两个配置文件合为一个。这里将所有的配置文件均放入到了类路径下的 resources 目录中。

(2) 注册 ServletContext 监听器

注册 ServletContext 监听器的实现类 ContextLoaderListener,用于创建 Spring 容器及将创建好的 Spring 容器对象放入到 ServletContext 的域属性空间中。

(3) 注册字符集过滤器

注册字符集过滤器,用于解决请求参数中携带中文时产生乱码问题。

(4) 配置中央调度器

配置中央调度器时需要注意,SpringMVC 的配置文件名与其它Spring 配置文件名不相同。这样做的目的是 Spring 容器创建管理 Spring 配置文件中的 bean, SpringMVC 容器中负责视图层 bean 的初始。

SSM 整合注解开发(掌握)

项目:ssm
需求:完成学生注册和信息浏览。

建表 Student

使用 Student 表

新建 Web 工程

导入 jar

1) Spring 的相关 jar
2) SpringMVC 的相关 jar
3) MyBatis 相关 jar
4) MyBatis 和 Spring 的 整 合 jar 5)数据库的驱动,数据库连接池,log4j.jar

定义包,组织程序的结构。


编写配置文件

Jdbc 属性配置文件 jdbc.properties

Spring 配置文件 applicationContext.xml

Springmvc 配置文件:springmvc.xml

mybatis.xml

定义 web.xml

1)注册 ContextLoaderListener
2) 注 册 DisatcherServlet 3)注册字符集过滤器 4)同时创建 Spring 的配置文件和 SpringMVC 的配置文件

实体类 Student

Dao 接口和 sql 映射文件






Service 接口和实现类

Service 接口

Service 实现类

处理器定义

JumpController.java

StuentController.java

定义视图-首页文件--- index.jsp


注册学生页面 --- addStudent.jsp


浏览学生页面 --- liststu.jsp

页面表格

js 内 容 : 引入 JQuery
js 发起 ajax

注册成功页面--- success.jsp


注册失败页面--- fail.jsp

猜你喜欢

转载自blog.csdn.net/qq_30347133/article/details/84189536
今日推荐