springMVC -- 4、①Model、Map、ModelMap②ModelAndView③session④@ModelAttribute模型属性⑤forward转发⑥redirect重定向⑦静态

本文详细介绍了SpringMVC中数据传输的各种方式,包括Model、Map、ModelMap,ModelAndView对象,session,@ModelAttribute注解的使用,以及forward转发和redirect重定向操作。此外,还讲解了如何访问静态资源及其配置方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

4、使用Model,Map,ModelMap传输数据到页面(回滚参数值)

5、使用ModelAndView对象传输数据到页面

6、使用session传输数据到页面

7、使用@ModelAttribute(模型属性)来获取请求中的数据

8、使用forward(转发)实现页面转发

9、使用redirect(重定向)来实现重定向

10、静态资源的访问


4、使用Model,Map,ModelMap传输数据到页面(回滚参数值)

    在刚开始的helloworld项目中,我们传递了参数回到我们页面,但是后续的操作都只是接受用户的请求,那么在SpringMVC中除了可以使用原生servlet的对象传递数据之外,还有什么其他的方式呢?

    可以在方法的参数上传入Model,ModelMap,Map类型,此时都能够将数据传送回页面

导入依赖:

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-web</artifactId>
        <version>5.2.3.RELEASE</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.2.3.RELEASE</version>
    </dependency>
</dependencies>

web.xml

================================= 过滤器 ======================================
<filter>
    <filter-name>encoding</filter-name>
    <filter-class>
org.springframework.web.filter.CharacterEncodingFilter
    </filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
    <init-param>
        <param-name>forceEncoding</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>
//过滤器映射
<filter-mapping>
    <filter-name>encoding</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
===============================================================================
<servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:springmvc.xml</param-value>
    </init-param>
</servlet>
//控制器映射
<servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

springmvc.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans    
       http://www.springframework.org/schema/beans/spring-beans.xsd 
       http://www.springframework.org/schema/context 
       https://www.springframework.org/schema/context/spring-context.xsd 
       http://www.springframework.org/schema/mvc 
       https://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <context:component-scan base-package="com.mashibing">
</context:component-scan>
    <bean class="
org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="suffix" value=".jsp"></property> //后缀
        <property name="prefix" value="/WEB-INF/page/"></property> //前缀
    </bean>
</beans>

java文件:OutputController(输出控制器)

@Controller
public class OutputController {

    @RequestMapping请求路径("/output")
    public String output(Map<String,String> map){
        map.put("msg","hello,springmvc ");
        return "success";
    }
}

success.jsp

设置服务器:

java文件:OutputController(输出控制器)

@Controller
public class OutputController {

    @RequestMapping请求路径("/output")
    public String output(Map<String,String> map){
        map.put("msg","hello,springmvc ");
        return "success";
    }
================================== 添加 =======================================
    @RequestMapping("/output2")
    public String output2(Model model){
        model.addAttribute("msg","hello,springmvc");
        return "success";
    }
    @RequestMapping("/output3")
    public String output3(ModelMap modelMap){
        modelMap.addAttribute("msg","hello,springmvc");
        return "success";
    }
===============================================================================
}

下面三个结果都一样:

在向页面回显数据的时候,可以在方法的参数中显示的声明      
  Map:
  ModelMap:
  Model:

success.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
欢迎<br>
${msg}<br>
================================== 添加 =======================================
page:${pageScope.msg}<br> //当前页面范围
request:${requestScope.msg}<br> //请求范围
session:${sessionScope.msg}<br> //会话范围
application:${applicationScope.msg}<br> //应用范围
===============================================================================
</body>
</html>

下面三个结果都一样:

都可以将数据进行回显:回显之后数据是保存在哪个作用域中的?(使用范围)
  page:  当前页面
  request: 当前请求
  session: 当前会话
  application:当前应用

 

当使用上述参数传递数据的时候回把数据都放置到Request作用域

java文件:OutputController(输出控制器)

@Controller
public class OutputController {

