Spring中Model、ModelMap、ModelAndView理解和具体使用总结

Spring中Model、ModelMap、ModelAndView理解和具体使用总结在了解这三者之前,需要知道一点:SpringMVC在调用方法前会创建一个隐含的数据模型,作为模型数据的存储容器,成为”隐含模型”。也就是说在每一次的前后台请求的时候会随带这一个背包,不管你用没有,这个背包确实是存在的,用来盛放我们请求交互传递的值;关于这一点,spring里面有一个注解:@ModelAttribute:被该注解修饰的方法,会在每一次请求时优先执行,用于接收前台js…

大家好,又见面了,我是你们的朋友全栈君。

在了解这三者之前,需要知道一点:SpringMVC在调用方法前会创建一个隐含的数据模型,作为模型数据的存储容器, 成为”隐含模型”。
也就是说在每一次的前后台请求的时候会随带这一个背包,不管你用没有,这个背包确实是存在的,用来盛放我们请求交互传递的值;关于这一点,spring里面有一个注解:
@ModelAttribute :被该注解修饰的方法,会在每一次请求时优先执行,用于接收前台jsp页面传入的参数
例子:

@Controller
public class User1Controller{

    private static final Log logger = LogFactory.getLog(User1Controller.class);

    // @ModelAttribute修饰的方法会先于login调用,该方法用于接收前台jsp页面传入的参数
    @ModelAttribute
    public void userModel(String loginname,String password,
             Model model){
        logger.info("userModel");
        // 创建User对象存储jsp页面传入的参数
        User2 user = new User2();
        user.setLoginname(loginname);
        user.setPassword(password);
        // 将User对象添加到Model当中
        model.addAttribute("user", user);
    }

