- 发起请求到前端控制器(DispatcherServlet)
- 前端控制器请求处理器映射器(HandlerMapping)查找Handler(可根据xml配置、注解进行查找)
- 处理器映射器(HandlerMapping)向前端控制器返回Handler
- 前端控制器调用处理器适配器(HandlerAdapter)执行Handler
- 处理器适配器(HandlerAdapter)去执行Handler
- Handler执行完,给适配器返回ModelAndView(Springmvc框架的一个底层对象)
- 处理器适配器(HandlerAdapter)向前端控制器返回ModelAndView
- 前端控制器(DispatcherServlet)请求视图解析器(ViewResolver)进行视图解析,根据逻辑视图名解析成真正的视图(jsp)
- 视图解析器(ViewResolver)向前端控制器(DispatcherServlet)返回View
- 前端控制器进行视图渲染,即将模型数据(在ModelAndView对象中)填充到request域
- 前端控制器向用户响应结果
pom依赖文件
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-catalina</artifactId>
<version>7.0.78</version>
</dependency>
在web.xml配置文件
<!-- springmvc 前端控制器 -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- contextConfigLocation配置springmvc加载的配置文件(配置处理器映射器、适配器等等)
若不配置,默认加载WEB-INF/servlet名称-servlet(springmvc-servlet.xml)
-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<!--
第一种:*.action,访问以.action三结尾,由DispatcherServlet进行解析
第二种:/,所有访问的地址由DispatcherServlet进行解析,对静态文件的解析需要配置不让DispatcherServlet进行解析,
使用此种方式和实现RESTful风格的url
第三种:/*,这样配置不对,使用这种配置,最终要转发到一个jsp页面时,仍然会由DispatcherServlet解析jsp地址,
不能根据jsp页面找到handler,会报错
-->
<url-pattern>*.action</url-pattern>
</servlet-mapping>
springmvc.xml
<!-- 配置Handler -->
<bean id="itemsController" name="/queryItems.action" class="com.iot.ssm.controller.ItemsController"/>
<!-- 处理器映射器
将bean的name作为url进行查找,需要在配置Handler时指定beanname(就是url)
所有的映射器都实现了HandlerMapping接口
-->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<!-- 简单url映射-->
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<!-- 对 itemsController进行url映射-->
<prop key="/queryItems1.action">itemsController</prop>
<prop key="/queryItems2.action">itemsController</prop>
</props>
</property>
</bean>
<!-- 处理器适配器
所有处理器适配器都实现了HandlerAdapter接口
-->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
<!-- 另一个非注解的适配器-->
<bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"/>
<!-- 视图解析器
解析jsp,默认使用jstl,classpath下要有jstl的包
-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"/>
itemsController实现了Controller接口
public interface Controller {
/**
* @param request current HTTP request
* @param response current HTTP response
* @return a ModelAndView to render, or {@code null} if handled directly
* @throws Exception in case of errors
*/
ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception;
}
进入DispatcherServlet的父类HttpServlet
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException {
HttpServletRequest request;
HttpServletResponse response;
request = (HttpServletRequest) req;
response = (HttpServletResponse) res;
service(request, response);
}
//进入FrameworkServlet
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
if (HttpMethod.PATCH.matches(request.getMethod())) {
processRequest(request, response);
}
else {
super.service(request, response);
}
}
//进入HttpServlet
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String method = req.getMethod();
if (method.equals(METHOD_GET)) {
long lastModified = getLastModified(req);
if (lastModified == -1) {
// servlet doesn't support if-modified-since, no reason
// to go through further expensive logic
doGet(req, resp);
}
}
...
}
//进入FrameworkServlet
protected final void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
...
doService(request, response);
}
//进入DispatcherServlet
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
....
doDispatch(request, response);
}
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);
mappedHandler = getHandler(processedRequest); //handlerMapping里去找handler,与拦截器一起被封装成 HandlerExecutionChain
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response); //没有找到handler会发404
return;
}
// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());//适配器模式,统一handler
...
if (!mappedHandler.applyPreHandle(processedRequest, response)) {//拦截器前置处理
return;
}
mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); //执行handler
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv); //mv没设view话根据request设
mappedHandler.applyPostHandle(processedRequest, response, mv); //拦截器后置处理
}
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);//根据mv写到view
}
...
}
寻找拦截器链
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
for (HandlerMapping hm : this.handlerMappings) { //handlerMappings在bean里配置过了
HandlerExecutionChain handler = hm.getHandler(request); //根据请求获取拦截器
if (handler != null) {
return handler; //按照配置顺序,如果先找到了映射地址就返回了
}
}
return null;
}
//进入AbstractHandlerMapping
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
Object handler = getHandlerInternal(request);
if (handler == null) {
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = getApplicationContext().getBean(handlerName);
}
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
...
return executionChain;
}
protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request); //获得查询路径
Object handler = lookupHandler(lookupPath, request); //查询匹配的handler
if (handler == null) {
Object rawHandler = null;
if ("/".equals(lookupPath)) {
rawHandler = getRootHandler();
}
if (rawHandler == null) {
rawHandler = getDefaultHandler();//没配置返回空
}
if (rawHandler != null) {
if (rawHandler instanceof String) {
String handlerName = (String) rawHandler;
rawHandler = getApplicationContext().getBean(handlerName);
}
validateHandler(rawHandler, request);
handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);
}
}
return handler;
}
protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
Object handler = this.handlerMap.get(urlPath); //直接匹配
if (handler != null) {
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = getApplicationContext().getBean(handlerName);
}
validateHandler(handler, request);
return buildPathExposingHandler(handler, urlPath, urlPath, null);
}
...
}
protected Object buildPathExposingHandler(Object rawHandler, String bestMatchingPattern,
String pathWithinMapping, Map<String, String> uriTemplateVariables) {
HandlerExecutionChain chain = new HandlerExecutionChain(rawHandler);
chain.addInterceptor(new PathExposingHandlerInterceptor(bestMatchingPattern, pathWithinMapping)); // 添加拦截器
...
return chain;
}
public HandlerExecutionChain(Object handler) { //创建拦截器链
this(handler, null);
}
public HandlerExecutionChain(Object handler, HandlerInterceptor[] interceptors) {
if (handler instanceof HandlerExecutionChain) {
HandlerExecutionChain originalChain = (HandlerExecutionChain) handler;
this.handler = originalChain.getHandler();
this.interceptorList = new ArrayList<HandlerInterceptor>();
CollectionUtils.mergeArrayIntoCollection(originalChain.getInterceptors(), this.interceptorList);
CollectionUtils.mergeArrayIntoCollection(interceptors, this.interceptorList);
}
else {
this.handler = handler;
this.interceptors = interceptors;
}
}
//执行拦截器
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
if (getInterceptors() != null) {
for (int i = 0; i < getInterceptors().length; i++) {
HandlerInterceptor interceptor = getInterceptors()[i];
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
}
return true;
}
业务处理
//获取adapter
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
for (HandlerAdapter ha : this.handlerAdapters) {
if (ha.supports(handler)) {
return ha;
}
}
throw new ServletException("No adapter for handler [" + handler +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
//比如 SimpleControllerHandlerAdapter
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return ((Controller) handler).handleRequest(request, response); //执行业务逻辑
}
//进入自己的实现的Controller
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
//返回ModelAndView
ModelAndView modelAndView = new ModelAndView();
//相当于request的setAttribute方法,在jsp页面中通过itemsList取数据
modelAndView.addObject("xx", 1);
//指定视图
modelAndView.setViewName("/WEB-INF/jsp/xx.jsp");
return modelAndView;
}
寻找视图
private void applyDefaultViewName(HttpServletRequest request, ModelAndView mv) throws Exception {
if (mv != null && !mv.hasView()) {
mv.setViewName(getDefaultViewName(request));
}
}
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {
boolean errorView = false;
...
// Did the handler return a view to render?
if (mv != null && !mv.wasCleared()) {
render(mv, request, response); //页面渲染
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
...
if (mappedHandler != null) {
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
// Determine locale for request and apply it to the response.
Locale locale = this.localeResolver.resolveLocale(request);
response.setLocale(locale);
View view;
if (mv.isReference()) { //string名称引用,beanFactory进行管理
view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
}
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 '" + getServletName() + "'");
}
}
view.render(mv.getModelInternal(), request, response);
}
//进入AbstractView
public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
...
Map<String, Object> mergedModel = createMergedOutputModel(model, request, response); //转成map
prepareResponse(request, response); //针对下载文件处理一下
renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
}
//进入InternalResourceView
protected void renderMergedOutputModel(
Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
exposeModelAsRequestAttributes(model, request); //将kv放入request的属性里
// Expose helpers as request attributes, if any.
exposeHelpers(request);
// Determine the path for the request dispatcher.
String dispatcherPath = prepareForRendering(request, response);
RequestDispatcher rd = getRequestDispatcher(request, dispatcherPath); //从tomcat获取转发器
...
// If already included or response already committed, perform include, else forward.
if (useInclude(request, response)) {
response.setContentType(getContentType());
rd.include(request, response);
}
else {
rd.forward(request, response);
}
}