    @RequestMapping请求路径("/output")
    public String output(Map<String,String> map){
        map.put("msg","hello,springmvc ");
        return "success";
    }
    @RequestMapping("/output2")
    public String output2(Model model){
        model.addAttribute("msg","hello,springmvc");
        return "success";
    }
    @RequestMapping("/output3")
    public String output3(ModelMap modelMap){
        modelMap.addAttribute("msg","hello,springmvc");
        return "success";
    }
================================== 添加 =======================================
    @RequestMapping请求路径("/output4")
    public ModelAndView output4(){
        ModelAndView mv = new ModelAndView();
        mv.setViewName("success");
        mv.addObject("msg","springmvc");
        return mv;
===============================================================================
    }
}

下面三个结果都一样:

当使用此方式进行设置之后,会发现所有的参数值都设置到了request作用域中,那么这三个对象是什么关系呢?

5、使用ModelAndView对象传输数据到页面

java文件:OutputController(输出控制器)

@Controller
================================== 添加 =======================================
@SessionAttributes会话属性(value = "username")
===============================================================================
public class OutputController {

    @RequestMapping("/output")
    public String output(Map<String,String> map){
        map.put("msg","hello,springmvc ");
        System.out.println(map.getClass());
        return "success";
    }
    @RequestMapping("/output2")
    public String output2(Model model){
        model.addAttribute("msg","hello,springmvc");
        System.out.println(model.getClass());
        return "success";
    }
    @RequestMapping("/output3")
    public String output3(ModelMap modelMap){
        modelMap.addAttribute("msg","hello,springmvc");
        System.out.println(modelMap.getClass());
        return "success";
    }
    @RequestMapping("/output4")
    public ModelAndView output4(){
        ModelAndView mv = new ModelAndView();
        mv.setViewName("success");
        mv.addObject("msg","springmvc");
        return mv;
    }
================================== 添加 =======================================
    @RequestMapping("/testSession")
    public String testSession(Model model){
        model.addAttribute("username","zhangsan");
        return "success"; //成功
    }
===============================================================================
}

success.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
欢迎<br>
${msg}<br>
page:${pageScope.msg}<br> //当前页面范围
request:${requestScope.msg}<br> //请求范围
session:${sessionScope.msg}<br> //会话范围
application:${applicationScope.msg}<br> //应用范围
================================== 添加 =======================================
<hr>
session:${sessionScope.username}<br> //会话范围
request:${requestScope.username}<br> //请求范围
===============================================================================
</body>
</html>

    发现当使用modelAndView对象的时候,返回值的类型也是此对象,可以将要跳转的页面设置成view的名称,来完成跳转的功能,同时数据也是放到request作用中

6、使用session传输数据到页面

@SessionAttribute(会话属性):此注解可以表示,当向request作用域设置数据的时候同时也要向session中保存一份,此注解有两个参数,一个value(表示将哪些值设置到session中),另外一个type(表示按照类型来设置数据,一般不用,因为有可能会将很多数据都设置到session中,导致session异常)

java文件:OutputController(输出控制器)

@Controller
================================ 添加"msg" ====================================
@SessionAttributes会话属性(value = {"username","msg"}) //测试两个谁的优先级高
===============================================================================
public class OutputController {

    @RequestMapping("/output")
    public String output(Map<String,String> map){
        map.put("msg","hello,output"); //改output
        System.out.println(map.getClass());
        return "success";
    }
    @RequestMapping("/output2")
    public String output2(Model model){
        model.addAttribute("msg","hello,output2"); //改output2
        System.out.println(model.getClass());
        return "success";
    }
    @RequestMapping("/output3")
    public String output3(ModelMap modelMap){
        modelMap.addAttribute("msg","hello,output3"); //改output3
        System.out.println(modelMap.getClass());
        return "success";
    }
    @RequestMapping("/output4")
    public ModelAndView output4(){
        ModelAndView mv = new ModelAndView();
        mv.setViewName("success");
        mv.addObject("msg","output4"); //改output4
        return mv;
    }
    @RequestMapping("/testSession")
    public String testSession(Model model){
        model.addAttribute("username","zhangsan");
        return "success"; //成功
    }
}

     当需要向session(会话)中设置数据的时候,可以在当前Controller(控制器)上添加@SessionAttributes(会话属性)
     此注解表示,每次在向request作用中设置属性值的时候,顺带着向session(会话)中保存一份

     valuetype(类型)都写上之后表示session(会话)中可以存储名字为value值的参数以及类型为Integer的参数
    