    @RequestMapping(value="/login1")
     public String login(Model model){
        logger.info("login");
        // 从Model当中取出之前存入的名为user的对象
        User2 user = (User2) model.asMap().get("user");
        System.out.println(user);
        // 设置user对象的username属性
        user.setUsername("测试");
        return "result1";
    }

在前端向后台请求时,spring会自动创建Model与ModelMap实例,我们只需拿来使用即可;
这里写图片描述
无论是Mode还是ModelMap底层都是使用BindingAwareModelMap,所以两者基本没什么区别;
我们可以简单看一下两者区别:

①Model

Model是一个接口,它的实现类为ExtendedModelMap,继承ModelMap类

public class ExtendedModelMap extends ModelMap implements Model

②ModelMap

ModelMap继承LinkedHashMap,spring框架自动创建实例并作为controller的入参,用户无需自己创建

public class ModelMap extends LinkedHashMap

而是对于ModelAndView顾名思义,ModelAndView指模型和视图的集合,既包含模型 又包含视图;ModelAndView的实例是开发者自己手动创建的,这也是和ModelMap主要不同点之一;ModelAndView其实就是两个作用,一个是指定返回页面,另一个是在返回页面的同时添加属性; 它的源码:

public class ModelAndView { 
  
/** View instance or view name String */  
private Object view  //该属性用来存储返回的视图信息
/** Model Map */  
private ModelMap model;//<span style="color: rgb(0, 130, 0); font-family: Consolas, 'Courier New', Courier, mono, serif; line-height: 18px;">该属性用来存储处理后的结果数据</span> 
/** * Indicates whether or not this instance has been cleared with a call to {@link #clear()}. */  
private boolean cleared = false;  
/** * Default constructor for bean-style usage: populating bean * properties instead of passing in constructor arguments. * @see #setView(View) * @see #setViewName(String) */  
public ModelAndView() {  
}  
/** * Convenient constructor when there is no model data to expose. * Can also be used in conjunction with <code>addObject</code>. * @param viewName name of the View to render, to be resolved * by the DispatcherServlet's ViewResolver * @see #addObject */  
public ModelAndView(String viewName) {  
this.view = viewName;  
}  
/** * Convenient constructor when there is no model data to expose. * Can also be used in conjunction with <code>addObject</code>. * @param view View object to render * @see #addObject */  
public ModelAndView(View view) {  
this.view = view;  
}  
/** * Creates new ModelAndView given a view name and a model. * @param viewName name of the View to render, to be resolved * by the DispatcherServlet's ViewResolver * @param model Map of model names (Strings) to model objects * (Objects). Model entries may not be <code>null</code>, but the * model Map may be <code>null</code> if there is no model data. */  
public ModelAndView(String viewName, Map<String, ?> model) {  
this.view = viewName;  
if (model != null) {  
getModelMap().addAllAttributes(model);  
}  
}  
/** * Creates new ModelAndView given a View object and a model. * <emphasis>Note: the supplied model data is copied into the internal * storage of this class. You should not consider to modify the supplied * Map after supplying it to this class</emphasis> * @param view View object to render * @param model Map of model names (Strings) to model objects * (Objects). Model entries may not be <code>null</code>, but the * model Map may be <code>null</code> if there is no model data. */  
public ModelAndView(View view, Map<String, ?> model) {  
this.view = view;  
if (model != null) {  
getModelMap().addAllAttributes(model);  
}  
}  
/** * Convenient constructor to take a single model object. * @param viewName name of the View to render, to be resolved * by the DispatcherServlet's ViewResolver * @param modelName name of the single entry in the model * @param modelObject the single model object */  
public ModelAndView(String viewName, String modelName, Object modelObject) {  
this.view = viewName;  
addObject(modelName, modelObject);  
}  
/** * Convenient constructor to take a single model object. * @param view View object to render * @param modelName name of the single entry in the model * @param modelObject the single model object */  
public ModelAndView(View view, String modelName, Object modelObject) {  
this.view = view;  
addObject(modelName, modelObject);  
}  
/** * Set a view name for this ModelAndView, to be resolved by the * DispatcherServlet via a ViewResolver. Will override any * pre-existing view name or View. */  
public void setViewName(String viewName) {  
this.view = viewName;  
}  
/** * Return the view name to be resolved by the DispatcherServlet * via a ViewResolver, or <code>null</code> if we are using a View object. */  
public String getViewName() {  
return (this.view instanceof String ? (String) this.view : null);  
}  
/** * Set a View object for this ModelAndView. Will override any * pre-existing view name or View. */  
public void setView(View view) {  
this.view = view;  
}  
/** * Return the View object, or <code>null</code> if we are using a view name * to be resolved by the DispatcherServlet via a ViewResolver. */  
public View getView() {  
return (this.view instanceof View ? (View) this.view : null);  
}  
/** * Indicate whether or not this <code>ModelAndView</code> has a view, either * as a view name or as a direct {@link View} instance. */  
public boolean hasView() {  
return (this.view != null);  
}  
/** * Return whether we use a view reference, i.e. <code>true</code> * if the view has been specified via a name to be resolved by the * DispatcherServlet via a ViewResolver. */  
public boolean isReference() {  
return (this.view instanceof String);  
}  
/** * Return the model map. May return <code>null</code>. * Called by DispatcherServlet for evaluation of the model. */  
protected Map<String, Object> getModelInternal() {  
return this.model;  
}  
/** * Return the underlying <code>ModelMap</code> instance (never <code>null</code>). */  
public ModelMap getModelMap() {  
if (this.model == null) {  
this.model = new ModelMap();  
}  
return this.model;  
}  
/** * Return the model map. Never returns <code>null</code>. * To be called by application code for modifying the model. */  
public Map<String, Object> getModel() {  
return getModelMap();  
}  
/** * Add an attribute to the model. * @param attributeName name of the object to add to the model * @param attributeValue object to add to the model (never <code>null</code>) * @see ModelMap#addAttribute(String, Object) * @see #getModelMap() */  
public ModelAndView addObject(String attributeName, Object attributeValue) {  
getModelMap().addAttribute(attributeName, attributeValue);  
return this;  
}  
/** * Add an attribute to the model using parameter name generation. * @param attributeValue the object to add to the model (never <code>null</code>) * @see ModelMap#addAttribute(Object) * @see #getModelMap() */  
public ModelAndView addObject(Object attributeValue) {  
getModelMap().addAttribute(attributeValue);  
return this;  
}  
/** * Add all attributes contained in the provided Map to the model. * @param modelMap a Map of attributeName -> attributeValue pairs * @see ModelMap#addAllAttributes(Map) * @see #getModelMap() */  
public ModelAndView addAllObjects(Map<String, ?> modelMap) {  
getModelMap().addAllAttributes(modelMap);  
return this;  
}  
/** * Clear the state of this ModelAndView object. * The object will be empty afterwards. * <p>Can be used to suppress rendering of a given ModelAndView object * in the <code>postHandle</code> method of a HandlerInterceptor. * @see #isEmpty() * @see HandlerInterceptor#postHandle */  
public void clear() {  
this.view = null;  
this.model = null;  
this.cleared = true;  
}  
/** * Return whether this ModelAndView object is empty, * i.e. whether it does not hold any view and does not contain a model. */  
public boolean isEmpty() {  
return (this.view == null && CollectionUtils.isEmpty(this.model));  
}  
/** * Return whether this ModelAndView object is empty as a result of a call to {@link #clear} * i.e. whether it does not hold any view and does not contain a model. * <p>Returns <code>false</code> if any additional state was added to the instance * <strong>after</strong> the call to {@link #clear}. * @see #clear() */  
public boolean wasCleared() {  
return (this.cleared && isEmpty());  
}  
/** * Return diagnostic information about this model and view. */  
@Override  
public String toString() {  
StringBuilder sb = new StringBuilder("ModelAndView: ");  
if (isReference()) {  
sb.append("reference to view with name '").append(this.view).append("'");  
}  
else {  
sb.append("materialized View is [").append(this.view).append(']');  
}  
sb.append("; model is ").append(this.model);  
return sb.toString();  
} 

a 它有很多构造方法,对应会有很多使用方法:
例子:
(1)当你只有一个模型属性要返回时,可以在构造器中指定该属性来构造ModelAndView对象:

package com.apress.springrecipes.court.web;  
...  
import org.springframework.web.servlet.ModelAndView;  
import org.springframework.web.servlet.mvc.AbstractController;  
public class WelcomeController extends AbstractController{ 
  
public ModelAndView handleRequestInternal(HttpServletRequest request,  
HttpServletResponse response)throws Exception{  
Date today = new Date();  
return new ModelAndView("welcome","today",today);  
}  
} 

(2)如果有不止一个属性要返回,可以先将它们传递到一个Map中再来构造ModelAndView对象。

package com.apress.springrecipes.court.web;  
...  
import org.springframework.web.servlet.ModelAndView;  
import org. springframework.web.servlet.mvc.AbstractController;  
public class ReservationQueryController extends AbstractController{  
...  
public ModelAndView handleRequestInternal(HttpServletRequest request,  
HttpServletResponse response)throws Exception{  
...  
Map<String,Object> model = new HashMap<String,Object>();  
if(courtName != null){  
model.put("courtName",courtName);  
model.put("reservations",reservationService.query(courtName));  
}  
return new ModelAndView("reservationQuery",model);  
}  
}  

当然也可以使用spring提供的Model或者ModelMap,这是java.util.Map实现;

package com.apress.springrecipes.court.web;  
...  
import org.springframework.ui.ModelMap;  
import org.springframework.web.servlet.ModelAndView;  
import org.springframework.web.servlet.mvc.AbstractController;  
public class ReservationQueryController extends AbstractController{  
...  
public ModelAndView handleRequestInternal(HttpServletRequest request,  
HttpServletResponse response)throws Exception{  
...  
ModelMap model = new ModelMap();  
if(courtName != null){  
model.addAttribute("courtName",courtName);  
model.addAttribute("reservations",reservationService.query(courtName));  
}  
return new ModelAndView("reservationQuery",model);  
}  
}  

在页面上可以通过el变量方式${key}或者bboss的一系列数据展示标签获取并展示modelmap中的数据;上面主要讲了ModelAndView的使用,其实Model与ModelMap使用方法都是一致;

下面我通过一个下例子展示一下:
在spring项目中,在配置文件中配置好 视图解析器:

<!-- 视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 前缀 -->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!-- 后缀 -->
<property name="suffix" value=".jsp"/>
</bean>

在后台写:

