SpringMVC--获取请求参数 / 域对象共享数据

目录

1. SpringMVC 获取请求参数

1.1. 通过ServletAPI获取

1.2. 控制器方法形参获取

1.3. @RequestParam

1.4. @RequestHeader

1.5. @CookieValue

1.6. 通过POJO获取请求参数

1.7. 解决获取请求参数的乱码问题

2. 域对象共享数据

2.1. 三大域对象

2.2. 准备工作

2.3. ServletAPI向request域对象共享数据

2.3.1. 代码示例

2.3.2. 小总结

2.4. ModelAndView向request域对象共享数据

2.4.1. 代码示例

2.4.2. 小总结

2.5. Model向request域对象共享数据

2.5.1. 代码示例

2.5.2. 小总结

2.6. Map向request域对象共享数据

2.6.1. 代码示例

2.6.2. 小总结

2.7. ModelMap向request域对象共享数据

2.7.1. 代码示例

2.7.2. 小总结

2.8. Model/ModelMap/Map的关系

2.9. 向session域共享数据

2.9.1. 代码示例

2.9.2. 小总结

2.10. 向application域共享数据

2.10.1. 代码示例

2.10.2. 小总结


1. SpringMVC 获取请求参数

在SpringMVC中,获取请求参数是指从客户端(如浏览器)发送的HTTP请求中提取信息的过程。这些信息可以是用户在浏览器地址栏输入的查询字符串中的键值对,也可以是通过表单提交的数据。

当用户访问一个URL时,URL后面经常跟着一些由问号(?)开始,由一系列键值对(param1=value1&param2=value2)组成的查询字符串。在SpringMVC中,你可以通过特定的注解或者方法来获取这些参数的值。

例如,如果你有一个查询字符串example.com?name=Kimi&age=5,你想要获取name的值,你可以在你的控制器方法中使用@RequestParam注解,如下所示:

public String getUserInfo(@RequestParam("name") String name) {
    // 在这里,name变量将会包含"Kimi"
    // ...
}

如果参数是嵌入在URL路径中的,比如example.com/user/1,你可以使用@PathVariable注解来获取路径中的参数值:

public String getUserById(@PathVariable("userId") String userId) {
    // 在这里,userId变量将会包含"1"
    // ...
}

SpringMVC会自动将请求中相应的参数值映射到你的控制器方法的参数上。如果请求中没有相应的参数,而你又没有提供默认值,那么SpringMVC会抛出一个异常。


1.1. 通过ServletAPI获取

在SpringMVC框架中,获取客户端发送的请求参数是一项基本而重要的操作。其中一种方式是利用HttpServletRequest对象,该对象是Servlet API的一部分,提供了对当前HTTP请求的封装和访问。


当你在控制器方法中添加HttpServletRequest作为参数时,你可以直接调用该对象的方法来获取请求中的数据。以下是一个简化的示例,用以解释如何操作:

<a th:ref="@{/testParam}(username='admin', password='123456')">
    测试ServletAPI获取请求参数 </a>
@RequestMapping("/testParam")
public String testParam(HttpServletRequest request){
    // 从请求中获取名为"username"的参数值,并将其存储在局部变量username中
    String username = request.getParameter("username");
    // 从请求中获取名为"password"的参数值,并将其存储在局部变量password中
    String password = request.getParameter("password");
    // 打印获取到的用户名和密码
    System.out.println("username:" + username + ", password:" + password);
    // 返回视图名称,这里为"success"
    return "success";
}

在这个例子中,我们使用了@RequestMapping注解来映射一个特定的URL路径("/testParam")到控制器方法testParam。当有请求发送到这个路径时,SpringMVC会调用这个方法。
在方法内部,我们通过调用HttpServletRequest对象的getParameter方法来获取请求参数。getParameter方法接受一个参数名称作为输入,并返回与该名称对应的请求参数的值。
例如,如果我们的请求URL是http://example.com/testParam?username=admin&password=123456,那么request.getParameter("username")将返回字符串"admin",request.getParameter("password")将返回字符串"123456"。
最后,方法返回一个字符串"success",这通常对应于一个视图名称,SpringMVC的视图解析器会根据这个名称来渲染相应的页面。


1.2. 控制器方法形参获取

在SpringMVC中,除了通过HttpServletRequest对象获取请求参数外,还可以直接通过控制器方法的参数来获取。这种方式更为直观和便捷。

首先,假设你有一个HTML页面,其中包含一个链接,如下所示:

<a th:href="@{/testParam(username='admin',password=123456)}">
  测试获取请求参数-->/testParam </a>

这里使用了Thymeleaf模板引擎(由th:前缀标识)来构建一个指向/testParam路径的链接,并且预先设置了usernamepassword两个请求参数的值。当用户点击这个链接时,浏览器会向服务器发送一个包含这两个参数的GET请求。

接下来,在SpringMVC的控制器中,你可以定义一个方法来处理这个请求,如下所示:

@RequestMapping("/testParam")
public String testParam(String username, String password){
    System.out.println("username:" + username + ", password: " + password);
    return "success";
}

在这个例子中,@RequestMapping注解将/testParam路径的请求映射到了testParam方法。方法中的两个参数usernamepassword与请求中的参数同名。当请求到达时,SpringMVC会自动将请求参数的值赋给控制器方法的对应参数。

现在,如果你的请求中有多个同名参数,例如:

http://example.com/testParam?username=Kimi&username=Admin

在这种情况下,如果你想接收所有的username参数,你可以在控制器方法中使用字符串数组来接收:

@RequestMapping("/testParam")
public String testParam(String[] usernames, String password){
    System.out.println("usernames: " + Arrays.toString(usernames) + ", password: " + password);
    return "success";
}

这里,usernames是一个字符串数组,它将包含所有名为username的请求参数的值。Arrays.toString方法用于将数组转换为字符串,以便于打印输出。

如果你仍然只想要一个单一的字符串参数,即使有多个同名参数,你可以保持使用单个字符串类型的参数。在这种情况下,SpringMVC会取最后一个同名参数的值作为该参数的值。在上面的例子中,username参数的值将会是"Admin",因为这是请求中username参数的最后一个值。


1.3. @RequestParam

@RequestParam 是在Spring框架中使用的注解,它允许你将HTTP请求的参数映射到你的控制器方法的参数上。这个注解主要用于处理请求参数,提供了一种灵活的方式来获取和验证这些参数。

这个注解的三个主要属性是

  1. value:这个属性用于指定HTTP请求参数的名称。当你在方法的参数前使用@RequestParam注解时,可以通过value属性来明确指定你想要从请求中获取哪个参数。例如,如果你有一个名为page的请求参数,你可以这样使用@RequestParam
@GetMapping("/users")
public String getUsers(@RequestParam(value = "page") int pageNumber) {
    // ...
}

在这个例子中,value="page"告诉Spring框架,你想要将请求中的page参数映射到pageNumber变量上。

  1. required:这个属性是一个布尔值,用于指示请求中是否必须包含指定的参数。默认情况下,required属性的值是true,这意味着请求必须包含value属性指定的参数。如果请求中没有这个参数,或者参数的值为空,那么就会抛出一个400错误,提示参数缺失。
    如果将required属性设置为false,那么这个参数就不再是必须提供的。在这种情况下,如果请求中没有提供该参数,或者参数值为空,那么方法的参数将会被赋予null值。

  1. defaultValue:这个属性允许你为参数指定一个默认值。无论required属性是true还是false,如果请求中没有提供value指定的参数,或者参数值为空,那么方法的参数将会被赋予defaultValue属性指定的值。
    例如:
@GetMapping("/users")
public String getUsers(@RequestParam(value = "page", required = false, 
        defaultValue = "1") int pageNumber) {
    // ...
}

在这个例子中,如果请求中没有page参数,或者page参数的值为空,那么pageNumber将会被赋予默认值1

当然可以。以下是一个使用@RequestParam注解的简单Spring MVC控制器方法的例子。这个例子中,我们将创建一个处理HTTP GET请求的方法,该方法接受一个可选的查询参数sort,用于指定返回用户列表的排序方式。

举个栗子

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {

    // 定义一个处理"/users"路径GET请求的方法
    @GetMapping("/users")
    public String getUsers(
            // 使用@RequestParam注解来绑定请求参数到方法的参数
            @RequestParam(value = "sort", required = false, 
                defaultValue = "name") String sort) {
        
        // 这个方法将会根据sort参数的值返回不同的字符串
        if ("name".equals(sort)) {
            return "Users are sorted by name.";
        } else if ("age".equals(sort)) {
            return "Users are sorted by age.";
        } else {
            return "Invalid sorting parameter.";
        }
    }
}