valuetype可以分开单独使用,但是尽量不要一起使用,因为type类型会把所有符合类型的数据都设置到session(会话)中,导致session(会话)异常

推荐这样写:

java文件:OutputController(输出控制器)

@Controller
================================== 修改 =======================================
@SessionAttributes(types = String.class) //把所有符合类型的数据都设置到session(会话)中
===============================================================================
public class OutputController {

    @RequestMapping("/output")
    public String output(Map<String,String> map){
        map.put("msg","hello,output"); //改output
        System.out.println(map.getClass());
        return "success";
    }
    @RequestMapping("/output2")
    public String output2(Model model){
        model.addAttribute("msg","hello,output2"); //改output2
        System.out.println(model.getClass());
        return "success";
    }
    @RequestMapping("/output3")
    public String output3(ModelMap modelMap){
        modelMap.addAttribute("msg","hello,output3"); //改output3
        System.out.println(modelMap.getClass());
        return "success";
    }
    @RequestMapping("/output4")
    public ModelAndView output4(){
        ModelAndView mv = new ModelAndView();
        mv.setViewName("success");
        mv.addObject("msg","output4"); //改output4
        return mv;
    }
    @RequestMapping("/testSession")
    public String testSession(Model model){
        model.addAttribute("username","zhangsan");
        return "success"; //成功
    }
}

7、使用@ModelAttribute(模型属性)来获取请求中的数据

java文件:User(用户)

public class User {

    private Integer id;      //id
    private String name;     //名字
    private String password; //密码
    private Integer age;     //年龄

    public User() {}

    public Integer getId() {return id;}
    public void setId(Integer id) {this.id = id;}

    public String getName() {return name;}
    public void setName(String name) {this.name = name;}

    public String getPassword() {return password;}
    public void setPassword(String password) {this.password = password;}

    public Integer getAge() {return age;}
    public void setAge(Integer age) {this.age = age;}

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", password='" + password + '\'' +
                ", age=" + age +
                '}';
    }
}

update更新.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
================================== 添加 =======================================
<%
    pageContext.setAttribute("ctp",request.getContextPath());
%>
<body>
<form action="${ctp}/update">
    <input type="hidden" value="1" name="id"><br>
    name:张三<br> //直接显示名字,不显示输入框
    password:<input type="password" name="password"><br>
    age:<input type="text" name="age"><br>
    <input type="submit" value="更新"><br>
===============================================================================
</form>
</body>
</html>

java文件:UserController(用户控制器)

@Controller
public class UserController {

    @RequestMapping("/update")
    public String update(User user){
        System.out.println(user);
        return "success";
    }
}

//里面张三直接显示

跳转到:

 //idea里面张三

没显示

(先查询,再取出)

====================== 解决方式 ===========================

java文件:UserController(用户控制器)

@Controller
public class UserController {
============ 添加@ModelAttribute("user"),就是每次执行都创建User =============
    @RequestMapping("/update")
    public String update(@ModelAttribute("user") User user){
        System.out.println(user);
        return "success";
    }
================================== 添加 =======================================
@ModelAttribute
    public void testModelAttribute(Model model){
        User user = new User();
        user.setId(1);
        user.setName("李四");
        user.setAge(11);
        user.setPassword("1234");
        model.addAttribute("user",user); //增加属性
===============================================================================
    }
}

跳转到:

 //成功

 //比较地址空间

如果是true两个就相同:

 //改成2都一样?

结论:先执行第二个属性值方法,再执行第一个方法

 //一样

java文件:UserController(用户控制器)

@Controller
public class UserController {

Object o1 = null;
    Object o2 = null;
    Model m1 = null;

