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

目录
相关文章
|
22天前
|
XML 存储 Java
Spring重要类解析
Spring重要类解析
20 0
|
1月前
|
消息中间件 Cloud Native Java
【Spring云原生系列】SpringBoot+Spring Cloud Stream:消息驱动架构(MDA)解析,实现异步处理与解耦合
【Spring云原生系列】SpringBoot+Spring Cloud Stream:消息驱动架构(MDA)解析,实现异步处理与解耦合
|
21天前
|
安全 Java 数据安全/隐私保护
【深入浅出Spring原理及实战】「EL表达式开发系列」深入解析SpringEL表达式理论详解与实际应用
【深入浅出Spring原理及实战】「EL表达式开发系列」深入解析SpringEL表达式理论详解与实际应用
44 1
|
1月前
|
XML Java 开发者
深入解析 Spring 和 Spring Boot 的区别
深入解析 Spring 和 Spring Boot 的区别
|
7天前
|
SQL Java 数据库连接
深度解析MyBatis核心:探寻其核心对象的精妙设计
深度解析MyBatis核心:探寻其核心对象的精妙设计
16 1
深度解析MyBatis核心:探寻其核心对象的精妙设计
|
7天前
|
XML Java 数据格式
Bean工厂探秘:解析Spring底层工厂体系BeanFactory的神奇之道
Bean工厂探秘:解析Spring底层工厂体系BeanFactory的神奇之道
17 0
Bean工厂探秘:解析Spring底层工厂体系BeanFactory的神奇之道
|
7天前
|
XML Java 数据格式
从入门到精通:Spring基础注解的全面解析
从入门到精通:Spring基础注解的全面解析
22 2
从入门到精通:Spring基础注解的全面解析
|
7天前
|
Java 数据库 Spring
切面编程的艺术:Spring动态代理解析与实战
切面编程的艺术:Spring动态代理解析与实战
21 0
切面编程的艺术:Spring动态代理解析与实战
|
7天前
|
Java 关系型数据库 MySQL
高级对象装配:解析Spring创建复杂对象的秘诀
高级对象装配:解析Spring创建复杂对象的秘诀
20 0
高级对象装配:解析Spring创建复杂对象的秘诀
|
25天前
|
Python
Python类与对象:深入解析与应用
本文介绍了Python中的核心概念——类和对象,以及它们在面向对象编程中的应用。类是用户定义的类型,描述具有相同属性和行为的对象集合;对象是类的实例,具备类的属性和方法。文章通过示例讲解了如何定义类、创建及使用对象,包括`__init__`方法、属性访问和方法调用。此外,还阐述了类的继承,允许子类继承父类的属性和方法并进行扩展。掌握这些概念有助于提升Python编程的效率和灵活性。

推荐镜像

更多