springMVC的笔记

  1. DispatcherServlet接收所有请求
  2. 调用doDispatcher() 方法进行处理
    1). getHandler() 根据当前请求地址找到能处理这个请求的目标类(处理器)
    2). getHandlerAdapter() 根据当前处理器类拿到能执行这个处理器方法的适配器
    3). 使用适配器执行目标方法
    4). 目标方法执行完返回一个ModelAndView对象
    5). 根据ModelAndView的信息转发到具体页面,并可以在请求域中取出ModelAndView中的模型数据
	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 {
				// 检查是否是文件上传的请求,如果是,那么包装一个新的request
				processedRequest = checkMultipart(request);
				// 如果不是文件上传请求,该属性为true, 否则为false
				multipartRequestParsed = (processedRequest != request);
				// 根据当前请求找到哪一个Controller类来处理请求
				mappedHandler = getHandler(processedRequest);
				// 如果没有找到那个处理器类,这个请求就404,或者抛异常
				if (mappedHandler == null || mappedHandler.getHandler() == null) {
					noHandlerFound(processedRequest, response);
					return;
				}

				// 获取能执行这个处理器类中的所有目标方法的适配器 (相当于一个反射工具)
				// mappedHandler.getHandler() 返回的就是控制器类
				HandlerAdapter ha = 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 (logger.isDebugEnabled()) {
						logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
					}
					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;
				}
			
				// 如果目标方法返回值没有视图名,设置一个默认的视图名
				applyDefaultViewName(processedRequest, 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
				if (mappedHandler != null) {
					mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
				}
			}
			else {
				// Clean up any resources used by a multipart request.
				if (multipartRequestParsed) {
					cleanupMultipart(processedRequest);
				}
			}
		}
	}
getHandler() 细节: 怎么通过当前请求找到那个控制器类来处理
  • gethandler() 返回类型是HandlerExecutionChain 目标处理器的执行链
  • HandlerMapping 中维护了一个map,map中存放了请求和处理该请求的控制器类,HandlerMapping 有多个:
    • BeanNameUrlHandlerMapping,
    • DefaultAnnotationHandlerMapping
	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;
	}
如何找到目标处理器类的适配器HandlerAdapter

HandlerAdapter用于调用处理器方法,并且为处理器方法提供参数解析、返回值处理等适配工作,使使用者专心于业务逻辑的实现。 HandlerAdapter 共有三种

  • HttpRequestHandlerAdapter
  • SimpleControllerHandlerAdapter
  • AnnotationMethodHandlerAdapter(当前使用)
	protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
		for (HandlerAdapter ha : this.handlerAdapters) {
			if (logger.isTraceEnabled()) {
				logger.trace("Testing handler adapter [" + ha + "]");
			}
			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");
	}
初始化

在spring容器启动时,在初始化容器后,会初始后以下内容:

	protected void initStrategies(ApplicationContext context) {
		initMultipartResolver(context);
		initLocaleResolver(context);
		initThemeResolver(context);
		initHandlerMappings(context);
		initHandlerAdapters(context);
		initHandlerExceptionResolvers(context);
		initRequestToViewNameTranslator(context);
		initViewResolvers(context);
		initFlashMapManager(context);
	}
View 和ViewResolver

ViewResolver的作用就是得到View对象

Interceptor

  • 实现HandlerInterceptor接口

  • 三个方法 preHandler(), postHandler(), afterCompletion()

  • 使用mvc:interceptors标签来声明需要加入到SpringMVC拦截器链中的拦截器

    <mvc:interceptors>
    <!-- 使用bean定义一个Interceptor,直接定义在mvc:interceptors根下面的Interceptor将拦截所有的请求 -->
    	<bean class="com.host.app.web.interceptor.AllInterceptor"/>
    	<mvc:interceptor>
    		<mvc:mapping path="/test/number.do"/>
    		<!-- 定义在mvc:interceptor下面的表示是对特定的请求才进行拦截的 -->
    		<bean class="com.host.app.web.interceptor.LoginInterceptor"/>
    	</mvc:interceptor>
    </mvc:interceptors>
    

异常处理

  1. 使用SimpleMappingExceptionResolver实现异常处理

    <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">  
        <!-- 定义默认的异常处理页面,当该异常类型的注册时使用 -->  
        <property name="defaultErrorView" value="error"></property>  
        <!-- 定义异常处理页面用来获取异常信息的变量名,默认名为exception -->  
        <property name="exceptionAttribute" value="ex"></property>  
        <!-- 定义需要特殊处理的异常,用类名或完全路径名作为key,异常也页名作为值 -->  
        <property name="exceptionMappings">  
            <props>  
               <prop key="cn.exception.BusinessException">error-business</prop>  
        </property>  
        </bean>  
    
  2. 实现HandlerException

    public class MyExceptionResolver implements HandlerExceptionResolver{
    
        public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
                Exception ex) {
            // TODO Auto-generated method stub
            ModelAndView mav = new ModelAndView();
            if(ex instanceof ArithmeticException){
                //处理运算异常
                mav.setViewName("ae_error");
            }else if(ex instanceof NullPointerException){
                //处理空指针异常
                mav.setViewName("npe_error");
            }else{
                //处理其他异常
                mav.setViewName("error");
            }
            return mav;
        }
    }
    
  3. @ExceptionHandler局部异常处理

    @Controller
    public class DemoController {
        @RequestMapping("/login2.form")
        public String excute(){
            int a = 1/0;
            return "ok";
        }
        @ExceptionHandler
        public String handlerExcepting(HttpServletRequest request,Exception ex){
            return "he_error";
        }
    }
    
  4. @ControllerAdvice处理全局异常

    @ControllerAdvice
    public class ExceptionControllerAdvice {
      
        @ExceptionHandler(Throwable.class)
        @ResponseBody
        public Map<String, Object> ajaxError(Throwable error, HttpServletRequest request, HttpServletResponse response) {
            Map<String, Object> map = new HashMap<String, Object>();
            map.put("error", error.getMessage());
            return map;
        }  
    }
    
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值