Spring Web MVC

Spring Web MVC

Spring Web MVC is the original web framework built on the Servlet API and included in the Spring Framework from the very beginning. The formal name "Spring Web MVC" comes from the name of its source module spring-webmvc but it is more commonly known as " Spring MVC".
Parallel to Spring Web MVC, Spring Framework 5.0 introduced a reactive stack, web framework whose name Spring WebFlux is also based on its source module spring-webflux. This section covers Spring Web MVC. The next section covers Spring WebFlux.
For baseline information and compatibility with Servlet container and Java EE version ranges please visit the Spring Framework Wiki.

Spring MVC入门

入门教程能够参考: https://course.tianmaying.com/spring-mvc

Spring MVC是什么

Spring Web MVC(下文简称Spring MVC)和Struts2都属于表现层的框架,它 是Spring框架的一部分,咱们能够从Spring的总体结构中看得出来,以下图:

Spring MVC处理一次请求到响应的流程

快速入门

基本步骤

  1. 建立项目
  2. 导入jar包
  3. 建立springmvc.xml文件并配置Controller扫描
  4. 在web.xml文件中配置前端控制器
  5. 建立jsp文件用于测试
  6. 建立POJO
  7. 建立Controller类
  8. 进行测试
步骤详见附件
建立springmvc.xml文件并配置Controller扫描
SpringMVC自己就是Spring的子项目,对Spring兼容性很好,不须要作不少配置, 这里只配置一个Controller扫描,让Spring对页面控制层Controller进行管理
在web.xml文件中配置前端控制器
建立POJO
加入jsp页面
将jsp页面放置到WEB-INF/jsp文件夹下
建立Controller
根据jsp页面编写Controller类
  • Controller是一个普通的java类,不须要实现任何接口
  • 须要在类上添加@Controller注解,把Controller交由Spring管理
  • 在方法上面添加@RequestMapping注解,里面指定请求的url
    • 其中“.action”能够加也能够不加

Spring MVC的架构

框架结构

上图中,前端控制器(紫色)仅须要配置,处理器映射器、处理器适配器和视图解析器(灰色)是固有的组件,须要咱们编码的仅有处理器和视图(橙色)

架构处理请求的流程

  1. 用户发送请求至前端控制器DispatcherServlet
  2. DispatcherServlet收到请求调用HandlerMapping处理器映射器
  3. 处理器映射器根据请求url在Spring容器中(经过RequestMapping注解内容)寻找对应的处理器Controller(也叫后端控制器),若找到,为其生成处理器对象及处理器拦截器(若是有则生成)一并返回给DispatcherServlet
  4. DispatcherServlet经过HandlerAdapter处理器适配器调用处理器
  5. 执行处理器
  6. Controller执行完成返回ModelAndView
  7. HandlerAdapter将Controller执行结果ModelAndView返回给DispatcherServlet
  8. DispatcherServlet将ModelAndView传给ViewReslover视图解析器
  9. ViewReslover解析后返回具体View
  10. DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)
  11. DispatcherServlet响应用户
组件详细说明
如下组件一般使用框架提供实现:
DispatcherServlet:前端控制器
用户请求到达前端控制器,它就至关于mvc模式中的c,DispatcherServlet是整个流程控制的中心,由它调用其它组件处理用户的请求,DispatcherServlet的存在下降了组件之间的耦合性
HandlerMapping:处理器映射器
HandlerMapping负责根据用户请求url找到Handler即处理器,springmvc提供了不一样的映射器实现不一样的映射方式,例如:配置文件方式,实现接口方式,注解方式等
Handler:处理器
Handler 是继DispatcherServlet前端控制器的后端控制器,在DispatcherServlet的控制下Handler对具体的用户请求进行处理
因为Handler涉及到具体的用户业务请求,因此通常状况须要程序员根据业务需求开发Handler
HandlerAdapter:处理器适配器
经过HandlerAdapter对处理器进行执行,这是适配器模式的应用,经过扩展适配器能够对更多类型的处理器进行执行
下图是许多不一样的适配器,最终均可以使用usb接口链接
ViewResolver:视图解析器
View Resolver负责将处理结果生成View视图,View Resolver首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象,最后对View进行渲染将处理结果经过页面展现给用户
View:视图
Spring MVC框架提供了不少的View视图类型的支持,包括:jstlView、freemarkerView、pdfView等,咱们最经常使用的视图就是jsp
通常状况下须要经过页面标签或页面模版技术将模型数据经过页面展现给用户,须要由程序员根据业务需求开发具体的页面
说明:在Spring MVC的各个组件中, 处理器映射器 处理器适配器 视图解析器称为 Spring MVC的三大组件。
须要用户开发的组件有 HandlerView

