了解 Spring RequestMapping

2024-06-23 15:48

本文主要是介绍了解 Spring RequestMapping,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1. 概述

 

这篇文章会集中讨论 Spring MVC 的一个重要注解 @RequestMapping。

 

简要地说,该注解用于把 Web 请求映射到 Spring Controller 方法。

 

2. @RequestMapping 基础

 

先从一个简单的示例开始:通过设置基本条件把 HTTP 请求映射到某个方法。

 

2.1. 路径映射

 

@RequestMapping(value = "/ex/foos", method = RequestMethod.GET)
@ResponseBody
public String getFoosBySimplePath() {return "Get some Foos";
}

 

使用 curl 命令测试:

 

curl -i http://localhost:8080/spring-rest/ex/foos

 

2.2. HTTP 方法映射

 

HTTP 方法参数没有缺省值,如果不设参数值,请求会映射到所有 HTTP 请求。

 

下面的示例中,映射的是 HTTP POST 请求:

 

@RequestMapping(value = "/ex/foos", method = POST)
@ResponseBody
public String postFoos() {return "Post some Foos";
}

 

通过 curl 命令测试 POST 请求:

 

curl -i -X POST http://localhost:8080/spring-rest/ex/foos

 

3. 根据 HTTP Header 映射

 

3.1. 指定 Header 属性

 

通过为请求指定一个 header 进一步缩小映射:

 

@RequestMapping(value = "/ex/foos", headers = "key=val", method = GET)
@ResponseBody
public String getFoosWithHeader() {return "Get some Foos with Header";
}

 

使用 curl 命令带 header 测试:

 

curl -i -H "key:val" http://localhost:8080/spring-rest/ex/foos

 

还可以 @RequestMapping 的 headers 属性设置多个 header:

 

@RequestMapping(value = "/ex/foos",headers = { "key1=val1", "key2=val2" }, method = GET)
@ResponseBody
public String getFoosWithHeaders() {return "Get some Foos with Header";
}

 

使用以下命令测试:

 

curl -i -H "key1:val1" -H "key2:val2" http://localhost:8080/spring-rest/ex/foos

 

注意:curl 分隔 key 和 value 的语法是冒号与 HTTP 规范相同,而 Spring 中使用的是等号。

 

3.2. consume 与 produce 属性

 

对 Controller 媒体类型映射时需要特别注意:使用 @RequestMapping headers 还可以处理 Accept header:

 

@RequestMapping(value = "/ex/foos",method = GET,headers = "Accept=application/json")
@ResponseBody
public String getFoosAsJsonFromBrowser() {return "Get some Foos with Header Old";
}

 

定义 Accept Header 的匹配方式非常灵活。不仅支持 = 精确匹配,也支持多条件匹配,像下面这样:

 

curl -H "Accept:application/json,text/html"http://localhost:8080/spring-rest/ex/foos

 

自 Spring 3.1 开始,@RequestMapping 注解已支持 produce 和 consume 属性,适用以下的场景:

 

@RequestMapping(value = "/ex/foos",method = RequestMethod.GET,produces = "application/json"
)
@ResponseBody
public String getFoosAsJsonFromREST() {return "Get some Foos with Header New";
}

 

同时,header 映射会自动转换为新的 produces 机制,执行的效果相同。

 

使用 curl 命令测试:

 

curl -H "Accept:application/json"http://localhost:8080/spring-rest/ex/foos

 

此外,produces 也支持多个参数:

 

@RequestMapping(value = "/ex/foos",method = GET,produces = { "application/json", "application/xml" }
)

 

请注意:Spring 不支持同时用新旧两种方法指定 accept header,否则会抛出异常:

 

Caused by: java.lang.IllegalStateException: Ambiguous mapping found.
Cannot map 'fooController' bean method
java.lang.String
org.baeldung.spring.web.controller.FooController.getFoosAsJsonFromREST()
to
{ [/ex/foos],methods=[GET],params=[],headers=[],consumes=[],produces=[application/json],custom=[]
}:
There is already 'fooController' bean method
java.lang.String
org.baeldung.spring.web.controller.FooController.getFoosAsJsonFromBrowser()
mapped.

 

最后需要说明一点:produces 和 consumes 与其它注解的行为不同,方法级注解只覆盖不增加。

 

4. Path 变量

 

通过 @PathVariable 注解可以绑定 URI 变量。

 

4.1. @PathVariable 单个变量

 

单个变量使用示例:

 

@RequestMapping(value = "/ex/foos/{id}", method = GET)
@ResponseBody
public String getFoosBySimplePathWithPathVariable(@PathVariable("id") long id) {return "Get a specific Foo with id=" + id;
}

 

使用 curl 测试:

 

curl http://localhost:8080/spring-rest/ex/foos/1

 

如果方法的参数名与路径变量名完全匹配,可以直接使用@PathVariable 不带参数:

 

