Spring MVC学习 | 使用域对象共享数据

24 篇文章 0 订阅


学习视频🎥:https://www.bilibili.com/video/BV1Ry4y1574R

一、回顾域对象

🔑Java Web中的四种域对象及其作用域(范围)

  • pageContext ->当前页面,范围最小。pageContext一般用于jsp页面,作用域仅为当前jsp页面,而Spring MVC不使用jsp,都是用html页面,所以下面仅介绍后面三种

  • request ->一次请求

  • session ->一次会话

  • application ->整个web工程,范围最大

🔑域对象的使用规则:在能实现功能的前提下,选用范围更小的域对象


二、在request域共享数据

2.1 使用ServletAPI

💬概述:直接使用原生的servlet API向request域中共享数据,即使用req.setAttribute("数据名", "数据值")

🔑使用

① 在控制器方法形参上添加HttpServletRequest类型的对象req,此时req对象就表示当前请求,然后直接根据req对象调用setAttribute()方法,实现在request域中存储数据(与获取请求参数的使用类似)

@RequestMapping("/testScope01")
public String showTestScope01(HttpServletRequest req) {
    // 直接调用方法向request域中存储数据
    req.setAttribute("testData", "hello,servlet API!");
    
    return "testScope";
}

② 在测试域对象页面testScope.html中获取requet域中的数据,request域中的数据可以直接通过数据名获取(下面四种方式都是采用该页面进行测试)

<p th:text="${testData}"></p>

💡 html页面中不能使用EL表达式,所以需要使用thymeleaf语法(th:text)来获取域对象数据,注意${"数据名"}是写在th:text中,不是写在<p>的标签体内

2.2 使用ModelAndView对象

💬概述modelAndView对象是Spring MVC用来处理模型数据(model)和视图数据(view)的重要对象,Spring MVC使用域对象共享数据的5种方法底层都是通过modelAndView对象实现(后续分析源码可知)

🔑分析modelAndView对象

  • modelAndView可分为两个部分——model和view,两个部分负责不同功能
    ① model:表示模型数据,主要用于向request域中共享数据,相当于一个Model类型的对象
    ② view:表示视图数据,主要用于设置视图,实现页面的跳转
  • modelAndView对象的两个主要方法
    addObject("数据名", 数据值):通过数据名(String)和数据值(Object)往request域中存储数据,与原生servlet API的req.setAttribute()方法类似
    setViewName("视图名"):设置视图名称,该方法的功能与原先控制器中返回一个视图名的功能一样(return "视图名"),都是设置一个视图名称交给视图解析器(thymeleaf)解析,获取到完整页面路径后实现页面跳转

🔑使用:创建控制器方法,方法返回类型为ModelAndView,无需添加形参,在方法内先创建一个ModelAndView类型的对象mav,然后通过mav对象分别调用addObject()setViewName()两个方法,实现向域中存储数据和设置视图名,最后将mav对象返回

❓ 为什么要把控制器方法返回值类型为ModelAndView:Spring MVC(或者说前端控制器DispatcherServlet)需要获取modelAndView对象,才能知道我们在域中存储的数据以及要转发的页面,而modelAndView对象是在方法内创建的,不是作为方法形参,所以就必须要把我们创建的modelAndView对象返回,Spring MVC才能获取到

@RequestMapping("/testScope02")
public ModelAndView showTestScope02() {
    ModelAndView mav = new ModelAndView();
    
    // 往request域中存储数据
    mav.addObject("testData", "hello,ModelAndView!");
    
    // 设置视图名
    mav.setViewName("testScope");
    
    // 最后返回mav对象
    return mav;
}

2.3 使用Model对象

🔑分析model对象

  • model对象相当于ModelAndView对象中的model部分,主要用于向request域中存储数据
  • model对象的方法——addAttribute("数据名", 数据值):通过数据名和数据值向request域中存储数据,与mav.addObject()req.setAttribute()用法一样

🔑使用:创建控制器方法,方法返回值类型为String,并添加一个Model类型的形参model,然后在方法中直接使用model对象调用addAttribute()方法,往request域中存储数据,最后再返回视图名

@RequestMapping("/testScope03")
public String showTestScope03(Model model) {
    // 往request域中存储数据
    model.addAttribute("testData", "hello,Model!");
    
    return "testScope";
}

2.4 使用ModelMap对象

💬概述ModelMap对象和Model对象类似,modelMap对象同样通过是调用addAttribute()方法实现往request域中存储数据

🔑使用

@RequestMapping("/testScope04")
public String showTestScope04(ModelMap modelMap) {
    // 往request域中存储数据
    modelMap.addAttribute("testData", "hello,ModelMap!");
    
    return "testScope";
}

2.5 使用Map集合

💬概述:Spring MVC中可以使用Map集合向request域中存储数据,Map集合中的键值对(key-value)分别对应request域中的数据名(key)和数据值(value)