默认加载的组件

框架默认加载的组件配置文件位置以下
默认加载的组件已通过时,应该配置推荐使用的组件,见下文配置

组件扫描器

使用组件扫描器能够省去手动一一配置Controller类的繁复操做

注解式处理器映射器

注解式处理器映射器,会对类中标记了@ResquestMapping注解的方法进行映射。根据@ResquestMapping定义的url匹配@ResquestMapping标记的方法,匹配成功后返回HandlerMethod对象到前端控制器
HandlerMethod对象内部封装了url对应的方法Method
配置
从spring3.1版本开始,废除了DefaultAnnotationHandlerMapping的使用,推荐使用RequestMappingHandlerMapping完成注解式处理器映射
在springmvc.xml配置文件中配置以下

注解式处理器适配器

注解式处理器适配器,将对标记了@ResquestMapping注解的方法进行适配
配置
从spring3.1版本开始,废除了AnnotationMethodHandlerAdapter的使用,推荐使用RequestMappingHandlerAdapter完成注解式处理器适配
在springmvc.xml配置文件中配置以下

注解驱动

直接配置处理器映射器和处理器适配器比较麻烦,可使用注解驱动来加载
SpringMVC使用<mvc:annotation-driven>自动加载RequestMappingHandlerMapping和RequestMappingHandlerAdapter
能够在springmvc.xml配置文件中使用<mvc:annotation-driven>替代注解处理器和适配器的配置

视图解析器

能够理解为路径解析器
视图解析器使用SpringMVC框架默认的InternalResourceViewResolver, 这个视图解析器支持Jsp视图解析
在springmvc.xml配置文件中配置以下
逻辑视图名须要在controller中返回ModelAndView指定,好比逻辑视图名为ItemList,则最终返回的jsp视图地址为:/ WEB-INF/jsp/itemList.jsp
最终jsp物理地址:前缀 +  逻辑视图名 + 后缀
Controller配合上述配置使用
此后编写路径时就不须要写全称了

Spring MVC整合MyBatis

目标:控制层使用Spring MVC,持久层使用MyBatis实现
详细见附件

基本步骤

  1. 导入依赖
  2. 加入配置文件
  3. 根据数据库表生成/编写POJO和映射文件并引入
  4. 测试
配置文件整合思路
Dao层
  • SqlMapConfig.xml,空文件便可,可是须要文件头
  • applicationContext-dao.xml
    • 数据库链接池
    • SqlSessionFactory对象,须要Spring和MyBatis整合包下的
    • 配置mapper文件扫描器
Service层
  • applicationContext-service.xml包扫描器,扫描@service注解的类
  • applicationContext-trans.xml配置事务
Controller层
  • springmvc.xml
    • 包扫描器,扫描@Controller注解的类
    • 配置注解驱动
    • 配置视图解析器
Web.xml文件
  • 配置Spring
  • 配置前端控制器
配置文件汇总
  • sqlMapConfig.xml
  • applicationContext-dao.xml
  • db.properties
  • applicationContext-service.xml
  • applicationContext-trans.xml
  • springmvc.xml
  • web.xml

参数绑定

若Controller须要接收参数,则涉及到Spring MVC的参数绑定
Struts2的Action类是单例的,能够直接用属性来接收请求参数,而Spring MVC的Controller不是单例的,就不能够用属性来接收请求参数了
Spring MVC的Controller绑定参数的方法是 在Controller类中对应方法添加一个形式参数,Spring MVC会将请求参数传递给对应方法

Spring MVC默认支持的参数类型

  • HttpServletRequest:经过request对象获取请求信息
  • HttpServlcetResponse:经过response处理响应信息
  • HttpSession:经过session对象获得session中存放的对象

经过这种方式也能够获取请求参数并封装响应信息传递到前台,但不建议使用

Model/ModelMap

Model
除了ModelAndView之外,还可使用Model来向页面传递数据, Model是一个接口,在参数里直接声明model便可
若是使用Model则能够不使用ModelAndView对象,Model对象能够向页面传递数据,View对象则可使用String返回值替代
不论是Model仍是ModelAndView,其 本质都是使用Request对象向jsp传递数据
ModelMap
ModelMap是Model接口的实现类,也能够经过ModelMap向页面传递数据
使用Model和ModelMap的效果同样,若是直接使用Model,Spring MVC会实例化ModelMap
也可使用返回String的方式来设定视图

绑定简单类型

