SpringMvc
【源码仓库】
【本文仓库】
三层结构
-
表现层
- MVC模型
-
业务层
- service
-
持久层
- dao
工作流程
用户->前端控制器:用户发送请求
前端控制器-> 后端控制器:根据用户请求查询具体控制器
后端控制器-->前端控制器:处理后结果
前端控制器--> 视图:视图渲染
视图-->前端控制器:返回视图
前端控制器--> 用户:响应结果
简单案例
依赖
4.0.0
com.huifer
mySpringMvcBook
1.0-SNAPSHOT
war
UTF-8
UTF-8
1.8
5.1.5.RELEASE
4.12
org.springframework
spring-beans
${spring.version}
org.springframework
spring-core
${spring.version}
org.springframework
spring-context
${spring.version}
org.springframework
spring-expression
${spring.version}
org.springframework
spring-aspects
${spring.version}
aopalliance
aopalliance
1.0
org.springframework
spring-webmvc
${spring.version}
org.springframework
spring-web
${spring.version}
javax.servlet.jsp.jstl
jstl
1.2
javax.servlet
servlet-api
2.5
org.projectlombok
lombok
1.18.4
com.fasterxml.jackson.core
jackson-databind
2.9.3
com.fasterxml.jackson.core
jackson-core
2.9.3
com.fasterxml.jackson.core
jackson-annotations
2.9.3
src/main/java
**/*.xml
org.apache.maven.plugins
maven-compiler-plugin
1.8
1.8
UTF-8
spring-config
web.xml
springmvc
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
classpath:spring-mvc-config.xml
2
springmvc
/
-
controller
@Controller @RequestMapping("item") public class ItemController { @ResponseBody @GetMapping("/query") public ModelAndView query() throws Exception { List
- itemList = new ArrayList<>(); itemList.add(new Item("吃的", 3.3, new Date())); itemList.add(new Item("玩的", 3.3, new Date())); ModelAndView modelAndView = new ModelAndView(); modelAndView.addObject("itemList", itemList); modelAndView.setViewName("/WEB-INF/jsp/item.jsp"); return modelAndView; } }
-
item.JSP
<%-- Created by IntelliJ IDEA. User: huifer Date: 2019/3/10 Time: 11:26 To change this template use File | Settings | File Templates. --%> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" isELIgnored="false" %>
ItemList ITEM
${itemList}
web.xml 中的加载顺序
context-param->listener->filter->servlet
url-parttern 匹配顺序
- 精确匹配 ,如/baidu
- 目录匹配,如/*
- 拓展名匹配,如*.jpg
- 默认匹配 ,如/
tomcat中的url-parttern
- 文件在 ${tomcatHome}/conf/web.xml中
-
发布到tomcat的web应用共享下面两个配置
default / jsp *.jsp *.jspx
此处面试题
为什么在自己的项目中web.xml配置/* 报错。如图
- 根据tomcat的web.xml配置可以看到 / 和jsp的拦截是分开的 ,而我们直接用一个/*来拦截那么tomcat将不知道用什么来处理
spring-mvc大致流程源码翻阅
- 从配置文件中知道前端控制器DispatcherServlet
springmvc
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
classpath:spring-mvc-config.xml
2
在org.springframework.web.servlet.DispatcherServlet 看下面两个方法
- doService 将访问的数据接收到交给doDispatch
- 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 {
try {
ModelAndView mv = null;
Object dispatchException = null;
try {
processedRequest = this.checkMultipart(request);
multipartRequestParsed = processedRequest != request;
// 加载handler
mappedHandler = this.getHandler(processedRequest);
if (mappedHandler == null) {
this.noHandlerFound(processedRequest, response);
return;
}
// handler适配器
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 ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
return;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 适配器执行操作
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
this.applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
} catch (Exception var20) {
dispatchException = var20;
} catch (Throwable var21) {
dispatchException = new NestedServletException("Handler dispatch failed", var21);
}
// 操作结果返回
this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
} catch (Exception var22) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
} catch (Throwable var23) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
}
} finally {
if (asyncManager.isConcurrentHandlingStarted()) {
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
} else if (multipartRequestParsed) {
this.cleanupMultipart(processedRequest);
}
}
}
-
handler怎么来
- initHandlerMappings(context)
protected void initStrategies(ApplicationContext context) { this.initMultipartResolver(context); this.initLocaleResolver(context); this.initThemeResolver(context); this.initHandlerMappings(context); this.initHandlerAdapters(context); this.initHandlerExceptionResolvers(context); this.initRequestToViewNameTranslator(context); this.initViewResolvers(context); this.initFlashMapManager(context); }
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
if (this.detectAllHandlerMappings) {
Map matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerMappings = new ArrayList(matchingBeans.values());
AnnotationAwareOrderComparator.sort(this.handlerMappings);
}
} else {
try {
HandlerMapping hm = (HandlerMapping)context.getBean("handlerMapping", HandlerMapping.class);
this.handlerMappings = Collections.singletonList(hm);
} catch (NoSuchBeanDefinitionException var3) {
}
}
if (this.handlerMappings == null) {
// 读取默认配置文件
this.handlerMappings = this.getDefaultStrategies(context, HandlerMapping.class);
if (this.logger.isTraceEnabled()) {
this.logger.trace("No HandlerMappings declared for servlet '" + this.getServletName() + "': using default strategies from DispatcherServlet.properties");
}
}
}
- 默认配置文件
-
handler适配器也在配置文件中
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException { if (this.handlerAdapters != null) { Iterator var2 = this.handlerAdapters.iterator(); while(var2.hasNext()) { HandlerAdapter adapter = (HandlerAdapter)var2.next(); // 是否能够适配 if (adapter.supports(handler)) { return adapter; } } } throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler"); }
-
HttpRequestHandlerAdapter
public class HttpRequestHandlerAdapter implements HandlerAdapter { public HttpRequestHandlerAdapter() { } // 判断是否是当前类支持的适配器 public boolean supports(Object handler) { return handler instanceof HttpRequestHandler; } // 适配器执行操作 @Nullable public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { ((HttpRequestHandler)handler).handleRequest(request, response); return null; } public long getLastModified(HttpServletRequest request, Object handler) { return handler instanceof LastModified ? ((LastModified)handler).getLastModified(request) : -1L; } }
-
-
视图解析
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv, @Nullable Exception exception) throws Exception { boolean errorView = false; if (exception != null) { if (exception instanceof ModelAndViewDefiningException) { this.logger.debug("ModelAndViewDefiningException encountered", exception); mv = ((ModelAndViewDefiningException)exception).getModelAndView(); } else { Object handler = mappedHandler != null ? mappedHandler.getHandler() : null; mv = this.processHandlerException(request, response, handler, exception); errorView = mv != null; } } if (mv != null && !mv.wasCleared()) { // 这个地方在做渲染 this.render(mv, request, response); if (errorView) { WebUtils.clearErrorRequestAttributes(request); } } else if (this.logger.isTraceEnabled()) { this.logger.trace("No view rendering, null ModelAndView returned."); } if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) { if (mappedHandler != null) { mappedHandler.triggerAfterCompletion(request, response, (Exception)null); } } }
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception { Locale locale = this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale(); response.setLocale(locale); String viewName = mv.getViewName(); View view; if (viewName != null) { // 视图解析器 view = this.resolveViewName(viewName, mv.getModelInternal(), locale, request); if (view == null) { throw new ServletException("Could not resolve view with name '" + mv.getViewName() + "' in servlet with name '" + this.getServletName() + "'"); } } else { view = mv.getView(); if (view == null) { throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a View object in servlet with name '" + this.getServletName() + "'"); } } if (this.logger.isTraceEnabled()) { this.logger.trace("Rendering view [" + view + "] "); } try { if (mv.getStatus() != null) { response.setStatus(mv.getStatus().value()); } // 视图的渲染函数渲染到页面上 view.render(mv.getModelInternal(), request, response); } catch (Exception var8) { if (this.logger.isDebugEnabled()) { this.logger.debug("Error rendering view [" + view + "]", var8); } throw var8; } }
@Nullable protected View resolveViewName(String viewName, @Nullable Map
model, Locale locale, HttpServletRequest request) throws Exception { if (this.viewResolvers != null) { Iterator var5 = this.viewResolvers.iterator(); while(var5.hasNext()) { // 视图解析器 ViewResolver viewResolver = (ViewResolver)var5.next(); View view = viewResolver.resolveViewName(viewName, locale); if (view != null) { return view; } } } return null; }
spring-mvc请求具体流程图
用户->前端控制器\n org.springframework.web.servlet.DispatcherServlet\n 用来接收响应以及返回响应结果:1.用户发送请求
前端控制器\n org.springframework.web.servlet.DispatcherServlet\n 用来接收响应以及返回响应结果 -> HandlerMapper : 2.根据url进行处理
HandlerMapper -> 前端控制器\n org.springframework.web.servlet.DispatcherServlet\n 用来接收响应以及返回响应结果:3.将handlerMapper处理结果给前端控制器
前端控制器\n org.springframework.web.servlet.DispatcherServlet\n 用来接收响应以及返回响应结果-> HandlerAdapter:4.给适配器确认具体的适配器,比如我们这里给了HttpRequestHandlerAdapter
HandlerAdapter ->ModelAndView:5.用来执行业务操作
ModelAndView ->HandlerAdapter: 6.执行完成给HandlerAdapter返回
HandlerAdapter->前端控制器\n org.springframework.web.servlet.DispatcherServlet\n 用来接收响应以及返回响应结果:7.返回一个modelAndView
前端控制器\n org.springframework.web.servlet.DispatcherServlet\n 用来接收响应以及返回响应结果-> ViewResolver 视图解析器 :8.将第7步中的view进行解析
ViewResolver 视图解析器->前端控制器\n org.springframework.web.servlet.DispatcherServlet\n 用来接收响应以及返回响应结果:9.解析结果返回
前端控制器\n org.springframework.web.servlet.DispatcherServlet\n 用来接收响应以及返回响应结果 -> View : 9.将model渲染到view中
View->前端控制器\n org.springframework.web.servlet.DispatcherServlet\n 用来接收响应以及返回响应结果: 10.view 结果返回给前端控制器
前端控制器\n org.springframework.web.servlet.DispatcherServlet\n 用来接收响应以及返回响应结果 --> 用户:查看到完整的网页