一、RequestParam

1.1 RequestParam注解的基本使用

RequestParam注解作用:将请求参数与方法上的形参映射。

@PostMapping(value = "/register")
public String register(@RequestParam(value="username")String a,
        	@RequestParam(value="password")String b,
        	@RequestParam(value="sex")String c,
        	@RequestParam(value="hobby")String[] d,
        	@RequestParam(name="intro")String e) {
    System.out.println(a);
    System.out.println(b);
    System.out.println(c);
    System.out.println(Arrays.toString(d));
    System.out.println(e);
    return "success";
}

对于@RequestParam注解来说,属性value和name这两个注解作用相同,且不能写错,需要与发送请求时提交的数据相同。例:name1=value1&name2=value2,注解为@RequestParam(value=“name1”)、@RequestParam(value=“name2”)。

1.2 RequestParam注解的required属性

required属性用来设置该方法参数是否为必须的。默认情况下为true,可以设置为false,如果请求中缺少对应的参数,则方法的参数为null。

@PostMapping(value = "/register")
public String register(@RequestParam(value="username")String a,
        	@RequestParam(value="password")String b,
        	@RequestParam(value="sex")String c,
        	@RequestParam(value="hobby")String[] d,
        	@RequestParam(name="intro")String e
        	@RequestParam(value="age", required = false)Integer age) {
    System.out.println(a);
    System.out.println(b);
    System.out.println(c);
    System.out.println(Arrays.toString(d));
    System.out.println(e);
    System.out.println(age);
    return "success";
}

1.3 RequestParam注解的defaultValue属性

defaultValue属性用来设置形参的默认值,当没有提供对应的请求参数或者请求参数的值是空字符串""的时候,方法的形参会采用默认值。

@PostMapping(value = "/register")
public String register(@RequestParam(value="username")String a,
        	@RequestParam(value="password")String b,
        	@RequestParam(value="sex")String c,
        	@RequestParam(value="hobby")String[] d,
        	@RequestParam(name="intro")String e
        	@RequestParam(value="age", required = false, defaultValue = "20")Integer age) {
    System.out.println(a);
    System.out.println(b);
    System.out.println(c);
    System.out.println(Arrays.toString(d));
    System.out.println(e);
    System.out.println(age);
    return "success";
}

1.4 @RequestParam的省略,通过形参来接收

@RequestParam 这个注解是可以省略的,如果方法形参的名字和提交数据时的name相同,则 @RequestParam 可以省略。
如果你采用的是Spring6+版本,你需要在pom.xml文件中指定编译参数’-parameter’,配置如下:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.12.1</version>
            <configuration>
                <source>21</source>
                <target>21</target>
                <compilerArgs>
                    <arg>-parameters</arg>
                </compilerArgs>
            </configuration>
        </plugin>
    </plugins>
</build>

如果你使用的是Spring5的版本,以上配置是不需要的,但形参的名字必须和提交的数据的name一致!

@PostMapping(value="/register")
public String register(String username, String password, String sex, String[] hobby, String intro){
    System.out.println(username + "," + password + "," + sex + "," + Arrays.toString(hobby) + "," + intro);
    return "success";
}

1.5 使用POJO类接收请求参数

请求参数的参数名整合为pojo类的属性名,且要保持一致。例:

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private Long id;
    private String username;
    private String password;
    private String sex;
    private String[] hobby;
    private String intro;
}

在controller方法的形参位置上使用pojo类来接收请求参数:

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

1.6 RequestHeader注解

该注解的作用是:将请求头信息映射到方法的形参上。
和RequestParam注解功能相似,RequestParam注解的作用:将请求参数映射到方法的形参上。
当然,对于RequestHeader注解来说,也有三个属性:value、required、defaultValue,和RequestParam一样。

@PostMapping("/register")
public String register(User user, 
                       @RequestHeader(value="Referer", required = false, defaultValue = "") 
                       String referer){
    System.out.println(user);
    System.out.println(referer);
    return "success";
}