    @RequestMapping("/test1")
public ModelAndView test1(ModelMap mm ,HttpServletRequest request){
ModelAndView mv = new ModelAndView("mytest");
mv.addObject("key1","123");
mm.addAttribute("key1","1234");
return mv;
}//前端为 123 123
@RequestMapping("/test2")
public String test2(ModelMap mm ,HttpServletRequest request){
mm.addAttribute("key1", "1234");
return "mytest";
}//前端为 1234 1234 
@RequestMapping("/test3")
public String test3(Model mm ,HttpServletRequest request){
mm.addAttribute("key1", "12345");
return "mytest";
}
@RequestMapping("/test4")
public String test4(Model mm ,HttpServletRequest request){
mm.addAttribute("key1", "12345");
request.setAttribute("key1", "123456");
return "mytest";
}//前端为 12345 12345
@RequestMapping("/test5")
public String test5(Model mm ,ModelMap mmp,HttpServletRequest request){
request.setAttribute("key1", "123456");
mm.addAttribute("key1", "12345");
mmp.addAttribute("key1", "1234567");
return "mytest";
}//前端为 1234567 1234567

对应前端:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<% String test = String.valueOf(request.getAttribute("key1")); %>
</head>
<body>
<%=test %>
${key1 }
</body>
</html>

从上面测试可以看到Model,ModelMap与ModelAndView的具体使用;同时可以看出Model与ModelMap的值是能够替换的;并且两者赋值后作用比request.setAttribute()要大;这点在使用时需要注意;具体为啥,估计是最终解析时还是放在request上,最终还是替换了;我们知道

