SpringMVC中ModelAndView对象与“视图解析器”

简介: spring MVC这个环境中,Spring MVC会依据controller(或者你叫它handler)中处理方法的返回值,进行解析,解析之后提供一个视图,作为响应。 标注了@Controller的处理器,实际上本质是一个POJO,你标注了@Controller,我就高看你一眼。

spring MVC这个环境中,Spring MVC会依据controller(或者你叫它handler)中处理方法的返回值,进行解析,解析之后提供一个视图,作为响应。
标注了@Controller的处理器,实际上本质是一个POJO,你标注了@Controller,我就高看你一眼。但你的形态就是一个java代码文件。
你作为一个java的土土的文件,你里面处理方法的返回值,也就是return语句,返回了一个东西。这个东西可以是String 也可以是 ModelAndView对象。这就是标注了@Controller的方法的全部工作。

接下来,Spring容器(或者说Spring MVC容器)需要接着你抛来的返回值,不管你的返回值是String还是ModelAndView,我,作为一个容器,我全都封装成ModelAndView对象。然后,我,Spring容器的一部分,视图解析器,开始工作。

视图解析器的英文名字叫做 ViewResolver,这个东西首先是Spring定义得人一个接口,具体你的Spring容器中的视图解析器有怎样的功能,取决于你为你自己的Spring容器配置了哪种具体的Spring视图解析器的实现类。

看看之前我们看过的一个图:
这个是spring mvc 的jar中的默认配置
screenshot
当然你的spring项目也可以在配置文件中覆盖上述配置(我并没有用别的视图解析器取代默认的InternalResourceViewResolver):
screenshot

/**
     * @return 登录验证
     */
    @RequestMapping("/dologin")
    public ModelAndView dologin(HttpServletRequest request, User user) {
        
        User us1 = uss.getUserByName(user.getSrName());
        ModelAndView mav = new ModelAndView();
        mav.setViewName("forward:/login.jsp");
        if (us1 == null) {
            mav.addObject("errorMsg", "用户名不存在");
        } else if (!us1.getSrPwd().equals(user.getSrPwd())) {
            mav.addObject("errorMsg", "用户密码不正确");
        } else {
            
            
        } 
        
        
        return mav;
    }

@Controller中的方法返回值最终都是ModelAndView,我们需要搞清楚两件事:
1.ModelAndView是什么?
2.视图解析器究竟做了哪些工作,才能返回我们需要的视图?

我们应该先看看ModelAndView是怎么回事:
ModelAndView是Spring中标准的类,完全是Spring自己封装的对象。Spring API中如此描述这个对象:
public class ModelAndView extends java.lang.Object

Holder for both Model and View in the web MVC framework. Note that these are entirely distinct. This class merely holds both to make it possible for a controller to return both model and view in a single return value.

Represents a model and view returned by a handler, to be resolved by a DispatcherServlet. The view can take the form of a String view name which will need to be resolved by a ViewResolver object; alternatively a View object can be specified directly. The model is a Map, allowing the use of multiple objects keyed by name.

用人话解释一下ModelAndView是干什么用的,ModelAndView包含两部分:一个View和一个Model
View由setViewName()方法来决定,决定让ViewResolver去哪里找View文件,并找到是哪个jsp文件;
Model由addObject()方法来决定,它的本质是java的HashMap,键值对;
用人话来解释ModelAndView的功能就是,View负责渲染Model,让你找到代表View的jsp,用这个jsp去渲染Model中的数据。

看看Spring源码:
Spring官网提供的API
screenshot
去这个路径找一下:
screenshot
也就是说ModelAndView对象中的核心成员就是Object和ModelMap
其中ModelMap也是Spring自己定义的对象。
screenshot
ModelMap的本质是Java的标准容器:LinkedHashMap
属性成员我们已经搞清楚了,下面是方法成员:
setViewName()方法和addObject()方法

   public void setViewName(@Nullable String viewName)
  {
    this.view = viewName;
  }

  public ModelAndView addObject(String attributeName, Object attributeValue)
  {
    getModelMap().addAttribute(attributeName, attributeValue);
    return this;
  }

  public ModelAndView addObject(Object attributeValue)
  {
    getModelMap().addAttribute(attributeValue);
    return this;
  }

  public ModelMap getModelMap()
  {
    if (this.model == null) {
      this.model = new ModelMap();
    }
    return this.model;
  }

也就是说,ModelAndView对象没有什么神秘之处,解构一下核心就是ObjectLinkedHashMap,完全是Java的标准容器(对象)。
也就是说,关键不在于ModelAndView对象,而在于“视图解析器”这个Spring容器的核心部件。

那么视图解析器怎样工作呢?
你明明知道你用的ViewResolver的实现类就是InternalResourceViewResolver,那么你应该仔细看看Spring API中这一部分的详细内容:
https://docs.spring.io/spring/docs/5.0.1.RELEASE/javadoc-api/
screenshot
首先InternalResourceViewResolver extends(继承)了 UrlBasedViewResolver;
然后顺便说,把用于显示(view)的jsp文件放在WEB-INF文件夹下是一种安全的做法,这样不能通过url直接access这些jsp,只能通过Controller java类来访问它们。