    @RequestMapping("/update")
    public String update(@ModelAttribute("user2") User user,Model model){
        System.out.println("update--------------------");
        o2 = user;
        System.out.println(user);
        System.out.println(o1 == o2);
        System.out.println(m1 == model);
        return "success";
    }
@ModelAttribute
    public void testModelAttribute(Model model){
        System.out.println("testModelAttribute---------------+");
        User user = new User();
        user.setId(1);
        user.setName("李四");
        user.setAge(11);
        user.setPassword("1234");
        model.addAttribute("user2",user); //增加属性
        o1 = user;
        m1 = model;
    }
================================== 添加 =======================================
    @ModelAttribute
    public void testModelAttribute2(Model model){
        System.out.println("testModelAttribute2---------------+");
    }
===============================================================================
}

 //从下往上执行

java文件:UserController(用户控制器)

@Controller
public class UserController {

Object o1 = null;
    Object o2 = null;
    Model m1 = null;

    @RequestMapping("/update")
    public String update(@ModelAttribute("user2") User user,Model model){
        System.out.println("update--------------------");
        o2 = user;
        System.out.println(user);
        System.out.println(o1 == o2);
        System.out.println(m1 == model);
        return "success";
    }
================================== 添加 =======================================
    @RequestMapping("/update2")
    public String update2(){ //这里不添加@ModelAttribute(模型属性)
        System.out.println("update2----------");
        return "success";
    }
===============================================================================
@ModelAttribute
    public void testModelAttribute(Model model){
        System.out.println("testModelAttribute---------------+");
        User user = new User();
        user.setId(1);
        user.setName("李四");
        user.setAge(11);
        user.setPassword("1234");
        model.addAttribute("user2",user); //增加属性
        o1 = user;
        m1 = model;
    }
    @ModelAttribute
    public void testModelAttribute2(Model model){
        System.out.println("testModelAttribute2---------------+");
    }
}

其实在使用的时候可以简化写法,也就是说,在方法的参数上不加@ModelAttribute也不会有问题

 //那么问题来了,其中第一二个方法会执行吗?

跳转到:

 //成功

 //说白了就是刚创建的方法与第一个方法不相同

========================================================

