在SpringMVC框架中,请求分发是整个Web层架构的起点,而承担这一职责的核心注解就是@RequestMapping。它可以把一个特定的HTTP请求映射到某个Controller的处理方法上,从而建立起URL与Java方法之间的绑定关系。理解它的各种属性和匹配规则,是写好SpringMVC应用的基础。

@RequestMapping的基本定义与使用方法
在Controller类上使用@RequestMapping注解,需要先确保Spring容器扫描到了该类,通常配合@Controller注解一起使用。最简单的用法是直接标注在方法上,指定请求路径,框架在收到匹配的请求后会通过反射调用该方法。下面是一个典型的例子:
@Controller
public class UserController {
// 最基础的映射:访问 /user/list 时执行此方法
@RequestMapping("/user/list")
public String list() {
System.out.println("查询用户列表");
return "userList"; // 返回逻辑视图名
}
}
这个例子中,方法返回一个字符串,SpringMVC会借助视图解析器把它解析成具体的JSP或模板页面。除了返回字符串,处理方法还可以返回ModelAndView、void,或者加上@ResponseBody后直接返回JSON数据。方法参数也非常灵活,可以接收HttpServletRequest、HttpServletResponse、Model等Web对象,也可以自动绑定请求参数。
注解既可以放在方法上,也可以放在类上。放在类上时相当于给该类下所有方法统一添加路径前缀,这种方式称为请求映射的窄化。当项目中有多个Controller时,通过类级别的路径前缀可以有效避免路径冲突,同时让URL结构更加清晰。例如订单模块统一以/order开头,用户模块统一以/user开头,可读性明显提升。
@Controller
@RequestMapping("/order")
public class OrderController {
// 实际访问路径为 /order/detail
@RequestMapping("/detail")
public String detail() {
return "orderDetail";
}
// 实际访问路径为 /order/pay
@RequestMapping("/pay")
public String pay() {
return "payPage";
}
}
核心属性详解:精确控制请求映射条件
@RequestMapping提供了多个属性,支持从多个维度限定请求的匹配条件,这正是它功能强大的地方。value或path属性指定请求路径,是最常用的;method属性限定请求方式;params属性要求请求必须携带或不携带某些参数;headers属性限定请求头;consumes限定请求体的内容类型;produces限定响应的内容类型。
method属性接收RequestMethod枚举,同一个路径可以通过不同的请求方式区分到不同的方法,这是实现RESTful风格接口的基础。比如GET请求用于查询,POST请求用于新增,PUT用于修改,DELETE用于删除。params属性的写法比较灵活,params="userId"表示请求必须包含userId参数,params="!userId"表示不能包含,params="userId=100"表示参数值必须等于100。
@Controller
@RequestMapping("/product")
public class ProductController {
// 只接受 GET 请求,且必须带 category 参数
@RequestMapping(value = "/list", method = RequestMethod.GET, params = "category")
@ResponseBody
public String listByCategory(String category) {
return "查询分类为:" + category + "的商品";
}
// 只接受 POST 请求,且请求体必须是 application/json
@RequestMapping(value = "/add", method = RequestMethod.POST, consumes = "application/json")
@ResponseBody
public String add() {
return "新增商品成功";
}
// 指定响应内容类型和编码,避免中文乱码
@RequestMapping(value = "/info", produces = "application/json;charset=UTF-8")
@ResponseBody
public String info() {
return "{\"name\":\"测试商品\"}";
}
}
consumes和produces与HTTP协议中的Content-Type直接对应。前者用于过滤请求体类型,常用于区分JSON提交和表单提交;后者控制响应输出的类型,在返回中文字符串时务必显式指定UTF-8编码,否则很容易出现乱码问题。如果多个属性同时出现,它们之间是且的关系,即请求必须同时满足所有条件才会命中方法。
组合注解与RESTful路径匹配技巧
从Spring 4.3开始,框架提供了@GetMapping、@PostMapping、@PutMapping、@DeleteMapping、@PatchMapping这一系列组合注解。它们等价于@RequestMapping加上对应method属性的写法,代码更简洁,语义也更明确。日常开发中推荐优先使用这些组合注解,只有在一个方法需要响应多种请求方式时才使用原生的@RequestMapping。
@RestController
@RequestMapping("/api/users")
public class ApiUserController {
@GetMapping("/{id}")
public String getById(@PathVariable("id") Long id) {
return "查询用户:" + id;
}
@PostMapping
public String create(@RequestBody String body) {
return "创建用户:" + body;
}
@PutMapping("/{id}")
public String update(@PathVariable("id") Long id) {
return "更新用户:" + id;
}
@DeleteMapping("/{id}")
public String delete(@PathVariable("id") Long id) {
return "删除用户:" + id;
}
}
路径中的{id}是路径变量占位符,配合@PathVariable注解可以把URL中的动态片段绑定到方法参数上,这是实现RESTful风格的关键。此外,SpringMVC还支持ant风格的通配符:?匹配单个字符,*匹配任意字符但不跨路径段,**匹配任意层级路径。需要注意的是,通配符越精确优先级越高,当多个路径都能匹配同一个请求时,不含通配符的精确路径优先级最高,其次是含单个*的,最后才是**。
在使用路径变量时有一个常见的坑:占位符中的值如果包含斜杠或点号,可能出现匹配异常。比如文件名形式的路径/file/report.pdf,绑定到@PathVariable时可能只拿到report,点号后面的部分被当作文件后缀截断了。遇到这种情况可以在占位符中使用正则表达式,写成{filename:.+}来强制匹配完整内容。
常见问题排查与最佳实践
开发中与请求映射相关的问题集中在三类。第一类是404,通常是路径拼写错误、类未加@Controller注解、包未被组件扫描覆盖,或者类级别与方法级别路径拼接出错导致。第二类是路径冲突,即两个方法映射了完全相同的路径和请求方式,SpringMVC在启动阶段就会抛出Ambiguous mapping异常,解决办法是调整路径或通过method、params等属性进一步区分。第三类是参数绑定失败,比如方法参数名与请求参数名不一致导致值为null,此时应使用@RequestParam("name")显式指定映射关系。
在最佳实践层面,建议团队统一采用RESTful路径设计,资源名用名词复数形式,动作用HTTP方法表达;类级别注解统一添加模块前缀,方法级别只写相对路径;返回JSON的接口统一使用@RestController,避免每个方法都重复写@ResponseBody;接口方法尽量显式声明produces编码,把乱码问题挡在编码阶段。另外,方法命名最好能体现业务含义,如getUserById、createOrder,方便后续维护和日志排查。
掌握@RequestMapping之后,还可以进一步了解HandlerMapping与HandlerAdapter的协作原理。简单来说,SpringMVC启动时会把所有标注了该注解的方法解析成RequestMappingInfo并缓存到注册表中,请求到来时通过DispatcherServlet查找匹配项,再交给适配器反射调用方法。理解这条链路,遇到映射不生效或拦截异常时,就能顺着源码快速定位问题根源。
SpringMVC@RequestMappingSpring注解修改时间:2026-08-31 04:22:38