于是我们继续去看UrlBasedViewResolver
screenshot
我想这样一个Spring官方的API中的说明性文字已经足以解开所有疑惑:那就是ModelAndView对象的方法setViewName()中的参数,看上去像是一个普通字符串的参数,究竟应该采用哪种格式?应该怎么写?已经有了定论。

As a special feature, redirect URLs can be specified via the "redirect:" prefix. E.g.: "redirect:myAction.do" will trigger a redirect to the given URL, rather than resolution as standard view name. This is typically used for redirecting to a controller URL after finishing a form workflow.

Furthermore, forward URLs can be specified via the "forward:" prefix. E.g.: "forward:myAction.do" will trigger a forward to the given URL, rather than resolution as standard view name. This is typically used for controller URLs; it is not supposed to be used for JSP URLs - use logical view names there.

上述两段文字就是forward和redirect两个关键词的用法。

受到这篇文章的启发:http://blog.sina.com.cn/s/blog_6d3c1ec601014h1h.html

目录
相关文章
|
11月前
|
存储 Java 文件存储
微服务——SpringBoot使用归纳——Spring Boot使用slf4j进行日志记录—— logback.xml 配置文件解析
本文解析了 `logback.xml` 配置文件的详细内容,包括日志输出格式、存储路径、控制台输出及日志级别等关键配置。通过定义 `LOG_PATTERN` 和 `FILE_PATH`,设置日志格式与存储路径;利用 `<appender>` 节点配置控制台和文件输出,支持日志滚动策略(如文件大小限制和保存时长);最后通过 `<logger>` 和 `<root>` 定义日志级别与输出方式。此配置适用于精细化管理日志输出,满足不同场景需求。
2717 1
|
12月前
|
编译器 C++ 开发者
【C++篇】深度解析类与对象(下)
在上一篇博客中,我们学习了C++的基础类与对象概念,包括类的定义、对象的使用和构造函数的作用。在这一篇,我们将深入探讨C++类的一些重要特性,如构造函数的高级用法、类型转换、static成员、友元、内部类、匿名对象,以及对象拷贝优化等。这些内容可以帮助你更好地理解和应用面向对象编程的核心理念,提升代码的健壮性、灵活性和可维护性。
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
427 2
|
XML Java 开发者
Spring底层架构核心概念解析
理解 Spring 框架的核心概念对于开发和维护 Spring 应用程序至关重要。IOC 和 AOP 是其两个关键特性,通过依赖注入和面向切面编程实现了高效的模块化和松耦合设计。Spring 容器管理着 Beans 的生命周期和配置,而核心模块为各种应用场景提供了丰富的功能支持。通过全面掌握这些核心概念,开发者可以更加高效地利用 Spring 框架开发企业级应用。
392 18
|
设计模式 XML Java
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
本文详细介绍了Spring框架的核心功能,并通过手写自定义Spring框架的方式,深入理解了Spring的IOC(控制反转)和DI(依赖注入)功能,并且学会实际运用设计模式到真实开发中。
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
|
传感器 监控 安全
智慧工地云平台的技术架构解析:微服务+Spring Cloud如何支撑海量数据?
慧工地解决方案依托AI、物联网和BIM技术,实现对施工现场的全方位、立体化管理。通过规范施工、减少安全隐患、节省人力、降低运营成本,提升工地管理的安全性、效率和精益度。该方案适用于大型建筑、基础设施、房地产开发等场景,具备微服务架构、大数据与AI分析、物联网设备联网、多端协同等创新点,推动建筑行业向数字化、智能化转型。未来将融合5G、区块链等技术,助力智慧城市建设。
614 1
|
XML Java 数据库连接
Spring高手之路25——深入解析事务管理的切面本质
本篇文章将带你深入解析Spring事务管理的切面本质,通过AOP手动实现 @Transactional 基本功能,并探讨PlatformTransactionManager的设计和事务拦截器TransactionInterceptor的工作原理,结合时序图详细展示事务管理流程,最后引导分析 @Transactional 的代理机制源码,帮助你全面掌握Spring事务管理。
277 2
Spring高手之路25——深入解析事务管理的切面本质
|
12月前
|
安全 编译器 C语言
【C++篇】深度解析类与对象(中)
在上一篇博客中,我们学习了C++类与对象的基础内容。这一次,我们将深入探讨C++类的关键特性,包括构造函数、析构函数、拷贝构造函数、赋值运算符重载、以及取地址运算符的重载。这些内容是理解面向对象编程的关键,也帮助我们更好地掌握C++内存管理的细节和编码的高级技巧。
|
12月前
|
存储 程序员 C语言
【C++篇】深度解析类与对象(上)
在C++中,类和对象是面向对象编程的基础组成部分。通过类,程序员可以对现实世界的实体进行模拟和抽象。类的基本概念包括成员变量、成员函数、访问控制等。本篇博客将介绍C++类与对象的基础知识,为后续学习打下良好的基础。
|
Java 开发者 Spring
深入解析:Spring AOP的底层实现机制
在现代软件开发中,Spring框架的AOP(面向切面编程)功能因其能够有效分离横切关注点(如日志记录、事务管理等)而备受青睐。本文将深入探讨Spring AOP的底层原理,揭示其如何通过动态代理技术实现方法的增强。
610 8

推荐镜像

更多
  • DNS