Spring MVC返回视图原理(五)

简介: Spring MVC非常灵活,在使用的时候可以返回视图,也可以直接返回普通数据,在想,内部是怎么实现的呢?经过了几天研究Spring MVC的源码,可以看前几篇文章,今天再弄明白下为什么有时候返回视图,有时候直接返回数据呢。

Spring MVC非常灵活,在使用的时候可以返回视图,也可以直接返回普通数据,在想,内部是怎么实现的呢?

经过了几天研究Spring MVC的源码,可以看前几篇文章,今天再弄明白下为什么有时候返回视图,有时候直接返回数据呢。

分析

  1. 首先配置web.xml并且准备好视图,做一些准备工作
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

dispatcher-servlet.xml中视图配置


    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/view/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

Controller类

    @RequestMapping("/hello")
    @ResponseBody
    public String hello(){
        return "hello";
    }

    @RequestMapping("/index")
    public String indexView(){
        return "index";
    }
img_22adefd2a8e37f81e26cb0f9b77f1f71.png
image.png
  1. 访问进行调试,关于DispatcherServlet的流程,我们前面的文章已经都说过了,这里不做太多的赘述,getHandler, getHandlerAdapter,基本不变,在HandlerAdapter.handler(Handler)的时候内部有些不同。

返回视图与返回数据刚开始步骤基本都一样,invoke返回的值也是相同的。

真正产生变化的地方,在处理最后的返回值时

img_7134dc6908e171a1e7fe50a64dbf375d.png
image.png
  1. 处理返回值,在激发方法之后,要决定要用什么返回值处理器来处理返回的类型。其中涉及到一个接口HandlerMethodReturnValueHandler,真正用来处理的。

HandlerMethodReturnValueHandler有两个方法:

  • supportsReturnType是否支持当前的返回值类型,如果支持的话使用当前的HandlerMethodReturnValueHandler处理
  • handleReturnValue,处理返回值
/**
     * Iterate over registered {@link HandlerMethodReturnValueHandler}s and invoke the one that supports it.
     * @throws IllegalStateException if no suitable {@link HandlerMethodReturnValueHandler} is found.
     */
    @Override
    public void handleReturnValue(Object returnValue, MethodParameter returnType,
            ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {

        HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
        if (handler == null) {
            throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
        }
        handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
    }

    private HandlerMethodReturnValueHandler selectHandler(Object value, MethodParameter returnType) {
        boolean isAsyncValue = isAsyncReturnValue(value, returnType);
        for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
            if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) {
                continue;
            }
            if (handler.supportsReturnType(returnType)) {
                return handler;
            }
        }
        return null;
    }
img_83cd64e04de559d6fbe2b87a5f9bb227.png
image.png

如果是@ResponseBody注解的时候由RequestResponseBodyMethodProcessor处理。

//RequestResponseBodyMethodProcessor
@Override
    public boolean supportsReturnType(MethodParameter returnType) {
       //判断是否有ResponseBody.class的注解
        return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||
                returnType.hasMethodAnnotation(ResponseBody.class));
    }

返回值是String,但不加@ResponseBody注解的时候由ViewNameMethodReturnValueHandler处理。

  // ViewNameMethodReturnValueHandler
    @Override
    public boolean supportsReturnType(MethodParameter returnType) {
       //参数类型如果是void或者可以CharSequence.class.isAssignableFrom
        Class<?> paramType = returnType.getParameterType();
        return (void.class == paramType || CharSequence.class.isAssignableFrom(paramType));
    }

如果返回值为ModelAndView的时候,由ModelAndViewMethodReturnValueHandler处理


    @Override
    public boolean supportsReturnType(MethodParameter returnType) {
        return ModelAndView.class.isAssignableFrom(returnType.getParameterType());
    }

其余的可以自行查看。

  1. 上一步因为不同的ReturnValueHandler处理returnValue的结果不一样,Spring可以进行下一步的操作。

对于返回数据类型的操作,其将mavContainer的requestHandled设置为true,然后ModelAndView就会返回为null,后续的处理就不按照视图来处理。

如果返回的是视图,那么requestHandled仍然为false,后续再processDispatchResult中进行render.

  1. 后续和之前提到的DispatcherServlet都一样了。

回顾

Spring MVC对不同的返回值处理的方式不同,依靠的是HandlerMethodReturnValueHandler的不同实现。

主要在invoke方法之后,返回值与刚才激发的方法都被封装在ServletInvocableHandlerMethod里面了,其可以通过Method对象获取加在方法上的注解,类等等信息,最后做出结果。

最后