@RequestMapping(value = "/ex/foos/{id}", method = GET)
@ResponseBody
public String getFoosBySimplePathWithPathVariable(@PathVariable String id) {return "Get a specific Foo with id=" + id;
}

 

注意:@PathVariable 支持自动类型转换,id 还可以声明为:

 

@PathVariable long id

 

4.2. @PathVariable 多个变量

 

复杂 URI 可以把多个部分映射为多个 value:

 

@RequestMapping(value = "/ex/foos/{fooid}/bar/{barid}", method = GET)
@ResponseBody
public String getFoosBySimplePathWithPathVariables(@PathVariable long fooid, @PathVariable long barid) {return "Get a specific Bar with id=" + barid +" from a Foo with id=" + fooid;
}

 

同样可以使用 curl 测试:

 

curl http://localhost:8080/spring-rest/ex/foos/1/bar/2

 

4.3. @PathVariable 正则表达式

 

@PathVariable 支持正则表达式,比如用正则限制 id 只允许数值输入:

 

@RequestMapping(value = "/ex/bars/{numericId:[\\d]+}", method = GET)
@ResponseBody
public String getBarsBySimplePathWithPathVariable(@PathVariable long numericId) {return "Get a specific Bar with id=" + numericId;
}

 

下面 URI 可以匹配:

 

http://localhost:8080/spring-rest/ex/bars/1

 

下面 URI 不能匹配:

 

http://localhost:8080/spring-rest/ex/bars/abc

 

5. Request Parameters

 

@RequestMapping 通过 @RequestParam 注解可以对 URL 参数进行映射。

 

比如下面这个 URI:

 

http://localhost:8080/spring-rest/ex/bars?id=100

 

Java 代码:

 

@RequestMapping(value = "/ex/bars", method = GET)
@ResponseBody
public String getBarBySimplePathWithRequestParam(@RequestParam("id") long id) {return "Get a specific Bar with id=" + id;
}

 

然后,为 Controller 方法加上 @RequestParam("id") 注解提取 id 参数值。

 

使用 curl 命令发送带 id 请求:

 

curl -i -d id=100 http://localhost:8080/spring-rest/ex/bars

 

在上面的例子中,参数直接绑定,没有提前声明。

 

@RequestMapping 可以根据需要有选择地定义参数 减少请求映射:

 

@RequestMapping(value = "/ex/bars", params = "id", method = GET)
@ResponseBody
public String getBarBySimplePathWithExplicitRequestParam(@RequestParam("id") long id) {return "Get a specific Bar with id=" + id;
}

 

还支持更灵活的映射,设置多个 params 值,不需要全部映射:

 

@RequestMapping(value = "/ex/bars", params = "id", method = GET)
@ResponseBody
public String getBarBySimplePathWithExplicitRequestParam(@RequestParam("id") long id) {return "Get a specific Bar with id=" + id;
}

 

还可以设置多个 params 值,只使用其中一部分:

 

@RequestMapping(value = "/ex/bars",params = { "id", "second" },method = GET)
@ResponseBody
public String getBarBySimplePathWithExplicitRequestParams(@RequestParam("id") long id) {return "Narrow Get a specific Bar with id=" + id;
}

 

下面这个 URI:

 

http://localhost:8080/spring-rest/ex/bars?id=100&second=something

 

总能找到最佳的映射匹配(窄匹配),即同时定义了 id 和 second。

 

6. 边界案例

 

6.1. 多个 Path 映射到同一个 Controller 方法

 

虽然 @RequestMapping Path 通常与 Controller 方法一一对应,但这只是最佳实践而非硬性规定。某些情况需要把多个请求映射到同一个方法。这种情况下,@RequestMappingvalue 会包含多个映射:

 

@RequestMapping(value = { "/ex/advanced/bars", "/ex/advanced/foos" },method = GET)
@ResponseBody
public String getFoosOrBarsByPath() {return "Advanced - Get some Foos or Bars";
}

 

下面两个 curl 命令会命中相同的方法:

 

curl -i http://localhost:8080/spring-rest/ex/advanced/foos
curl -i http://localhost:8080/spring-rest/ex/advanced/bars

 

6.2. 多个 HTTP 请求映射到同一个 Controller 方法

 

可以把不同的 HTTP 请求映射到同一个 Controller 方法:

 

@RequestMapping(value = "*", method = RequestMethod.GET)
@ResponseBody
public String getFallback() {return "Fallback for GET Requests";
}

 

甚至可以处理所有请求:

 

@RequestMapping(value = "*",method = { RequestMethod.GET, RequestMethod.POST ... })
@ResponseBody
public String allFallback() {return "Fallback for All Requests";
}

 

6.4. 映射模糊错误

 