🔑使用:创建控制器方法,方法中添加Map<String, Object>集合类型的形参scopeMap,然后在方法中直接使用map集合的put()方法,将数据名和数据值建立键值对关系,从而实现request域中存储数据

@RequestMapping("/testScope05")
public String showTestScope05(Map<String, Object> scopeMap) {
    // 直接在map集合中存储数据
    scopeMap.put("testData", "hello,Map!");
    
    return "testScope";
}

2.6 Model、ModelMap和Map的关系

  • 在上述测试控制器方法中分别打印出modelmodelMapscopeMap三个对象,观察控制台打印结果。打印结果显示,三个对象的打印结果类似,都是{数据名=数据值}的形式
    model-print01

    💡 一般直接打印对象,结果会显示对象的内存地址,说明实例化这三个对象的类中的toString()方法被重写过,且重写后的打印形式类型,说明实例化三个对象的类有可能是同一个

  • 通过反射的方式——对象.getClass().getName()获取实例化三个对象的类的全类名并打印到控制台,打印结果发现,实例化三个对象的类是同一个,都是BindingAwareModelMap
    model-print02

  • 分析四个类各自的源码

    ① Map:JDK中的底层接口
    map

    ② Model:Spring MVC底层的接口(与其他类或接口无继承关系)
    model

    ③ ModelMap:继承LinkHashMap<String, Object>类,而LinkHashMap<String, Object>实现Map接口
    modelMap ④ BindingAwareModelMap:继承ExtendedModelMap类,而ExtendedModelMap类又继承ModelMap,并实现Model接口
    binding
    extendsModelMap
    extends

  • 四个类的关系图(类图):由类图中可以看出BindingAwareModelMap类与ModelModelMapMap三个类或接口之间的关系,以及ModelModelMapMap都能被BindingAwareModelMap实例化
    extends02.

2.7 使用域对象的底层原理

🔑底层原理:在控制器方法执行后,前端控制器DispatcherServlet会将控制器方法中的模型数据和视图数据封装成一个ModelAndView对象,然后根据该对象向request域中共享数据,并将视图数据(视图名)交给视图解析器解析,最后实现页面跳转

🔑分析源码

  • 在控制器方法中打上断点,debug模式启动,在页面点击链接跳转到断点处,此时在方法栈中可以看到所有间接或直接调用控制器方法的底层方法,我们关心前端控制器DispatcherServlet中的方法——doDispatch()
    doDispatch()

  • doDispatch()方法中,可以看到ha.handle()方法返回了一个mv对象,该对象就是一个ModelAndView对象,而ha.handle()方法的执行还会间接或直接调用控制器方法,由此可得,前端控制器DispatcherServlet在调用控制器方法之后,将控制器方法中的模型数据和视图数据封装成一个ModelAndView对象并获取,然后再根据该对象来进行后续操作
    mv

  • 在前端控制器获取mv对象中打上断点,进一步查看该对象的详细信息。mv对象信息中,正好有控制器方法中设置的模型数据(往request域中存储数据)和视图数据(视图名),这里的控制器方法为showTestScope03(),即使用model对应的控制器方法
    mv-data


三、在session域共享数据

💬概述:Spring MVC中可以通过原生的Servlet API获取session对象,然后再根据session对象调用setAttribute("数据名", 数据值)方法往session域中存储数据

🔑使用

① 创建控制器方法,方法上添加HttpSession类型的形参session,然后根据session对象调用方法,往session域中存储数据(与request域中共享数据类似)

@RequestMapping("/testSession")
public String showTestSession(HttpSession session) {
    // 直接使用session对象调用方法,往session域中存储数据
    session.setAttribute("testSessionData", "hello,session!");

    return "testScope";
}

② 在testScope.html页面中通过thymeleaf语法获取session域中的数据,注意要使用thymeleaf内置对象(session)来获取域中的数据,不能直接写数据名(request域中数据获取才可以直接写数据名)

<!-- 获取session域中数据 -->
<p th:text="${session.testSessionData}"></p>

四、在application域共享数据

💬概述:Spring MVC中同样可以通过原生的Servlet API获取servletContext对象,然后再根据servletContext对象调用setAttribute("数据名", 数据值)方法往application域中存储数据

🔧使用

① 创建控制器方法,方法上添加HttpSession类型的形参session先根据session对象获取servletContext对象(或者说application对象),然后根据servletContext对象调用方法,往application域中存储数据

@RequestMapping("/testApplication")
public String showTestApplication(HttpSession session) {
    // 直接使用session对象获取servletContext对象
    ServletContext servletContext = session.getServletContext();

    // 根据servletContext对象往application域中存储数据
    servletContext.setAttribute("testApplicationData", "hello,application!");

    return "testScope";
}

② 在testScope.html页面中通过thymeleaf语法获取application域中的数据,注意要使用thymeleaf内置对象(application)来获取域中的数据,不能直接写数据名

<!-- 获取application域中数据 -->
<p th:text="${application.testApplicationData}"></p>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值