whatzyt

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

Spring MVC的主要组件有那些?

spring mvc 在使用 DispatcherServlet 处理 web 请求的时候,会用到 spring 中的九大组件,以下是几个关键的组件:

 

1、List<HandlerMapping> handlerMappings:映射处理器;

用来加载、解析容器中的 controller;

HandlerMapping 接口一共有 3 个实现类:

1)BeanNameUrlHandlerMapping -> @Controller("/xxx") 类注解 + HttpRequestHandler 接口

2)RequestMappingHandlerMapping -> @Controller 类注解 + @RequestMapping("/xxx")方法注解

3)RouterFunctionMapping ->函数式映射方式;

 

2、List<HandlerAdapter> handlerAdapters:映射适配器;

handlerMappings 用来寻找请求对应的 controller,handlerAdapters 就是使用反射机制,执行 controller 中处理请求的方法;

常用的就是 RequestMappingHandlerAdapter,如果 controller 类的方法中带有 @RequestMapping 注解,就是会被 RequestMappingHandlerAdapter 所处理的目标方法;

RequestMappingHandlerAdapter 实现了 InitializingBean 接口;

在 getBean 创建该对象时执行了 InitializingBean 接口的方法进行了初始化;

给对象中添加了【参数解析器】和【返回值处理器】,使用 27 种参数解析器创建目标方法的参数,使用 15 种返回值处理器对目标方法的返回值进行处理,生成 ModelAndView 对象;

 

3、List<HandlerExceptionResolver> handlerExceptionResolvers:异常解析器;

默认异常解析器有以下 3 类:

(1)DefaultHandlerExceptionResolver:判断是不是 spring mvc 自己定义的异常,如果是就处理了;

其实底层代码就是使用 if else 挨个判断异常类型来实现的;

(2)ResponseStatusExceptionResolver:判断该异常有没有继承 ResponseStatusException 类,或者有没有标注 @ResponseStatus 注解;

(1)注解版:
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
public class ExceptionAnnotation extends RuntimeException {
    private String errorMessage;
    public ExceptionAnnotation(String errorMessage) {
        super(errorMessage);
    }
}
(2)继承类:
public class ExceptionClass extends ResponseStatusException {
    public ExceptionClass(HttpStatus status) {
        super(status);
    }
    public ExceptionClass(HttpStatus status, String reason) {
        super(status, reason);
    }
    public ExceptionClass(HttpStatus status, String reason, Throwable cause) {
        super(status, reason, cause);
    }
}

(3)ExceptionHandlerExceptionResolver:找到一个{@code @ExceptionHandler}方法并调用它来处理引发的异常;

@ExceptionHandler
public String error() {
    return "error";
}

 

4、List<ViewResolver> viewResolvers:视图解析器;

相当于这个请求怎么去其他页面,比如说转发还是重定向,还是返回一个图片或文档;

以下是 DispatcherServlet 属性源码:

DispatcherServlet 的属性中有【九大组件】,在处理请求时,就是用这些组件进行相应的处理:

  /** 文件上传解析器 */
 @Nullable
 private MultipartResolver multipartResolver;

 /** 国际化解析器 */
 @Nullable
 private LocaleResolver localeResolver;

 /** 主题解析器 */
 @Nullable
 private ThemeResolver themeResolver;

 /** 请求映射处理器 List 集合,其实就是【请求地址 和 controller】的映射关系集合 */
 @Nullable
 private List<HandlerMapping> handlerMappings;

 /** 处理器的适配器,可以理解为对应的【超级反射工具】 */
 /** 这是一个 Adapter 适配器,适配的是 【handlerMappings 中的映射方法】,和【响应的处理】进行适配
 @Nullable
 private List<HandlerAdapter> handlerAdapters;

 /** 处理器的异常解析器 */
 @Nullable
 private List<HandlerExceptionResolver> handlerExceptionResolvers;

 /** (其实这个没啥用,不用管)请求到视图名的转换器,把请求转换为要跳转的页面地址的转换器 */
 @Nullable
 private RequestToViewNameTranslator viewNameTranslator;

 /** 闪存管理器 */
 @Nullable
 private FlashMapManager flashMapManager;

 /** 视图解析器,相当于这个请求怎么去其他页面,比如说转发还是重定向,还是返回一个图片或文档 */
 @Nullable
 private List<ViewResolver> viewResolvers;

什么是DispatcherServlet

DispatcherServlet 的继承结构是这样的:

DispatcherServlet -> FrameworkServlet -> HttpServletBean -> HttpServlet -> Servlet;

DispatcherServlet、FrameworkServlet 、HttpServletBean 这三个 spring mvc 中的类;

HttpServlet、Servlet 是 javax.servlet 中的类;

也就是说,DispatcherServlet 实现了 servlet 标准接口,遵循 servlet 的生命周期;

Spring 的 MVC 框架是围绕 DispatcherServlet 来设计的,用来处理所有的 HTTP 请求和响应;


请描述Spring MVC的工作流程?描述一下 DispatcherServlet 的工作流程?

(1)用户发送请求至前端控制器 DispatcherServlet;

(2) DispatcherServlet 收到请求后,调用 HandlerMapping 处理器映射器, 请求获取 Handle;

(3)处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给 DispatcherServlet;

(4)DispatcherServlet 调用 HandlerAdapter 处理器适配器;

(5)HandlerAdapter 经过适配调用具体处理器(Handler,也叫后端控制器);

(6)Handler 执行完成返回 ModelAndView;

(7)HandlerAdapter 将 Handler 执行结果 ModelAndView 返回给 DispatcherServlet;

(8)DispatcherServlet 将 ModelAndView 传给 ViewResolver 视图解析器进行解析;

(9)ViewResolver 解析后返回具体 View;

(10)DispatcherServlet 对 View 进行渲染视图(即将模型数据填充至视图中);

(11)DispatcherServlet响应用户;

以下是 doDispatch 方法的源码解析:

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    
    // 创建异步请求处理管理器,这也是响应式 web 的基础
    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

    // 检查请求是不是文件上传请求,其实就是根据 http 规范,检查 request 的 header 的 Content-Type 是不是 "multipart/" 开头的
    // 如果是文件上传请求,就创建一个 MultipartHttpServletRequest 类型的 request 替换之前的 HttpServletRequest 类型的 request
    processedRequest = checkMultipart(request);

    // 获取能够处理当前请求的 controller 的方法,mappedHandler 中封装了该方法(问题【2】和【3】)
    mappedHandler = getHandler(processedRequest);

    // 如果 mappedHandler 为 null,返回相应 404(404 就是这么来的!)
    if (mappedHandler == null) {
       // 该方法中会 throw 报错,或者 response.sendError(HttpServletResponse.SC_NOT_FOUND); 抛出 404 错误
       noHandlerFound(processedRequest, response); 
       return;
    }

    // 确定当前请求的处理程序适配器,一共 4 种适配器,对应处理不同的 controller,适配器的加载和 handlerMappings 基本一样
    HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
    
    // 执行过滤器链 HandlerExecutionChain 中的拦截器的前置拦截过程
    if (!mappedHandler.applyPreHandle(processedRequest, response)) {
       return;
    }
    
    // 适配器真正执行 controller 处理请求的方法
    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

    // 如果没有指定的 view,设置默认的 view,注意:这里使用了九大组件之一的 viewNameTranslator,其实没啥用;
    applyDefaultViewName(processedRequest, mv);

    // 执行拦截器链的 postHandle 方法
    mappedHandler.applyPostHandle(processedRequest, response, mv);

    /* 以上所有代码,均被 try catch 包裹 */

    // 处理调度结果,处理处理程序选择和处理程序调用的结果,它是一个 ModelAndView 或一个要解析为 ModelAndView 的异常。
    processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);

}

Spring MVC常用的注解有哪些?

@RequestMapping:用于处理请求 url 映射的注解,可用于类或方法上。用 于类上,则表示类中的所有响应请求的方法都是以该地址作为父路径。

@RequestBody:注解实现接收http请求的json数据,将json转换为java对 象。

@ResponseBody:注解实现将conreoller方法返回对象转化为json对象响应给 客户。


@ResponseBody注解的作用

作用: 该注解用于将Controller的方法返回的对象,通过适当的 HttpMessageConverter 转换为指定格式后,写入到 Response 对象的 body 数据区。

使用时机:返回的数据不是html标签的页面,而是其他某种格式的数据时(如json、xml等)使用;


Spring MVC怎么样设定重定向和转发的?

(1) 转发:在返回值前面加"forward:",譬如"forward:user.do?name=method4"

(2) 重定向:在返回值前面加"redirect:",譬如"redirect:http://www.baidu.com"

 

 

 

posted on 2022-04-07 11:13  whatzyt  阅读(94)  评论(0编辑  收藏  举报