springMVC01-特点、创建项目、@RequestMapping、获取参数请求,三种域对象

一、简介

SpringMVC 就是 Spring 框架中的 MVC 模块,用于构建 Web 应用中的"控制层"。

SpringMVC 是 Spring 提供的一个基于 Servlet 的 Web MVC 框架模块,是 Spring 整个体系中的"Web 层核心"。

SpringMVC 是 Spring 的一部分,Spring 框架的主要模块包括:

复制代码
1. Core(核心容器)
2. AOP(面向切面)
3. Data Access(JDBC、ORM)
4. Web(包括 Web、Web MVC、Web WebSocket)
5. Messaging
6. Test

1-1、SpringMVC 的职责是什么?

它实现了经典的 MVC 架构中的 控制器 Controller 和前端分发器 DispatcherServlet 功能。

MVC分工:

角色 SpringMVC 中的实现
Model Service 层 + Java Bean
View JSP、Thymeleaf、Freemarker 等
Controller 控制层,工程中的servlet,@Controller / @RestController 注解的类;功能:接受请求,响应浏览器
Dispatcher DispatcherServlet,是 SpringMVC 的核心

JavaBean分为两类:

一类称为**实体类Bean:**专门存储业务数据的,如 Student、User 等

一类称为**业务处理 Bean:**指 Service 或 Dao 对象,专门用于处理业务逻辑和数据访问。

1-2、MVC的工作流程:

复制代码
                ┌───────────────┐
浏览器请求 ---> │ DispatcherServlet │
                └───────────────┘
                          │
                          ▼
                ┌────────────────────┐
                │  Controller(控制器) │  <== 负责接收请求、调服务
                └────────────────────┘
                          │
                          ▼
                ┌────────────────────┐
                │  Service(业务逻辑) │  <== 处理逻辑,调数据库
                └────────────────────┘
                          │
                          ▼
                ┌────────────────────┐
                │  DAO / Model(数据) │  <== 数据层/模型层
                └────────────────────┘
                          │
                          ▼
                ┌────────────────────┐
                │  View(JSP/HTML)   │  <== 渲染页面
                └────────────────────┘

1-3、SpringMVC 和 SpringBoot 是什么关系?

  • SpringMVC 是"Spring体系中的 MVC 模块"

  • SpringBoot 是"简化 Spring 配置的一套框架"

  • SpringBoot 内部集成了 SpringMVC,所以你写 SpringBoot Web 项目,底层其实就是用的 SpringMVC。

1-4、SpringMVC 和 Servlet 是什么关系?

SpringMVC 是基于 Servlet 的高级封装:

对比 Servlet SpringMVC
入口 每个 Servlet 写一个类 一个 DispatcherServlet 就能接收所有请求
映射 在 web.xml 或注解中配置路径 使用 @RequestMapping 等注解
请求处理 自己解析参数 自动绑定参数(甚至对象)
响应处理 手动写输出 自动 JSON 返回或视图渲染
扩展性 不好扩展 支持拦截器、参数解析器、数据转换器

二、SpringMVC的特点

2-1**、SpringMVC 的核心特点(总结 + 示例 + 对比)**


1. 基于注解,开发简洁

使用注解(如 @Controller, @RequestMapping, @ResponseBody)快速定义控制器和请求路径。

示例:

java 复制代码
@Controller
public class UserController {

    @RequestMapping("/hello")
    @ResponseBody
    public String sayHello() {
        return "Hello SpringMVC!";
    }
}

对比传统 Servlet:

传统 Servlet SpringMVC 注解风格
需配置 web.xml 映射路径 用注解快速映射 URL
手动解析参数 自动参数绑定
写出响应内容麻烦 支持 @ResponseBody 返回 JSON

2. 请求参数自动绑定

SpringMVC 自动将请求参数绑定到方法参数、对象属性,支持类型转换。

示例:

java 复制代码
@PostMapping("/addUser")
public String add(User user) {
    // 请求中 name=Tom&age=18 自动注入到 user 对象
    return "ok";
}

对比传统 Servlet:

Servlet 中这样写
String name = request.getParameter("name");
手动封装 User 实例

3. 强大的 RESTful 支持

SpringMVC 原生支持 REST 风格请求(不同方法映射到不同逻辑)。

示例:

java 复制代码
@GetMapping("/user/{id}")
public User getUser(@PathVariable int id) { ... }

@DeleteMapping("/user/{id}")
public String deleteUser(@PathVariable int id) { ... }

对比传统方式:

Servlet 只能识别 URL,不能区分 GET/POST/DELETE/PATCH,需手动判断 request.getMethod()


4. 内置视图解析器支持多种视图(JSP/Thymeleaf/JSON)

说明:

SpringMVC 可返回逻辑视图名,由视图解析器处理,或返回 JSON 数据(配合 @ResponseBody@RestController

示例:

java 复制代码
@GetMapping("/list")
public String list(Model model) {
    model.addAttribute("students", studentService.getAll());
    return "studentList"; // JSP 或 Thymeleaf
}

或者:

java 复制代码
@RestController
@RequestMapping("/api")
public class ApiController {
    @GetMapping("/info")
    public Map<String, Object> info() {
        return Map.of("status", "ok", "time", System.currentTimeMillis());
    }
}

5. 全局异常处理、拦截器、数据转换器可插拔扩展

你可以很方便地实现:

  • 自定义参数校验器(@Valid + @ControllerAdvice

  • 请求拦截器(HandlerInterceptor

  • 统一异常处理(@ExceptionHandler / @ControllerAdvice


2-2、总结对比表:SpringMVC vs Servlet vs Struts2

比较维度 SpringMVC Servlet Struts2
架构模式 MVC 非 MVC,结构混乱 MVC
开发方式 注解驱动,自动装配 手动获取 request/response 配置繁琐,OGNL 绑定
REST 支持 ✅ 原生支持 ❌ 不支持 ❌ 需要插件支持
参数绑定 ✅ 自动对象绑定 + 转换器 ❌ 手动处理 ✅ OGNL,但性能较差
异常处理 ✅ 注解 + 全局统一 ❌ 需 try-catch ❌ 自定义 filter 实现
视图选择 多视图支持 JSP JSP / Freemarker
JSON 返回 ✅ 内置支持 ❌ 需写输出流 ✅ 支持 JSON 插件
社区活跃度 ✅ 非常高,主流标准 ❌ 已过时 ❌ 弃用趋势

2-3、RESTful 接口

RESTful 接口开发 = "资源 URL" + "HTTP 方法" ,在 SpringMVC 中,就是用 @GetMapping@PostMapping@PutMapping@DeleteMapping 来准确表达"我要对这个资源做什么"。

举个比喻:

  • /users 是一群"用户"

  • /users/1 是用户 1

  • 然后你要"干什么",就用 HTTP 方法说清楚

想干什么 URL 方法 注解
查所有用户 /users GET @GetMapping
新增一个用户 /users POST @PostMapping
查询某个用户 /users/1 GET @GetMapping("/{id}")
修改某个用户 /users/1 PUT @PutMapping("/{id}")
删除某个用户 /users/1 DELETE @DeleteMapping("/{id}")

三、idea创建spring-mvc项目 (maven)

1、不使用maven-webapp模版,直接创建maven项目

2、在pom.xml中导入相关依赖

XML 复制代码
    <dependencies>
        <!-- spring MVC -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.3.1</version>
        </dependency>

        <!-- 日志 -->
        <!-- 日志门面 API -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.30</version>
        </dependency>

        <!-- slf4j 到 logback 的实现桥接器(含 core 和 classic)-->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>


        <!-- servlet api -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <!-- tomcat中自带了servlet api和jsp的jar包的! -->
            <!-- provided:已被提供,当项目打成war包,这个servlet的jar包就不会存在于当前war包中的web-inf的lib中 -->
            <scope>provided</scope>
        </dependency>

        <!-- spring5和thymeleaf的整合包 -->
        <dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf-spring5</artifactId>
            <version>3.0.11.RELEASE</version>
        </dependency>
    </dependencies>

【注意】:

pom.xml中添加的依赖对应的jar,在当前project打成war包后,会被自动加入到web-inf下的lib文件夹下,但是加了<scope>provided<scope>的,不会被加入到web-inf下的lib文件夹下。

3、添加webapp文件夹

4、添加web.xml文件

【注意】:

修改此处的路径地址!

3-1、手动配置 DispatcherServlet ------ SpringMVC 的核心组件(前端控制器)

DispatcherServlet 是整个 SpringMVC 的入口

配置 DispatcherServlet 的两种方式(推荐 XML)

1、默认配置方式

springMVC的配置文件默认位于web-inf下:

XML 复制代码
<!-- 注册 DispatcherServlet,对浏览器发送的请求统一处理 -->
    <servlet>
        <!--
            这个 <servlet-name> 其实是给 DispatcherServlet 起的一个"别名"
            自定义
            它与配置文件名有关!
            当你不给 DispatcherServlet 指定配置文件路径时(省略 <init-param>),Spring 会默认去加载这个路径:
            /WEB-INF/<servlet-name>-servlet.xml

            示例:
            如果你写成:<servlet-name>abc</servlet-name>
            默认加载:/WEB-INF/abc-servlet.xml

            但是可以通过 <init-param> 指定配置文件:
         -->
        <servlet-name>springMVC</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>springMVC</servlet-name>
        <!--
            给 Servlet(如 DispatcherServlet)指定它要拦截哪些 URL 请求

            设置 springMVC 的核心控制器所能处理的请求的请求路径
            / 所匹配的请求可以是 /login 或.html 或.js 或.css 方式的请求路径
            但是 / 不能匹配.jsp 请求路径的请求

            /*,匹配所有的请求路径,包括.jsp 请求路径的请求
        -->
        <url-pattern>/</url-pattern>
    </servlet-mapping>

但是maven项目,约定,所有的配置文件要统一放到resource文件夹下!

所以,推荐用扩展配置方式

<url-pattern>/</url-pattern>:将所有的请求都交给 DispatcherServlet 来处理(也就是 SpringMVC)

<url-pattern> 有哪些写法?

写法 说明
/ 拦截所有请求(包括 .jsp 和静态资源,注意需特殊配置)
*.do 只拦截 .do 结尾的请求
/app/* 拦截以 /app/ 开头的路径
/hello 只拦截 /hello 这个路径
*.action 拦截 .action 的请求(老项目常见)

2、扩展配置方式 (推荐)

XML 复制代码
<!-- 注册 DispatcherServlet,对浏览器发送的请求统一处理 -->
    <servlet>
        <servlet-name>springMVC</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

        <!-- 加载 SpringMVC 配置文件:/resource/springMVC.xml -->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <!-- 
                classpath:默认就是当前项目下的resources文件夹下
             -->
            <param-value>classpath:springMVC.xml</param-value>
        </init-param>

        <!--
            指定当前 Servlet 是否在服务器启动时立即加载(初始化),以及加载的优先级。
         -->
        <load-on-startup>1</load-on-startup>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>springMVC</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

<load-on-startup> 是干什么用的?

指定当前 DispatcherServlet 是否在服务器启动时立即加载(初始化),以及加载的优先级。

含义
大于等于 0 启动Tomcat时立即创建 Servlet 实例,值越小优先级越高(先加载)
小于 0 或不写 服务器启动时不会加载 这个 Servlet,第一次请求它时才创建实例(要创建的内容很懂的时候,会影响性能!)

若是:第一次请求时才会加载 DispatcherServlet(延迟初始化),可能出现"首次访问慢"或配置未生效问题

创建springMVC.xml配置文件

3-2、创建SpringMVC 中的"控制器":Controller 类

@Controller 注解的类,就是 SpringMVC 中用于接收请求、处理业务逻辑、返回视图或数据的控制器。

示例:

java 复制代码
@Controller
public class HelloController {

    // "/" -->/WEB-INF/views/index.html
    @RequestMapping("/")
    public String index(){
        return "index";
    }

}

3-3、配置springMVC.xml配置文件

既然使用了注解,就要配置扫描组件

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
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/mvc
       http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!-- 开启注解驱动 -->
    <mvc:annotation-driven/>

    <!-- 扫描 Controller 包 -->
    <context:component-scan base-package="com.wsbazinga.controller"/>

    <!-- 视图解析器 -->
    <bean id="viewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
        <!-- 可以有多个视图解析器,用order属性配置优先级 -->
        <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">
                        <!-- 视图前缀 -->
                        <property name="prefix" value="/WEB-INF/views/"/>
                        <!-- 视图后缀 -->
                        <property name="suffix" value=".html"/>
                        <property name="characterEncoding" value="UTF-8"/>
                        <property name="templateMode" value="HTML"/>
                    </bean>
                </property>
            </bean>
        </property>

    </bean>

</beans>

1、<mvc:annotation-driven/>说明:

启用 SpringMVC 对注解(如 @RequestMapping@ResponseBody@RequestParam 等)的支持功能,也就是告诉 Spring:"我要用注解方式来开发控制器"。

它自动注册以下组件:

组件名 作用
RequestMappingHandlerMapping 处理 URL 和方法的映射关系
RequestMappingHandlerAdapter 调用控制器方法并处理参数和返回值
HttpMessageConverter 负责 JSON ↔ Java 对象 的转换(如使用 Jackson)
Validator 表单参数校验支持(如 @Valid

3-4、配置tomcat启动项目

此时,直接启动tomcat,会通过域名:http://localhost:8080/WsSpringMvc/,直接访问web-inf/views/index.html文件!

3-5、跳转到制定页面

inde.html

html 复制代码
<body>

    <h1>首页</h1>

    <!-- 以/开头的路径:绝对路径(浏览器解析、服务器解析) -->
    <!-- thymeleaf语法检测到是绝对路径,自动添加上下文路径,不怕部署路径变化。 -->
    <a th:href="@{/target}">访问目标页面target.html</a>

</body>
复制代码
HelloController.java
java 复制代码
    @RequestMapping("/target")
    public String toTarget(){
        return "target";
    }

再添加target.html即可。

四、@RequestMapping注解讲解

@RequestMapping 是用来 映射浏览器请求 URL 到后端控制器Controller类 的注解,是 SpringMVC 中的"路由"。


4-1、基本用法

java 复制代码
@Controller
@RequestMapping("/user")
public class UserController {

    @RequestMapping("/hello")
    public String hello() {
        return "hello";
    }
}

当用户访问:http://localhost:8080/项目名/hello

就会调用这个方法,然后返回 "hello",通过视图解析器跳转到页面。

【注意】:

1、@RequestMapping注解可以放在上,也可以放在方法上!

2、确保@RequestMapping映射的URL在当前的project中是唯一的


4-2、常用属性详解:

属性名 作用
valuepath 请求的 URL 路径(必写),类型是String[]数组
method 限定请求方式(GET、POST 等),类型是:RequestMethod[]数组,若是不设置method属性,任何的请求方式都能匹配!
params 请求必须包含某些参数时才执行,类型:String[] 数组,多个params必须同时满足
headers 请求头匹配时才执行
produces 指定响应的内容类型(如 application/json
consumes 指定请求的数据类型(如 application/json

1. 指定 GET 请求

java 复制代码
@RequestMapping(value = "/user", method = RequestMethod.GET)
public String getUser() {
    return "user";
}

访问 /user 且必须是 GET 请求,否则报错。


2. 指定多个方法

java 复制代码
@RequestMapping(value = "/user", method = {RequestMethod.GET, RequestMethod.POST})

支持 GET 和 POST。


3. 限定参数存在

java 复制代码
@RequestMapping(value = "/search", params = "keyword")

只有请求中带有 keyword 参数才会匹配这个方法。

示例:

html 复制代码
    <form th:action="@{/testParams(password=1234)}" method="get">
        <input type="submit" value="测试requestmapping注解的params参数">
    </form>
java 复制代码
    @RequestMapping(
            value = "/testParams",
            params = {"!username", "password!=123456"}
    )
    public String testParams(){
        return "success";
    }

4. 映射类和方法组合路径(推荐做法)

java 复制代码
@Controller
@RequestMapping("/user")
public class UserController {

    @RequestMapping("/add")
    public String addUser() {
        return "add";
    }

    @RequestMapping("/delete")
    public String deleteUser() {
        return "delete";
    }
}

最终路径就是 /user/add/user/delete

5、请求头属性

6、SpringMVC支持ant风格的路径

Ant 风格路径 是 SpringMVC 中的一种通配符路径匹配规则,主要用于 @RequestMappingvalue 属性中,用来更灵活地匹配 URL。

通配符 含义 示例
? 匹配任意的 单个字符 /user? → 匹配 /user1/users(长度固定)
* 匹配任意数量的 字符 (0 个或多个) /user* → 匹配 /user/user123/user_abc
** 匹配任意数量的 目录层级 /a/**/b → 匹配 /a/b/a/x/b/a/x/y/z/b

【注意】:SpringMVC 中,** 只能用于 /xx/**/yy 的结构中,不能直接写成 /** 放在中间或结尾。

✔️ 正确用法:

java 复制代码
@RequestMapping("/admin/**/page")

❌ 错误用法:

java 复制代码
@RequestMapping("/admin**page") // 无效
@RequestMapping("**/page")      // 报错

4-3、和 @GetMapping / @PostMapping 的关系?

注解 等价写法
@GetMapping("/xxx") @RequestMapping(value="/xxx", method=RequestMethod.GET)
@PostMapping("/xxx") @RequestMapping(value="/xxx", method=RequestMethod.POST)
@DeleteMapping 用于 DELETE 请求
@PutMapping 用于 PUT 请求

所以在 RESTful 风格中,推荐使用 @GetMapping@PostMapping 等简化注解。

@RequestMapping的派生注解

【注意】:

浏览器只能处理get和post请求,即使form表单有method属性,可以指定请求方式,也只有get和post两种!(put和delete请求怎么处理,见后面的内容)


4-4、springmvc支持路径中的占位符

这是 RESTful 风格中非常核心的一项功能。

SpringMVC 支持通过 {} 的形式在请求路径中定义占位符 ,然后通过 @PathVariable 注解将 URL 中的路径变量绑定到方法参数上。

举个例子说明:

java 复制代码
@Controller
@RequestMapping("/user")
public class UserController {

    @RequestMapping("/detail/{id}")
    public String getUserById(@PathVariable("id") String id) {
        System.out.println("查询用户 ID: " + id);
        return "user_detail";
    }
}

如果你访问:

复制代码
http://localhost:8080/user/detail/123

就会打印:

复制代码
查询用户 ID: 123

1、语法说明:

用法 说明
/user/{id} {id} 是路径中的占位符
@PathVariable("id") {id} 的值绑定到参数上

2、常见变种:

(1)多个路径变量
java 复制代码
@RequestMapping("/user/{userId}/order/{orderId}")
public String getOrder(@PathVariable("userId") String uid,
                       @PathVariable("orderId") String oid) {
    // ...
}

访问:

复制代码
/user/10/order/555

就会自动绑定:

  • uid = "10"

  • oid = "555"


(2)占位符名和参数名一致时,@PathVariable 可以省略参数名
java 复制代码
@RequestMapping("/user/{id}")
public String getUserById(@PathVariable String id) {
    // OK,变量名和参数名一致
}

(3)占位符 + 通配符
java 复制代码
@RequestMapping("/file/{path}/**")
public String getFile(@PathVariable String path) {
    // 捕捉一部分路径,同时保留通配符
}

匹配以 /file/xxx/... 开头的所有路径,xxx 这一段会被当作路径变量 path** 表示后面还有任意多层路径。


(4)动态 RESTful 风格操作

你可以用路径来表示操作行为,例如:

java 复制代码
// 删除用户
@RequestMapping(value = "/user/{id}", method = RequestMethod.DELETE)
public void deleteUser(@PathVariable int id) {
    // DELETE 操作
}

配合前端的 RESTful 请求或 Postman 测试非常方便。


3、与 @RequestParam 的区别

对比项 @PathVariable @RequestParam
来源 URL 的路径部分 URL 的查询参数部分
示例 /user/123 /user?id=123
用法 @PathVariable("id") @RequestParam("id")

五、SpringMVC获取请求参数

5-1、servletapi获取请求参数(不推荐)

原生的获取方法,从HttpServletRequest中获取请求参数

请求参数通常来自:

  1. URL 查询参数 :例如 /login?username=Tom&password=123

  2. 表单提交(POST) :例如 <form> 提交的数据

  3. 请求体(body):JSON、XML 等格式的原始数据

1、最常用的方式:getParameter()

示例:

html 复制代码
    <form th:action="@{/testParams/testRequestParams}" method="post">
        username: <input type="text" name="username"><br>
        password: <input type="text" name="password">
        <input type="submit" value="测试testRequestParams">
    </form>
java 复制代码
    @PostMapping("/testRequestParams")
    public String testRequestParams(HttpServletRequest request){
        String username = request.getParameter("username");
        String password = request.getParameter("password");

        System.out.println("username = " + username + "; password = " + password);

        return "success";
    }
  • 无论是 GET 还是 POST 请求都可以使用

  • 只能获取 key=value 结构的表单数据或 URL 参数

  • 不能处理 JSON 请求体数据!!!

【注意】:

1、HttpServletRequest中的值是DispatcherServlet放入的。

2、这是原生的获取请求参数的方法,SpringMVC已经做了封装,不再建议使用!

5-2、通过控制器获取请求参数

直接,将Controller类中的方法里面的形参的参数名 = 请求参数的参数名

示例:

html 复制代码
    <form th:action="@{/testParams/testControllerParams}" method="post">
        username: <input type="text" name="username"><br>
        password: <input type="text" name="password">
        <input type="submit" value="测试testRequestParams">
    </form>

【备注】:当有多个同名的请求参数的时候,比如:复选框

html 复制代码
    <form th:action="@{/testParams/testControllerParams}" method="post">
        username: <input type="text" name="username"><br>
        password: <input type="text" name="password"><br>
        
        hobby: <input type="checkbox" name="hobby" value="a">a
        <input type="checkbox" name="hobby" value="b">b
        <input type="checkbox" name="hobby" value="c">c<br>
        <input type="submit" value="测试testRequestParams">
    </form>

1、直接使用String获取(多个值逗号分离)

2、使用String[]获取

5-3、使用 @RequestParam ------ 获取URL参数或表单参数

@RequestParam是将请求参数和控制器方法的形参创建映射关系。

示例:

java 复制代码
@PostMapping("/login")
public String login(@RequestParam("username") String username,
                    @RequestParam("password") String password) {
    System.out.println(username + " - " + password);
    return "success";
}

此时可以解决表单请求的参数名和controller方法里面的形参名不一致的问题!

@RequestParam 不能 用来直接获取 JSON 格式的请求体数据

@RequestParam注解一共有3个属性:

用法 含义
@RequestParam("xxx") 从请求中取出名为 xxx 的参数
required = false 表示该参数可以为空,默认是 true
defaultValue 没传参数,或传参为""时,用默认值(和required无关

5-4、@RequestHeader

@RequestHeader是将请求头信息和控制器方法的形参创建映射关系

@RequestHeader注解一共有三个属性:value、required、defaultValue,用法同@RequestParam

示例:

java 复制代码
@GetMapping("/header")
public String testHeader(@RequestHeader("User-Agent") String userAgent) {
    System.out.println("客户端浏览器信息:" + userAgent);
    return "ok";
}

如果你想获取所有请求头,可以使用 HttpServletRequest@RequestHeader Map

java 复制代码
@GetMapping("/allHeaders")
public String allHeaders(@RequestHeader Map<String, String> headers) {
    headers.forEach((k, v) -> System.out.println(k + ": " + v));
    return "ok";
}

使用场景举例:

场景 请求头 用法
判断浏览器类型 User-Agent 适配页面或功能
语言国际化 Accept-Language 根据浏览器语言返回不同语言的页面
认证 Authorization Token 认证、JWT 登录
CORS 请求 OriginReferer 用于跨域校验或来源过滤

5-5、@CookieValue

@CookieValue是将cookie数据和控制器方法的形参创建映射关系

@CookieValue注解一共有三个属性:value、required、defaultValue,用法同@RequestParam。

示例:

java 复制代码
@Controller
public class CookieController {

    @RequestMapping("/readCookie")
    @ResponseBody
    public String readCookie(@CookieValue("username") String username,
                             @CookieValue(value = "token", defaultValue = "no-token") String token) {

        return "用户名:" + username + ",Token:" + token;
    }
}

5-6、通过pojo获取请求参数

通过 POJO(JavaBean)对象接收请求参数

相比一个个用 @RequestParam 接收参数,使用 POJO 可以自动封装多个参数,非常方便、清晰、结构化


1、什么是 POJO 获取请求参数?

SpringMVC 会自动根据前端传来的请求参数名/URL参数,将它们填充进你定义的 JavaBean(POJO)对象中。


2、使用条件

只要满足下面两个条件,SpringMVC 就可以自动封装:

  1. 请求参数名(form 中的 name)/URL参数 和 JavaBean 的属性名相同

  2. JavaBean 有 无参构造器 + setter 方法


3、示例

  1. 定义 POJO 类(如 User.java)
java 复制代码
public class User {
    private String username;
    private String password;
    private String role;

    // 必须要有 setter 和 getter
    public String getUsername() { return username; }
    public void setUsername(String username) { this.username = username; }

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

    public String getRole() { return role; }
    public void setRole(String password) { this.role = role; }
}

  1. 前端 HTML 表单
html 复制代码
<form action="/user/login?role=admin" method="post">
    用户名:<input type="text" name="username"><br>
    密码:<input type="password" name="password"><br>
    <input type="submit" value="登录">
</form>

  1. Controller 中用 POJO 接收参数
java 复制代码
@Controller
@RequestMapping("/user")
public class UserController {

    @PostMapping("/login")
    public String login(User user) {
        // Spring 会自动把参数封装到 user 对象里
        System.out.println("用户名: " + user.getUsername());
        System.out.println("密码: " + user.getPassword());
        System.out.println("角色: " + user.getRole());

        return "success";
    }
}

【注意】:省略的是:@ModelAttribute注解,SpringMVC 会默认使用,只要参数名匹配!

它的解析顺序大致如下:

  1. 先从请求 URL 中找参数

  2. 再从表单字段(POST)中找参数

  3. 两边都有,就以表单字段为准(POST 参数优先)

  4. 找到的参数会通过 JavaBean 的 setXxx() 注入到对象里


4、支持嵌套对象封装

你可以封装嵌套对象,比如:

java 复制代码
public class Student {
    private String name;
    private Address address;

    // getter/setter ...
}

public class Address {
    private String city;
    private String street;

    // getter/setter ...
}

表单字段名需要使用点语法(Spring 自动识别):

html 复制代码
<input name="name">
<input name="address.city">
<input name="address.street">

5、支持集合类型(List/Map)

如果你的类中有:

java 复制代码
private List<String> hobbies;

你可以使用以下方式提交:

html 复制代码
<input name="hobbies" value="唱歌">
<input name="hobbies" value="跳舞">

Spring 会自动将它封装成 List。

6、完整示例

功能目标

  1. 嵌套封装 :学生有地址信息(Student 包含 Address

  2. List 集合封装 :学生可以选多个兴趣爱好(List<String>

  3. 表单提交 → SpringMVC Controller → 自动封装 POJO → 打印输出


(1)、定义 POJO 类

Address.java

java 复制代码
public class Address {
    private String city;
    private String street;

    // getter 和 setter 必须有
    public String getCity() { return city; }
    public void setCity(String city) { this.city = city; }

    public String getStreet() { return street; }
    public void setStreet(String street) { this.street = street; }
}

Student.java

java 复制代码
import java.util.List;

public class Student {
    private String name;
    private Address address;
    private List<String> hobbies;

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

    public Address getAddress() { return address; }
    public void setAddress(Address address) { this.address = address; }

    public List<String> getHobbies() { return hobbies; }
    public void setHobbies(List<String> hobbies) { this.hobbies = hobbies; }
}

(2)、HTML 表单(studentForm.jsp

html 复制代码
<form action="/student/register" method="post">
    姓名:<input type="text" name="name"><br>

    城市:<input type="text" name="address.city"><br>
    街道:<input type="text" name="address.street"><br>

    爱好:<br>
    <input type="checkbox" name="hobbies" value="唱歌">唱歌<br>
    <input type="checkbox" name="hobbies" value="跳舞">跳舞<br>
    <input type="checkbox" name="hobbies" value="篮球">篮球<br>

    <input type="submit" value="提交">
</form>

(3)、SpringMVC Controller(StudentController.java

java 复制代码
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;

@Controller
@RequestMapping("/student")
public class StudentController {

    @PostMapping("/register")
    public String register(Student student) {

        // 输出接收到的学生信息
        System.out.println("姓名: " + student.getName());

        if (student.getAddress() != null) {
            System.out.println("城市: " + student.getAddress().getCity());
            System.out.println("街道: " + student.getAddress().getStreet());
        }

        if (student.getHobbies() != null) {
            System.out.println("爱好: ");
            for (String h : student.getHobbies()) {
                System.out.println(" - " + h);
            }
        }

        return "success"; // 视图名称
    }
}

【注意】:

此时获取到的hobby的value是乱码的!因为是中文。

7、设置请求对象编码

乱码问题分为两种:

  1. get请求的乱码;
  2. post请求的乱码。
(1)、get请求的乱码

GET 请求的参数是放在 URL 地址栏里的,例如:http://localhost:8080/app?name=张三

这些参数在到达 Servlet 之前,Tomcat 已经解析好了 ,此时用的默认编码(早期是 ISO-8859-1),你设置编码已来不及,乱码已经发生。

所以这是tomcat的问题,需要在tomcat的server.xml 中明确指定:

{Tomcat目录}/conf/server.xml

加上 URIEncoding="UTF-8" 就可以防止 GET 请求中文乱码。

(2)、post请求乱码
请求类型 参数位置 解决方式
POST 请求体 body 使用 request.setCharacterEncoding("UTF-8")
GET URL 地址栏 设置 Tomcat 的 URIEncoding="UTF-8"

【注意点】:必须在第一次获取参数之前设置编码!

一旦调用了以下任意方法:

java 复制代码
request.getParameter()
request.getParameterMap()
request.getParameterNames()
request.getParameterValues()

Servlet 容器就会立即解析请求体,并把参数缓存起来。

如果你在调用之后再设置编码,就无效了,编码已经决定,不会重新解析请求体。

❌ 错误做法(设置编码太晚)

java 复制代码
String name = request.getParameter("name"); // 已经触发解析
request.setCharacterEncoding("UTF-8");      // ✘ 已经没用了!

✅ 正确做法(先设置编码)

java 复制代码
request.setCharacterEncoding("UTF-8");      // ✔ 先设置编码
String name = request.getParameter("name"); // 然后获取参数

但是应为此时我们用的是pojo获取请求参数,使用request.setCharacterEncoding("UTF-8");是无效的,应为dispatcherServlet已经解析了参数了!

所以用过滤器统一处理,因为,过滤器在servlet之前执行!

在web.xml中配置如下过滤器:

XML 复制代码
    <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>
        </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>

5-7、【回顾】使用 @PathVariable(获取 REST 风格路径参数)

java 复制代码
@GetMapping("/user/{id}")
public String getUserById(@PathVariable("id") int id) {
    System.out.println("id = " + id);
    return "user";
}

5-8、使用 @RequestBody(接收 JSON 数据)

java 复制代码
@PostMapping("/user")
public String createUser(@RequestBody User user) {
    System.out.println("user = " + user);
    return "success";
}
  • 会从 请求体中读取 JSON ,然后通过 Jackson 自动反序列化成 User 对象。

  • 需要前端设置 Content-Type: application/json

需要前端发送 Content-Type: application/json 请求头,示例:

javascript 复制代码
<!-- requestbody.html -->
<script>
  function register() {
    const user = {
      username: "Alice",
      email: "alice@example.com",
      password: "123456"
    };

    fetch("/json/register", {
      method: "POST",
      headers: {
        "Content-Type": "application/json"
      },
      body: JSON.stringify(user)
    }).then(response => {
      if (response.ok) {
        alert("Registered successfully!");
      }
    });
  }
</script>

<button onclick="register()">Register via JSON</button>

五、SpringMVC 中的三种域对象

requestsession、和 servletContext(application),它们统称为 "三大作用域对象"

5-1、什么是域对象?

域对象(也叫作用域对象)是 Web 中用来 在不同范围内共享数据 的容器。

域对象 生命周期范围 使用场景
request 一次请求内有效 请求转发、表单处理
session 一个用户会话内有效 登录状态、用户信息保存
servletContext 整个 Web 应用范围内都有效(太大) 全局参数、在线人数统计等

1、区分:什么是一"次请求",什么是一"次会话"

(1)、 什么是一"次请求"

一次请求 = 浏览器或客户端 发出的一次 HTTP 请求。它从你访问某个 URL 的那一刻开始,到服务器响应并返回结果为止。

判断是不是"一次请求":你可以在控制器方法中打印 request 对象的地址或哈希值:

java 复制代码
@RequestMapping("/test")
public String test(HttpServletRequest request) {
    System.out.println("request hash: " + request.hashCode());
    return "success";
}

如果你在多个方法里都打了这个语句,只有同一个请求转发时(比如 forward:/page),request.hashCode() 是相同的。

【注意】:

页面刷新或重新点击链接 → 就是新的请求!!!

即使访问的是同一个地址,但每点击一次或刷新一次,就是一个新的 request。

特点:生命周期短

  • 请求来了就创建

  • 响应完成就销毁

  • 不同请求之间,request 互不影响

(2)、一次会话(session)

一次会话 = 用户打开浏览器 → 访问网站 → 关闭浏览器或长时间不操作 → 会话结束。

浏览器不关、用户不断操作,这个会话就一直保持。

判断是不是"一次会话":打印 session ID

java 复制代码
@RequestMapping("/checkSession")
public String checkSession(HttpSession session) {
    System.out.println("session ID: " + session.getId());
    return "session";
}
  • 多次访问 /checkSession,只要浏览器没关,session ID 不变,说明是同一个会话。

  • 如果你关掉浏览器再访问,或等上20~30分钟,session ID 就会变,说明是新会话。

【注意】:

域名不同就不是同一个 session!

一般,同一个项目下共享 session!!!

情景:同一浏览器访问两个项目

  • http://localhost:8080/app1

  • http://localhost:8080/app2

虽然端口和浏览器一样,但项目上下文不同(app1 ≠ app2) ,默认是两个不同的 session,除非你显式配置 Cookie 的路径。

5-2、request 域对象

特点

  • 生命周期:一次请求内有效

  • 随着请求的完成而销毁(如访问页面、转发等)

  • 适合存储:表单校验信息、错误提示、一次性数据传递

1、使用ServletAPI向request域对象共享数据

示例:

index.html页面:

html 复制代码
<h2>test request scope value</h2>
<a th:href="@{/testRequestByServletApi}">set request attribute and then go to success page</a>

点击之后发送一次请求:http://localhost:8080/WsSpringMvc/testRequestByServletApi

java 复制代码
@Controller
public class ScopeController {

    @RequestMapping("/testRequestByServletApi")
    public String testRequestByServletApi(HttpServletRequest request){
        // 每一个域对象都有三种方法:
        // setAttribute
        // getAttribute
        // removeAttribute
        request.setAttribute("testRequestScope", "hello servletAPI");
        return "successScope";
    }

}

【注意】:

return "success" 是"请求转发"forward)。

在 Spring MVC 中,当你的控制器方法返回一个字符串(如 "success"),默认行为是:

  • Spring 会将这个字符串当作视图名

  • 然后交给视图解析器(ViewResolver)来处理

  • 最终会使用请求转发(forward)到对应的页面

等价于:

java 复制代码
request.getRequestDispatcher("/WEB-INF/views/success.jsp").forward(request, response);

所以,这是一次请求转发,而不是重定向

如果你想"重定向",需要显式写上:

java 复制代码
return "redirect:/someOtherPath";
返回值 行为 地址栏是否变化 请求是否共享 request 域
"success" 请求转发 ❌ 不变 ✅ 可以用 ${msg} 取值
"redirect:/xx" 重定向 ✅ 会变 ❌ request 域不共享(已经不是一次请求了!)

successScope.html页面

html 复制代码
<body>

    <h1>success</h1>

    <p th:text="${testRequestScope}"></p>

</body>

【注意】:

在 Thymeleaf 中,"${}" 表达式用于获取变量,但不同作用域(request、session、application)中的变量访问方式有所不同

  1. Request 域(HttpServletRequest):
html 复制代码
​​​​​​​<p th:text="${key}"></p>
  1. Session 域(HttpSession
java 复制代码
<p th:text="${session.key}"></p>
  1. Application 域(ServletContext
java 复制代码
<p th:text="${application.key}"></p>

2、使用ModelAndView向request域对象共享数据(Springmvc)

下面的2,3,4,5方式,都是Springmvc中提供的向request域对象共享数据的方法,最终原码都是包装成一个ModelAndView对象!

ModelAndView有model和view的功能:

  • model主要用于向请求域共享数据;
  • view用于设计视图,实现页面跳转!

示例:

java 复制代码
    @RequestMapping("/testModelAndViewApi")
    public ModelAndView testModelAndViewApi(){
        ModelAndView modelAndView = new ModelAndView();
        // 处理model数据:即,向请求域request共享数据
        modelAndView.addObject("testRequestScopeModelAndView", "hello modelAndView");
        // 设置视图名称
        modelAndView.setViewName("successScope");
        return modelAndView;
    }

【注意】:

返回值一定要是ModelAndView,因为要把视图返回给视图解析器!

3、使用Model向request域对象共享数据(Springmvc)

4、使用Map集合向request域对象共享数据(Springmvc)

map集合一般key就是string类型,value就是object类型!

5、使用ModelMap集合向request域对象共享数据(Springmvc)

5-3、Session域对象

使用方法:

java 复制代码
@RequestMapping("/login")
public String login(HttpSession session) {
    session.setAttribute("user", "Tom");
    return "home";
}
  • 获取 session:HttpSession session

  • 读取 session 数据:session.getAttribute("user")

5-4、servletContext(application)域对象

特点:

  • 生命周期:整个 Web 应用运行期间有效

  • 所有用户共享,全局作用域

  • 适合存储:全局配置、网站访问量、缓存等

application域对象,范围太大了,用的最多的还是request和session!

使用方法:

java 复制代码
@RequestMapping("/app")
public String applicationScope(HttpSession session) {
    ServletContext context = session.getServletContext();
    context.setAttribute("count", 100);
    return "global";
}

也可以直接通过 @Autowired 注入:

java 复制代码
@Autowired
ServletContext context;

5-5、总结一句话

你想用什么作用域对象(如 request、session、application),直接写在控制器方法参数中即可获取,Spring MVC 会自动注入,不用你手动 new 或额外配置。

示例:

java 复制代码
@RequestMapping("/demo")
public String demo(HttpServletRequest request,
                   HttpSession session,
                   ServletContext context) {
    request.setAttribute("reqData", "数据来自 request 域");
    session.setAttribute("sessData", "数据来自 session 域");
    context.setAttribute("appData", "数据来自 application 域");
    return "success"; // 视图解析到 success.html 或 JSP
}
相关推荐
ruleslol2 天前
springMVC02-视图解析器、RESTful设计风格,静态资源访问配置
springmvc
endswel3 天前
Spring MVC HandlerInterceptor 拦截请求及响应体
springmvc·springboot
sniper_fandc7 天前
SpringMVC详解
java·springmvc
保持学习ing18 天前
SpringBoot电脑商城项目--创建订单+统计业务方法耗时
java·spring boot·spring·springmvc·jquery
编程大全23 天前
47道SpringMVC高频题整理(附答案背诵版)
springmvc·面试题
周星星日记1 个月前
1.springmvc基础入门(一)
spring·springmvc
abcnull1 个月前
springboot中过滤器配置使用
java·spring boot·后端·springmvc·过滤器
liubo666_2 个月前
SpringMVC(结合源码浅析工作流程)
java·spring·springmvc
唐僧洗头爱飘柔95272 个月前
【SSM-SSM整合】将Spring、SpringMVC、Mybatis三者进行整合;本文阐述了几个核心原理知识点,附带对应的源码以及描述解析
java·spring·mybatis·springmvc·动态代理·ioc容器·视图控制器