1.SpringMVC介绍
Spring框架提供了完成企业级Web开发所需的功能,而SpringMVC是包含这些实现过程的一个子项目,它完全符合如今web应用程序开发框架中所广泛使用的MVC(Model View Controller,模型-视图-控制器)模式。
SpringMVC是一个分层的Java Web开发框架,MVC提供了一个分层体系结构。
Model(模型):是应用程序使用的特定域信息的表现形式;
View(视图):域模型的表现形式,如输入文本框,按钮等页面元素,这些元素与模型进行交互。
Controller(控制器):主要负责解释用户输入,并转换为模型,并将结果显示给用户。
SpringMVC是一个基于动作的MVC框架,该框架突出了HTTP协议中的请求/响应特性。在该框架中,用户的每一个请求都对应一个需要执行的动作,即每一个用户请求,都需要有对应的处理方法,SpringMVC将每个请求映射到一个可执行的方法来对其处理。
因为SpringMVC是Spring的子项目,所以SpringMVC集成了Spring的核心功能,如依赖注入。
2. SpringMVC处理请求流程解析
DsipatcherServet(前端控制器)是SpringMVC的核心元素,它是主要的Servlet,负责处理用户请求,并将请求分发给对应的Controller。
具体请求处理流程如下:
该图来自 :SpringMVC处理请求流程
请求处理流程解释:
1. 用户向服务器发送请求,请求被前端控制器 DispatcherServlet捕获;
2. DispatcherServlet对请求URL进行解析,得到请求资源标识符(URI)。然后根据该URI,调用处理器映射器HandlerMapping获得该Handler配置的所有相关的对象(包括Handler对象以及Handler对象对应的拦截器),最后以HandlerExecutionChain对象的形式返回;
3. DispatcherServlet 根据获得的Handler,选择一个合适的处理器适配器HandlerAdapter。(附注:如果成功获得HandlerAdapter后,此时将开始执行拦截器的preHandler(...)方法)
4. DispatcherServlet提取Request中的模型数据,填充Handler入参,然后由处理器适配器HandlerAdapter调用它的handle()方法,开始执行Handler(Controller)中对应处理方法。 在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作:
HttpMessageConveter: 将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息
数据转换:对请求消息进行数据转换。如String转换成Integer、Double等
数据格式化:对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等
数据验证: 验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中
5. Handler执行完成后(handle()方法执行完成后),向DispatcherServlet 返回一个ModelAndView对象;
6. DispatcherServlet根据返回的ModelAndView,选择一个适合的ViewResolver(必须是已经注册到Spring容器中的ViewResolver)返回给DispatcherServlet ;
7. ViewResolver 结合Model和View,来渲染视图
8. DispatcherServlet将渲染结果返回给客户端。
以下是DispatcherServlet源码中的doDispatch等方法,并未列全,帮助理解上面的请求处理过程。方法中加了一些注释,是自己的理解。
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
//1.用户请求
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
processedRequest = this.checkMultipart(request);
multipartRequestParsed = processedRequest != request;
//2.DispatcherServlet调用处理器映射器HandlerMapping,获得HandlerExecutionChain对象,包含Handler配置的所有相关的对象
mappedHandler = this.getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
this.noHandlerFound(processedRequest, response);
return;
}
//3. DispatcherServlet 根据获得的Handler,获得一个合适的处理器适配器HandlerAdapter。
HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (this.logger.isDebugEnabled()) {
this.logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
return;
}
}
//如果成功获得HandlerAdapter后,此时将开始执行拦截器的preHandler(...)方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
//4.提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)。 在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作.
//5.处理器方法执行完成后,向DispatcherServlet 返回一个ModelAndView对象;
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
// 6. 根据返回的ModelAndView,选择一个适合的ViewResolver(必须是已经注册到Spring容器中的ViewResolver)返回给DispatcherServlet ;
this.applyDefaultViewName(processedRequest, mv);
//拦截器中的方法,处理器方法执行完,返回ModelAndView前执行
mappedHandler.applyPostHandle(processedRequest, response, mv);
} catch (Exception var19) {
dispatchException = var19;
}
// 8. 将渲染结果返回给客户端。
this.processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
} catch (Exception var20) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, var20);
} catch (Error var21) {
this.triggerAfterCompletionWithError(processedRequest, response, mappedHandler, var21);
}
} finally {
if (asyncManager.isConcurrentHandlingStarted()) {
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
} else if (multipartRequestParsed) {
this.cleanupMultipart(processedRequest);
}
}
}
//获得HandlerExecutionChain
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
Iterator var2 = this.handlerMappings.iterator();
HandlerExecutionChain handler;
do {
if (!var2.hasNext()) {
return null;
}
//处理器映射器
HandlerMapping hm = (HandlerMapping)var2.next();
if (this.logger.isTraceEnabled()) {
this.logger.trace("Testing handler map [" + hm + "] in DispatcherServlet with name '" + this.getServletName() + "'");
}
handler = hm.getHandler(request);
} while(handler == null);
return handler;
}
//
private void applyDefaultViewName(HttpServletRequest request, ModelAndView mv) throws Exception {
if (mv != null && !mv.hasView()) {
mv.setViewName(this.getDefaultViewName(request));
}
}
3. SpringMVC绑定机制
SpringMVC提供一种绑定机制,通过该机制可以从用户请求中提取数据,然后将数据转换为预定义格式,最后通过映射到一个模型类,从而创建一个对象。
每一个web应用程序都需要与表单进行交互,SpringMVC使用自定义的JSP表单标签库提供表单处理方法。表单标签库使用自定义标签创建视图,并提供了与模型类的绑定功能。通过SpringMVC框架绑定功能,可以将浏览器提交的Http请求中的参数映射到模型属性。
3.1 表单标签库使用
(1)通过taglib指令,将SpringMVC的JSP标签库定义添加到页面中。
(2)在页面中使用SpringMVC的jsp标签,如<mvc:input>等
<%@taglib prefix="mvc" uri="http://www.springframework.org/tags/form" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"><head>
</head>
<body style="background: #e1e9eb;">
<mvc:form modelAttribute="user" action="/result">
<table >
<tbody>
<tr>
<td ><mvc:label path="userName">用户名</mvc:label></td>
<td >
<mvc:input path="userName"/>
</td>
</tr>
</tbody>
</table>
</mvc:form>
</body>
</html>
form标签的modelAttribute特性执行了模型类user,mvc:input的path特性实现了对模型属性的绑定,意思是将该输入框的数据与模型类user的属性userName绑定。这样,在提交表单请求给服务器时,Controller中可以获得模型user,其中属性userName的值是用户输入值。其他mvc输入标签类似。
4.SpringMVC常用注解
下面这个链接博客对SpringMVC常用的注解讲解的非常清楚。