在这个例子中,我们定义了一个名为getUsers的方法,它映射到HTTP GET请求的/users路径。这个方法有一个参数sort,我们使用@RequestParam注解来绑定请求中的sort查询参数到这个方法的参数上。

  • value = "sort":这指定了请求参数的名称,即我们在URL中使用的名称。例如,在浏览器中访问http://localhost:8080/users?sort=name时,sort就是请求参数的名称。
  • required = false:这表明sort参数是可选的。如果请求中没有提供这个参数,那么方法的sort参数将会是null
  • defaultValue = "name":这为sort参数提供了一个默认值。如果请求中没有sort参数,或者参数值为空字符串,那么sort参数将会被赋予默认值"name"

所以,如果你访问http://localhost:8080/users,没有提供sort参数,那么getUsers方法将会返回"Users are sorted by name.",因为sort参数的默认值是"name"。如果你提供了sort参数,比如访问http://localhost:8080/users?sort=age,那么它将会返回"Users are sorted by age."。如果你提供了一个无效的参数,比如http://localhost:8080/users?sort=height,那么它将会返回"Invalid sorting parameter."


1.4. @RequestHeader

@RequestHeader注解在Spring框架中用于将HTTP请求头信息映射到控制器方法的参数上。这个注解允许你访问和处理请求头中的信息,例如认证令牌、客户端信息等。用法同@RequestParam。

@RequestHeader注解三个属性的简单解释

  1. value:这个属性用于指定HTTP请求头的名称。当你在方法的参数前使用@RequestHeader注解时,通过value属性来明确指出你想要获取哪个请求头的值。例如,如果你想获取名为Authorization的请求头,你可以这样使用@RequestHeader
@GetMapping("/resource")
public String getResource(
    @RequestHeader(value = "Authorization") String authHeader) {
    // ...
}

在这个例子中,value="Authorization"告诉Spring框架,你想要将请求中的Authorization请求头的值映射到authHeader变量上。

  1. required:这个属性是一个布尔值,用来指示请求头是否必须存在于请求中。默认情况下,required的值是true,这意味着请求必须包含value属性指定的请求头。如果请求中缺少这个请求头,那么将会抛出一个异常。
    如果将required属性设置为false,那么这个请求头就不是必须提供的。在这种情况下,如果请求中没有提供该请求头,那么方法的参数将会被赋予null值。

  1. defaultValue:这个属性允许你为请求头指定一个默认值。无论required属性是true还是false,如果请求中没有提供value指定的请求头,或者请求头的值为空,那么方法的参数将会被赋予defaultValue属性指定的值。

举个栗子,创建一个处理HTTP GET请求的方法,该方法接受一个名为User-Agent的请求头,这个请求头通常包含了发出请求的客户端(如浏览器)的信息。

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ResourceController {

    // 定义一个处理"/resource"路径GET请求的方法
    @GetMapping("/resource")
    public String getResource(@RequestHeader(value = "User-Agent", 
        required = false, defaultValue = "Unknown") String userAgent) {
        
        // 这个方法将会根据User-Agent请求头发送不同的响应
        return "The resource was requested by: " + userAgent;
    }
}

在这个例子中,我们定义了一个名为getResource的方法,它映射到HTTP GET请求的/resource路径。这个方法有一个参数userAgent,我们使用@RequestHeader注解来绑定请求中的User-Agent请求头到这个方法的参数上。

  • value="User-Agent":这指定了请求头的名称,即我们想要获取的请求头的名称。在这个例子中,我们关注的是User-Agent请求头。
  • required = false:这表明User-Agent请求头不是必须提供的。如果请求中没有这个请求头,或者请求头的值为空字符串,那么userAgent参数将会是null
  • defaultValue = "Unknown":这为User-Agent请求头提供了一个默认值。如果请求中没有提供User-Agent请求头,或者请求头的值为空,那么userAgent参数将会被赋予默认值"Unknown"

所以,如果你访问/resource路径,并且你的浏览器提供了User-Agent请求头,那么getResource方法将会返回包含这个请求头信息的字符串。如果你的请求没有包含User-Agent请求头,或者请求头的值为空,那么方法将会返回一个字符串,表明请求是由一个未知的客户端发起的。


1.5. @CookieValue

@CookieValue注解在Spring框架中用于将HTTP请求中的cookie值映射到控制器方法的参数上。这个注解允许你轻松地读取和处理客户端发送的cookie数据。

@CookieValue注解三个属性:

  1. value:这个属性用来指定cookie的名称。当你使用@CookieValue注解时,通过value属性来明确你想要从请求的cookie中获取哪个cookie的值。例如,如果你的请求中有一个名为sessionToken的cookie,你可以这样使用@CookieValue
@GetMapping("/dashboard")
public String getDashboard(
    @CookieValue(value = "sessionToken") String sessionToken) {
    // ...
}

在这个例子中,value="sessionToken"告诉Spring框架,你想要将名为sessionToken的cookie的值映射到sessionToken变量上。

  1. required:这个属性是一个布尔值,用来指示请求中是否必须包含指定的cookie。默认情况下,required的值是true,这意味着请求必须包含value属性指定的cookie。如果请求中缺少这个cookie,那么将会抛出一个异常。
    如果将required属性设置为false,那么这个cookie就不是必须提供的。在这种情况下,如果请求中没有提供该cookie,那么方法的参数将会被赋予null值。

  1. defaultValue:这个属性允许你为cookie指定一个默认值。无论required属性是true还是false,如果请求中没有提供value指定的cookie,或者cookie的值为空,那么方法的参数将会被赋予defaultValue属性指定的值。

举个栗子

import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class CookieController {

    // 定义一个处理"/dashboard"路径GET请求的方法
    @GetMapping("/dashboard")
    public String showDashboard(
        @CookieValue(value = "sessionToken", required = false,
        defaultValue = "no_session") String sessionToken) {
        
        // 这个方法将会根据sessionToken的值来显示不同的信息
        if ("admin".equals(sessionToken)) {
            return "Welcome back, Admin!";
        } else if ("user".equals(sessionToken)) {
            return "Hello, User!";
        } else {
            return "You are not logged in.";
        }
    }
}

定义了一个名为showDashboard的方法,它映射到HTTP GET请求的/dashboard路径。这个方法有一个参数sessionToken,我们使用@CookieValue注解来绑定请求中的名为sessionToken的cookie的值到这个方法的参数上。

  • value="sessionToken":这指定了cookie的名称,即我们想要获取的cookie的名称。
  • required = false:这表明sessionTokencookie不是必须提供的。如果请求中没有这个cookie,或者cookie的值为空字符串,那么sessionToken参数将会是null
  • defaultValue = "no_session":这为sessionTokencookie提供了一个默认值。如果请求中没有提供sessionTokencookie,或者cookie的值为空,那么sessionToken参数将会被赋予默认值"no_session"

所以,如果你访问/dashboard路径,并且你的请求包含了名为sessionToken的cookie,那么showDashboard方法将会根据cookie的值来返回不同的欢迎信息。如果你的请求没有包含sessionTokencookie,或者cookie的值为空,那么方法将会返回一条信息,表明用户未登录。


1.6. 通过POJO获取请求参数

在Spring框架中,可以通过POJO(Plain Old Java Object,简单的旧Java对象)来获取HTTP请求的参数。这意味着你可以创建一个普通的Java类,其属性与请求参数的名称相匹配,Spring框架会自动将请求参数的值绑定到这个类的实例上。

举个栗子

定义一个简单的Java类User,它将代表我们要从请求中获取的数据:

public class User {
    private String username;
    private String password;
    private String sex;
    private int age;
    private String email;

    // 省略getter和setter方法
}

创建一个Spring控制器,它将处理一个提交到/testpojo路径的POST请求:

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class UserController {

    // 处理对/testpojo路径的POST请求
    @RequestMapping(value = "/testpojo", method = RequestMethod.POST)
    public String testPOJO(User user) {
        // 打印User对象的信息
        System.out.println(user);
        // 返回一个字符串表示请求已成功处理
        return "success";
    }
}

在这个控制器中,我们定义了一个方法testPOJO,它接受一个User类型的参数。当一个POST请求到达/testpojo路径时,Spring框架会自动将请求中的参数绑定到User对象的属性上,前提是请求参数的名称必须与User类中属性的名称相匹配。