1.7 CookieValue注解

该注解的作用:将请求提交的Cookie数据映射到方法形参上
同样是有三个属性:value、required、defaultValue
前端页面中编写发送cookie的代码:

<script type="text/javascript">
    function sendCookie(){
        document.cookie = "id=123456789; expires=Thu, 18 Dec 2025 12:00:00 UTC; path=/";
        document.location = "/springmvc/register";
    }
</script>

<button onclick="sendCookie()">向服务器端发送Cookie</button>

后端UserController代码:

 @GetMapping("/register")
    public String register(User user,
                           @RequestHeader(value="Referer", required = false, defaultValue = "")
                           String referer,
                           @CookieValue(value="id", required = false, defaultValue = "2222222222")
                           String id){
        System.out.println(user);
        System.out.println(referer);
        System.out.println(id);
        return "success";
    }

二、Servlet中的三个域对象

请求域:request
会话域:session
应用域:application
三个域都有以下三个方法:

// 向域中存储数据
void setAttribute(String name, Object obj);

// 从域中读取数据
Object getAttribute(String name);

// 删除域中的数据
void removeAttribute(String name);

2.1 request域

接口名:HttpServletRequest
简称:request
request对象代表了一次请求。一次请求一个request。
使用请求域的业务场景:在A资源中通过转发的方式跳转到B资源,因为是转发,因此从A到B是一次请求,如果想让A资源和B资源共享同一个数据,可以将数据存储到request域中。
在SpringMVC中,在request域中共享数据有以下几种方式:

2.1.1 使用原生Servlet API方式访问request域

在Controller的方法上使用HttpServletRequest:

@Controller
public class RequestScopeTestController {

    @RequestMapping("/testServletAPI")
    public String testServletAPI(HttpServletRequest request){
        // 向request域中存储数据
        request.setAttribute("testRequestScope", "在SpringMVC中使用原生Servlet API实现request域数据共享");
        return "view";
    }
}

超链接:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>index</title>
    
</head>
<body>
<h1>Index Page</h1>
<a th:href="@{/testServletAPI}">在SpringMVC中使用原生Servlet API实现request域数据共享</a><br>
</body>
</html>

页面:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>view</title>

</head>
<body>
<div th:text="${testRequestScope}"></div>
</body>
</html>

在浏览器里点击超链接,浏览器发送 GET 请求http://localhost:8080/springmvc/testServletAPI,Spring MVC 的 DispatcherServlet 接收到请求,找到 @RequestMapping(“/testServletAPI”) 对应的方法testServletAPI(),返回 “view”,Spring 会去解析 view.html 模板,${testRequestScope} 会从当前 request 域中获取刚存入的数据。

2.1.2 使用Model接口

@RequestMapping("/testModel")
public String testModel(Model model){
    // 向request域中存储数据
    model.addAttribute("testRequestScope", "在SpringMVC中使用Model接口实现request域数据共享");
    return "view";
}

2.1.3 使用Map接口

@RequestMapping("/testMap")
public String testMap(Map<String, Object> map){
    // 向request域中存储数据
    map.put("testRequestScope", "在SpringMVC中使用Map接口实现request域数据共享");
    return "view";
}

2.1.4 使用ModelMap类

@RequestMapping("/testModelMap")
public String testModelMap(ModelMap modelMap){
    // 向request域中存储数据
    modelMap.addAttribute("testRequestScope", "在SpringMVC中使用ModelMap实现request域数据共享");
    return "view";
}

Model、Map、ModelMap的关系
无论是Model、Map还是ModelMap,底层实例化的对象都是:BindingAwareModelMap。通过源码来看:BindingAwareModelMap继承了ModelMap,而ModelMap又实现了Map接口。
public class BindingAwareModelMap extends ExtendedModelMap{}
public class ExtendedModelMap extends ModelMap implements Model{}

2.1.5 使用ModelAndView类