当请求的参数名称和处理器形参 名称一致时会将请求参数与形参进行绑定
参数绑定支持的简单类型
  • 整形:Integer、int
  • 字符串:String
  • 单精度:Float、float
  • 双精度:Double、double
  • 布尔型:Boolean、boolean
    • 对于布尔类型的参数,请求的参数值为true/false或者1/0
    • 如:url为http://localhost:8080/xxx.action?id=2&status=false,处理器方法为public String editItem(Model model,Integer id,Boolean status) 
@RequestParam注解
@RequestParam注解经常使用于处理简单类型的绑定
其用法以下:
  • value:参数名字,即入参的请求参数名字
    • 如value=“itemId”表示请求的参数区中的名字为itemId的参数的值将传入
  • required:是否必须,默认是true,表示请求中必定要有相应的参数,不然将报错
  • defaultValue:默认值,表示若是请求中没有同名参数时的默认值
示例:

绑定POJO

若是请求参数较多,或提交的表单中内容不少时,可使用简单类型接收数据,但更推荐使用POJO对象接收数据
使用方法:
POJO类中的属性应该与input内name属性一致
如图

解决修改post提交数据乱码问题

须要在web.xml文件中添加Spring的编码过滤器相关配置
另外,对于get请求中文参数出现乱码的解决方法有两个
绑定包装POJO
使用包装POJO接收参数
建立包装POJO类,修改前台页面,input的name属性应该加上被包装的POJO名称前缀,以下

自定义参数绑定

Spring MVC提供数据类型自定义转换功能,能够经过手动编写转换器转换规则来转换前台传入的数据类型,如:字符串按必定规则转换成日期
需求
在商品修改页面能够修改商品的生产日期,而且根据业务需求自定义日期格式。
需求分析
因为日期数据有不少种格式,Spring MVC没办法把字符串转换成日期类型,因此须要自定义参数绑定
前端控制器接收到请求后,找到注解形式的处理器适配器,对RequestMapping标记的方法进行适配,并对方法中的形参进行参数绑定
能够在Spring MVC处理器适配器上自定义转换器Converter进行参数绑定
通常使用<mvc:annotation-driven/>注解驱动加载处理器适配器,能够在此标签上进行配置
在set标签内能够配置多个Converter
Converter代码以下

Spring MVC与Struts2的对比

  • Spring MVC的入口是一个servlet即前端控制器,而struts2入口是一个filter过滤器
  • Spring MVC基于方法开发(一个url对应一个方法),请求参数传递到方法的形参,能够设计为单例或多例(建议单例),Struts2是基于类开发,传递参数是经过类的属性,只能设计为多例
  • Struts2采用值栈存储请求和响应的数据,经过OGNL存取数据Spring MVC经过参数解析器是将request请求内容解析,并给方法形参赋值,将数据和视图封装成ModelAndView对象,最后又将ModelAndView中的模型数据经过request域传输到页面(Jsp视图解析器默认使用jstl)

Spring MVC进阶

高级参数绑定

绑定数组

能够在Controller的方法中添加String[]类型的形参,也可使用POJO的String[]类型属性接收数组类型的请求参数
以下
绑定List
请求参数能够是存放多个POJO的List对象,经过在QueryVo中增长List<*>类型的属性能够接收List类型的参数
要求:jsp页面中input标签的name属性应该为List类型的属性名称 + 下标 + 元素属性
以下
实际前端HTML页面代码应该以下
注意
List类型不能直接由Controller中方法的形参接收,必须由POJO来间接接收List类型的参数
*关于foreach遍历标签
  • ${current}:当前此次迭代的(集合中的)项
  • ${status.first}判断当前项是否为集合中的第一项,返回值为true或false
  • ${status.last}判断当前项是否为集合中的最后一项
  • varStatus属性经常使用参数总结下:
    • ${status.index}输出行号,从0开始。
    • ${status.count}输出行号,从1开始。
    • ${status.next}后一项,返回值为true或false
    • begin、end、step分别表示:起始序号,结束序号,步长

@RequestMapping注解

经过@RequestMapping注解能够定义不一样的处理器映射规则
又如下的功能

设置URL路径映射

用法:
  • 设置单个路径映射
    • @RequestMapping(value="/item")
      • 或当仅须要配置value属性时,能够省略value=:@RequestMapping("/item")
  • value值的类型是数组,能够将多个URL映射到同一个方法中
    • @RequestMapping(value = { "itemList", "itemListAll" })

设置通用请求前缀

在class类名前添加@RequestMapping(url)指定通用请求前缀,能够限制此类下的全部方法请求url必须以请求前缀开头
可使用此方法来对URL进行分类管理
以下
此后访问这个Controller的特定方法的URL应该如:*/item/itemList.action

