springMVC前端控制器Dispatcher

springMVC前端控制器Dispatcher

一、springMVC执行流程

  • 首先在接收到请求时,首先获取HandlerMapping
  • 然后根据HandlerMapping获取对应的HandlerExecutionChain,这个执行链内置了Handler(可以理解为Controller)
  • HandlerExecutionChain除了内置Handler外,还有拦截器HandlerInterceptor,首先有一个默认的拦截器,就是ConversionServiceExposingInterceptor(用于将请求里的参数转换为controller方法里的参数,这个转换拦截器没有提供日期转换的服务,所以使用springMVC时,要自己提供一个转换日期的)…还有其他拦截未完…
  • 接着会根据Handler获取HandlerAdapter
  • 然后就是执行HandlerExecutionChain里的拦截器,先执行HandlerInterceptorAdapter接口的preHandle方法,如果preHandle方法返回false的话,就直接执行afterCompletion方法
  • preHandle方法如果返回true,那么接着就是由HandlerAdapter执行Handler,Handler执行时较复杂,放到后面讲解…
  • 如果执行Handler时,没有出现异常,那么会执行postHanlder方法,反之不执行
  • 不论Handler是否出现异常,Dispatcher都会处理结果,在处理时,会检查是否由全局异常处理器HandlerExceptionResolver,如果我们需要使用全局异常处理器,只要实现该接口并注入IOC容器即可
  • 如果前面未执行afterCompletion方法,那么afterCompletion就会执行,afterCompletion不论什么情况,都一定会执行
    二、简单流程
    获取HandlerMapping->获取Handler(实际是这个HandlerExecutionChain)->
    由HandlerApdter执行Handler,封装成ModelAndView->最后在处理处理ModelAndView
    三、执行Handler时
  • 在执行Handler时,首先最主要的就是获取参数了,因为反射时需要传入参数
  • 所以第一步就是解析参数,解析Handler方法的参数
  • 解析参数时,会根据参数的类型获取对应的参数解析器HandlerMethodArgumentResolver的实现类
  • 我们一般使用到的参数解析器有
1.RequestParamMethodArgumentResolver支持基本类型以及对应的包装类型,还有常用的Date、Enum、URI、URL、Class...,还支持使用了@RequestParam注解的其他类型,还支持带有@RequestParam且有注解值的Map
此时获取参数是通过从Request.getParameter,所以这种情况不支持前端发送json字符串,只支持表单数据

2.MapMethodProcessor支持不使用注解的Map类型参数,没啥用,返回的是默认的BindingAwareModelMap容器

3.RequestParamMapMethodArgumentResolver支持使用注解@RequestParam("map")并且注解有值的Map,这时获取HttpServletRequest.getParameterMap容器,将值一一复制到Map里面

4.RequestResponseBodyMethodProcessor支持使用注解@ResquestBody的参数,并且一个方法里只能有一个@ResquestBody注解(留个心眼...)
此时通过jackson读取HttpServletRequest里的请求流(InputStream),并且将里面的请求体转换成json,还有流被读取完就关闭了,所以不能使用俩次@ResquestBody
所以这里要注意,请求体只有post请求才有,还有jackson转换成json,那么请求体里的数据必须是json字符串
所以使用@ResquestBody注解,必须在post请求下使用,并且必须提交json字符串,还有一个方法里只能有一个@ResquestBody注解,该注解不能用于单个List集合

5.ServletModelAttributeMethodProcessor支持我们自定义的类(一般用于pojo类),并且还有支持使用@ModelAttribute的类,所以我们使用自定义类时,也可以加上该注解,注解是否有值不影响
首先会尝试获取参数的构造器,一般都是获取空参构造器即可,然后进行实例化,接着会去Request里获取参数,然后按照方法参数的属性去寻找Request的参数,找到时对调用属性的set方法进行注入
当使用ArrayList作为参数时,并且没有注解,就会用该解析器,虽然实例化可以成功,但是无法添加数据,因为是采用set方法的

6.其他解析器就比较少见,可以去看HandlerMethodArgumentResolver对应的实现类,然后查看supportsParameter方法
  • 解析器总结:

  • 使用@ReuqestParam注解,底层通过参数名来去参数值,HttpServletRequest.getParameterValues()

  • 使用@RequestBody注解,底层通过将请求体转换成json对象,将内容出入到参数里,使用完该HttpRequest的输入流就被关闭了,此时就不能在获取请求体了

  • 不使用注解,针对Pojo来说,底层通过获取HttpServletRequest的所有参数,封装成类似key,value的结构,然后寻找pojo是否有对应的key值,也就是对应的属性值,有的话就调用set方法.

  • 详细介绍:

  • 对于一般类型

  • String、Integer、int…可以不使用注解@ReuqestParam,也可以使用,并且注解有值无值都可以。

  • 对于List集合

  • 必须使用@ReuqestParam注解!注解有值无值都可以,不使用@ReuqestParam注解会被当成pojo类来处理(需要调用调用属性的set方法),很明显List不适合;并且使用@RequestBody注解也不行,跟pojo处理类似,也不适合

  • 对于Map集合

  • 使用注解@RequestParam,注解有值时,可以等价于一般类型来使用,也就是通过注解值,获取实际参数。此时的参数是String类型或者String数组,底层没有提高将String类型的参数转为Map的转换器(org.springframework.core.convert.converter.Converter),所以要想这么使用,必须提供一个转换器(转换器配置在最下面)。

  • 使用注解@RequestParam,注解无值时,此时情况就比较简单了,通过获取HttpServletRequest.getParameterMap获取参数集合,然后将参数集合的值一一复制到Map里。

  • 使用@RequestBody,底层采取jackson将json对象值全部注入Map里

  • 不适用注解,会注入一个BindingAwareModelMap容器

  • 对于POJO类型

  • 不使用注解时(或者@ModelAttribute注解,有无值都可以),先进行实例化(一般采取无参构造),底层通过获取HttpServletRequest的所有参数,封装成类似key、value的结构,然后再从pojo获取属性与key比对,存在的话就调用对应的set方法注入

  • 使用@RequestBody注解,与Map使用一样的处理

  • 不可以使用@RequestParam

四、Converter转换器配置

import org.springframework.core.convert.converter.Converter;

import java.util.HashMap;
import java.util.Map;

//将String类型转换为Map,source就是客户端上传的值
public class ArrayToMapConverter implements Converter<String[], Map> {
    @Override
    public Map convert(String[] source) {
        Map map=new HashMap();
        map.put("array",source);
        return map;
    }
}

<!--接着在xml这样配置,这个容器储存着所有的Converter转换器-->
 <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
        <!-- 转换器 -->
        <property name="converters">
            <list>
                <!-- 有多个转换器,可以这里加入-->
                <!--<bean class="com.xxf.demo.mvc.CustomDateConverter"/>-->
                <bean class="com.xxf.demo.mvc.ArrayToMapConverter"/>
            </list>
        </property>
    </bean>

五、拦截器配置

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
public class LoginInterceptor extends HandlerInterceptorAdapter {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("我进行拦截了");
        return true;
    }
}
<mvc:interceptors>
     <mvc:interceptor>
     	<!--指定拦截路径-->
         <mvc:mapping path="/user/**" />
         <!--依赖对应的bean-->
         <ref bean="loginInterceptor"/>
     </mvc:interceptor>
 </mvc:interceptors>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值