在SpringMVC框架中为了更好的体现MVC架构模式,提供了一个类:ModelAndView。这个类的实例封装了Model和View。也就是说这个类既封装业务处理之后的数据,也体现了跳转到哪个视图。使用它也可以完成request域数据共享。

@RequestMapping("/testModelAndView")
public ModelAndView testModelAndView(){
    // 创建“模型与视图对象”
    ModelAndView modelAndView = new ModelAndView();
    // 绑定数据
    modelAndView.addObject("testRequestScope", "在SpringMVC中使用ModelAndView实现request域数据共享");
    // 绑定视图
    modelAndView.setViewName("view");
    // 返回
    return modelAndView;
}

2.1.6 ModelAndView源码分析

Model、Map、ModelMap、ModelAndView,这四种方式在底层DispatcherServlet调用我们的Controller之后,返回的对象都是ModelAndView,这个可以通过源码进行分析。
在这里插入图片描述
查看DispatcherServlet的1089行,源码如下:
在这里插入图片描述
此时接着往下运行,可以在控制台观察到此时mv为ModelAndView对象:
在这里插入图片描述

2.2 session域

接口名:HttpSession
简称:session
session对象代表了一次会话。从打开浏览器开始访问,到最终浏览器关闭,这是一次完整的会话。每个会话session对象都对应一个JSESSIONID,而JSESSIONID生成后以cookie的方式存储在浏览器客户端。浏览器关闭,JSESSIONID失效,会话结束。
使用会话域的业务场景:

  1. 在A资源中通过重定向的方式跳转到B资源,因为是重定向,因此从A到B是两次请求,如果想让A资源和B资源共享同一个数据,可以将数据存储到session域中。
  2. 登录成功后保存用户的登录状态。

2.2.1 使用原生Servlet API访问session域

流程与使用原生Servlet API方式访问request域差不多:

@Controller
public class SessionScopeTestController {

    @RequestMapping("/testSessionScope1")
    public String testServletAPI(HttpSession session) {
        // 向会话域中存储数据
        session.setAttribute("testSessionScope1", "使用原生Servlet API实现session域共享数据");
        return "view";
    }
}

视图页面:

<div th:text="${session.testSessionScope1}"></div>

超链接:

<a th:href="@{/testSessionScope1}">在SpringMVC中使用原生Servlet API实现session域共享数据</a><br>

2.2.2 使用SessionAttributes注解

使用SessionAttributes注解标注Controller:

@Controller
@SessionAttributes(value = {"x", "y"})
public class SessionScopeTestController {

	//这里也可以用Model,Map
    @RequestMapping("/testSessionScope2")
    public String testSessionAttributes(ModelMap modelMap){
        // 向session域中存储数据
        modelMap.addAttribute("x", "我是埃克斯");
        modelMap.addAttribute("y", "我是歪");

        return "view";
    }
}

注意:SessionAttributes注解使用在Controller类上。标注了当key是 x 或者 y 时,数据将被存储到会话session中。如果没有 SessionAttributes注解,默认存储到request域中。

2.3 application域

接口名:ServletContext
简称:application
application对象代表了整个web应用,服务器启动时创建,服务器关闭时销毁。对于一个web应用来说,application对象只有一个。
使用应用域的业务场景:记录网站的在线人数。

2.3.1 直接使用Servlet API访问application域

@Controller
public class ApplicationScopeTestController {

    @RequestMapping("/testApplicationScope")
    public String testApplicationScope(HttpServletRequest request){
        
        // 获取ServletContext对象
        ServletContext application = request.getServletContext();

        // 向应用域中存储数据
        application.setAttribute("applicationScope", "我是应用域当中的一条数据");

        return "view";
    }
}

视图页面:

<div th:text="${application.applicationScope}"></div>

超链接:

<a th:href="@{/testApplicationScope}">在SpringMVC中使用ServletAPI实现application域共享数据</a><br>

最后感谢动力节点提供的优质学习资源,让我们在技术道路上能够站在巨人的肩膀上继续前行。本资料仅为学习过程的副产品,希望能帮助到更多同样在努力学习的开发者。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