假设用户通过前面提供的HTML表单提交了数据,表单中的字段如下:

<form action="/testpojo" method="post">
    用户名:<input type="text" name="username" value="张三"><br>
    密码:<input type="password" name="password" value="123"><br>
    性别:<input type="radio" name="sex" value="男" checked>男<input type="radio" name="sex" value="女">女<br>
    年龄:<input type="text" name="age" value="23"><br>
    邮箱:<input type="text" name="email" value="123@qq.com"><br>
    <input type="submit" value="提交">
</form>

当用户填写表单并点击提交按钮时,表单数据会被发送到服务器。Spring框架会创建一个User对象,并根据表单中的输入字段自动填充usernamepasswordsexageemail属性。

testPOJO方法中,我们打印出User对象的内容,结果可能如下:

User{username='张三', password='123', sex='男', age=23, email='123@qq.com'}

最后,该方法返回一个字符串"success",表示请求已成功处理。这个例子展示了如何使用POJO来简化请求参数的绑定和处理过程。


1.7. 解决获取请求参数的乱码问题

在Web开发中,乱码问题通常是由于客户端和服务器端在字符编码上不匹配导致的。为了解决这个问题,我们需要确保在数据传输过程中使用统一的字符编码。在Spring MVC中,可以通过配置CharacterEncodingFilter来解决获取请求参数时出现的乱码问题。

CharacterEncodingFilter是Spring提供的一个过滤器,它可以强制请求和响应使用指定的字符编码,通常是UTF-8。这个过滤器需要在web.xml文件中进行注册,以便在请求处理之前对字符编码进行正确的设置。

下面是一个配置CharacterEncodingFilter的例子:

<!-- 配置springMVC的编码过滤器 -->
<filter>
    <filter-name>CharacterEncodingFilter</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>forceResponseEncoding</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>CharacterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

在这个配置中,我们定义了一个名为CharacterEncodingFilter的过滤器,并指定了它的类为org.springframework.web.filter.CharacterEncodingFilter。我们设置了两个初始化参数:

  1. encoding:这个参数指定了过滤器使用的字符编码,这里我们设置为UTF-8,这是一种广泛使用的字符编码,可以表示几乎所有语言的字符。
  2. forceResponseEncoding:这个参数设置为true,意味着过滤器会强制响应(即服务器发送给客户端的数据)也使用UTF-8编码。

