1.springmvc框架
1.1什么是springmvc
springmvc是spring框架的一个模块,springmvc和spring无需通过中间整合层进行整合。
springmvc是一个基于mvc的web框架。
1.2mvc在b/s系统下的应用
mvc是一个设计模式,
1.3springmvc框架
第一步:发起请求到前端控制器(DispatcherServlet)
第二步:前端控制器请求HandlerMapping查找Handler
可以根据xml配置、注解进行查找。
第三步:处理器映射器HandlderMapping向前端控制器返回Handler
第四步:前端控制器调用处理器适配器去执行Handler
第五步:处理器适配器去执行Handler
第六步:Handler执行完给适配器返回ModelAndView
第步七:处理器适配器向前端控制器返回ModelAndView
ModelAndView是springmvc框架的一个底层对象,包含了Model和View.
第八步:前端控制器请求视图解析器区进行视图解析。
根据逻辑视图名解析成真正的视图(jsp)
第九步:视图解析器向前端控制器返回View
第十步:前端控制器进行视图渲染
视图渲染将模型数据(在ModelAndView对象中)填充到request域
第十一步:前端控制器向对象响应结果
组件:
1、前端控制器:DispatcherServlet
作用接收请求,响应结果,相当于转发器,中央处理器。
有了DispatcherServlet就减少勒其他组件之间的耦合性
2.处理器映射器HandlerMapping
作用:根据请求的url查找Handler,Handler需要程序员开发。
3.处理器适配器HandlerAdapter
作用:按照特定规则(HandlerAdapter)去执行Handler
注意:编写Handler时按照HandlerAdapter的要求去做,这样适配器才可以区正确执行Handler.
4.视图解析器View resolver
作用:进行视图解析,根据逻辑视图名解析成真正的视图(view)
5.视图View(需要程序员开发jsp)
View是一个接口,实现支持步同的view类型(jsp、freemarker、pdf.....)
2.入门程序
2.1环境准备
2.2需求
以案例作为驱动。
springmvc和mybatis使用一个案列(商品订单管理)
功能需求:商品的列表查询
2.3配置前端控制器
2.4配置处理器适配器
在classpath下的springmvc.xml中配置处理器映射器
通过查看源代码:
此适配器能执行实现Controller接口的Handler.
2.5开发Handler
需要实现controller接口,才能由"org.springframework.web.servllet.mvc.SimpleController"适配器执行。
2.6视图编写
2.7配置Handler
将编写Handler在spring容器加载。
2.8配置处理器映射器
在classpath下的springmvc.xml中配置处理器映射器。
2.9配置视图解析器
需要配置解析jsp的视图解析器。
3.非注解的处理器映射器和适配器
3.1非注解处理器映射器:
org.springframework.web.servlet.handler.BeanNameUrlHandllerMapping
另一个映射器:
org.spring framework.web.servlet.handler.SimpleUrlHandlerMapping
多个映射器可以并存,前端控制器判断url能让那个映射器处理就让那个映射器处理.
3.2非注解的适配器
org.springframework.web.servllet.mvc.SimpleControllerAdapter
要求编写的Handler实现Controller接口。
org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter
要求编写的Handler实现HttpRequestHandler接口。
4.DispatcherSerlvet.properties
前端控制器从上边的文件中加载处理映射器、适配器、试图解析器等组件,如果不在spring.xml中配置,使用默认加载的。
5.注解的处理器映射器和适配器
在spring3.1之前使用org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping注解映射器。
在spring3.1之后使用org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping注解映射器。
在spring3.1之前使用org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter注解适配器。
在spring3.1之后使用org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter注解适配器
5.1配置注解映射器和适配器
<!-- 配置注解Handler -->
<!-- <bean class="cn.itcast.ssm.controller.ItemController1"></bean>-->
<!-- 当应用中有多个handler时,可以使用组件扫描所有Handler -->
<context:component-scan base-package="cn.itcast.ssm.controller"></context:component-scan>
<!-- 注解映射器 -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"></bean>
<!-- 注解适配器 -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"></bean>
<!--使用mvc:annotation-driven代替上面的注解映射器和注解适配器
mvc:annotation-driven默认加载了很多参数绑定方法,
-->
<!-- <mvc:annotation-driven/>-->
<!-- 配置视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 配置视图解析器的前缀和后缀 -->
<property name="prefix" value="/WEB-INF/jsp/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
5.2开发注解Handler
使用注解的映射器和注解的适配器.(注解的适配器和映射器必须配对使用),
6.源码分析
通过前端控制器源码分析springMVC的执行过程
第一步:前端接收器接收请求
调用doDispatch
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
processedRequest = checkMultipart(request);
multipartRequestParsed = processedRequest != request;
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest, false);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (logger.isDebugEnabled()) {
String requestUri = urlPathHelper.getRequestUri(request);
logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
try {
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
}
applyDefaultViewName(request, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Error err) {
triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
return;
}
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
第二步:前端控制器调用处理器映射器查找Handler
在doDiapatch()方法中调用了DispatcherServlet类的getHandler方法
HandlerExecutionChain mappedHandler = null;
......
mappedHandler = getHandler(processedRequest, false);
其中getHandler方法:
@Deprecated
protected HandlerExecutionChain getHandler(HttpServletRequest request, boolean cache) throws Exception {
return getHandler(request);
}
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
for (HandlerMapping hm : this.handlerMappings) {
if (logger.isTraceEnabled()) {
logger.trace(
"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
}
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
return null;
}
说明映射器根据request当中的URL,找到了Handler,最终返回一个执行器的链(HandlerExecutionChain)。这个链里面有Handler。
第三步:调用处理器适配器执行Handler,得到执行结果ModelAndView
ModelAndView mv = null;
......
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
第四步:视图渲染,将model数据填充到request域
视图解析,得到view
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
调用view的渲染方法,将模型数据填充到request域
渲染方法
view.render(mv.getModelInternal(), request, response);
调用view的渲染方法,将model数据填充到request域
protected void exposeModelAsRequestAttributes(Map<String, Object> model, HttpServletRequest request) throws Exception {
//遍历model里面的数据,填充到request域
for (Map.Entry<String, Object> entry : model.entrySet()) {
String modelName = entry.getKey();
Object modelValue = entry.getValue();
if (modelValue != null) {
request.setAttribute(modelName, modelValue);
if (logger.isDebugEnabled()) {
logger.debug("Added model object '" + modelName + "' of type [" + modelValue.getClass().getName() +
"] to request in view with name '" + getBeanName() + "'");
}
}
else {
request.removeAttribute(modelName);
if (logger.isDebugEnabled()) {
logger.debug("Removed model object '" + modelName +
"' from request in view with name '" + getBeanName() + "'");
}
}
}
}
7入门程序小结
通过入门程序理解springmvc前端控制器、处理器映射器、处理器适配器、视图解析器用法。
前端控制器配置器:
第一种:*.action,访问.action结尾,由DispatcherServlet进行解析
第二种:/,所有访问地址都由DispatcherServlet进行解析,对静态文件的解析需要配置不让DispatcherServlet进行解析
处理器映射器:
非注解处理器映射器(了解)
注解的处理器映射器(掌握)
对标记又@Controller类忠标记又@RequestMapping的方法进行映射。在@RequestMapping里面定义映射的url。实用注解的映射器不用再xml中配置url和Handler的映射关系。
处理器适配器:
非注解处理器适配器(了解)
注解的处理器映射器(掌握)
注解处理器适配器和注解的处理器映射器是配对使用的。
<!-- 注解的映射器 -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
<!-- 注解的适配器 -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
以上代码可以用以下代码代替,实际开发使用下者。
<mvc:annotation-driven></mvc:annotation-driven>
参考博客:
https://blog.youkuaiyun.com/nuoWei_SenLin/article/details/53698834
https://blog.youkuaiyun.com/h3243212/article/details/50834272
https://blog.youkuaiyun.com/acmman/article/details/46980497
https://blog.youkuaiyun.com/nuoWei_SenLin/article/details/53698834