设置限定的请求方法

能够限定请求进入这个Controller的方法(post/get)
使用RequestMethod属性配置特定请求可入
其类型也是一个数组
  • 限定GET方法@RequestMapping(method = RequestMethod.GET)
    • 若是经过POST访问则报错:HTTP Status 405 - Request method 'POST' not supported
  • 限定POST方法:@RequestMapping(method = RequestMethod.POST)
    • 若是经过GET访问则报错:HTTP Status 405 - Request method 'GET' not supported
  • GET和POST都可:@RequestMapping(method = {RequestMethod.GET,RequestMethod.POST})
  • DELETE等等其余方法(国内少用)

Controller中方法的返回值

Controller中方法的返回值有如下几种
  • 返回ModelAndView
  • 返回void
  • 返回String

返回ModelAndView

Controller中方法中定义ModelAndView对象并返回,对象中可添加model数据,指定view视图
不推荐使用这种方式

返回void

在Controller方法形参上能够定义request和response,使用request或response指定响应结果来处理、控制请求,相似servlet开发
这种方式适合处理ajax的请求,由于处理ajax请求只须要返回(响应)数据,不须要返回视图,直接使用response对象返回json数据便可

返回String

携带数据
使用Model对象来携带数据传递
逻辑视图名
Controller方法返回字符串能够 指定逻辑视图名经过视图解析器解析为物理视图地址
Redirect重定向
Contrller方法返回字符串能够重定向到一个url地址
用法:在返回的字符串前加上 redirect: 字段
如:return "redirect:/itemEdit.action";
若带参数重定向:return "redirect:/itemEdit.action?itemId=" + item.getId();
Forward转发
某个Controller方法执行后继续执行另外一个Controller方法
用法:相似重定向,加上 forward: 字段
如:return "forward: /itemEdit.action";
官方推荐使用返回String的方式开发Controller,这种方式能够将数据和视图分离、解耦,符合MVC架构的思想

异常处理器

Spring MVC在处理请求过程当中出现异常信息将交由 异常处理器进行处理, 自定义异常处理器能够编写代码实现系统的异常处理逻辑

异常处理思路

系统中异常包括两类:预期异常和运行时异常RuntimeException,前者经过捕获异常从而获取异常信息,后者主要经过规范代码开发、测试经过手段减小运行时异常的发生
系统的Dao、Service、Controller出现都经过throws Exception向上抛出,最后由Spring MVC前端控制器交由异常处理器进行异常处理,以下图

自定义异常类

为了区别不一样的异常,一般根据异常类型进行区分,能够自定义一个异常类

自定义异常处理器

能够自定义一个异常处理器按照编写的逻辑处理接收到的异常
异常处理器要实现HandlerExceptionResolver接口,并重写resolveException方法
其中resolveException方法的参数意义以下
  • HttpServletRequest request:当前请求对象
  • HttpServletResponse response:当前响应对象
  • Object obj:发生异常的位置所在(异常发生在哪一个类)
  • Exception e:当前发生的异常对象

配置异常处理器

在springmvc.xml文件配置

引入错误页面

Spring MVC异常处理基本开发思路

Spring MVC已经提供好了HandlerExceptionResolver接口供开发者实现,要处理异常:
  1. 首先编写自定义异常处理器,实现HandlerExceptionResolver接口
    1. 异常处理器内部编写异常处理逻辑
    2. 定义发生异常时转发到什么页面
  2. 配置异常处理器到Spring容器中
  3. 引入错误页面并配置发生异常时转发

上传图片

上传图片的功能其实就是接收图片/文件请求参数

上传图片的步骤

在Tomcat上配置虚拟目录
在Tomcat下conf/server.xml中添加<Context docBase="D:\develop\upload\temp" path="/pic" reloadable="false"/>
在IDEA配置Tomcat的虚拟目录以下图
访问对应地址(加上具体资源名称和后缀)便可访问本地目录下的图片