        request.setAttribute("key1", "123456");
request.setAttribute("key1", "123457");

这样的代码最终得到的是“123457”;具体原因这里不看了,先学会熟练使用;

终上所述,我们知道了Model与ModelMap其实都是实现了hashMap,并且用法都是一样的;两者都是spring在请求时自动生成,拿来用便可;ModelAndView就是在两者的基础上可以指定返回页面;
赋值能力 ModelAndView > Model/ModelMap>request ;

附加: 转发与重定向:
a 原始servlet:

转发时可以将页面的资源传给另一个页面,使用相对路径!
重定向只是单纯的进行页面跳转。使用绝对路径
if(username.equals("123")&&password.equals("123")){  
request.getRequestDispatcher("/success.html").forward(request, response); 
}else{  
//在sendRedict中url前必须加上当前web程序的路径名.....  
response.sendRedirect(request.getContextPath()+"/fail.html"); 
}  

springMVC中,默认转发,重定向的话使用如下:

@RequestMapping("filesUpload")
public String filesUpload(@RequestParam("files") MultipartFile[] files) {
//判断file数组不能为空并且长度大于0
if(files!=null&&files.length>0){
//循环获取file数组中得文件
for(int i = 0;i<files.length;i++){
MultipartFile file = files[i];
//保存文件
saveFile(file);
}
}
// 重定向
return "redirect:/list.html";
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/148457.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • 《数据仓库与数据挖掘教程》ch01绪论 章节整理

    《数据仓库与数据挖掘教程》ch01绪论 章节整理数据仓库概述从传统数据库到数据仓库计算机数据处理有两种主要方式事务型处理分析型处理传统数据库与事务处理传统数据库是长期存储在计算机内的、有组织的、可共享的数据集合有严格的数学理论支持,并在商业领域得到普及应用。联机事务处理(On-LineTransactionProcessing)系统,简称OLTP系统。数据存储在传统数据库中,成为OLTP数据库处理特点:实时响应,数…

  • 十大经典排序算法java(几种排序算法的比较)

    四种常用排序算法冒泡排序特点:效率低,实现简单思想(从小到大排):每一趟将待排序序列中最大元素移到最后,剩下的为新的待排序序列,重复上述步骤直到排完所有元素。这只是冒泡排序的一种,当然也可以从后往前排。publicvoidbubbleSort(intarray[]){intt=0;for(inti=0;i&amp;amp;lt;…

  • 没有sln文件怎么打开「建议收藏」

    没有sln文件怎么打开「建议收藏」没有sln文件怎么用相信这个问题应该是初学者,对.net了解不深的同学会发问的一、很多人学习.net网站开发的时候,使用MicrosoftVisualStudio工具,却没使用过IIS配置网站,我学习的时候就没用过IIS。二、.net网站有个website和webApplication区分,估计很多初学者都不了解这个。可以点击这个了解下三、网站分层架构估计也不是很了解。…

  • Java中Scanner用法总结

    Java中Scanner用法总结最近在做OJ类问题的时候,经常由于Scanner的使用造成一些细节问题导致程序不通过(最惨的就是网易笔试,由于sc死循环了也没发现,导致AC代码也不能通过。。。),因此对Scanner进行了一些总结整理。Scanner类简介Java5添加了java.util.Scanner类,这是一个用于扫描输入文本的新的实用程序。它是以前的StringTokenizer和Matcher类之间的某种结合。由于任何

  • 传感器尺寸与像素密度对相片分辨率的影响「建议收藏」

    传感器尺寸与像素密度对相片分辨率的影响「建议收藏」在人们日常生活摄影中,相机的传感器尺寸以及像素素往往决定了一幅图像的清晰度,当然,不同的镜头,不同的CMOS质量等等都会对相片的质量产生影响,今天就简单讨论讨论传感器尺寸和像素密度对图像分辨率的影响。当传感器尺寸一定时,像素越多,也就是像素密度越大,所能记录到的信息也就越多,当然,也不是没有上限的,当像素密度过大的时候,单个感光像素获取到的光线量无疑会变少,所以要提高感光度才能获取到和

  • ubuntu安装超详细教程_执手锁怎么安装

    ubuntu安装超详细教程_执手锁怎么安装Python进阶者18-06-1916:21前几天带大家一起安装了Ubuntu14.04系统,没来得及上车的伙伴可以戳这篇文章:手把手教你在VMware虚拟机中安装Ubuntu14.04系统。今天小编带大家一起在Ubuntu14.04中安装Pycharm,具体的教程如下。1、首先在主目录下创建software文件夹,此时该文件夹为空文件夹。这个文件夹下用于放置安装软件,当然这…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号