抓住DispatcherServlet的大体框架之后,其中的细节就简答的多了。

相关文章
|
2月前
|
缓存 Java 开发者
【Spring】原理:Bean的作用域与生命周期
本文将围绕 Spring Bean 的作用域与生命周期展开深度剖析,系统梳理作用域的类型与应用场景、生命周期的关键阶段与扩展点,并结合实际案例揭示其底层实现原理,为开发者提供从理论到实践的完整指导。
|
2月前
|
人工智能 Java 开发者
【Spring】原理解析:Spring Boot 自动配置
Spring Boot通过“约定优于配置”的设计理念,自动检测项目依赖并根据这些依赖自动装配相应的Bean,从而解放开发者从繁琐的配置工作中解脱出来,专注于业务逻辑实现。
|
26天前
|
XML Java 测试技术
《深入理解Spring》:IoC容器核心原理与实战
Spring IoC通过控制反转与依赖注入实现对象间的解耦,由容器统一管理Bean的生命周期与依赖关系。支持XML、注解和Java配置三种方式,结合作用域、条件化配置与循环依赖处理等机制,提升应用的可维护性与可测试性,是现代Java开发的核心基石。
|
26天前
|
前端开发 Java 微服务
《深入理解Spring》:Spring、Spring MVC与Spring Boot的深度解析
Spring Framework是Java生态的基石,提供IoC、AOP等核心功能;Spring MVC基于其构建,实现Web层MVC架构;Spring Boot则通过自动配置和内嵌服务器,极大简化了开发与部署。三者层层演进,Spring Boot并非替代,而是对前者的高效封装与增强,适用于微服务与快速开发,而深入理解Spring Framework有助于更好驾驭整体技术栈。
|
1月前
|
XML Java 应用服务中间件
【SpringBoot(一)】Spring的认知、容器功能讲解与自动装配原理的入门,带你熟悉Springboot中基本的注解使用
SpringBoot专栏开篇第一章,讲述认识SpringBoot、Bean容器功能的讲解、自动装配原理的入门,还有其他常用的Springboot注解!如果想要了解SpringBoot,那么就进来看看吧!
302 2
|
1月前
|
JSON 前端开发 JavaScript
Mvc视图的4种提交方式
本文介绍了jQuery中get/post与ajax提交方式,以及原生JS通过请求头和FormData对象发送数据的方法。涵盖参数配置、请求类型、回调处理等要点,适用于表单及数据提交场景。
70 0
|
3月前
|
Java 关系型数据库 数据库
深度剖析【Spring】事务:万字详解,彻底掌握传播机制与事务原理
在Java开发中,Spring框架通过事务管理机制,帮我们轻松实现了这种“承诺”。它不仅封装了底层复杂的事务控制逻辑(比如手动开启、提交、回滚事务),还提供了灵活的配置方式,让开发者能专注于业务逻辑,而不用纠结于事务细节。
|
7月前
|
存储 人工智能 自然语言处理
RAG 调优指南:Spring AI Alibaba 模块化 RAG 原理与使用
通过遵循以上最佳实践,可以构建一个高效、可靠的 RAG 系统,为用户提供准确和专业的回答。这些实践涵盖了从文档处理到系统配置的各个方面,能够帮助开发者构建更好的 RAG 应用。
3323 114
|
4月前
|
前端开发 Java API
Spring Cloud Gateway Server Web MVC报错“Unsupported transfer encoding: chunked”解决
本文解析了Spring Cloud Gateway中出现“Unsupported transfer encoding: chunked”错误的原因,指出该问题源于Feign依赖的HTTP客户端与服务端的`chunked`传输编码不兼容,并提供了具体的解决方案。通过规范Feign客户端接口的返回类型,可有效避免该异常,提升系统兼容性与稳定性。
298 0
|
4月前
|
缓存 安全 Java
Spring 框架核心原理与实践解析
本文详解 Spring 框架核心知识,包括 IOC(容器管理对象)与 DI(容器注入依赖),以及通过注解(如 @Service、@Autowired)声明 Bean 和注入依赖的方式。阐述了 Bean 的线程安全(默认单例可能有安全问题,需业务避免共享状态或设为 prototype)、作用域(@Scope 注解,常用 singleton、prototype 等)及完整生命周期(实例化、依赖注入、初始化、销毁等步骤)。 解析了循环依赖的解决机制(三级缓存)、AOP 的概念(公共逻辑抽为切面)、底层动态代理(JDK 与 Cglib 的区别)及项目应用(如日志记录)。介绍了事务的实现(基于 AOP
152 0