这步的目的是为了让前台页面经过上述设置的虚拟目录访问到这个图片( 毋需经过本地目录访问图片了
 
导入jar包依赖
  • commons-fileupload-1.2.2.jar
  • commons-io-2.4.jar
配置文件上传解析器
在springmvc.xml中配置文件上传解析器
文件上传解析器配置的bean的id必须为multipartResolver
修改jsp页面
在jsp页面中form标签添加enctype属性,值为multipart/form-data
在Controller对应方法中添加图片上传逻辑
按照这个步骤开发的文件上传功能能够将上传的文件(目录)与发布的war包分离,互相独立不影响

JSON数据交互

@RequestBody注解

JSON  -->  Java对象
@RequestBody注解用于读取HTTP 请求的内容(字符串),而后能够经过Spring MVC提供的 HttpMessageConverter接口将读到的内容(json数据)转换为Java对象并绑定到Controller方法的参数上

@ResponseBody

Java对象 --> JSON
@ResponseBody注解用于Controller中的方法返回的对象,能够经过Spring MVC提供的HttpMessageConverter接口转换为指定格式的数据如:json,xml等,经过Response响应给客户端

实现JSON数据交互的步骤

引入依赖的jar包
Gson/Jackson/FastJson/等等
此处使用Jackson
编写Controller
安装浏览器的测试工具
如Postman等
测试
*若不使用注解驱动(annotation-driven)则须要手动配置JSON转换器
若是不使用注解驱动<mvc:annotation-driven/>,就须要给处理器适配器配置json转换器, 参考以前学习的自定义参数绑定

RESTful支持

RESTful简介

RESTful就是一个 资源定位资源操做风格
RESTful不是标准也不是协议,只是一种风格。基于这个风格设计的软件能够更简洁,更有层次,更易于实现缓存等机制
资源:互联网全部的事物均可以被抽象为资源
资源操做:使用:POST、DELETE、PUT、GET,使用不一样方法对资源进行操做, 分别对应:添加、删除、修改、查询
经过请求method的不一样来区分此次请求要怎样操做资源

Spring MVC支持的RESTful

经过@RequestMapping注解能够识别RESTful风格的请求
  • 其中{*}为占位符
  • 使用@PathVariable注解能够获取URL上的数据
  • 若是@RequestMapping中表示为"item/{id}",id和形参名称一致,@PathVariable不用指定名称,若是不一致,例如"item/{ItemId}"则须要指定名称@PathVariable("itemId")
  • @PathVariable是获取url上数据的,而@RequestParam获取请求参数的(包括post表单提交)
  • 若是加上@ResponseBody注解,就不会走视图解析器,不会返回页面,目前返回的json数据,若是不加,就走视图解析器,返回页面

拦截器

Spring Web MVC的处理器拦截器 相似于Servlet开发中的过滤器Filter过滤器,用于对处理器进行 预处理后处理

拦截器定义

拦截器内能够定义三个方法,分别对应三个时间点
  • preHandle:执行Controller方法前
  • postHandle:执行Controller方法后
  • afterCompletion:页面渲染后
拦截器须要实现HandlerInterceptor接口

拦截器配置

在spirngmvc.xml中配置拦截器

测试

多个拦截器的拦截规则

详见附件
配置两个拦截器HandlerInterceptor1和HandlerInterceptor2
正常运行流程
中断运行流程
HandlerInterceptor1的preHandler方法返回false,HandlerInterceptor2返回true,运行流程以下:
HandlerInterceptor1..preHandle..
从日志看出第一个拦截器的preHandler方法返回false后第一个拦截器只执行了preHandler方法,其它两个方法没有执行,第二个拦截器的全部方法不执行,且Controller也不执行了
HandlerInterceptor1的preHandler方法返回true,HandlerInterceptor2返回false,运行流程以下:
HandlerInterceptor1..preHandle..
HandlerInterceptor2..preHandle..
HandlerInterceptor1..afterCompletion..
从日志看出第二个拦截器的preHandler方法返回false后第一个拦截器的postHandler没有执行,第二个拦截器的postHandler和afterCompletion没有执行,且 Controller也不执行了
结论
  • preHandle按拦截器配置顺序调用
  • postHandle按拦截器配置逆序调用
  • afterCompletion按拦截器定义逆序调用
  • postHandler在拦截器链内全部拦截器返true成功才调用
  • afterCompletion只有同一个拦截器定义的preHandle返回true才调用
preHandle和postHandle相似俄罗斯套娃

拦截器应用示例

需求
  1. 有一个登陆页面,须要写一个Controller访问登陆页面
  2. 登陆页面有一提交表单的动做。须要在Controller中处理。
    1. 判断用户名密码是否正确(在控制台打印)
    2. 若是正确,向session中写入用户信息(写入用户名username)
    3. 跳转到商品列表
  3. 拦截器。
    1. 拦截用户请求,判断用户是否登陆(登陆请求不能拦截)
    2. 若是用户已经登陆则放行
    3. 若是用户未登陆,跳转到登陆页面
详细开发细节见附件
细节
只拦截访问商品的URL请求,修改ItemController,让全部的请求都必须以item开头
配置拦截器时使用如下方式拦截对/item/开头的URL的请求

附件列表

相关文章
相关标签/搜索