1、SpringMVC概述
1.1、SpringMVC概念
SpringMVC也叫Spring web mvc。是Spring内置的一个MVC框架,在Spring3.0后发布。SpringMVC框架解决了WEB开发中常见的问题(参数接收、文件上传、表单验证等等),而且使用简单,与Spring无缝集成。支持RESTful风格的URL请求,采用了松耦合可插拔组件结构,比其他MVC框架更具扩展性和灵活性。
1.2、SpringMVC原理
在没有使用SpringMVC之前我们都是使用Servlet在做Web开发。但是使用Servlet开发在接收请求参数,数据共享,页面跳转等操作相对比较复杂。servlet是java进行web开发的标准,既然springMVC是对servlet的封装,那么很显然SpringMVC底层就是Servlet,SpringMVC就是对Servlet进行深层次的封装。
1.3、SpringMVC的优势
1、基于MVC架构,功能分工明确。解决页面代码和后台代码的分离。
2、简单易用。SpringMVC也是轻量级的,jar很小。不依赖的特定的接口和类就可以开发一个注解的SpringMVC项目
3、作为Spring框架一部分,能够使用Spring的Ioc和AOP。方便正合MyBatis,Hiberate,JPA等其他框架。
4、springMVC的注解强大易用
2、MVC模式回顾
模型1:jsp+javabean模型--在jsp页面中嵌入了大量的java代码
模型2:jsp+servlet+javabean模型--jsp页面将请求发送给servlet,有servlet调用javabean,再有servlet将指定jsp页面响应给用户。
模型2一般就是现在的MVC模式,也是我们一直使用的。
Model-View-Controller: 模型-视图-控制器
Model:模型层javaBean 负责数据访问和业务处理 dao service pojo
View: 视图 JSP技术 负责收集和展示数据
Controller:控制器 servlet技术 中间调度
控制器的工作:
1、接收客户端的请求(包括请求中携带的数据)
2、处理请求:调用后台的模型层中的业务逻辑
3、页面导航:处理完毕给出响应:JSP页面
3、MVC容器
当Spring和SpringMVC同时出现时,项目中会存在两个容器,一个是Spring容器,而另外一个则是SpringMVC容器,Spring容器通过COntextLoaderListener来加载,SpringMVC容器则通过DispatherServlet来加载:
如图所示:
- ContextLoaderListener 初始化的上下文加载的 Bean 是对于整个应用程序共享的,不管是使用什 么表现层技术,一般如 dao层、service层 的bean;
- DispatcherServlet 初始化的上下文加载的 bean 是只对 Spring Web MVC 有效的 bean,如 Controller、HandlerMapping、HandlerAdapter 等等,该初始化上下文应该只加载 Web相关组 件。
1、Spring容器不能扫描所有的Bean,当用户发送请求到服务端后,会寻找前端控制器DispatcherServlet去处理,只在SpringMVC容器中找,所以Controller必须在SpringMVC容器中扫描。
2、Spring可以扫描所有Bean,可以在SpringMVC容器中扫描所有的Bean。但是实际开发中不会这么做,原因如下:
(1)为了方便配置文件管理
(2)未来在SSM框架中,要写的配置内容有很多,一般会根据功能分开编写
4、SpringMVC工作流程
4.1、工作流程分析
(1)用户通过浏览器发送请求到前端控制器DispatcherServlet。
(2)前端控制器直接将请求转给处理器映射器HandleMapping。
(3)处理器映射器HandleMapping会根据请求,找到负责处理该请求的处理器,并将其封装为处理器 执行链HandlerExecutionChina后返回给前端控制器DispatcherServlet。
(4)前端控制器DispatcherServlet根据处理器执行链中的处理器,找到能够执行该处理器的处理器适 配器HandlerAdaptor。
(5)处理器适配器HandlerAdaptor调用执行处理器Controller。
(6)处理器Controller将处理结果及要跳转的视图封装到一个对象 ModelAndView 中,并将其返回给处理器适配器HandlerAdaptor。
(7)处理器适配器直接将结果返回给前端控制器DispatcherServlet。
(8)前端控制器调用视图解析器,将 ModelAndView 中的视图名称封装为视图对象。
(9)视图解析器ViewResolver将封装了的视图View对象返回给前端控制器DispatcherServlet.
(10)前端控制器DispatcherServlet调用视图对象,让其自己进行渲染,即进行数据填充,形成响应对 象。
(11)前端控制器响应浏览器。
4.3、SpringMVC组件
1.DispatcherServlet:前端控制器,也称为中央控制器或者核心控制器。
用户请求的入口控制器,它就相当于 mvc 模式中的c,DispatcherServlet 是整个流程控制的中心,相当 于是 SpringMVC 的大脑,由它调用其它组件处理用户的请求,DispatcherServlet 的存在降低了组件之 间的耦合性。SpringMVC框架提供的该核心控制器需要我们在web.xml文件中配置。
2.HandlerMapping:处理器映射器
HandlerMapping也是控制器,派发请求的控制器。我们不需要自己控制该类,但是他是springmvc运 转历程中的重要的一个控制器。 HandlerMapping负责根据用户请求找到 Handler 即处理器(也就是我 们所说的 Controller),SpringMVC 提供了不同的映射器实现不同的映射方式,例如:配置文件方式, 实现接口方式,注解方式等,在实际开发中,我们常用的方式是注解方式。
3.Handler:处理器
Handler 是继 DispatcherServlet 前端控制器的后端控制器,在DispatcherServlet 的控制下 Handler 对 具体的用户请求进行处理。由于 Handler 涉及到具体的用户业务请求,所以一般情况需要程序员根据业 务需求开发 Handler。(这里所说的 Handler 就是指我们的 Controller)
4.HandlAdapter:处理器适配器
通过 HandlerAdapter 对处理器进行执行,这是适配器模式的应用,通过扩展处理器适配器,支持更多 类型的处理器,调用处理器传递参数等工作。
5.ViewResolver:视图解析器
ViewResolver 负责将处理结果生成 View 视图,ViewResolver 首先根据逻辑视图名解析成物理视图名 称,即具体的页面地址,再生成 View 视图对象,最后对 View 进行渲染将处理结果通过页面展示给用 户。 SpringMVC 框架提供了很多的 View 视图类型,包括:jstlView、freemarkerView、pdfView 等。 一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由程序员根据业务 需求开发具体的页面
5、@RequestMapping注解
5.1、@RequestMapping出现的位置
@RequestMapping 注解定义了处理器对于请求的映射规则。该注解可以定义在类上,也可以定义在 方法上,但是含义不同。
一个@Controller 所注解的类中,可以定义多个处理器方法。当然,不同的处理器方法所匹配的 URI 是 不同的。这些不同的 URI 被指定在注解于方法之上的@RequestMapping 的value 属性中。但若这些请 求具有相同的 URI 部分,则这些相同的 URI,可以被抽取到注解在类之上的RequestMapping 的 value 属性中。此时的这个 URI 表示模块的名称。URI 的请求是相对于 Web 的根目录。在类的级别上的注解 会将一个特定请求或者请求模式映射到一个控制器之上。之后你还可以另外添加方法级别的注解来进一 步指定到处理方法的映射关系。
5.2、指定请求提交方式
@RequestMapping的method属性,用来对被注解方法所处理请求的提交方式进行限制,即只有满足method 属性指定的提交方式的请求,才会执行该被注解方法。
Method 属性的取值为 RequestMethod 枚举常量。常用的为 RequestMethod.GET 与 RequestMethod.POST,分别表示提交方式的匹配规则为 GET 与 POST 提交。
常用提交方式:
5.3、补充url-pattern解析
5.3.1、 url-pattern解析
在web.xml配置SpringMVC的前端控制器时有这个节点。这个节点中的值一般有两种写法:
1、*.do
在没有特殊要求的情况下,SpringMVC 的前端控制器 DispatcherServlet 的常使用后辍匹配方
式,可以写为*.do 或者 *.action, *.mvc 等。
2、/
可以写为/,但是 DispatcherServlet 会将向静态内容--例如.css、.js、图片等资源的获取请求 时,也会当作是一个普通的 Controller 请求。前端控制器会调用处理器映射器为其查找相应的处理器。肯 定找不到啊,所以所有的静态资源获取请求也均会报 404 错误。
5.3.2、静态资源访问
如果的值配置为/后,静态资源可以通过以下两种方法解决。
5.3.2.1、使用< mvc:default-servlet-handler/>
在springmvc的配置文件中添加如下内容:
< mvc:default-servlet-handler/>
5.3.2.2、使用**< mvc:resources/ >**
在spring的配置文件中添加如下内容:
<mvc:resources location="/images/" mapping="/images/**" />
在 Spring3.0 版本后,Spring 定义了专门用于处理静态资源访问请求的处理器 ResourceHttpRequestHandler。并且添加了< mvc:resources/ >标签,专门用于解决静态资源无法访问题。
6、请求参数中文乱码
对于前面所接收的请求参数,若含有中文,则会出现中文乱码问题。Spring 对于请求参数中的中文乱码 问题,给出了专门的字符集过滤器CharacterEncodingFilter 类。如图所示。
6.1、乱码解决方案
在 web.xml 中注册字符集过滤器,推荐将该过滤器注册在其它过滤器之前。因为过滤器的执行是按照其注册顺序进行的。
在web.xml配置文件直接注册字符集
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceRequestEncoding</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
6.2、解决方案原理
7、处理方法的返回值
使用@Controller 注解的处理器的处理器方法,其返回值常用的有四种类型:
1、ModelAndView
2、String
3、返回自定义类型对象
4、无返回值void
根据实际的业务选择不同的返回值。
7.1、返回ModelAndView
如果是前后端部分开的开发,大部分情况下,我们返回ModelAndView,即数据模型+视图:
控制器ResultController.java中添加方法:
@RequestMapping("test01")
public ModelAndView test01(){
ModelAndView mv=new ModelAndView();
mv.addObject("teamName","湖人队");
mv.setViewName("result");
return mv;
}
Model中,放我们的数据,然后再ModelAndView中指定视图名称。
当处理器方法处理完后,需要跳转到其他资源的同时传递数据,选择返回ModelAndView比较好,但是如果只是需要传递数据或者跳转之一,这个时候ModelAndView就不是最优选择。
7.2、返回String
上一种方式中的 ModelAndView 可以拆分为两部分,Model 和 View,在 SpringMVC 中,Model 我们 可以直接在参数中指定,然后返回值是逻辑视图名,视图解析器解析可以将逻辑视图名称转换为物理视 图地址。
视图解析器通过内部资源视图解析器****InternalResourceViewResolver将字符串与解析器中的prefix和 suffix结合形成要跳转的额URI。
7.3、返回对象类型
当处理器方法返回Object对象类型的时候,可以是Integer、String、Map、List,也可以是自定义的对 象类型。但是无论是什么类型,都不是作为逻辑视图出现,而是直接作为数据返回然后展示的。一般前 端发起Ajax请求的时候都会使用直接返回对象的形式。
返回对象的时候,需要使用@ResponseBody 注解,将转换后的 JSON 数据放入到响应体中。
pom.xml文件中添加两个依赖
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
7.3.1、返回基础类型
@ResponseBody
@RequestMapping("test03-1")
public Integer test031(){
return 666;
}
@ResponseBody
@RequestMapping("test03-2")
public String test032(){
return "test";
}
8、异常处理
SpringMVC框架常用@ExceptionHandLer注解处理异常
@ExecptionHandler注解
@ExceptionHandler 可以将一个方法指定为异常处理方法。
被注解的方法,其返回值可以是 ModelAndView、String,或 void,方法名随意,方法参数可以是 Exception 及其子类对象、HttpServletRequest、HttpServletResponse 等。系统会自动为这些方法参 数赋值。
对于异常处理注解的用法,也可以直接将异常处理方法注解于 Controller 之中.
9、拦截器
SpringMVC 中的 拦截器( Interceptor)是非常重要的,它的主要作用是拦截指定的用户请求,并进行相应的预处理与后处理。
拦截的时间点在“处理器映射器HandlerMapping根据用户提交的请求映射出了所要执行的处理器类,并且也找到了要执行该处理器类的处理器适配器,在处理器适配器HandlerAdaptor执行处理器之前”。
在处理器映射器映射出所要执行的处理器类时,已经将拦截器与处理器组合为了一个处理器执行链
HandlerExecutionChain,并返回给了前端控制器。自定义拦截器,需要实现 HandlerInterceptor 接口。而该接口中含有三个方法:
preHandle(request,response, Object handler):
该方法在处理器方法执行之前执行。其返回值为boolean,若为true,则紧接着会执行处理器方法,且会将afterCompletion()方法放入到一个专门的方法栈中等待执行。
postHandle(request,response, Object handler,modelAndView):
该方法在处理器方法执行之后执行。处理器方法若最终未被执行,则该方法不会执行。由于该方法是在处理器方法执行完后执行,且该方法参数中包含 ModelAndView,所以该方法可以修改处理器方法的处理结果 数据,且可以修改跳转方向。
afterCompletion(request,response, Object handler, Exception ex):
当 preHandle()方法返回true时,会将该方法放到专门的方法栈中,等到对请求进行响应的所工作完
成之后才执行该方法。即该方法是在前端控制器渲染(数据填充)了响应页面之后执行的,此时对 ModelAndView再操作也对响应无济于事。
afterCompletion最后执行的方法,清除资源,例如在Controller方法中加入数据
9.1、自定义拦截器
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyInterceptor implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse
response, Object handler) throws Exception {
System.out.println("preHandle-------------------");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle-------------------");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse
response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion-------------------");
} }
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyInterceptor2 implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse
response, Object handler) throws Exception {
System.out.println("preHandle2-------------------");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse
response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle-2------------------");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse
response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion2-------------------");
}
}
9.2、配置拦截器
在springmvc.xml中添加如下配置
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="类路径" id="myInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
如果有多个拦截器的时候:
preHandle:按照配置前后顺序执行
postHandle:按照配置前后逆序执行
afterCompletion:按照配置前后逆序执行
10、RESTful风格
10.1、REST概念
REST(英文:Representational State Transfer, 简称REST,意思:表述性状态转换,描述了一个架构样式的网络系统,比如web应用)。
它是一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件,它主要用于客户端和服务端交互类的软件。基于这个风格设计的软件可以更简介,更有层次,更易于实现缓存等机制。
它本身并没有什么使用性,其核心价值在于如何设计出符合REST风格的网络接口。
10.2、RESTful概念
REST指的是一组架构约束条件和原则。满足这些约束条件和原则的应用程序或设计就是RESTful。
RESTful的特性:
资源(Resources): 互联网所有的事物都可以被抽象为资源。它可以是一段文本、一张图片、一首歌曲、一种服务、总之就是一个具体的存在。可以用一个URI(统一资源定位符)指向它,每种资源对应一个特性的URI。要获取这个资源,访问它的URI就可以,因此URI即为每一个资源的独一无二的识别符。
表现层(Representation): 把资源具体呈现出现的形式,叫做它的表现层(Representation)。比如,文本可以用txt格式表现,也可以用HTML格式、XML格式、JSON格式表现,甚至可以采用二进制格式。
状态转换(State Transfer):没发出一个请求,就代表了客户端和服务器的一次交互过程。HTTP协议,是一个无状态协议,及所有的状态都保存在服务器端。因此,如果客户端想要操作服务器,必须通过某种手段,让服务端发生“状态转换“(State Transfer)。而这种转换是建立在表现层之上的,所以就是”表现层状态转换“。
具体来说就是HTTP协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。他们分别对应四种基本操作:GET用来获取资源,POST用来新建资源,PUT用来更新资源,DELETE用来删除资源。
10.3、API设计/URL设计
10.3.1、动词+宾语
RESTful的核心思想就是客户端的用户发出的数据操作指令都是”动词+宾语“的结构。例如GET/expresses这个命令,GET是动词,/express是宾语。
动词通常就是五种 HTTP 方法,对应 CRUD 操作。
GET:读取(Read)
POST:新建(Create)
PUT:更新(Update)
PATCH:更新(Update),通常是部分更新
DELETE:删除(Delete)
PS: 1、根据 HTTP 规范,动词一律大写。
2、一些代理只支持POST和GET方法, 为了使用这些有限方法支持RESTful API,需要一种办法覆盖http原来的方法。使用订制的HTTP头 X-HTTP-Method-Override 来覆盖POST 方法.
10.3.2、宾语必须是名词
宾语就是 API 的 URL,是 HTTP 动词作用的对象。它应该是名词,不能是动词。
比如,/expresses 这个 URL 就是正确的。
以下这些URL都是不推荐的,因为带上了动词,不是推荐写法。
/getAllExpresses
/getExpress
/createExpress
/deleteAllExpress
ps:不要混淆名词单数和复数,为了保持简单,只对所有资源使用复数。
10.3.3、避免多级URL
如果资源中有多级分类,也不建议写出多级的URL。例如要获取球队中某个队员,有人可能这么写:
GET /team/1001/player/1005
这种写法的语义不够明确,所以推荐使用查询字符串做后缀,改写为
GET /team/1001?player=1005.
10.4、HTTP状态码
客户端的用户发起的每一次请求,服务器都必须给出响应。响应包括 HTTP 状态码和数据两部分。
HTTP 状态码就是一个三位数,分成五个类别。这五大类总包含了100多种状态码(不需要全都记住,不用紧张哈,覆盖了绝大部分可能遇到的情况。每一种状态码都有标准的(或者约定的)解释,客户端只需查看状态码,就可以判断出发生了什么情况,所以服务器应该返回尽可能精确的状态码。
五类状态码分别如下:
1xx:相关信息
2xx:操作成功
3xx:重定向
4xx:客户端错误
5xx:服务器错误
PS:API 不需要1xx状态码,所以这个类别直接忽略。
10.5、服务器响应
服务器返回的信息一般不推荐纯文本,而是建议大家选择JSON 对象,因为这样才能返回标准的结构化数据。
所以,服务器回应的 HTTP 头的 Content-Type 属性要设为 application/json 。客户端请求时,也要明确告诉服务器,可以接受 JSON 格式,即请求的 HTTP 头的 ACCEPT 属性也要设成application/json 。
当发生错误的时候,除了返回状态码之外,也要返回错误信息。所以我们可以自己封装要返回的信息。
|