如果添加的@ModelAttribute模型属性(" "属性的值不对,那么也是获取不到值的。同时可以添加@SessionAttributes会话属性,但是注意,如果没有设置值的话,会报错

跳转到://报错:没有该属性值

@SessionAttributes(会话属性)要注意,在使用的时候如果没有对应的值,可能会报异常

@ModelAttribute(模型属性)注解用于将方法的参数或者方法的返回值绑定到指定的模型属性上,并返回给web视图。首先来介绍一个业务场景,来帮助大家做理解,在实际工作中,有些时候我们在修改数据的时候可能只需要修改其中几个字段,而不是全部的属性字段都获取,那么当提交属性的时候,从form表单中获取的数据就有可能只包含了部分属性,此时再向数据库更新的时候,肯定会丢失属性,因为对象的封装是springmvc自动帮我们new的,所以此时需要先将从数据库获取的对象保存下来,当提交的时候不是new新的对象,而是在原来的对象上进行属性覆盖,此时就需要使用@ModelAttribute(模型属性)

 

注意:@ModelAttribute除了可以使用设置值到model中之外,还可以利用返回值

 //李四拿到这个值

在使用@ModelAttribute的时候,需要注意:
 1、如果参数中的注解没有写名字的话,默认是用参数名称的首字母小写来匹配
 2、如果有值,直接返回,如果没有值,会去
session中进行查找,也就是说会判断当前类上是否添加过@SessionAttributes(会话属性)

推荐:注解中最好添加参数,来作为标识,进行对象属性的赋值

 

总结:通过刚刚的给参数赋值,大家应该能够发现,当给方法中的参数设置值的时候,如果添加了@ModelAttribute(模型属性),那么在查找值的时候,是遵循以下方式:

1、方法的参数使用参数的类型首字母小写,或者使用@ModelAttribute("")的值

2、先看之前是否在model中设置过该属性值,如果设置过就直接获取

3、看@SessionAttributes(会话属性)注解标注类中的方法是否给session中赋值,如果有的话,也是直接获取,没有报异常

8、使用forward(转发)实现页面转发

在发送请求的时候,可以通过forward(转发):来实现转发的功能:

index.jsp  

java文件:ForWardController(转发控制器)

@Controller
public class ForWardController {

    @RequestMapping("/forward")
    public String forward(){
        System.out.println("forward");
        return "forward:/index.jsp";
    }

    @RequestMapping("/forward2")
    public String forward2(){
        System.out.println("forward2");
        return "forward:/forward";
//"forward:/forward"意思是:返回到public String forward(){..}的方法里面
 
(转发的除了可以转发回到页面之外,还可以转发到其他请求中)
    }
}

在使用转发的时候前面要添加forward:前缀,同时通过写的字符串能够看到forward请求,而不经过视图处理器

9、使用redirect(重定向)来实现重定向

java文件:RedirectController(重定向控制器)

@Controller
public class RedirectController {
//使用重定向的时候需要注意,添加redirect:前缀
//重定向操作也不会经过视图处理器(视图解析器?)

    @RequestMapping("/redirect")
    public String redirect(){
        System.out.println("redirect");
        return "redirect:/index.jsp";
    }

    @RequestMapping("/redirect2")
    public String redirect2(){
        System.out.println("redirect2");
        return "redirect:/redirect";
    }
 
}

在javaweb的时候大家应该都接触过重定向和转发的区别:

转发:

由服务器的页面进行跳转,不需要客户端重新发送请求,特点如下:

        1、地址栏的请求不会发生变化,显示的还是第一次请求的地址

        2、请求的次数,有且仅有一次请求

        3、请求域中的数据不会丢失

        4、根目录:localhost:8080/项目地址/,包含了项目的访问地址

重定向:

在浏览器端进行页面的跳转,需要发送两次请求(第一次是人为的,第二次是自动的)

特点如下:

        1、地址栏的地址发生变化,显示最新发送请求的地址

        2、请求次数:2次

        3、请求域中的数据会丢失,因为是不同的请求

        4、根目录:localhost:8080/ 不包含项目的名称

对比:

区别

转发forward()

重定向sendRedirect()

根目录

包含项目访问地址

没有项目访问地址

地址栏

不会发生变化

会发生变化

哪里跳转

服务器端进行的跳转

浏览器端进行的跳转

请求域中数据

不会丢失

会丢失

10、静态资源的访问

java文件:StaticController(静态控制器)

@Controller
public class StaticController {

    @RequestMapping("/static")
    public String testStatic(){
        System.out.println("static");
        return "forwrd:/index.jsp";
    }
}

添加图片:

index.jsp   

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>$Title$</title>
  </head>
================================== 添加 =======================================
  <%
    pageContext.setAttribute("ctp",request.getContextPath());
  %>
  <body>
666666666<br>
  <img src="${ctp}/images/timg.jpg">
===============================================================================
  </body>
</html>

 //(图片在imagse文件夹下)

此时大家发现我们请求的图片根本访问不到,根据查看发现路径是没有问题的,那么为什么会找不到静态资源呢?

    大家发现此时是找不到对应的mapping(映射),此时是因为DispatcherServlet(前端控制器)会拦截所有的请求,而此时我们没有对应图片的请求处理方法,所以此时报错了,想要解决的话非常简单,只需要添加一个配置即可

=================== 解决图片(静态资源)问题 ====================

springmvc.xml

上面第一行代码:默认-控制器-处理

此配置表示  我们自己配置的请求由controller(控制器)来处理,但是不能请求的处理交由tomcat来处理
静态资源可以访问,但是动态请求无法访问

上面第二行代码:注解-被动

第二个也可以简化这样写:<mvc:annotation-driven>

       但是加上此配置之后,大家又发现此时除了静态资源无法访问之外,我们正常的请求也无法获取了,因此还需要再添加另外的配置

保证静态资源和动态请求都能够访问

 

使用默认的servlet-handler来处理静态资源,原来请求不到原因在于所有的请求都交由DispatcherServlet来处理
但是
DispatcherServlet中没有对应静态资源的处理逻辑,所以访问不到,添加默认之后就可以了,但是会发现此时动态请求无法完成
所以需要配合另外一个标签类配合使用

//也可以在web.xml内添加:

//

===============================================================

如果出现这种情况,就刷新整个项目试试(不用重启idea):

============================================================

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值