目录
一、模型数据-如何将数据存入request域
二、模型数据-如何将数据存入session域
三、@ModelAttribute
四、视图解析器
相关文章
【SpringMVC】入门篇:带你了解SpringMVC的执行流程 | 【SpringMVC】入门篇:带你了解SpringMVC的执行流程 |
【SpringMVC】使用篇:SpringMVC的开始 | 【SpringMVC】使用篇:SpringMVC的开始 |
一、模型数据-如何将数据存入request域
我们在上一节已经对SpringMVC的基本使用有了一个大致的了解。当但我们提出一个新的需求:如何在request
域中存入数据呢❓
方案一:利用上一节所讲的,使用ServletAPI来存入。
方案二:利用SpringMVC的机制,将其自动放入request
域。
使用方案二,我们有三种实现方式。
演示需要用到的前端页面:
<h2>测试[HttpServletRequest 放入]</h2>
<hr/>
<form action="vote/vote05" method="post">
主人编号<input type="text" name="id"><br/>
主人姓名<input type="text" name="name"><br/>
宠物号<input type="text" name="pet.id"><br/>
宠物名<input type="text" name="pet.name"><br/>
<input type="submit" value="提交">
</form>
获取request域信息的页面:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>获取数据显示页面</title>
</head>
<body>
<h2>添加主人信息</h2>
<hr/>
${requestScope.master.name}<br/>
${requestScope.master.id}<br/>
${requestScope.master.pet.name}<br/>
${requestScope.master.pet.id}<br/>
<h2>手动放入的信息</h2>
<hr/>
${requestScope.address}
</body>
</html>
方式一
@RequestMapping(value = "/vote05")
public String test05(Master master100,HttpServletRequest request){
// 除了自动放到request中
// 我们也可以手动放到request中
request.setAttribute("address","beijing");
// 我们也可以修改自动放入request域中的 master对象
master100.setName("mary");
// springMVC 默认的是将参数名的 首字母小写 作为request中的key
// 所以:即使我们的形参名和key不对应,但还是可以修改request中的这个对象的属性值(引用的是同一个对象)
return "vote_ok";
}
- 当我们发送请求,封装到对象之后。SpringMVC底层会将其存到
request域
中,key是该类的类名首字母小写,这个key和形参名没有任何关系。我们形参最终也是指向了这个对象(同一个引用),所以当我们在Handler方式中修改这个对象的值之后,request域中的对象的值也会改变。
方式二
@RequestMapping(value = "/vote06")
public String test06(Master master100, Map<String,Object> map){
// 通过map对象,将数据放入到request当中
// 原理:springMVC会遍历我们的这个Map集合,将我们Map的key-val放入到request当中。
map.put("address","shanghai");
// 如果我们的map中存在和request中的key重复的情况的话,map中的val会覆盖request原来的那个val
map.put("master",null);
return "vote_ok";
}
- 当我们的Handler方法的形参中有一个
Map对象
的时候,springMVC会遍历我们的这个Map集合,将我们Map的key-val放入到request域
当中。 - 如果我们的map中存在和request中的key重复的情况的话,map中的val会覆盖request原来的那个val。
方式三
@RequestMapping(value = "/vote07")
public ModelAndView test07(Master master100){
ModelAndView modelAndView = new ModelAndView();
// 将属性放入到modelAndView
modelAndView.addObject("address","shenzhen");
// 同样的,我们要是有相同的key。他就会覆盖request原有的val
modelAndView.addObject("master",null);
// 指定跳转的视图名称
modelAndView.setViewName("vote_ok");
return modelAndView;
}
我们在前边在调用Handler方法最后会返回一个字符串,其实本质是返回了一个ModelAndView
。所以这里我们可以通过创建一个ModelAndView
来将其存到request域
中。
二、模型数据-如何将数据存入session域
我们这里使用的是ServletAPI,可以通过HttpSession
作为形参传进来。也可以通过HttpServletRequest
获取Session对象。
/**
* 测试如何将数据放到session域中
* @return
*/
@RequestMapping(value = "/vote08")
public String test08(Master master,HttpSession session){
// master默认是放在request域中的
// 将master放入session中
session.setAttribute("master",master);
session.setAttribute("address","guangzhou");
return "vote_ok";
}
三、@ModelAttribute
@ModelAttribute
的功能有点像我们的前置通知,它可以在当前的Handler中的方法执行前进行业务的操作。
/**
* 问题的提出?
* 当我们在执行Handler之前,需要执行一些前置的工作。如何做到?
* 答案:
* @ModelAttriibute
*/
@ModelAttribute
public void prepareModel(){
// 当我们调用其他的Handler的时候。都会执行这个前置方法
// 它的底层是我们的AOP
System.out.println("前置工作....");
}
四、视图解析器
还记得在环境搭建的时候,我们在Spring配置文件中配置了一个默认视图解析器
。在正式的了解它之前,我们先来了解一下另外一个:自定义视图解析器
。这里说的自定义视图解析器,是解析我们自定义视图的解析器。并不是我们自定义一个解析器(有没有感juo有点绕😋)。
下边来对其进行演示。
自定义视图解析器
前端的页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>自定义视图测试</title>
</head>
<body>
<h1>自定义视图测试</h1>
<a href="goods/buy">点击到自定义视图</a><br/>
<a href="goods/order">测试在目标方法中指定请求转发或者重定向的页面</a>
</body>
</html>
需要跳转的页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>my_view页面</title>
</head>
<body>
<h1>进入到my_view页面</h1>
<p>是从自定义视图来的</p>
</body>
</html>
自定义视图类
package com.jl.web.viewreslover;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.view.AbstractView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
/**
* ClassName: Myview
* Package: com.jl.web.viewreslover
* Description: 自定义视图类
*
* @Author: Long
* @Create: 2022/11/27 - 16:27
* @Version: v1.0
*/
/**
* 继承了 AbstractView 就可以作为一个视图
* @Component(value = "myView"),该视图会注入到容器中,名字是myView(可以理解为是一个视图名)
*/
@Component(value = "myView")
public class MyView extends AbstractView {
@Override
protected void renderMergedOutputModel(Map<String, Object> model,
HttpServletRequest request,
HttpServletResponse response) throws Exception {
// 完成视图渲染
// 并且可以确定我们要跳转的页面【请求转发】
System.out.println("进入到我们自己的视图....");
request.getRequestDispatcher("/WEB-INF/pages/my_view.jsp").forward(request,response);
}
}
Handler
@RequestMapping(value = "/goods")
@Controller
public class GoodsHandler {
@RequestMapping(value = "/buy")
public String buy(){
System.out.println("buy()...");
return "myView";
}
配置自定义视图解析器
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver">
<property name="order" value="99"/>
</bean>
- BeanNameViewResolver:可以去解析我们自定义的视图。
- order :表示视图解析器的执行顺序,值越小优先级越高。默认order是
Integer.MAX_VALUE
。 - 注意:我们必须保证自定义视图解析器的执行顺序在默认的视图解析器之前。
梳理
到了这里,肯定很多朋友没看懂这都干了些啥。我们通过下面的一张图来梳理一下:
默认视图解析器
相较于我们的自定义视图解析器,默认的视图解析器它封装了很多东西。在使用的时候,我们只是在目标方法中使用了一个return xxx
,返回了一个字符串。但它又是如何进行请求转发和重定向的,这将是我们下面将要探讨的问题❓
这个字符串也是视图名称,而这个视图是SpringMVC帮我们来创建的。
我们通过Debug来看一下(这里演示的是重定向)。
- 发送请求,中央控制器首先会拦截请求。
- 通过反射调用目标Handler。
- 返回模型数据(ModelAndView)。
- 拿到视图名称(就是
return xxx
)。 - 处理返回的结果。
- 做视图的渲染。
到这一步,我们可以看到。他和自定义视图解析器一样,都是继承了AbstractView
调用renderMergedOutputModel。我们继续来看一下它的内部都干了什么:
在内部它真正的调用了我们原生Servlet的API,进行了请求的重定向。当然请求重定向流程也是一样的,但它对应的视图不是RedircetView
。
最后我们来通过一张图梳理一下,清楚我们这里详解的是哪一步:
如果文章中有描述不准确或者错误的地方,还望指正。您可以留言📫或者私信我。🙏
最后希望大家多多 关注+点赞+收藏^_^,你们的鼓励是我不断前进的动力!!!
感谢感谢~~~🙏🙏🙏