对于不同的 Controller 方法,Spring 会根据 HTTP 方法、URL、参数、Header 和媒体类型计算请求映射,如果结果相同会报告模糊映射错误。下面是一个映射模糊案例:

 

@GetMapping(value = "foos/duplicate")
public String duplicate() {return "Duplicate";
}
@GetMapping(value = "foos/duplicate")
public String duplicateEx() {return "Duplicate";
}

 

抛出的异常包含以下错误信息:

 

Caused by: java.lang.IllegalStateException: Ambiguous mapping.Cannot map 'fooMappingExamplesController' methodpublic java.lang.String org.baeldung.web.controller.FooMappingExamplesController.duplicateEx()to {[/ex/foos/duplicate],methods=[GET]}:There is already 'fooMappingExamplesController' bean methodpublic java.lang.String org.baeldung.web.controller.FooMappingExamplesController.duplicate() mapped.

 

 

上面的报错信息可以看到,Spring 无法映射 org.baeldung.web.controller.FooMappingExamplesController.duplicateEx(),因为已经与 org.baeldung.web.controller.FooMappingExamplesController.duplicate() 发生了冲突。

 

下面这两个方法返回的内容类型不同,就不会发生映射模糊错误:

 

@GetMapping(value = "foos/duplicate", produces = MediaType.APPLICATION_XML_VALUE)
public String duplicate() {return "Duplicate";
}
@GetMapping(value = "foos/duplicate", produces = MediaType.APPLICATION_JSON_VALUE)
public String duplicateEx() {return "Duplicate";
}

 

要解决上面例子中的问题,最简单的方法修改其中一个 URL。

 

7. 快速映射

 

Spring Framework 4.3 加入了一些 HTTP 映射新注解:

 

  • @GetMapping

  • @PostMapping

  • @PutMapping

  • @DeleteMapping

  • @PatchMapping

 

提高了代码的可读性,代码得到精简。下同是一个数据库 CRUD 操作 RESTful API 示例:

 

@GetMapping("/{id}")
public ResponseEntity<?> getBazz(@PathVariable String id){return new ResponseEntity<>(new Bazz(id, "Bazz"+id), HttpStatus.OK);
}
@PostMapping
public ResponseEntity<?> newBazz(@RequestParam("name") String name){return new ResponseEntity<>(new Bazz("5", name), HttpStatus.OK);
}
@PutMapping("/{id}")
public ResponseEntity<?> updateBazz(@PathVariable String id,@RequestParam("name") String name) {return new ResponseEntity<>(new Bazz(id, name), HttpStatus.OK);
}
@DeleteMapping("/{id}")
public ResponseEntity<?> deleteBazz(@PathVariable String id){return new ResponseEntity<>(new Bazz(id), HttpStatus.OK);
}

 

8. Spring Configuration

 

Spring MVC 配置非常简单,FooController 定义如下:

 

package org.baeldung.spring.web.controller;
@Controller
public class FooController { ... }

 

加上 @Configuration 就能启用 MVC并把 Controller 加到 classpath 搜索路径:

 

@Configuration
@EnableWebMvc
@ComponentScan({ "org.baeldung.spring.web.controller" })
public class MvcConfig {//
}

 

9. 总结

 

本文详细讨论了 Spring @RequestMapping 注解,包括基础用例、HTTP header 映射、@PathVariable 和 @RequestParam 示例。

 

想了解 Spring MVC 中另一个核心注解 @ModelAttribute 。

 

本文的完整代码可以在 Github 上找到。

github.com/eugenp/tutorials/tree/master/spring-rest-simple

这篇关于了解 Spring RequestMapping的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1087595

相关文章

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

Spring Security--Architecture Overview

1 核心组件 这一节主要介绍一些在Spring Security中常见且核心的Java类,它们之间的依赖,构建起了整个框架。想要理解整个架构,最起码得对这些类眼熟。 1.1 SecurityContextHolder SecurityContextHolder用于存储安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

关于数据埋点,你需要了解这些基本知识

产品汪每天都在和数据打交道,你知道数据来自哪里吗? 移动app端内的用户行为数据大多来自埋点,了解一些埋点知识,能和数据分析师、技术侃大山,参与到前期的数据采集,更重要是让最终的埋点数据能为我所用,否则可怜巴巴等上几个月是常有的事。   埋点类型 根据埋点方式,可以区分为: 手动埋点半自动埋点全自动埋点 秉承“任何事物都有两面性”的道理:自动程度高的,能解决通用统计,便于统一化管理,但个性化定

Java进阶13讲__第12讲_1/2

多线程、线程池 1.  线程概念 1.1  什么是线程 1.2  线程的好处 2.   创建线程的三种方式 注意事项 2.1  继承Thread类 2.1.1 认识  2.1.2  编码实现  package cn.hdc.oop10.Thread;import org.slf4j.Logger;import org.slf4j.LoggerFactory

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听