本文共 11106 字,大约阅读时间需要 37 分钟。
简单总结:
1、请求进入中央处理器(DispatcherServlet) 2、通过HandlerMapping查询业务逻辑类 3、通过HandlerAdapter执行业务逻辑 4、通过ViewReslover渲染视图 5、DispatcherServlet响应用户为什么要设计适配器?
适配器是专门用来执行业务方法的,业务方法的Controller有很多种类型,如果没有适配器的话,在DispatcherServlet中调用Controller中业务方法的时,需要判断Controller类型后再调用;如果这是我们想扩展一个自己的Controller,是需要改源码做判断调用。违反扩展开放,修改关闭的原则。如果有个适配器,这时要扩展Contrller,只需要编写自己的Controller和实现适配器接口就可以了。4.0.0 com.springmvc SpringMVCTest 1.0.0-SNAPSHOT war 4.10 1.6.4 4.1.3.RELEASE 1.2 2.5 2.0 org.springframework spring-webmvc ${spring.version} org.slf4j slf4j-log4j12 ${slf4j.version} jstl jstl ${jstl.version} javax.servlet servlet-api ${servlet-api.version} provided javax.servlet jsp-api ${jsp-api.version} provided org.apache.tomcat.maven tomcat7-maven-plugin 80 /
在src/main/webapp下创建WEB-INF目录以及web.xml
配置DispatcherServletspingmvc springmvc org.springframework.web.servlet.DispatcherServlet contextConfigLocation classpath:springmvc-servlet.xml 1 springmvc *.do
CharacterEncodingFilter
类是一个过滤器,当前台JSP页面和JAVA代码中使用了不同的字符集进行编码的时候就会出现表单提交的数据或者上传/下载中文名称文件出现乱码的问题,那这个类就可以出场了。
CharacterEncodingFilter
类具有encoding和forceEncoding两个属性,其中encoding是表示设置request的编码,forceEncoding表示是否同时设置response的编码。 encodingFilter org.springframework.web.filter.CharacterEncodingFilter encoding UTF-8 forceEncoding true encodingFilter /*
在web.xml中定义contextConfigLocation参数,Spring会使用这个参数去加载所有逗号分隔的xml文件,如果没有这个参数,Spring默认加载WEB-INF/applicationContext.xml文件。
配置Spring加载的配置文件:contextConfigLocation classpath*:spring-basic.xml, classpath*:conf/spring/applicationContext_core*.xml, /WEB-工NF/daoContext.xml org.springframework.web.context.ContextLoaderListener
配置SpringMVC:
spring-mvc org.springframework.web.servlet.DispatcherServlet contextConfigLocation classpath*:spring-mvc.xml 1 spring-mvc *.do
在web.xml中有两种配置error-page的方法,一是通过错误码来配置,而是通过异常的类型来配置。
通过错误码来配置error-page:404 /index.jsp
通过异常的类型配置error-page:
java.lang.Exception /index.jsp
注意:<error-code>
和 <exception-type>
不能在同一个<error-page>
标签上同时出现。
默认从webapp目录下寻找首页,也可以配置WEB-INF目录下的文件。
index.jsp
/WEB-INF/views/index.jsp
在src/main/resources下创建log4j.properties
log4j.rootLogger=DEBUG,A1log4j.logger.org.mybatis = DEBUGlog4j.appender.A1=org.apache.log4j.ConsoleAppenderlog4j.appender.A1.layout=org.apache.log4j.PatternLayoutlog4j.appender.A1.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%c]-[%p] %m%n
在src/main/resources下创建springmvc-servlet.xml
SpringMVC默认从WEB-INF下读取servlet配置文件,文件的命名规则是:servletName-servlet.xml
如果要自定义servlet文件,需要在servlet定义时指定contextConfigLocation。配置文件解析:
1、配置处理器映射器HandlerMapping 2、配置处理器适配器HandlerAdapter 3、配置模型Handler 4、配置视图解析器ViewResolverHandlerMapping:
Controller是多种类型的,如果没有适配器,在DispatcherServlet中调用Hadnler,需要判断Controller类型做调用,我们想去扩展自己的Controller,需要去改源码做判断调用。违反开闭(对扩展开放,对修改关闭)原则。
如果有了适配器,如果要扩展Controller,只需要写自己的Controller和实现适配器接口即可。package com.springmvc.handler;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.springframework.web.servlet.ModelAndView;import org.springframework.web.servlet.mvc.Controller;public class HelloHandler implements Controller { public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { // 处理业务逻辑 ModelAndView mv = new ModelAndView(); mv.setViewName("hello");// 设置视图名称 mv.addObject("msg", "我的第一个SpringMVC应用!");// 设置模型数据 // request.setAttribute("msg", "xxxxx"); return mv; }}
DispatcherServlet源码初始化过程
protected void initStrategies(ApplicationContext context) { initMultipartResolver(context); //文件上传组件 initLocaleResolver(context); //国际化 initThemeResolver(context);// 主题 initHandlerMappings(context);// HandlerMapping 处理器映射 initHandlerAdapters(context);// HandlerAdapter 适配器 initHandlerExceptionResolvers(context); //异常相关组件 initRequestToViewNameTranslator(context); // 转化 initViewResolvers(context); // ViewResolvers 视图解析器 initFlashMapManager(context); // 闪存 }
初始化映射器
发现默认的配置文件中已经配置了默认的映射器和适配器,所以可以简化配置,无需配置映射器和适配器。
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); if (mappedHandler == null || mappedHandler.getHandler() == null) { noHandlerFound(processedRequest, response); return; } // Determine handler adapter for the current request. // 获取Handler的适配器 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()) { logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified); } if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) { return; } } // 执行链中拦截器的前置方法,如果返回false则终止执行。 if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } try { // Actually invoke the handler. // 通过Handler适配器执行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); } } }// 1、定义执行处理器执行链(HandlerExecutionChain mappedHandler = null;)// 2、获取处理器执行链(mappedHandler = getHandler(processedRequest);)// 3、获取处理器适配器(HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());)// 4、执行链中拦截器的前置方法,如果返回false则终止执行(if (!mappedHandler.applyPreHandle(processedRequest, response)))// 5、通过适配器执行真正的业务处理器逻辑,并返回模型和视图对象(mv = ha.handle(processedRequest, response, mappedHandler.getHandler());)// 6、执行链中拦截器的后置方法(mappedHandler.applyPostHandle(processedRequest, response, mv);)// 7、处理返回的结果,视图解析器的处理(processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);)// 8、查找到视图后进行渲染,然后响应给请求端
在第一个SpringMVC应用的基础上修改SpringMVC配置文件和编写模型对象处理器。
下面两个配置不是SpringMVC默认配置,所以不能省略。使用@RequestMapping映射请求URL
使用@Controller注解使HelloHandler 成为处理请求的控制器package com.springmvc.handler;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.servlet.ModelAndView;@Controller@RequestMapping("/hello")public class HelloHandler { @RequestMapping("/show") public ModelAndView show() { // 处理业务逻辑 ModelAndView mv = new ModelAndView(); mv.setViewName("hello");// 设置视图名称 mv.addObject("msg", "我的第一个注解SpringMVC应用!");// 设置模型数据 return mv; }}
作用:SpringMVC默认配置的升级版;
对应的java类是:
org.springframework.web.servlet.config.AnnotationDrivenBeanDefinitionParser
使用<mvc:annotation-driven />后默认加入的HandlerMapping和Adapter有:
HandlerMapping有2个:org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMappingorg.springframework.web.servlet.handler.BeanNameUrlHandlerMappingAdapter有3个:org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapterorg.springframework.web.servlet.mvc.HttpRequestHandlerAdapterorg.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter
转载地址:http://pdchb.baihongyu.com/