乐途乐途
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • MyBatis
    • Spring
    • Spring MVC
    • Maven 入门
    • Maven 进阶
    • Java 设计模式
  • 缓存

    • Redis
联系
阿里云
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • MyBatis
    • Spring
    • Spring MVC
    • Maven 入门
    • Maven 进阶
    • Java 设计模式
  • 缓存

    • Redis
联系
阿里云
  • 学习路径
  • 第1章 SpringMVC概述与DispatcherServlet

    • 本章导读:Spring MVC概述与DispatcherServlet
    • Spring MVC 是什么
    • MVC 设计模式
    • 前端控制器模式
    • DispatcherServlet
    • 核心组件协作
  • 第2章 控制器与请求映射

    • 本章导读:控制器与请求映射
    • Controller
    • RestController
    • RequestMapping
    • GetMapping
    • PostMapping
    • PutMapping
    • DeleteMapping
    • PathVariable
    • RESTful
    • 请求映射原理
  • 第3章 请求参数获取与转换

    • 本章导读:请求参数获取与转换
    • RequestParam
    • RequestBody
    • RequestHeader
    • CookieValue
    • Model
    • ModelAttribute
    • 数据绑定原理
    • 数据校验
  • 第4章 响应数据与视图解析

    • 本章导读:响应数据与视图解析
    • ResponseBody
    • ResponseEntity
    • ModelAndView
    • ViewResolver
    • HttpMessageConverter
    • forward与redirect
  • 第5章 拦截器过滤器与跨域

    • 本章导读:拦截器、过滤器与跨域
    • HandlerInterceptor
    • WebMvcConfigurer
    • CrossOrigin
    • 登录验证实战
  • 第6章 文件上传与异常处理

    • 本章导读:文件上传与异常处理
    • MultipartFile
    • 文件下载
    • ExceptionHandler
    • ControllerAdvice
    • RestControllerAdvice
    • ResponseStatus
  • 第7章 高级特性与最佳实践

    • 本章导读:高级特性与最佳实践
    • SessionAttributes
    • SessionAttribute
    • RedirectAttributes
    • MockMvc测试
    • 国际化
    • 最佳实践
  • 第8章 扩展与异步机制

    • 本章导读:扩展与异步机制
    • 异步请求处理
    • 自定义参数解析器
    • 内容协商

RequestMapping

本章是 Spring MVC 请求映射体系的核心。DispatcherServlet 需要知道"哪个 URL 交给哪个方法处理",@RequestMapping 正是声明这种映射关系的元注解。@GetMapping、@PostMapping 等所有方法级映射注解,本质上都是 @RequestMapping 的特化。理解 @RequestMapping,就掌握了 Spring MVC 路由规则的完整表达能力。


定义与作用

@RequestMapping 是 Spring MVC 的核心映射注解,可以标注在类级和方法级。它的职责可以用一句话概括:声明控制器类或方法所处理的 HTTP 请求映射规则,包括 URL 路径、HTTP 方法、请求参数、请求头、消费/生产媒体类型等约束条件。

@RequestMapping 是所有 HTTP 方法注解的元注解:

// @GetMapping 的源码定义
@RequestMapping(method = RequestMethod.GET)
public @interface GetMapping { }

// @PostMapping 的源码定义
@RequestMapping(method = RequestMethod.POST)
public @interface PostMapping { }

// 同理:@PutMapping、@DeleteMapping、@PatchMapping

掌握 @RequestMapping,就等于掌握了所有映射注解的底层机制。


核心原理

类级 + 方法级路径拼接

拼接规则:

  • 类级路径 + 方法级路径 = 完整请求路径
  • 如果类级没有 @RequestMapping,方法级路径就是完整路径
  • 路径拼接时自动处理斜杠,无需手动添加或删除

多维度匹配机制

图解:@RequestMapping 的匹配是多维度交集,所有条件同时满足才算匹配。这种精细控制使得同一个 URL 可以根据 HTTP 方法、请求头、Content-Type 等分发给不同的方法。


适用位置与常用属性

属性对比表

属性类型作用示例
value / pathString[]URL 路径映射"/employees"、"/{id}"
methodRequestMethod[]约束 HTTP 方法RequestMethod.GET
paramsString[]约束请求参数"department"、"!archived"
headersString[]约束请求头"X-Api-Version=2"
consumesString[]约束请求 Content-Type"application/json"
producesString[]约束响应 Accept / 设置响应 Content-Type"application/json"

Ant 风格 URL 模式

Spring MVC 支持 Ant 风格的路径模式,用于模糊匹配:

通配符含义示例
?匹配单个字符/employees/? 匹配 /employees/1
*匹配零个或多个字符(单层路径)/employees/* 匹配 /employees/list,不匹配 /employees/1/detail
**匹配零个或多个路径段(多层路径)/employees/** 匹配 /employees/1/detail/address

完整示例

场景

飞翔科技的员工管理系统需要精细控制请求路由。架构师白歌要求同一个基础路径 /employees 下,根据 HTTP 方法、请求参数、请求头的不同,分发给不同的处理方法。

控制器代码

package com.feixiang.web;

import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/employees")
public class EmployeeController {

    // 容器已注入该 Bean,本教程不展开 Service 实现
    @Autowired
    private EmployeeService employeeService;

    // 映射 1:GET /employees(无参数)
    @RequestMapping(method = RequestMethod.GET)
    public List<Employee> listAll() {
        return employeeService.findAll();
    }

    // 映射 2:GET /employees?department=技术部
    @RequestMapping(method = RequestMethod.GET, params = "department")
    public List<Employee> listByDepartment(@RequestParam String department) {
        return employeeService.findByDepartment(department);
    }

    // 映射 3:GET /employees/{id}
    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    public Employee getById(@PathVariable Long id) {
        return employeeService.findById(id);
    }

    // 映射 4:POST /employees(只接受 JSON)
    @RequestMapping(method = RequestMethod.POST,
                    consumes = "application/json",
                    produces = "application/json")
    public Employee create(@RequestBody Employee employee) {
        return employeeService.save(employee);
    }

    // 映射 5:GET /employees/export(要求请求头 X-Format=csv)
    @RequestMapping(value = "/export", method = RequestMethod.GET,
                    headers = "X-Format=csv")
    public String exportCsv() {
        return employeeService.exportCsv();
    }
}

映射规则汇总:

请求特征匹配的方法
GET /employeeslistAll()
GET /employees?department=技术部listByDepartment()
GET /employees/1001getById()
POST /employees + Content-Type: application/jsoncreate()
GET /employees/export + X-Format: csvexportCsv()

HTTP 请求示例 1:带参数的分发

# 请求 A:无参数 → 调用 listAll()
curl -X GET http://localhost:8080/employees

# 请求 B:带 department 参数 → 调用 listByDepartment()
curl -X GET "http://localhost:8080/employees?department=技术部"

请求 A 响应:

[
  {"id": 1001, "name": "张伟", "department": "技术部"},
  {"id": 1002, "name": "李娜", "department": "市场部"},
  {"id": 1003, "name": "王强", "department": "技术部"}
]

请求 B 响应:

[
  {"id": 1001, "name": "张伟", "department": "技术部"},
  {"id": 1003, "name": "王强", "department": "技术部"}
]

分析:

  • 两个请求的 URL 都是 /employees,但 params = "department" 使它们分发给不同方法
  • listByDepartment() 只返回技术部员工,因为 department=技术部 作为查询参数传入
  • 这是 @RequestMapping 多维度匹配的典型应用

HTTP 请求示例 2:consumes 和 headers 约束

# 请求 C:正确的 POST(Content-Type 为 application/json)
curl -X POST http://localhost:8080/employees \
  -H "Content-Type: application/json" \
  -d '{"name":"赵敏","department":"财务部"}'

# 请求 D:错误的 POST(Content-Type 为 text/plain)
curl -X POST http://localhost:8080/employees \
  -H "Content-Type: text/plain" \
  -d 'name=赵敏'

请求 C 响应(201 Created):

{"id": 1004, "name": "赵敏", "department": "财务部"}

请求 D 响应(415 Unsupported Media Type):

{
  "timestamp": "2024-06-15T10:30:00",
  "status": 415,
  "error": "Unsupported Media Type",
  "message": "Content type 'text/plain;charset=UTF-8' not supported"
}

分析:

  • consumes = "application/json" 要求请求必须携带 Content-Type: application/json
  • 请求 D 的 text/plain 不匹配,Spring MVC 直接返回 415,不会进入 Controller 方法
  • 这种前置约束避免了方法内部做 Content-Type 检查

易错场景与面试考点

误区一:类级和方法级路径拼接时重复写斜杠

错误写法:

@RequestMapping("/employees")      // 类级以 / 开头
public class EmployeeController {

    @RequestMapping("/list")       // 方法级也以 / 开头
    public String list() { }
}
// 实际映射路径:/employees/list(Spring 自动处理重复斜杠)

纠正:虽然 Spring 会自动处理重复斜杠,但推荐风格是类级以 / 开头,方法级不以 / 开头:

@RequestMapping("/employees")
public class EmployeeController {

    @RequestMapping("list")          // 推荐:方法级不加前导 /
    public String list() { }
}

误区二:params 和 headers 的否定写法

错误认知:"params = "department" 表示请求可以有也可以没有 department 参数。"

纠正:params = "department" 表示必须有 department 参数。如果要表达"必须没有",使用 ! 前缀:

// 必须有 department 参数
@RequestMapping(params = "department")

// 必须没有 archived 参数
@RequestMapping(params = "!archived")

// 必须有 department=技术部
@RequestMapping(params = "department=技术部")

// 必须有 department,且值不是 离职
@RequestMapping(params = "department!=离职")

面试高频:@RequestMapping 的匹配维度

标准回答:

  • @RequestMapping 可以从六个维度约束请求:path、method、params、headers、consumes、produces
  • 匹配是交集逻辑,所有条件同时满足才算匹配
  • 类级和方法级的 value(path)会拼接为完整路径
  • consumes 不匹配返回 415,produces 不匹配返回 406,method 不匹配返回 405
  • Spring 4.3+ 推荐使用 @GetMapping、@PostMapping 等派生注解,语义更清晰

小结

@RequestMapping 是 Spring MVC 请求映射体系的元注解,它通过 path、method、params、headers、consumes、produces 六个维度精确控制请求路由。类级和方法级的路径自动拼接,Ant 风格通配符支持模糊匹配。它是 @GetMapping、@PostMapping 等所有派生注解的底层基础。

本章与全局的关系:本章讲解了 @RequestMapping 的完整能力。后续章节将分别讲解其派生注解 @GetMapping、@PostMapping、@PutMapping、@DeleteMapping,它们在语义上更精确,是实际开发中的首选。

上一页
RestController
下一页
GetMapping