最后,我们通过<filter-mapping>将过滤器映射到所有的URL路径(/*)。

注:在Spring MVC中,处理编码的CharacterEncodingFilter应该配置在其他过滤器之前,这是因为过滤器是按它们在web.xml中出现的顺序来执行的。如果你有其他过滤器(比如日志记录过滤器、安全过滤器等),你需要确保CharacterEncodingFilter是第一个执行的,以便在其他过滤器处理请求之前就设置好正确的字符编码。这样可以确保整个请求处理过程中字符编码的一致性,避免乱码问题的发生。


2. 域对象共享数据

域对象共享数据是一种在Web应用程序中常见的概念,它涉及到在不同请求之间保持和共享数据的需求。在Web开发中,由于HTTP协议是无状态的,这意味着服务器默认情况下不会记住之前的请求信息。然而,在实际应用中,我们经常需要在多个页面或者多个请求之间共享某些数据,这时候就需要用到域对象。

域对象(Session Object)是一种用于存储用户特定数据的对象,它可以跨越多个页面请求和多个会话。简单来说,就像你在商场购物,你的购物车会随着你在不同商店之间走动而一直跟着你,直到你完成购物。在Web应用程序中,域对象就像这个购物车,它允许服务器跟踪用户的状态和信息,如登录信息、用户偏好设置等。


2.1. 三大域对象

域对象是一种用于存储和传递数据的对象,在不同的范围之间传递数据。不同的域对象代表不同的范围,并且共享数据的范围也不同。

在web项目中,我们通常会使用请求域、会话域应用域这三种域对象。

举个简单的例子就是:

请求域对象是HttpServletRequest:它与单个请求关联,用于在处理一个特定请求的过程中传递数据。这个对象是临时存在的,一旦请求结束就不存在了。就像张三的工位一样,只有他可以使用工位上的东西,一旦他离开工位,其他人就无法使用了。

会话域对象是HttpSession:这个对象与用户会话关联,用于在整个会话期间传递数据,可以跨越多个请求。它与办公室的公共区有些相似,因为办公室内的所有人都可以访问这个区域,就像在同一会话中的所有人都可以访问HttpSession对象一样。

应用域对象是ServletContext:这个对象是整个Web应用程序的上下文,它可以被该应用程序中的所有用户访问。它类似于楼层走廊区,因为该楼层的所有人都可以访问这个区域,就像使用该应用程序的所有用户都可以访问ServletContext对象一样。


  • 请求域

  • 会话域

  • 应用域


2.2. 准备工作

创建子模块SpringMVC-demo03

添加依赖

<dependencies>
    <!-- SpringMVC -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.3.14</version>
    </dependency>
    
    <!-- 日志 -->
    <!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-c
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.4.14</version>
        <!--<scope>test</scope>-->
    </dependency>
    
    <!-- ServletAPI -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>4.0.1</version>
        <scope>provided</scope>
    </dependency>
    
    <!--Spring5和Thymeleaf整合包-->
    <dependency>
        <groupId>org.thymeleaf</groupId>
        <artifactId>thymeleaf-spring5</artifactId>
        <version>3.0.12.RELEASE</version>
    </dependency>
</dependencies>

设置打包方式,添加 webapp,创建 web.xml 文件

设置编码过滤器

<!-- 定义web应用程序的配置 -->
<!-- 配置springMVC的编码过滤器,确保请求和响应的编码为UTF-8 -->
<filter>
    <filter-name>CharacterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
        <!-- 指定请求和响应的编码格式为UTF-8 -->
    </init-param>
    <init-param>
        <param-name>forceResponseEncoding</param-name>
        <param-value>true</param-value>
        <!-- 强制响应使用指定的编码格式 -->
    </init-param>
</filter>
<!-- 映射编码过滤器到所有请求 -->
<filter-mapping>
    <filter-name>CharacterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

配置springMvc的前端控制器Dispatcherservlet

<!-- 配置Spring MVC核心控制器(DispatcherServlet) -->
<servlet>
    <servlet-name>springMVC</servlet-name>
    <!-- 指定DispatcherServlet的全限定类名 -->
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

    <!-- 初始化参数配置 -->
    <init-param>
        <!-- 参数名:指定Spring MVC配置文件的位置 -->
        <param-name>contextConfigLocation</param-name>
        <!-- 参数值:设置Spring MVC配置文件的路径 -->
        <param-value>classpath:SpringMVC-config.xml</param-value>
    </init-param>

    <!-- 设置DispatcherServlet在应用启动时加载的优先级,值越小,优先级越高 -->
    <load-on-startup>1</load-on-startup>
</servlet>

<!-- 配置Spring MVC核心控制器的请求映射规则 -->
<servlet-mapping>
    <!-- 与上述<servlet>标签中定义的<servlet-name>对应 -->
    <servlet-name>springMVC</servlet-name>
    <!-- URL模式:所有以'/'开头的请求都将交由该DispatcherServlet处理 -->
    <url-pattern>/</url-pattern>
</servlet-mapping>

完整 web.xml 配置如下

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <!-- 配置springMVC的编码过滤器,确保请求和响应的编码为UTF-8 -->
    <filter>
        <filter-name>EncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
            <!-- 指定请求和响应的编码格式为UTF-8 -->
        </init-param>
        <init-param>
            <param-name>forceResponseEncoding</param-name>
            <param-value>true</param-value>
            <!-- 强制响应使用指定的编码格式 -->
        </init-param>
    </filter>
    <!-- 映射编码过滤器到所有请求 -->
    <filter-mapping>
        <filter-name>EncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    
    <!-- 配置Spring MVC核心控制器(DispatcherServlet) -->
    <servlet>
        <servlet-name>springMVC</servlet-name>
        <!-- 指定DispatcherServlet的全限定类名 -->
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        
        <!-- 初始化参数配置 -->
        <init-param>
            <!-- 参数名:指定Spring MVC配置文件的位置 -->
            <param-name>contextConfigLocation</param-name>
            <!-- 参数值:设置Spring MVC配置文件的路径 -->
            <param-value>classpath:SpringMVC-config.xml</param-value>
        </init-param>
        
        <!-- 设置DispatcherServlet在应用启动时加载的优先级,值越小,优先级越高 -->
        <load-on-startup>1</load-on-startup>
    </servlet>
    
    <!-- 配置Spring MVC核心控制器的请求映射规则 -->
    <servlet-mapping>
        <!-- 与上述<servlet>标签中定义的<servlet-name>对应 -->
        <servlet-name>springMVC</servlet-name>
        <!-- URL模式:所有以'/'开头的请求都将交由该DispatcherServlet处理 -->
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

创建测试类

package com.sakurapaid.mvc.test;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class TestController {
    @RequestMapping("/")
    public String test()
    {
        return "index";
    }
}

设置 Spring 配置文件--SpringMVC-config.xml

再 resource 文件夹下创建

添加组件扫描

<!-- 开启组件扫描,自动发现并注册Bean到Spring容器中 -->
<context:component-scan base-package="com.sakurapaid.mvc"/>

配置视图解析器

<!-- 配置JSP视图解析器 -->
<bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="order" value="1"/> <!-- 解析器的优先级 -->
    <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
    <property name="prefix" value="/WEB-INF/jsp/"/>
    <property name="suffix" value=".jsp"/>
    <property name="contentType" value="text/html;charset=UTF-8"/>
</bean>

<!-- 可选,配置html视图解析器 -->
<!-- 配置Thymeleaf视图解析器,用于将控制器返回的逻辑视图名解析为实际的HTML页面 -->
    <bean id="viewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
        <property name="order" value="1"/> <!-- 解析器的优先级 -->
        <property name="characterEncoding" value="UTF-8"/> <!-- 解析结果的字符编码 -->
        <property name="templateEngine">
            <bean class="org.thymeleaf.spring5.SpringTemplateEngine">
                <property name="templateResolver">
                    <bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
                        
                        <!-- 设置视图的前缀,例如:如果逻辑视图名为home,则实际查找的路径为/WEB-INF/templates/home.html -->
                        <property name="prefix" value="/WEB-INF/templates/"/>
                        
                        <!-- 设置视图的后缀,即视图文件的扩展名 -->
                        <property name="suffix" value=".html"/>
                        <property name="templateMode" value="HTML5"/> <!-- 指定模板解析模式为HTML5 -->
                        <property name="characterEncoding" value="UTF-8"/> <!-- 模板的字符编码 -->
                    </bean>
                </property>
            </bean>
        </property>
    </bean>

完整代码如下

<?xml version="1.0" encoding="UTF-8"?>
<!-- Spring核心 beans 命名空间 -->
<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"
       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">

    <!-- 开启组件扫描,自动发现并注册Bean到Spring容器中 -->
    <context:component-scan base-package="com.sakurapaid.mvc"/>
    
    <!-- 配置JSP视图解析器 -->
    <bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="order" value="1"/> <!-- 解析器的优先级 -->
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
        <property name="contentType" value="text/html;charset=UTF-8"/>
    </bean>
    
</beans>

创建前端 jsp 页面代码

根据视图解析器规则,jsp 文件存放位置应该是 WEB-INF 下的 jsp 文件夹下

test.jsp 文件

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>我是测试文件</h1>
</body>
</html>

配置本地服务器

注意是对应的工件部署

测试成功


2.3. ServletAPI向request域对象共享数据

2.3.1. 代码示例

index.jsp 界面代码

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>首页</h1>
    <%--使用ServletAPI向request域对象共享数据--%>
    <a href="${pageContext.request.contextPath}/RequestByServletAPI">ServletAPI</a>
</body>
</html>

Controller 控制器

package com.sakurapaid.mvc.test;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;

/**
 * TestController类用于处理请求。
 */
@Controller
public class TestController {

    /**
     * 处理"/RequestByServletAPI"请求的方法。
     *
     * @param request HttpServletRequest对象,用于获取请求信息和设置响应信息。
     * @return 返回一个字符串"success",指示视图解析器解析成功。
     */
    @RequestMapping("/RequestByServletAPI")
    public String test(HttpServletRequest request)
    {
        // 设置请求属性"testScope"的值为"hello,servletAPI"
        request.setAttribute("testScope", "hello,servletAPI");
        return "success";
    }
}

成功跳转界面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!-- 页面定义部分,指定页面的输出内容类型和使用的语言 -->
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>Success</h1>
    <!-- 显示操作成功的标题 -->
    <p>从请求作用域获取的值: ${testScope}</p>
    <!-- 通过表达式从请求作用域中获取名为"testScope"的属性值,并显示在页面上 -->
</body>

</html>

测试输出


2.3.2. 小总结

代码过程

  1. index.jsp 是一个网页文件,用户可以在浏览器中看到和与之交互。在这个页面上,有一个链接,当用户点击这个链接时,浏览器会向服务器发送一个请求。
  2. Controller 控制器 (TestController) 是服务器端的一个组件,它的任务是处理来自index.jsp页面的链接点击请求。当请求到来时,它会执行 test 方法。
  3. test 方法中,使用 request.setAttribute("testScope", "hello,servletAPI") 这行代码,我们实际上是在请求对象上加了一个标签(称为“属性”),这个标签的名字是 "testScope",值是 "hello,servletAPI"。你可以把这个过程想象成在信封上贴了一个标签,这样邮递员(这里的邮递员就是浏览器)就知道要把信封(请求)送到哪里,并且知道里面装的是什么。
  4. 然后,test 方法返回一个字符串 "success",这个字符串告诉Spring框架,处理请求成功后,应该显示名为 "success" 的视图(在这个例子中,就是一个JSP页面)。
  5. 成功跳转界面 是用户在浏览器中看到的另一个网页,当请求成功处理后,浏览器会显示这个页面。在这个页面的代码中,有一段 <p> 标签,它包含了一个表达式 ${testScope}。这个表达式的作用是从之前我们在请求对象上贴上的标签(属性)中取出值,并显示在这个段落中。所以,用户会在这个页面上看到 "hello,servletAPI" 这段文字。

总结来说,"使用ServletAPI向request域对象共享数据" 就是指我们使用服务器端的代码(Servlet API)来存储和传递信息(在这个例子中是 "hello,servletAPI"),然后在用户的浏览器中显示这些信息。这个过程让我们能够创建动态的、能够响应用户操作的网页。


或者举个例子

想象一下,你在玩一个接力赛跑游戏。在这个游戏中,Servlet API就像是一个接力棒,而request域对象就像是一个可以传递接力棒的盒子。当你跑到终点时,你需要把接力棒放到这个盒子里,这样下一个跑者就可以从盒子中取出接力棒,继续比赛。

在Web开发中,我们也经常需要在不同的部分(比如不同的页面或者不同的请求处理方法)之间传递信息。这就是Servlet API和request域对象发挥作用的地方。

  • Servlet API:它是一组工具,可以帮助我们处理来自用户的请求,并向用户发送响应。就像接力棒一样,它是用来传递信息的媒介。
  • request域对象:这是一个特殊的存储空间,它属于当前用户的请求。你可以把它想象成一个盒子,你可以在这个盒子里放入信息(比如比分、状态等),然后在需要的时候取出来。这个盒子是临时的,只在当前请求过程中有效。

现在,让我们看看这个过程是如何在代码中实现的:

  1. 用户在浏览器中点击一个链接,这个链接会触发服务器上的一个方法(比如 test 方法)。
  2. test 方法中,我们使用 request.setAttribute("testScope", "hello,servletAPI") 这行代码,就像是把一条信息("hello,servletAPI")放入了接力棒(request域对象)中。
  3. 当方法执行完毕,我们返回一个字符串 "success",这告诉系统我们已经处理完请求,并且一切顺利。
  4. 系统随后会加载一个新的页面(成功跳转界面),在这个页面中,我们用 ${testScope} 这个表达式来取出之前放入接力棒(request域对象)中的信息,并显示在页面上。

所以,"使用ServletAPI向request域对象共享数据" 就像是在游戏中传递接力棒,我们把需要的信息放入一个临时的存储空间(request域对象),然后在适当的时候取出来,以供下一步使用。这样,不同的部分就可以共享和使用同一条信息了。


2.4. ModelAndView向request域对象共享数据

2.4.1. 代码示例

修改 index.jsp 代码

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>首页</h1>
    <%--使用ServletAPI向request域对象共享数据--%>
    <a href="${pageContext.request.contextPath}/RequestByServletAPI">ServletAPI</a> <br>
    <%--使用ModelAndView向request域对象共享数据--%>
    <a href="${pageContext.request.contextPath}/testModelAndView">ModelAndView</a>
</body>
</html>

控制器类添加新方法

package com.sakurapaid.mvc.test;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;

/**
 * TestController类用于处理请求。
 */
@Controller
public class TestController {

    /**
     * 处理"/RequestByServletAPI"请求的方法。
     *
     * @param request HttpServletRequest对象,用于获取请求信息和设置响应信息。
     * @return 返回一个字符串"success",指示视图解析器解析成功。
     */
    @RequestMapping("/RequestByServletAPI")
    public String test(HttpServletRequest request)
    {
        // 设置请求属性"testScope"的值为"hello,servletAPI"
        request.setAttribute("testScope", "hello,servletAPI");
        return "success";
    }

    /**
     * 测试ModelAndView功能的方法。
     * 该方法不接受任何参数,返回一个ModelAndView实例。
     * Model主要用于向请求域共享数据,View主要用于设置视图,实现页面跳转。
     *
     * @return ModelAndView 包含了模型数据和视图名称的对象。
     */
    @RequestMapping("/testModelAndView")
    public ModelAndView testModelAndView(){
        ModelAndView mav = new ModelAndView();

        // 向请求域中添加一个名为"testScope"的对象,其值为"hello,ModelAndView"。
        mav.addObject("testScope", "hello,ModelAndView");

        // 设置视图名称为"success",即将跳转到的页面。
        mav.setViewName("success");

        return mav;
    }

}

success.jsp 目标页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!-- 页面定义部分,指定页面的输出内容类型和使用的语言 -->
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>Success</h1>
    <!-- 显示操作成功的标题 -->
    <p>从请求作用域获取的值: ${testScope}</p>
    <!-- 通过表达式从请求作用域中获取名为"testScope"的属性值,并显示在页面上 -->
</body>

</html>

测试输出


2.4.2. 小总结

在Web开发中,我们经常需要在服务器端和客户端之间传递信息。为了实现这个目的,我们可以使用不同的技术。在Spring框架中,ModelAndView是一个非常重要的工具,它可以帮助我们将数据从服务器端传递到客户端,并且实现页面的跳转。

  1. 理解ModelAndView: ModelAndView是Spring框架中的一个对象,它包含了两部分信息:模型数据(Model)和视图名称(View)。模型数据是我们要传递给客户端的数据,而视图名称则告诉系统我们要跳转到哪个页面。
  2. 添加数据到模型: 通过调用ModelAndView对象的addObject方法,我们可以将数据添加到模型中。这些数据会被存储在请求域(request scope)中,这意味着数据只会在当前的HTTP请求中有效。
  3. 设置视图名称: 通过调用ModelAndView对象的setViewName方法,我们可以指定一个视图名称。这个名称会被视图解析器用来找到并渲染相应的页面。
  4. 返回ModelAndView对象: 在控制器方法中,我们将填充好的ModelAndView对象返回给Spring框架。框架会根据视图名称找到对应的页面,并把模型数据传递给这个页面。

testModelAndView方法的实现过程:

1. 创建ModelAndView对象

testModelAndView方法中,我们首先创建了一个ModelAndView对象。这个对象将用于存储我们将要传递给视图的数据(模型数据)以及指定要使用的视图(视图名称)。

ModelAndView mav = new ModelAndView();

2. 向模型中添加数据

接下来,我们使用addObject方法将一个属性添加到ModelAndView对象中。这个属性包括一个名称和一个值。在这个例子中,我们添加了一个名为"testScope"的属性,其值为"hello,ModelAndView"

mav.addObject("testScope", "hello,ModelAndView");

这个属性将被存储在HTTP请求的属性中,可以在视图中被访问和展示。

3. 设置视图名称

然后,我们使用setViewName方法来指定当这个ModelAndView对象被返回时,应该使用的视图名称。在这个例子中,我们指定视图名称为"success"。这意味着Spring框架的视图解析器将会寻找名为success.jsp的页面,并将模型数据传递给这个页面。

mav.setViewName("success");

4. 返回ModelAndView对象

最后,我们将填充好的ModelAndView对象返回给Spring框架。框架将处理这个对象,将模型数据传递给指定的视图,并执行页面跳转。

return mav;

5. 视图展示数据

success.jsp页面中,我们使用EL表达式${testScope}来访问并展示ModelAndView对象中添加的"testScope"属性的值。

<p>从请求作用域获取的值: ${testScope}</p>

当用户访问/testModelAndView路径时,testModelAndView方法会被触发,执行上述过程。最终,用户的浏览器会展示success.jsp页面,并在页面上显示"hello,ModelAndView"这个字符串。


2.5. Model向request域对象共享数据

2.5.1. 代码示例

控制器类添加 tesModel 方法

package com.sakurapaid.mvc.test;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;

/**
 * TestController类用于处理请求。
 */
@Controller
public class TestController {

    /**
     * 处理"/RequestByServletAPI"请求的方法。
     *
     * @param request HttpServletRequest对象,用于获取请求信息和设置响应信息。
     * @return 返回一个字符串"success",指示视图解析器解析成功。
     */
    @RequestMapping("/RequestByServletAPI")
    public String test(HttpServletRequest request)
    {
        // 设置请求属性"testScope"的值为"hello,servletAPI"
        request.setAttribute("testScope", "hello,servletAPI");
        return "success";
    }

    /**
     * 测试ModelAndView功能的方法。
     * 该方法不接受任何参数,返回一个ModelAndView实例。
     * Model主要用于向请求域共享数据,View主要用于设置视图,实现页面跳转。
     *
     * @return ModelAndView 包含了模型数据和视图名称的对象。
     */
    @RequestMapping("/testModelAndView")
    public ModelAndView testModelAndView(){
        ModelAndView mav = new ModelAndView();

        // 向请求域中添加一个名为"testScope"的对象,其值为"hello,ModelAndView"。
        mav.addObject("testScope", "hello,ModelAndView");

        // 设置视图名称为"success",即将跳转到的页面。
        mav.setViewName("success");

        return mav;
    }
    
    @RequestMapping("/testModel")
    public String testModel(Model model){
        model.addAttribute("testScope", "hello,Model");
        return "success";
    }

}

修改 index.jsp 文件

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>首页</h1>
    <%--使用ServletAPI向request域对象共享数据--%>
    <a href="${pageContext.request.contextPath}/RequestByServletAPI">ServletAPI</a> <br>
    <%--使用ModelAndView向request域对象共享数据--%>
    <a href="${pageContext.request.contextPath}/testModelAndView">ModelAndView</a> <br>
    <%--使用Model向request域对象共享数据--%>
    <a href="${pageContext.request.contextPath}/testModel">Model</a>
</body>
</html>

success.jsp 目标页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!-- 页面定义部分,指定页面的输出内容类型和使用的语言 -->
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>Success</h1>
    <!-- 显示操作成功的标题 -->
    <p>从请求作用域获取的值: ${testScope}</p>
    <!-- 通过表达式从请求作用域中获取名为"testScope"的属性值,并显示在页面上 -->
</body>

</html>

测试输出


2.5.2. 小总结

使用Model向request域对象共享数据的过程:

  1. 创建TestController类:这是一个Spring MVC控制器(@Controller注解),负责处理特定的HTTP请求。
  2. 定义testModel()方法
    • 使用@RequestMapping("/testModel")注解映射到URL路径/testModel
    • 方法接收一个Model类型的参数。Model是Spring MVC提供的一种接口,用于向视图传递模型数据。
    • 在方法内部,调用model.addAttribute("testScope", "hello,Model"),将键为testScope、值为"hello,Model"的数据添加到Model对象中。这一步实际上就是向请求作用域共享数据,因为Model会在渲染视图时将数据放入请求作用域。
  1. 配置success.jsp:作为目标页面,它负责显示从请求作用域获取的数据。
    • 使用JSP表达式 ${testScope} 来从请求作用域获取名为testScope的属性值。
    • success.jsp被渲染时,${testScope}会被替换为实际从请求作用域中获取的值。
  1. 测试过程
    • 用户访问首页index.jsp,点击链接“Model”,发起对/testModel的HTTP请求。
    • Spring MVC框架根据URL路径找到并调用TestController中的testModel()方法。
    • testModel()方法将数据"hello,Model"添加到Model对象,并返回视图名"success"
    • Spring MVC框架根据返回的视图名找到并渲染success.jsp页面。
    • 在渲染过程中,JSP引擎在success.jsp中遇到${testScope}表达式,从当前请求作用域查找并取出对应的值(即"hello,Model"),将其替换到HTML中。
    • 最终用户看到的success.jsp页面上显示了从请求作用域获取的值:“从请求作用域获取的值: hello,Model”。

综上所述,使用Model向request域对象共享数据的过程如下:

  • 在控制器方法中接收一个Model参数,通过调用addAttribute()方法将数据(键值对)添加到Model中。
  • 控制器方法返回视图名,触发视图渲染。
  • 在目标JSP页面中使用${}表达式从请求作用域获取已共享的数据,并动态插入到页面内容中。

2.6. Map向request域对象共享数据

2.6.1. 代码示例

控制器类添加 testMap 方法

package com.sakurapaid.mvc.test;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;

/**
 * TestController类用于处理请求。
 */
@Controller
public class TestController {

    /**
     * 处理"/RequestByServletAPI"请求的方法。
     * 通过HttpServletRequest来处理请求,设置请求属性,并返回一个字符串指示视图解析器如何处理响应。
     *
     * @param request HttpServletRequest对象,用于获取请求信息和设置响应信息。
     * @return 返回一个字符串"success",指示视图解析器解析成功。
     */
    @RequestMapping("/RequestByServletAPI")
    public String test(HttpServletRequest request)
    {
        // 设置请求属性
        request.setAttribute("testScope", "hello,servletAPI");
        return "success";
    }

    /**
     * 测试ModelAndView功能的方法。
     * 该方法不接受任何参数,返回一个ModelAndView实例,用于演示如何使用ModelAndView来处理请求和响应。
     *
     * @return ModelAndView 包含了模型数据和视图名称的对象。
     */
    @RequestMapping("/testModelAndView")
    public ModelAndView testModelAndView(){
        ModelAndView mav = new ModelAndView();

        // 添加模型数据
        mav.addObject("testScope", "hello,ModelAndView");

        // 设置视图名称
        mav.setViewName("success");

        return mav;
    }

    /**
     * 使用Model来传递数据的方法。
     * 通过Model来向请求域添加数据,然后返回一个视图名称。
     *
     * @param model 用于向请求域添加数据的Model对象。
     * @return 返回一个字符串"success",指示视图解析器解析成功。
     */
    @RequestMapping("/testModel")
    public String testModel(Model model){
        // 向Model中添加数据
        model.addAttribute("testScope", "hello,Model");
        return "success";
    }

    /**
     * 使用Map来传递数据的方法。
     * 通过Map来向请求域添加数据,然后返回一个视图名称。
     *
     * @param map 用于向请求域添加数据的Map对象。
     * @return 返回一个字符串"success",指示视图解析器解析成功。
     */
    @RequestMapping("/testMap")
    public String testMap(Map<String, Object> map){
        // 向Map中添加数据
        map.put("testScope", "hello,Map");
        return "success";
    }

}

修改 inde.jsp 文件

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>首页</h1>
    <%--使用ServletAPI向request域对象共享数据--%>
    <a href="${pageContext.request.contextPath}/RequestByServletAPI">ServletAPI</a> <br>
    <%--使用ModelAndView向request域对象共享数据--%>
    <a href="${pageContext.request.contextPath}/testModelAndView">ModelAndView</a> <br>
    <%--使用Model向request域对象共享数据--%>
    <a href="${pageContext.request.contextPath}/testModel">Model</a> <br>
    <%--使用Map向request域对象共享数据--%>
    <a href="${pageContext.request.contextPath}/testMap">Map</a>
</body>
</html>

success.jsp 目标页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!-- 页面定义部分,指定页面的输出内容类型和使用的语言 -->
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>Success</h1>
    <!-- 显示操作成功的标题 -->
    <p>从请求作用域获取的值: ${testScope}</p>
    <!-- 通过表达式从请求作用域中获取名为"testScope"的属性值,并显示在页面上 -->
</body>

</html>

测试输出


2.6.2. 小总结

使用Map向request域对象共享数据的过程如下:

  1. 创建TestController类:这是一个Spring MVC控制器(@Controller注解),负责处理特定的HTTP请求。
  2. 定义testMap()方法
    • 使用@RequestMapping("/testMap")注解映射到URL路径/testMap
    • 方法接收一个Map<String, Object>类型的参数。Map是一个通用的键值对容器,这里用来临时存储要共享的数据。
    • 在方法内部,调用map.put("testScope", "hello,Map"),将键为testScope、值为"hello,Map"的数据放入Map对象中。Spring MVC框架会自动将此Map对象的内容添加到请求作用域,从而实现数据共享。
  1. 配置success.jsp:作为目标页面,它负责显示从请求作用域获取的数据。
    • 使用JSP表达式 ${testScope} 来从请求作用域获取名为testScope的属性值。
    • success.jsp被渲染时,${testScope}会被替换为实际从请求作用域中获取的值。
  1. 测试过程
    • 用户访问首页index.jsp,点击链接“Map”,发起对/testMap的HTTP请求。
    • Spring MVC框架根据URL路径找到并调用TestController中的testMap()方法。
    • testMap()方法将数据"hello,Map"放入Map对象,并返回视图名"success"
    • Spring MVC框架接收到返回的视图名,开始渲染success.jsp页面。
    • 在渲染过程中,JSP引擎在success.jsp中遇到${testScope}表达式,从当前请求作用域查找并取出对应的值(即"hello,Map"),将其替换到HTML中。
    • 最终用户看到的success.jsp页面上显示了从请求作用域获取的值:“从请求作用域获取的值: hello,Map”。

总结起来,使用Map向request域对象共享数据的过程包括:

  • 在控制器方法中接收一个Map参数,通过调用put()方法将数据(键值对)放入Map中。
  • 控制器方法返回视图名,触发视图渲染。
  • 在目标JSP页面中使用${}表达式从请求作用域获取已共享的数据,并动态插入到页面内容中。

需要注意的是,虽然这里使用了Map来传递数据,但实际上是Spring MVC框架自动将Map中的数据添加到了请求作用域。对于初学者来说,更推荐直接使用Model对象(如testModel()方法所示),因为它与Spring MVC框架结合更紧密,使用更直观,且提供了更多与视图渲染相关的便捷功能。使用Map传递数据的方式在某些特殊场景下可能会出现,但在常规开发中并不常见。


2.7. ModelMap向request域对象共享数据

2.7.1. 代码示例

控制器类添加 testModelMap 方法

package com.sakurapaid.mvc.test;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;

/**
 * TestController类用于处理请求。
 */
@Controller
public class TestController {

    /**
     * 处理"/RequestByServletAPI"请求的方法。
     * 通过HttpServletRequest来处理请求,设置请求属性,并返回一个字符串指示视图解析器如何处理响应。
     *
     * @param request HttpServletRequest对象,用于获取请求信息和设置响应信息。
     * @return 返回一个字符串"success",指示视图解析器解析成功。
     */
    @RequestMapping("/RequestByServletAPI")
    public String test(HttpServletRequest request)
    {
        // 设置请求属性
        request.setAttribute("testScope", "hello,servletAPI");
        return "success";
    }

    /**
     * 测试ModelAndView功能的方法。
     * 该方法不接受任何参数,返回一个ModelAndView实例,用于演示如何使用ModelAndView来处理请求和响应。
     *
     * @return ModelAndView 包含了模型数据和视图名称的对象。
     */
    @RequestMapping("/testModelAndView")
    public ModelAndView testModelAndView(){
        ModelAndView mav = new ModelAndView();

        // 添加模型数据
        mav.addObject("testScope", "hello,ModelAndView");

        // 设置视图名称
        mav.setViewName("success");

        return mav;
    }

    /**
     * 使用Model来传递数据的方法。
     * 通过Model来向请求域添加数据,然后返回一个视图名称。
     *
     * @param model 用于向请求域添加数据的Model对象。
     * @return 返回一个字符串"success",指示视图解析器解析成功。
     */
    @RequestMapping("/testModel")
    public String testModel(Model model){
        // 向Model中添加数据
        model.addAttribute("testScope", "hello,Model");
        return "success";
    }

    /**
     * 使用Map来传递数据的方法。
     * 通过Map来向请求域添加数据,然后返回一个视图名称。
     *
     * @param map 用于向请求域添加数据的Map对象。
     * @return 返回一个字符串"success",指示视图解析器解析成功。
     */
    @RequestMapping("/testMap")
    public String testMap(Map<String, Object> map){
        // 向Map中添加数据
        map.put("testScope", "hello,Map");
        return "success";
    }

    /**
     * 使用ModelMap来传递数据的方法。
     * 通过ModelMap来向请求域添加数据,然后返回一个视图名称。
     *
     * @param modelMap 用于向请求域添加数据的ModelMap对象。
     * @return 返回一个字符串"success",指示视图解析器解析成功。
     */
    @RequestMapping("/testModelMap")
    public String testModelMap(ModelMap modelMap){
        modelMap.addAttribute("testScope", "hello,ModelMap");
        return "success";
    }

}

修改 inde.jsp 文件

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>首页</h1>
    <%--使用ServletAPI向request域对象共享数据--%>
    <a href="${pageContext.request.contextPath}/RequestByServletAPI">ServletAPI</a> <br>
    <%--使用ModelAndView向request域对象共享数据--%>
    <a href="${pageContext.request.contextPath}/testModelAndView">ModelAndView</a> <br>
    <%--使用Model向request域对象共享数据--%>
    <a href="${pageContext.request.contextPath}/testModel">Model</a> <br>
    <%--使用Map向request域对象共享数据--%>
    <a href="${pageContext.request.contextPath}/testMap">Map</a> <br>
    <%--使用ModelMap向request域对象共享数据--%>
    <a href="${pageContext.request.contextPath}/testModelMap">ModelMap</a>
</body>
</html>

success.jsp 目标页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!-- 页面定义部分,指定页面的输出内容类型和使用的语言 -->
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>Success</h1>
    <!-- 显示操作成功的标题 -->
    <p>从请求作用域获取的值: ${testScope}</p>
    <!-- 通过表达式从请求作用域中获取名为"testScope"的属性值,并显示在页面上 -->
</body>

</html>

测试输出


2.7.2. 小总结

使用ModelMap向request域对象共享数据的过程与使用Model非常相似,因为ModelMapModel接口的一个实现类。

  1. 定义testModelMap()方法
    • 使用@RequestMapping("/testModelMap")注解映射到URL路径/testModelMap
    • 方法接收一个ModelMap类型的参数。ModelMap是Spring MVC专门为视图模型设计的类,继承自LinkedHashMap,具有Map接口的所有功能,并额外提供了一些便于操作模型数据的方法。
    • 在方法内部,调用modelMap.addAttribute("testScope", "hello,ModelMap"),将键为testScope、值为"hello,ModelMap"的数据添加到ModelMap对象中。ModelMap对象会自动将其内容添加到请求作用域,实现数据共享。
  1. 配置success.jsp:与之前相同,目标页面success.jsp负责从请求作用域获取并显示名为testScope的属性值。
  2. 测试过程
    • 用户访问首页index.jsp,点击链接“ModelMap”,发起对/testModelMap的HTTP请求。
    • Spring MVC框架根据URL路径找到并调用TestController中的testModelMap()方法。
    • testModelMap()方法将数据"hello,ModelMap"添加到ModelMap对象,并返回视图名"success"
    • Spring MVC框架接收到返回的视图名,开始渲染success.jsp页面。
    • 在渲染过程中,JSP引擎在success.jsp中遇到${testScope}表达式,从当前请求作用域查找并取出对应的值(即"hello,ModelMap"),将其替换到HTML中。
    • 最终用户看到的success.jsp页面上显示了从请求作用域获取的值:“从请求作用域获取的值: hello,ModelMap”。

总结起来,使用ModelMap向request域对象共享数据的过程包括:

  • 在控制器方法中接收一个ModelMap参数,通过调用addAttribute()方法将数据(键值对)添加到ModelMap中。
  • 控制器方法返回视图名,触发视图渲染。
  • 在目标JSP页面中使用${}表达式从请求作用域获取已共享的数据,并动态插入到页面内容中。

尽管ModelMap提供了比Map更多的便利功能,但在实际开发中,通常更推荐直接使用Model接口作为方法参数(如testModel()所示)。这样做可以使代码更通用,因为Spring MVC会自动将传入的Model参数转换为合适的实现类(如ModelMapExtendedModelMap)。这样,即使以后Spring MVC内部实现发生变化,你的代码也不需要调整。因此,使用Model作为参数是一种更好的编程习惯。


2.8. Model/ModelMap/Map的关系

在Spring MVC中,当我们在控制器方法(如@RequestMapping注解的方法)中使用Model、ModelMap或Map类型的参数来向request域对象共享数据时,虽然它们表面上看起来不同,但本质上,这些参数都被Spring MVC框架处理为BindingAwareModelMap类型。


  1. Model
    • 接口定义:Model是一个接口,它定义了一组方法,用于在控制器中向一个数据模型添加属性。这些属性在后续的视图渲染过程中可供访问和展示。
    • 简化控制器逻辑:作为开发者,我们无需直接操作底层数据结构,只需通过Model接口提供的方法添加属性,简化了控制器的编码工作。
    • 基于Map的实现:虽然Model接口本身不直接实现Map接口,但在Spring MVC的实际应用中,传入控制器方法的Model参数通常会被实现为一个Map(如BindingAwareModelMap),因此可以像操作Map一样向其中添加键值对。

  1. ModelMap
    • 具体实现:ModelMap是Model接口的一个具体实现类,它不仅提供了Model接口所定义的方法,还内建了一个Map来实际存储属性数据。
    • 增强功能:相较于直接使用Map,ModelMap提供了额外的便利性和功能,如支持批量添加属性、自动类型转换等,使得数据管理更加高效。
    • 常用选择:由于其便捷性和针对视图渲染的优化,ModelMap在Spring MVC应用中被广泛用作控制器与视图间数据传递的标准工具。

  1. Map
    • 通用数据结构:Map是Java标准库中的一个接口,用于表示键值对(key-value pairs)的集合,是一种通用的数据存储结构。
    • 灵活运用:在Spring MVC中,任何实现了Map接口的对象(如HashMapLinkedHashMap等)都可以用来在控制器和视图之间传递数据。这种方式更为底层和灵活,但需要开发者自行处理一些细节问题,如属性添加、类型转换等。
    • 直接使用场景:尽管ModelMap是首选,但在某些特定场景下,开发者可能选择直接使用Map,如需要特定Map实现的特性,或者希望对数据传递过程有更精细的控制。

总结来说,Model作为接口,定义了在控制器和视图间传递数据的基本操作;ModelMap作为Model接口的实现,提供了一个功能丰富、专为Spring MVC优化的属性容器;而Map作为一种通用数据结构,虽然可以直接用于数据传递,但使用时需自行处理更多细节。在日常开发中,ModelMap因其便捷性和针对性优化,成为在Spring MVC中传递模型数据的主流选择。


2.9. 向session域共享数据

2.9.1. 代码示例

控制器类添加 testSession 方法

package com.sakurapaid.mvc.test;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.Map;

@Controller
public class TestController {
    /**
     * 测试会话功能的方法。
     * 
     * @param session  HttpSession对象,用于存储和获取会话属性。
     * @return 返回一个字符串"success",表示会话测试成功。
     */
    @RequestMapping("/testSession")
    public String testSession(HttpSession session){
        // 设置会话属性"testScope",值为"hello,session"
        session.setAttribute("testScope", "hello,session");
        return "success";
    }

    /**
     * 处理"/RequestByServletAPI"请求的方法。
     * 通过HttpServletRequest来处理请求,设置请求属性,并返回一个字符串指示视图解析器如何处理响应。
     *
     * @param request HttpServletRequest对象,用于获取请求信息和设置响应信息。
     * @return 返回一个字符串"success",指示视图解析器解析成功。
     */
    @RequestMapping("/RequestByServletAPI")
    public String test(HttpServletRequest request)
    {
        // 设置请求属性
        request.setAttribute("testScope", "hello,servletAPI");
        return "success";
    }

    /**
     * 测试ModelAndView功能的方法。
     * 该方法不接受任何参数,返回一个ModelAndView实例,用于演示如何使用ModelAndView来处理请求和响应。
     *
     * @return ModelAndView 包含了模型数据和视图名称的对象。
     */
    @RequestMapping("/testModelAndView")
    public ModelAndView testModelAndView(){
        ModelAndView mav = new ModelAndView();

        // 添加模型数据
        mav.addObject("testScope", "hello,ModelAndView");

        // 设置视图名称
        mav.setViewName("success");

        return mav;
    }

    /**
     * 使用Model来传递数据的方法。
     * 通过Model来向请求域添加数据,然后返回一个视图名称。
     *
     * @param model 用于向请求域添加数据的Model对象。
     * @return 返回一个字符串"success",指示视图解析器解析成功。
     */
    @RequestMapping("/testModel")
    public String testModel(Model model){
        // 向Model中添加数据
        model.addAttribute("testScope", "hello,Model");
        return "success";
    }

    /**
     * 使用Map来传递数据的方法。
     * 通过Map来向请求域添加数据,然后返回一个视图名称。
     *
     * @param map 用于向请求域添加数据的Map对象。
     * @return 返回一个字符串"success",指示视图解析器解析成功。
     */
    @RequestMapping("/testMap")
    public String testMap(Map<String, Object> map){
        // 向Map中添加数据
        map.put("testScope", "hello,Map");
        return "success";
    }

    /**
     * 使用ModelMap来传递数据的方法。
     * 通过ModelMap来向请求域添加数据,然后返回一个视图名称。
     *
     * @param modelMap 用于向请求域添加数据的ModelMap对象。
     * @return 返回一个字符串"success",指示视图解析器解析成功。
     */
    @RequestMapping("/testModelMap")
    public String testModelMap(ModelMap modelMap){
        modelMap.addAttribute("testScope", "hello,ModelMap");
        return "success";
    }

}

修改 index.jsp 界面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>首页</h1>
    <%--使用ServletAPI向request域对象共享数据--%>
    <a href="${pageContext.request.contextPath}/RequestByServletAPI">ServletAPI</a> <br>
    <%--使用ModelAndView向request域对象共享数据--%>
    <a href="${pageContext.request.contextPath}/testModelAndView">ModelAndView</a> <br>
    <%--使用Model向request域对象共享数据--%>
    <a href="${pageContext.request.contextPath}/testModel">Model</a> <br>
    <%--使用Map向request域对象共享数据--%>
    <a href="${pageContext.request.contextPath}/testMap">Map</a> <br>
    <%--使用ModelMap向request域对象共享数据--%>
    <a href="${pageContext.request.contextPath}/testModelMap">ModelMap</a> <br>
    <%--使用session域向request域对象共享数据--%>
    <a href="${pageContext.request.contextPath}/testSession">Session</a>
</body>
</html>

测试输出


2.9.2. 小总结

使用HttpSession向session域对象共享数据的过程如下:

  1. 定义testSession()方法
    • 使用@RequestMapping("/testSession")注解映射到URL路径/testSession
    • 方法接收一个HttpSession类型的参数,该参数代表当前用户的会话对象。
    • 在方法内部,调用httpSession.setAttribute("testScope", "hello,Session"),将键为testScope、值为"hello,Session"的数据添加到HttpSession对象中。HttpSession对象用于存储与用户会话相关的数据,这些数据在整个会话期间保持有效,直至会话过期或被显式清除。
  1. 配置success.jsp
    • 目标页面success.jsp负责从session作用域获取并显示名为testScope的属性值。与之前一样,使用${testScope}表达式来获取并显示session域中的数据。
  1. 测试过程
    • 用户访问首页index.jsp,点击链接“Session”,发起对/testSession的HTTP请求。
    • Spring MVC框架根据URL路径找到并调用TestController中的testSession()方法。
    • testSession()方法将数据"hello,Session"添加到HttpSession对象,并返回视图名"success"
    • Spring MVC框架接收到返回的视图名,开始渲染success.jsp页面。
    • 在渲染过程中,JSP引擎在success.jsp中遇到${testScope}表达式,从当前session作用域查找并取出对应的值(即"hello,Session"),将其替换到HTML中。
    • 最终用户看到的success.jsp页面上显示了从session作用域获取的值:“从session作用域获取的值: hello,Session”。

总结起来,使用HttpSession向session域对象共享数据的过程包括:

  • 在控制器方法中接收一个HttpSession参数,通过调用setAttribute()方法将数据(键值对)添加到HttpSession中。
  • 控制器方法返回视图名,触发视图渲染。
  • 在目标JSP页面中使用${}表达式从session作用域获取已共享的数据,并动态插入到页面内容中。

使用HttpSession可以实现跨请求的数据共享,适用于需要在用户整个会话期间持久化数据的场景,如用户登录状态、购物车信息等。但需要注意的是,过度依赖session可能导致内存消耗增加,应合理控制session中存储的数据量和生命周期。


2.10. 向application域共享数据

2.10.1. 代码示例

控制器类添加 testApplication 方法

/**
 * 测试应用程序的范围属性。
 *
 * @param session  HttpSession对象,用于获取Servlet上下文。
 * @return 返回一个字符串"success",表示操作成功。
 */
@RequestMapping("/testApplication")
public String testApplication(HttpSession session){
    // 获取Servlet上下文
    ServletContext application = session.getServletContext();
    // 向Servlet上下文设置一个属性,名称为"testScope",值为"hello,application"
    application.setAttribute("testScope", "hello,application");
    return "success";
}

修改 index.jsp 界面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>首页</h1>
    <%--使用ServletAPI向request域对象共享数据--%>
    <a href="${pageContext.request.contextPath}/RequestByServletAPI">ServletAPI</a> <br>
    <%--使用ModelAndView向request域对象共享数据--%>
    <a href="${pageContext.request.contextPath}/testModelAndView">ModelAndView</a> <br>
    <%--使用Model向request域对象共享数据--%>
    <a href="${pageContext.request.contextPath}/testModel">Model</a> <br>
    <%--使用Map向request域对象共享数据--%>
    <a href="${pageContext.request.contextPath}/testMap">Map</a> <br>
    <%--使用ModelMap向request域对象共享数据--%>
    <a href="${pageContext.request.contextPath}/testModelMap">ModelMap</a> <br>
    <%--使用session域向request域对象共享数据--%>
    <a href="${pageContext.request.contextPath}/testSession">Session</a>
    <%--使用application域向request域对象共享数据--%>
    <a href="${pageContext.request.contextPath}/testApplication">Application</a>
</body>
</html>

测试输出


2.10.2. 小总结

使用ServletContext向application域对象共享数据的过程:

  1. 定义testApplication()方法
    • 使用@RequestMapping("/testApplication")注解映射到URL路径/testApplication
    • 方法接收一个HttpSession类型的参数,通过该参数获取ServletContext对象(即应用程序上下文)。
    • 在方法内部,调用session.getServletContext()获取ServletContext对象。
    • 调用application.setAttribute("testScope", "hello,application"),将键为testScope、值为"hello,application"的数据添加到ServletContext对象中。ServletContext对象代表整个Web应用程序的全局共享区域,其存储的数据在整个应用程序范围内可见,直到应用程序被重新部署或服务器关闭。
  1. 配置success.jsp
    • 目标页面success.jsp负责从application作用域获取并显示名为testScope的属性值。与之前一样,使用${testScope}表达式来获取并显示application域中的数据。
  1. 测试过程
    • 用户访问首页index.jsp,点击链接“Application”,发起对/testApplication的HTTP请求。
    • Spring MVC框架根据URL路径找到并调用TestController中的testApplication()方法。
    • testApplication()方法将数据"hello,application"添加到ServletContext对象,并返回视图名"success"
    • Spring MVC框架接收到返回的视图名,开始渲染success.jsp页面。
    • 在渲染过程中,JSP引擎在success.jsp中遇到${testScope}表达式,从当前application作用域查找并取出对应的值(即"hello,application"),将其替换到HTML中。
    • 最终用户看到的success.jsp页面上显示了从application作用域获取的值:“从application作用域获取的值: hello,application”。

总结起来,使用ServletContext向application域对象共享数据的过程包括:

  • 在控制器方法中接收一个HttpSession参数,通过其获取ServletContext对象。
  • 调用setAttribute()方法将数据(键值对)添加到ServletContext
  • 控制器方法返回视图名,触发视图渲染。
  • 在目标JSP页面中使用${}表达式从application作用域获取已共享的数据,并动态插入到页面内容中。

使用ServletContext可以在整个Web应用程序范围内共享数据,适用于需要所有用户或所有请求都能访问的全局配置信息、静态资源映射等场景。由于application作用域的生命周期较长,应谨慎管理存储在其中的数据,避免占用过多内存或导致数据泄漏。


  • 45
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雨空集

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值