SpringMVC
概念
- SpringMVC 是一种基于 Java 的实现 MVC 设计模型的请求驱动类型的轻量级 Web 框架,属于 Spring FrameWork 的后续产品,已经融合在 Spring Web Flow 里面。Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块。
- 使用 Spring 可插入的 MVC 架构,从而在使用 Spring 进行 WEB 开发时,可以选择使用 Spring的 Spring MVC 框架或集成其他 MVC 开发框架,如 Struts1(现在一般不用),Struts2 等
- SpringMVC 已经成为目前最主流的 MVC 框架之一,并且随着 Spring3.0 的发布,全面超越 Struts2,成为最优秀的 MVC 框架。
- 它通过一套注解,让一个简单的 Java 类成为处理请求的控制器,而无须实现任何接口。同时它还支持RESTful 编程风格的请求。
入门
执行步骤
- 第一步:环境搭建
1 | <properties> |
- 第二步:在web.xml配置文件中核心控制器DispatcherServlet
1 | <servlet> |
- 第三步:编写springmvc.xml的配置文件
1 | "1.0" encoding="UTF-8" xml version= |
- 第四步:编写index.jsp和HelloController控制器类
- 第五步:在WEB-INF目录下创建pages文件夹,编写success.jsp的成功页面
- 第六步:启动Tomcat服务器,进行测试
执行流程
- 当启动Tomcat服务器的时候,因为配置了
load-on-startup
标签,所以会创建DispatcherServlet
对象,
就会加载springmvc.xml
配置文件 - 开启了注解扫描,那么
HelloController
对象就会被创建 - 从index.jsp发送请求,请求会先到达
DispatcherServlet
核心控制器,根据配置@RequestMapping
注解
找到执行的具体方法 - 根据执行方法的返回值,再根据配置的视图解析器,去指定的目录下查找指定名称的JSP文件
- Tomcat服务器渲染页面,做出响应
组件分析
- 前端控制器(DispatcherServlet);用户请求到达前端控制器,它就相当于 mvc 模式中的 c,dispatcherServlet 是整个流程控制的中心,由它调用其它组件处理用户的请求,dispatcherServlet 的存在降低了组件之间的耦合性。
- 处理器映射器(HandlerMapping):HandlerMapping 负责根据用户请求找到 Handler 即处理器,SpringMVC 提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等
- 处理器(Handler):它就是我们开发中要编写的具体业务控制器。由 DispatcherServlet 把用户请求转发到 Handler。由Handler 对具体的用户请求进行处理。
- 处理器适配器(HandlAdapter):通过 HandlerAdapter 对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。
- 视图解析器(View Resolver):View Resolver 负责将处理结果生成 View 视图,View Resolver 首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成 View 视图对象,最后对 View 进行渲染将处理结果通过页面展示给用户。
- 视图(View):SpringMVC 框架提供了很多的 View 视图类型的支持,包括:jstlView、freemarkerView、pdfView等。我们最常用的视图就是 jsp。一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由程序员根据业务需求开发具体的页面。
<mvc:annotation-driven>
说明
- 在SpringMVC的各个组件中,处理器映射器、处理器适配器、视图解析器称为 SpringMVC 的三大组件。
- 使用
<mvc:annotation-driven>
自动加载RequestMappingHandlerMapping
(处理映射器) 和RequestMappingHandlerAdapter
(处理适配器),可用在SpringMVC.xml
配置文件中使用<mvc:annotation-driven>
替代注解处理器和适配器的配置。
1 | <!-- 上面的标签相当于 如下配置--> |
@RequestMapping注解
RequestMapping
注解的作用是建立请求URL和处理方法之间的对应关系RequestMapping
注解可以作用在方法和类上- 作用在类上:第一级的访问目录
- 作用在方法上:第二级的访问目录
- 细节:路径可以不编写
/
表示应用的根目录开始 - 细节:
${ pageContext.request.contextPath}
也可以省略不写,但是路径上不能写/
RequestMapping
的属性- path:指定请求路径的url
- value :value属性和path属性是一样的
- method: 指定该方法的请求方式
- headers :发送的请求中必须包含的请求头
- params :指定限制请求参数的条件。它支持简单的表达式。要求请求参数的 key 和 value 必须和配置的一模一样.
- 例如:
- params = {“accountName”},表示请求参数必须有 accountName
- params = {“moeny!100”},表示请求参数中 money 不能是 100。
- 例如:
请求参数的绑定
绑定的机制
- 绑定机制
- 表单提交的数据都是k=v格式的 username=haha&password=123
- SpringMVC的参数绑定过程是把表单提交的请求参数,作为控制器中方法的参数进行绑定的
- 要求:提交表单的name和参数的名称是相同的
- 支持的数据类型
- 基本数据类型和字符串类型
- 实体类型(JavaBean)
- 集合数据类型(List、map集合等)
支持的数据类型
- 基本数据类型:基本类型和String
- 提交表单的name和参数的名称是相同的
- 区分大小写
- POJO类型参数:实体类以及关联的实体类
- 提交表单的name和JavaBean中的属性名称需要一致
- 如果一个JavaBean类中包含其他的引用类型,那么表单的name属性需要编写成:
对象.属性
例如:address.name
- 数组和集合类型参数:包括List结构和Map结构的集合
- JSP页面编写方式:
list[0].属性
- JSP页面编写方式:
请求参数中文乱码
- 在web.xml中配置Spring提供的过滤器类
1 | <!--配置解决中文乱码的过滤器--> |
- 注意如果出现控制台中文乱码,检查当前编码输出格式:
System.out.println(System.getProperty("file.encoding"));
自定义类型转换器
- 定义一个类,实现
Converter
接口,该接口有两个泛型 - 在 spring 配置文件中配置类型转换器。
- 在
annotation-driven
标签中引用配置的类型转换服务
1 | <!--配置自定义类型转换器--> |
使用 ServletAPI 对象作为方法参数
- 直接写在Controller控制的方法参数中使用
1 | "/testServletAPI") ( |
常用注解
@RequestParam
- 作用:把请求中指定名称的参数给控制器中的形参赋值。
- 属性:
- value:请求参数中的名称。
- required:请求参数中是否必须提供此参数。默认值:true。表示必须提供,如果不提供将报错。
- 示例代码:
1 | "/hello") (path= |
@RequestBody
- 作用:用于获取请求体内容。直接使用得到是
key=value&key=value..
结构的数据。get请求方式不适用。 - 属性:
- required:是否必须有请求体。默认值是:true。当取值为
true
时,get请求方式会报错。如果取值为false
,get请求得到是null
。
- required:是否必须有请求体。默认值是:true。当取值为
- 示例代码:
1 | "/hello") (path= |
@ResponseBody
- 作用:将controller的方法返回的对象通过适当的转换器转换为指定的格式之后,写入到response对象的body区,通常用来返回JSON数据或者是XML数据
- 注意:在使用此注解之后不会再走试图处理器,而是直接将数据写入到输入流中,他的效果等同于通过response对象输出指定格式的数据。
@PathVariable
- 作用:拥有绑定url中的 的。例如:url中有/delete/{id},{id}就是占位符
- 属性:
- value:指定url中的占位符名称
- Restful风格的URL
- 请求路径一样,可以根据不同的请求方式去执行后台的不同方法
- restful风格的URL优点
- 结构清晰
- 符合标准
- 易于理解
- 扩展方便
- 示例代码:
1 | "/hello/{id}") (path= |
@RequestHeader
- 作用:获取指定请求头的值
- 属性:
- value:请求头的名称
- 示例代码:
1 | "/hello") (path= |
@CookieValue
- 作用:用于获取指定cookie的名称的值
- 属性:
- value:cookie的名称
- 示例代码:
1 | "/hello") (path= |
@ModelAttribute
- 作用:
- 出现在方法上:表示当前方法会在控制器方法执行前先执行
- 出现在参数上:获取指定的数据给参数赋值
- 应用场景:
- 当提交表单数据不是完整的实体数据时,保证没有提交的字段使用数据库原来的数据
- 示例代码:
1 | /** |
@SessionAttribute
- 作用:用于多次执行控制器方法间参数共享,只能作用在类上
- 属性:
- value:指定存入属性的名称
- Model 是 spring 提供的一个接口,该接口有一个实现类 ExtendedModelMap
- 示例代码:
1 |
|
响应数据和结果视图
返回值分类
String
- Controller方法返回字符串可以指定逻辑视图的名称,根据视图解析器为物理视图的地址。
- 示例代码:
1 | /** |
Void
- 如果控制器的方法返回值编写成void,执行程序报404的异常,默认查找JSP页面没有找到。
- 默认会跳转到
@RequestMapping(value="/initUpdate") initUpdate
的页面。 - 可以使用请求转发或者重定向或者直接响应跳转到指定的页面
- 示例代码:
1 | /** |
ModelAndView
- ModelAndView对象是Spring提供的一个对象,可以用来调整具体的JSP视图
- 示例代码:
1 | /** |
转发和重定向
- 使用forward关键字进行请求转发
- 使用redirect关键字进行重定向
示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14/**
* 使用关键字的方式进行转发或重定向
* @return
*/
"/testForwardOrRedirect") (
public String testForwardOrRedirect(){
System.out.println("testForwardOrRedirect方法执行了");
//请求的转发
return "forward:/WEB-INF/pages/success.jsp";
//重定向,框架默认添加了项目名称request.getContextPath()
return "redirect:/index.jsp";
}
ResponseBody响应json数据
DispatcherServlet会拦截到所有的资源,导致一个问题就是静态资源(img、css、js)也会被拦截到,从而不能被使用。解决问题就是需要配置静态资源不进行拦截,在springmvc.xml配置文件添加如下配置
使用webjars,进行如下配置(WebJars是打包到JAR(Java Archive)文件中的客户端Web库(例如jQuery和Bootstrap)。)
1 | <!--前端控制器 设置静态资源不过滤--> |
- location:表示webapp目录下(即服务器根目录)的static包下的所有文件
- mapping:表示以
/static
开头的所有请求路径,如/static/a
或者/static/a/b
; - 作用:DispatcherServlet不会拦截以
/static
开头的所有请求路径,并当作静态资源交由Servlet处理;
1 | <!-- 设置静态资源不过滤 --> |
异步请求
1 | <%--引入jquery资源--%> |
使用@RequestBody
注解把json的字符串转换为javabean对象
- json字符串和JavaBean对象互相转换的过程中,需要使用jackson的jar包
1 | <!--jackson将json数据封装到javabean--> |
使用@ResponseBody
注解把javabean对象转换为json字符串
1 | /** |
SpringMVC实现文件上传
文件上传前提
- form表单的enctype(表单请求正文的类型)取值必须是:multipart/form-data(默认值是:application/x-www-form-urlencoded)
- method属性取值必须是:POST
- 提供一个文件选择域:
<input type="file"/>
- 借助第三方组件实现文件上传:
Commons-fileupload
传统方式文件上传
使用 Commons-fileupload 组件实现文件上传,需要导入该组件相应的支撑 jar 包:Commons-fileupload 和commons-io。commons-io 不属于文件上传组件的开发 jar 文件,但Commons-fileupload 组件从 1.1 版本开始,它工作时需要 commons-io 包的支持。
导入文件上传的Commons组件
1 | <!--文件上传--> |
- 文件上传
1 | /** |
SpringMVC传统方式文件上传
SpringMVC框架提供了MultipartFile对象,该对象表示上传的文件,要求变量名称必须和表单file标签的name属性名称相同。
原理:上传->前端控制器->文件解析器->前端控制器->Controller文件上传方法(参数绑定MultipartFile)
配置文件解析器
1 | <!--配置文件解析器对象 要求Id必须是multipartResolver--> |
- 代码:
1 | /** |
SpringMVC跨服务器方式文件上传
- 在实际开发中,我们会有很多处理不同功能的服务器
- 应用服务器:负责部署我们的应用
- 数据库服务器:运行我们的数据库
- 缓存和消息服务器:负责处理大并发访问的缓存和消息
- 文件服务器:负责存储用户上传文件的服务器。
SpringMVC的异常处理
- 异常处理思路
- Controller调用Service,Service调用Dao,异常都是向上抛出的,最终由DispatcherServlet招异常处理器进行异常的处理
- SpringMVC的异常处理
异常处理
- 第一步:自定义异常类
1 | /** |
- 第二步:自定义异常处理器
1 | /** |
- 第三步:配置异常处理器
1 | <!--配置异常处理器--> |
SpringMVC中的拦截器
- Spring MVC 的处理器拦截器类似于 Servlet 开发中的过滤器 Filter,用于对处理器进行预处理和后处理。
- 过滤器是 servlet 规范中的一部分,任何 java web 工程都可以使用。
- 拦截器是 SpringMVC 框架自己的,只有使用了 SpringMVC 框架的工程才能用。
- 过滤器在 url-pattern 中配置了/*之后,可以对所有要访问的资源拦截。
- 拦截器它是只会拦截访问的控制器方法,如果访问的是 jsp,html,css,image 或者 js 是不会进行拦截的。
- 自定义拦截器:实现
HandlerInterceptor
接口
拦截器的实现
第一步:编写拦截器类:实现HandlerInterceptor接口
- preHandle方法是controller方法执行前拦截的方法
- 可以使用request或者response跳转到指定的页面
- return true放行,执行下一个拦截器,如果没有拦截器,执行controller中的方法。
- return false不放行,不会执行controller中的方法。
- postHandle是controller方法执行后执行的方法,在JSP视图执行前。
- 可以使用request或者response跳转到指定的页面
- 如果指定了跳转的页面,那么controller方法跳转的页面将不会显示。
- afterCompletion方法是在JSP执行后执行
- request或者response不能再跳转页面了
- preHandle方法是controller方法执行前拦截的方法
第二步:配置拦截器
1 | <!--配置拦截器--> |