Loading...
Spring Framework Reference Documentation 7.0.2의 Mapping Requests의 한국어 번역본입니다.
아래의 경우에 피드백에서 신고해주신다면 반영하겠습니다.
감사합니다 :)
See equivalent in the Servlet stack
This section discusses request mapping for annotated controllers.
@RequestMappingSee equivalent in the Servlet stack
@RequestMapping 어노테이션은 요청을 controller 메서드에 매핑하는 데 사용됩니다. 이 어노테이션은
URL, HTTP 메서드, 요청 파라미터, 헤더, 미디어 타입으로 매칭하기 위한 다양한 속성을
가집니다. 클래스 레벨에서 사용하여 공유되는 매핑을 표현할 수도 있고, 메서드 레벨에서
사용하여 특정 엔드포인트 매핑으로 범위를 좁힐 수도 있습니다.
또한 @RequestMapping의 HTTP 메서드별 shortcut variant들도 있습니다:
@GetMapping@PostMapping@PutMapping@DeleteMapping@PatchMapping앞의 어노테이션들은 Custom Annotations이며,
대부분의 controller 메서드는 기본적으로 모든 HTTP 메서드와 매칭되는 @RequestMapping을
사용하기보다는 특정 HTTP 메서드에 매핑되어야 한다는 점에서 제공됩니다. 동시에,
클래스 레벨에서는 여전히 공유 매핑을 표현하기 위해 @RequestMapping이 필요합니다.
@RequestMapping은 동일한 요소(class, interface, method)에 선언된 다른@RequestMapping어노테이션과 함께 사용할 수 없습니다. 동일한 요소에서 여러 개의@RequestMapping어노테이션이 감지되면 경고가 로그에 기록되고, 첫 번째 매핑만 사용됩니다. 이는@GetMapping,@PostMapping등과 같은 composed@RequestMapping어노테이션에도 적용됩니다.
다음 예제는 타입 및 메서드 레벨 매핑을 사용합니다:
1@RestController 2@RequestMapping("/persons") 3class PersonController { 4 5 @GetMapping("/{id}") 6 public Person getPerson(@PathVariable Long id) { 7 // ... 8 } 9 10 @PostMapping 11 @ResponseStatus(HttpStatus.CREATED) 12 public void add(@RequestBody Person person) { 13 // ... 14 } 15}
1@RestController 2@RequestMapping("/persons") 3class PersonController { 4 5 @GetMapping("/{id}") 6 fun getPerson(@PathVariable id: Long): Person { 7 // ... 8 } 9 10 @PostMapping 11 @ResponseStatus(HttpStatus.CREATED) 12 fun add(@RequestBody person: Person) { 13 // ... 14 } 15}
See equivalent in the Servlet stack
glob 패턴과 와일드카드를 사용하여 요청을 매핑할 수 있습니다:
| Pattern | Description | Example |
|---|---|---|
spring | 리터럴 패턴 | "/spring"은 "/spring"과 매칭됩니다 |
? | 한 문자를 매칭합니다 | "/pages/t?st.html"은 "/pages/test.html" 및 "/pages/t3st.html"과 매칭됩니다 |
* | 경로 세그먼트 내에서 0개 이상의 문자를 매칭합니다 | "/resources/*.png"는 "/resources/file.png"와 매칭됩니다.<br>"/projects/*/versions"는 "/projects/spring/versions"와 매칭되지만 "/projects/spring/boot/versions"와는 매칭되지 않습니다.<br>"/projects/*"는 "/projects/spring"과 매칭되지만 경로 세그먼트가 존재하지 않으므로 "/projects"와는 매칭되지 않습니다. |
** | 0개 이상의 경로 세그먼트를 매칭합니다 | "/resources/**"는 "/resources", "/resources/file.png", "/resources/images/file.png"와 매칭됩니다.<br>"/**/info"는 "/info", "/spring/info", "/spring/framework/info"와 매칭됩니다.<br>"/resources/**/file.png"는 경로 중간에 **가 허용되지 않으므로 유효하지 않습니다.<br>"/**/spring/**"는 패턴당 단일 **/{*path} 인스턴스만 허용되므로 허용되지 않습니다. |
{name} | *와 유사하지만 경로 세그먼트를 "name"이라는 이름의 변수로 캡처합니다 | "/projects/{project}/versions"는 "/projects/spring/versions"와 매칭되고 project=spring을 캡처합니다.<br>"/projects/{project}/versions"는 하나의 경로 세그먼트만 캡처하므로 "/projects/spring/framework/versions"와는 매칭되지 않습니다. |
{name:[a-z]+} | "name"이라는 이름의 경로 변수로 정규식 "[a-z]+"와 매칭합니다 | "/projects/{project:[a-z]+}/versions"는 "/projects/spring/versions"와 매칭되지만 "/projects/spring1/versions"와는 매칭되지 않습니다 |
{*path} | **와 유사하지만 "path"라는 이름의 변수로 경로 세그먼트들을 캡처합니다 | "/resources/{*file}"는 "/resources/images/file.png"와 매칭되고 file=/images/file.png를 캡처합니다.<br>"{*path}/resources"는 "/spring/framework/resources"와 매칭되고 path=/spring/framework를 캡처합니다.<br>"/resources/{*path}/file.png"는 경로 중간에 {*path}가 허용되지 않으므로 유효하지 않습니다.<br>"/{*path}/spring/**"는 패턴당 단일 **/{*path} 인스턴스만 허용되므로 허용되지 않습니다. |
캡처된 URI 변수는 다음 예제와 같이 @PathVariable로 접근할 수 있습니다:
1@GetMapping("/owners/{ownerId}/pets/{petId}") 2public Pet findPet(@PathVariable Long ownerId, @PathVariable Long petId) { 3 // ... 4}
1@GetMapping("/owners/{ownerId}/pets/{petId}") 2fun findPet(@PathVariable ownerId: Long, @PathVariable petId: Long): Pet { 3 // ... 4}
다음 예제와 같이 클래스와 메서드 레벨에서 URI 변수를 선언할 수 있습니다:
1@Controller 2@RequestMapping("/owners/{ownerId}") // (1) 3public class OwnerController { 4 5 @GetMapping("/pets/{petId}") // (2) 6 public Pet findPet(@PathVariable Long ownerId, @PathVariable Long petId) { 7 // ... 8 } 9}
| 1 | 클래스 레벨 URI 매핑. |
| 2 | 메서드 레벨 URI 매핑. |
1@Controller 2@RequestMapping("/owners/{ownerId}") // (1) 3class OwnerController { 4 5 @GetMapping("/pets/{petId}") // (2) 6 fun findPet(@PathVariable ownerId: Long, @PathVariable petId: Long): Pet { 7 // ... 8 } 9}
| 1 | 클래스 레벨 URI 매핑. |
| 2 | 메서드 레벨 URI 매핑. |
URI 변수는 자동으로 적절한 타입으로 변환되거나 TypeMismatchException이 발생합니다.
기본적으로 단순 타입(int, long, Date 등)이 지원되며, 다른 데이터 타입에 대한
지원도 등록할 수 있습니다.
Type Conversion 및 DataBinder를 참조하십시오.
URI 변수는 명시적으로 이름을 줄 수 있습니다(예: @PathVariable("customId")).
그러나 이름이 동일하고 코드를 -parameters 컴파일러 플래그와 함께 컴파일하는 경우
그 세부 사항을 생략할 수 있습니다.
{*varName} 구문은 0개 이상의 남은 경로 세그먼트와 매칭되는 URI 변수를 선언합니다.
예를 들어 /resources/{*path}는 /resources/ 아래의 모든 파일과 매칭되며,
"path" 변수는 /resources 아래의 전체 경로를 캡처합니다.
{varName:regex} 구문은 {varName:regex} 구문을 갖는 정규 표현식이 있는
URI 변수를 선언합니다. 예를 들어 /spring-web-3.0.5.jar URL이 주어졌을 때,
다음 메서드는 name, version, 파일 확장자를 추출합니다:
1@GetMapping("/{name:[a-z-]+}-{version:\d\.\d\.\d}{ext:\.[a-z]+}") 2public void handle(@PathVariable String version, @PathVariable String ext) { 3 // ... 4}
1@GetMapping("/{name:[a-z-]+}-{version:\d\.\d\.\d}{ext:\.[a-z]+}") 2fun handle(@PathVariable version: String, @PathVariable ext: String) { 3 // ... 4}
URI 경로 패턴은 다음도 포함할 수 있습니다:
PropertySourcesPlaceholderConfigurer를 통해 로컬, 시스템, 환경
및 기타 프로퍼티 소스에 대해 resolve되는 ${…} 플레이스홀더를 포함할 수 있습니다.
이는 예를 들어 외부 설정을 기반으로 base URL을 매개변수화하는 데 유용합니다.#{…}.Spring WebFlux는 URI 경로 매칭 지원을 위해
PathPattern과PathPatternParser를 사용합니다. 두 클래스는spring-web에 위치하며, 런타임에 많은 수의 URI 경로 패턴이 매칭되는 웹 애플리케이션에서 HTTP URL 경로와 함께 사용하도록 명시적으로 설계되었습니다.
Spring WebFlux는 suffix 패턴 매칭을 지원하지 않습니다. 이는 /person과 같은
매핑이 /person.*과도 매칭되는 Spring MVC와는 다릅니다. URL 기반 콘텐츠
협상이 필요한 경우, 쿼리 파라미터를 사용하는 것을 권장합니다. 이는 더 단순하고,
더 명시적이며, URL 경로 기반 exploit에 덜 취약합니다.
See equivalent in the Servlet stack
여러 패턴이 하나의 URL과 매칭되는 경우, 최상의 매칭을 찾기 위해 비교해야 합니다.
이는 더 구체적인 패턴을 찾는 PathPattern.SPECIFICITY_COMPARATOR로 수행됩니다.
각 패턴에 대해 URI 변수와 와일드카드의 개수를 기반으로 점수가 계산되며, URI 변수는 와일드카드보다 낮은 점수를 가집니다. 총 점수가 낮은 패턴이 선택됩니다. 두 패턴이 동일한 점수를 가지면 더 긴 것이 선택됩니다.
catch-all 패턴(예: **, {*varName})은 점수 계산에서 제외되며 항상 마지막에
정렬됩니다. 두 패턴이 모두 catch-all인 경우 더 긴 것이 선택됩니다.
See equivalent in the Servlet stack
다음 예제와 같이 요청의 Content-Type에 따라 요청 매핑 범위를 좁힐 수 있습니다:
1@PostMapping(path = "/pets", consumes = "application/json") 2public void addPet(@RequestBody Pet pet) { 3 // ... 4}
1@PostMapping("/pets", consumes = ["application/json"]) 2fun addPet(@RequestBody pet: Pet) { 3 // ... 4}
consumes 속성은 부정 표현도 지원합니다. 예를 들어 !text/plain은
text/plain 이외의 모든 콘텐츠 타입을 의미합니다.
클래스 레벨에서 공유 consumes 속성을 선언할 수 있습니다. 그러나 대부분의 다른
요청 매핑 속성과 달리, 클래스 레벨에서 사용되는 경우 메서드 레벨의
consumes 속성은 클래스 레벨 선언을 확장하는 것이 아니라 오버라이드합니다.
MediaType은APPLICATION_JSON_VALUE,APPLICATION_XML_VALUE와 같이 일반적으로 사용되는 미디어 타입에 대한 상수를 제공합니다.
See equivalent in the Servlet stack
다음 예제와 같이 Accept 요청 헤더 및 controller 메서드가 생성하는
콘텐츠 타입 목록에 따라 요청 매핑 범위를 좁힐 수 있습니다:
1@GetMapping(path = "/pets/{petId}", produces = "application/json") 2@ResponseBody 3public Pet getPet(@PathVariable String petId) { 4 // ... 5}
1@GetMapping("/pets/{petId}", produces = ["application/json"]) 2@ResponseBody 3fun getPet(@PathVariable petId: String): Pet { 4 // ... 5}
미디어 타입은 문자 집합을 지정할 수 있습니다. 부정 표현도 지원합니다. 예를 들어
!text/plain은 text/plain 이외의 모든 콘텐츠 타입을 의미합니다.
클래스 레벨에서 공유 produces 속성을 선언할 수 있습니다. 그러나 대부분의 다른
요청 매핑 속성과 달리, 클래스 레벨에서 사용되는 경우 메서드 레벨의
produces 속성은 클래스 레벨 선언을 확장하는 것이 아니라 오버라이드합니다.
MediaType은APPLICATION_JSON_VALUE,APPLICATION_XML_VALUE와 같이 일반적으로 사용되는 미디어 타입에 대한 상수를 제공합니다.
See equivalent in the Servlet stack
쿼리 파라미터 조건에 따라 요청 매핑 범위를 좁힐 수 있습니다. 쿼리 파라미터의
존재(myParam), 부재(!myParam), 또는 특정 값(myParam=myValue)을 검사할 수 있습니다.
다음 예제는 값이 있는 파라미터를 검사합니다:
1@GetMapping(path = "/pets/{petId}", params = "myParam=myValue") // (1) 2public void findPet(@PathVariable String petId) { 3 // ... 4}
| 1 | myParam이 myValue와 같은지 확인합니다. |
1@GetMapping("/pets/{petId}", params = ["myParam=myValue"]) // (1) 2fun findPet(@PathVariable petId: String) { 3 // ... 4}
| 1 | myParam이 myValue와 같은지 확인합니다. |
다음 예제와 같이 요청 헤더 조건에서도 동일하게 사용할 수 있습니다:
1@GetMapping(path = "/pets/{petId}", headers = "myHeader=myValue") // (1) 2public void findPet(@PathVariable String petId) { 3 // ... 4}
| 1 | myHeader가 myValue와 같은지 확인합니다. |
1@GetMapping("/pets/{petId}", headers = ["myHeader=myValue"]) // (1) 2fun findPet(@PathVariable petId: String) { 3 // ... 4}
| 1 | myHeader가 myValue와 같은지 확인합니다. |
See equivalent in the Servlet stack
API 버전을 지정하는 표준 방법은 없으므로 WebFlux Config에서 API 버전 관리를 활성화할 때 버전을 resolve하는 방법을 지정해야 합니다.
WebFlux Config는 요청을 매핑하는 데 사용되는 ApiVersionStrategy를 생성합니다.
API 버전 관리가 활성화되면 버전과 함께 요청을 매핑할 수 있습니다.
@RequestMapping version 속성은 다음을 지원합니다:
여러 controller 메서드가 요청 버전보다 작거나 같은 버전을 가진 경우, 그 중에서 가장 높고 요청 버전에 가장 가까운 것이 고려되며, 실질적으로 나머지를 대체합니다.
이를 설명하기 위해 다음 매핑을 고려해 보겠습니다:
1@RestController 2@RequestMapping("/account/{id}") 3public class AccountController { 4 5 @GetMapping // (1) 6 public Account getAccount() { 7 } 8 9 @GetMapping(version = "1.1") // (2) 10 public Account getAccount1_1() { 11 } 12 13 @GetMapping(version = "1.2+") // (3) 14 public Account getAccount1_2() { 15 } 16 17 @GetMapping(version = "1.5") // (4) 18 public Account getAccount1_5() { 19 } 20}
| 1 | 모든 버전과 매칭 |
| 2 | 버전 1.1과 매칭 |
| 3 | 버전 1.2 및 그 이상과 매칭 |
| 4 | 버전 1.5와 매칭 |
버전 "1.3"을 가진 요청의 경우:
버전 "1.5"를 가진 요청의 경우:
버전 "1.6"을 가진 요청은 매칭이 없습니다. (1)과 (3)은 매칭되지만,
strict 매칭만 허용하고 따라서 매칭되지 않는 (4)에 의해 대체됩니다.
이 시나리오에서는 NotAcceptableApiVersionException이 발생하여 400 응답이 반환됩니다.
위 내용은 요청 버전이 "supported" 버전이라고 가정합니다. 그렇지 않으면 실패합니다.
기반 인프라 및 API 버전 관리 지원에 대한 자세한 내용은 API Versioning을 참조하십시오.
See equivalent in the Servlet stack
@GetMapping 및 @RequestMapping(method=HttpMethod.GET)은 요청 매핑 목적을 위해
HTTP HEAD를 투명하게 지원합니다. controller 메서드는 변경할 필요가 없습니다.
HttpHandler 서버 어댑터에 적용된 응답 래퍼는 실제로 응답에
쓰기 작업을 수행하지 않고도 Content-Length 헤더가 기록된 바이트 수로 설정되도록
보장합니다.
기본적으로 HTTP OPTIONS는 URL 패턴과 매칭되는 모든 @RequestMapping 메서드에
나열된 HTTP 메서드 목록으로 Allow 응답 헤더를 설정하여 처리됩니다.
HTTP 메서드 선언이 없는 @RequestMapping의 경우, Allow 헤더는
GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS로 설정됩니다. controller 메서드는 항상
지원되는 HTTP 메서드를 선언해야 합니다(예: HTTP 메서드별 variant인
@GetMapping, @PostMapping 등을 사용).
HTTP HEAD 및 HTTP OPTIONS에 @RequestMapping 메서드를 명시적으로 매핑할 수 있지만,
일반적인 경우에는 필요하지 않습니다.
See equivalent in the Servlet stack
Spring WebFlux는 요청 매핑을 위해
composed annotations의 사용을 지원합니다.
이는 @RequestMapping으로 메타 어노테이션되어 있고, 더 좁고 구체적인 목적을 위해
@RequestMapping 속성의 일부(또는 전체)를 다시 선언하도록 구성된 어노테이션입니다.
@GetMapping, @PostMapping, @PutMapping, @DeleteMapping, @PatchMapping은
composed 어노테이션의 예입니다. 이들은, 대부분의 controller 메서드는 기본적으로
모든 HTTP 메서드와 매칭되는 @RequestMapping을 사용하는 것보다 특정 HTTP 메서드에
매핑되어야 한다는 점에서 제공됩니다. composed 어노테이션을 구현하는 예가
필요하다면, 이러한 어노테이션이 어떻게 선언되어 있는지 살펴보십시오.
@RequestMapping은 동일한 요소(class, interface, method)에 선언된 다른@RequestMapping어노테이션과 함께 사용할 수 없습니다. 동일한 요소에서 여러 개의@RequestMapping어노테이션이 감지되면 경고가 로그에 기록되고, 첫 번째 매핑만 사용됩니다. 이는@GetMapping,@PostMapping등과 같은 composed@RequestMapping어노테이션에도 적용됩니다.
Spring WebFlux는 또한 custom 요청 매칭 로직이 있는 custom 요청 매핑
속성을 지원합니다. 이는 RequestMappingHandlerMapping을 서브클래싱하고
getCustomMethodCondition 메서드를 오버라이드해야 하는 좀 더 고급 옵션입니다.
여기서 custom 속성을 검사하고 자체 RequestCondition을 반환할 수 있습니다.
See equivalent in the Servlet stack
핸들러 메서드를 프로그래밍 방식으로 등록할 수 있으며, 이는 동적 등록이나 서로 다른 URL 아래에서 동일한 핸들러의 서로 다른 인스턴스와 같은 고급 사용 사례에 사용될 수 있습니다.
다음 예제는 그 방법을 보여줍니다:
1@Configuration 2public class MyConfig { 3 4 @Autowired 5 public void setHandlerMapping(RequestMappingHandlerMapping mapping, UserHandler handler) // (1) 6 throws NoSuchMethodException { 7 8 RequestMappingInfo info = RequestMappingInfo 9 .paths("/user/{id}").methods(RequestMethod.GET).build(); // (2) 10 11 Method method = UserHandler.class.getMethod("getUser", Long.class); // (3) 12 13 mapping.registerMapping(info, handler, method); // (4) 14 } 15 16}
| 1 | target 핸들러와 controller용 핸들러 매핑을 주입합니다. |
| 2 | 요청 매핑 메타데이터를 준비합니다. |
| 3 | 핸들러 메서드를 가져옵니다. |
| 4 | 등록을 추가합니다. |
1@Configuration 2class MyConfig { 3 4 @Autowired 5 fun setHandlerMapping(mapping: RequestMappingHandlerMapping, handler: UserHandler) { // (1) 6 7 val info = RequestMappingInfo.paths("/user/{id}").methods(RequestMethod.GET).build() // (2) 8 9 val method = UserHandler::class.java.getMethod("getUser", Long::class.java) // (3) 10 11 mapping.registerMapping(info, handler, method) // (4) 12 } 13}
| 1 | target 핸들러와 controller용 핸들러 매핑을 주입합니다. |
| 2 | 요청 매핑 메타데이터를 준비합니다. |
| 3 | 핸들러 메서드를 가져옵니다. |
| 4 | 등록을 추가합니다. |
@HttpExchangeSee equivalent in the Servlet stack
@HttpExchange의 주요 목적은
client with a generated proxy를 사용하는 HTTP 서비스이지만,
이러한 어노테이션이 배치되는 HTTP 서비스 인터페이스는 client와 server 사용에 대해
중립적인 계약입니다.
client 코드를 단순화하는 것 외에도, 서버가
client access를 위해 자신의 API를 노출하는 편리한 방법으로 HTTP 서비스 인터페이스가
사용될 수 있는 경우도 있습니다. 이는 client와 server 간의 결합을 증가시키며,
특히 public API의 경우 종종 좋은 선택이 아니지만, internal API의 경우에는
바로 그 목표일 수 있습니다. 이는 Spring Cloud에서 일반적으로 사용되는 접근 방식이며,
controller 클래스에서 서버 사이드 처리를 위해 @RequestMapping의 대안으로
@HttpExchange가 지원되는 이유입니다.
예를 들면 다음과 같습니다:
1@HttpExchange("/persons") 2interface PersonService { 3 4 @GetExchange("/{id}") 5 Person getPerson(@PathVariable Long id); 6 7 @PostExchange 8 void add(@RequestBody Person person); 9} 10 11@RestController 12class PersonController implements PersonService { 13 14 public Person getPerson(@PathVariable Long id) { 15 // ... 16 } 17 18 @ResponseStatus(HttpStatus.CREATED) 19 public void add(@RequestBody Person person) { 20 // ... 21 } 22}
1@HttpExchange("/persons") 2interface PersonService { 3 4 @GetExchange("/{id}") 5 fun getPerson(@PathVariable id: Long): Person 6 7 @PostExchange 8 fun add(@RequestBody person: Person) 9} 10 11@RestController 12class PersonController : PersonService { 13 14 override fun getPerson(@PathVariable id: Long): Person { 15 // ... 16 } 17 18 @ResponseStatus(HttpStatus.CREATED) 19 override fun add(@RequestBody person: Person) { 20 // ... 21 } 22}
@HttpExchange와 @RequestMapping에는 차이가 있습니다.
@RequestMapping은 경로 패턴, HTTP 메서드 등으로 여러 요청에 매핑될 수 있는 반면,
@HttpExchange는 구체적인 HTTP 메서드, 경로, 콘텐츠 타입을 가진 단일 엔드포인트를
선언합니다.
메서드 파라미터 및 반환 값의 경우, 일반적으로 @HttpExchange는
@RequestMapping이 지원하는 메서드 파라미터의 부분집합을 지원합니다. 특히,
서버 사이드 전용 파라미터 타입은 제외합니다.
자세한 내용은 @HttpExchange 및 @RequestMapping에 대한 목록을 참조하십시오.
@Controller
Handler Methods