1. 개요
이 예제에서는 Spring MVC 의 주요 어노테이션 중 하나인 @RequestMapping에 초점을 맞출 것입니다.
간단히 말해서 어노테이션은 웹 요청을 Spring Controller 메소드에 매핑하는 데 사용됩니다.
2. @ RequestMapping 기초
간단한 예부터 시작하겠습니다. 몇 가지 기본 기준을 사용하여 HTTP 요청을 메서드에 매핑합니다.
2.1. @RequestMapping — 경로별
@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. @RequestMapping — 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. RequestMapping 과 HTTP 헤더
3.1. 헤더 속성 이 있는 @RequestMapping
요청에 대한 헤더를 지정하여 매핑을 더욱 좁힐 수 있습니다.
@RequestMapping(value = "/ex/foos", headers = "key=val", method = GET)
@ResponseBody
public String getFoosWithHeader() {
return "Get some Foos with Header";
}
작업을 테스트하기 위해 curl 헤더 지원을 사용할 것입니다.
curl -i -H "key:val" http://localhost:8080/spring-rest/ex/foos
@RequestMapping 의 headers 속성을 통한 여러 헤더도 있습니다 .
@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 구문 의 경우 HTTP 사양과 동일하게 콜론으로 헤더 키와 헤더 값을 구분하지만 Spring에서는 등호가 사용됩니다.
3.2. @RequestMapping 소비 및 생성
컨트롤러 메서드로 생성된 미디어 유형 매핑 은 특별한 주의를 기울일 가치가 있습니다.
위에서 소개한 @RequestMapping 헤더 속성 을 통해 Accept 헤더를 기반으로 요청을 매핑할 수 있습니다 .
@RequestMapping(
value = "/ex/foos",
method = GET,
headers = "Accept=application/json")
@ResponseBody
public String getFoosAsJsonFromBrowser() {
return "Get some Foos with Header Old";
}
Accept 헤더 를 정의하는 이 방법에 대한 일치 는 유연합니다. equals 대신 contains를 사용하므로 다음과 같은 요청이 여전히 올바르게 매핑됩니다.
curl -H "Accept:application/json,text/html"
http://localhost:8080/spring-rest/ex/foos
Spring 3.1부터 @RequestMapping 어노테이션은 이제 특히 이 목적을 위해 생성 및 소비 속성 을 갖습니다.
@RequestMapping(
value = "/ex/foos",
method = RequestMethod.GET,
produces = "application/json"
)
@ResponseBody
public String getFoosAsJsonFromREST() {
return "Get some Foos with Header New";
}
또한 headers 속성이 있는 이전 유형의 매핑은 Spring 3.1부터 새로운 생성 메커니즘으로 자동 변환되므로 결과가 동일합니다.
이것은 같은 방식으로 curl 을 통해 소비됩니다.
curl -H "Accept:application/json"
http://localhost:8080/spring-rest/ex/foos
또한, 생성 은 여러 값도 지원합니다.
@RequestMapping(
value = "/ex/foos",
method = GET,
produces = { "application/json", "application/xml" }
)
Accept 헤더 를 지정하는 기존 방식과 새로운 방식 은 기본적으로 동일한 매핑이므로 Spring에서는 함께 사용하는 것을 허용하지 않습니다.
이 두 가지 방법을 모두 활성화하면 다음과 같은 결과가 발생합니다.
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.
새 항목에 대한 마지막 메모 는 대부분의 다른 어노테이션과 다르게 작동하는 메커니즘을 생성 하고 사용합니다 . 유형 수준에서 지정될 때 메서드 수준 어노테이션은 유형 수준 정보를 보완하지 않고 재정의 합니다.
물론 Spring을 사용하여 REST API를 빌드하는 방법을 더 자세히 알고 싶다면 Spring을 사용 하는 새로운 REST 과정을 확인하십시오 .
4. 경로 변수 를 사용한 RequestMapping
매핑 URI의 일부는 @PathVariable 어노테이션 을 통해 변수에 바인딩될 수 있습니다 .
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는 URI의 여러 부분을 여러 값 에 매핑해야 할 수 있습니다 .
@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 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
그러나 이것은 다음을 수행하지 않습니다.
http://localhost:8080/spring-rest/ex/bars/abc
5. 요청 매개변수를 사용한 RequestMapping
@RequestMapping을 사용하면 @RequestParam 어노테이션 으로 URL 매개변수를 쉽게 매핑 할 수 있습니다 .
이제 요청을 URI에 매핑합니다.
http://localhost:8080/spring-rest/ex/bars?id=100
@RequestMapping(value = "/ex/bars", method = GET)
@ResponseBody
public String getBarBySimplePathWithRequestParam(
@RequestParam("id") long id) {
return "Get a specific Bar with id=" + id;
}
그런 다음 컨트롤러 메서드 서명에서 @RequestParam("id") 어노테이션을 사용하여 id 매개 변수 의 값을 추출합니다 .
id 매개변수를 사용 하여 요청을 보내기 위해 curl 에서 매개변수 지원을 사용합니다 .
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;
}
훨씬 더 유연한 매핑이 허용됩니다. 여러 매개변수 값을 설정할 수 있으며 모든 매개변수를 사용할 필요는 없습니다.
@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 와 두 번째 매개변수 를 모두 정의하는 더 좁은 일치인 최상의 일치에 항상 매핑됩니다 .
6. RequestMapping 코너 케이스
6.1. @RequestMapping — 동일한 컨트롤러 메서드에 매핑된 여러 경로
단일 @RequestMapping 경로 값이 일반적으로 단일 컨트롤러 메서드에 사용되지만(단단하고 빠른 규칙이 아닌 좋은 방법임) 동일한 메서드에 여러 요청을 매핑해야 하는 경우가 있습니다.
이 경우 @RequestMapping 의 값 속성은 단일 매핑이 아닌 여러 매핑을 허용합니다 .
@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. @RequestMapping — 동일한 컨트롤러 메서드에 대한 여러 HTTP 요청 메서드
서로 다른 HTTP 동사를 사용하는 여러 요청을 동일한 컨트롤러 메서드에 매핑할 수 있습니다.
@RequestMapping(
value = "/ex/foos/multiple",
method = { RequestMethod.PUT, RequestMethod.POST }
)
@ResponseBody
public String putAndPostFoos() {
return "Advanced - PUT and POST within single method";
}
curl 을 사용하면 둘 다 이제 동일한 방법을 사용합니다.
curl -i -X POST http://localhost:8080/spring-rest/ex/foos/multiple
curl -i -X PUT http://localhost:8080/spring-rest/ex/foos/multiple
6.3. @RequestMapping — 모든 요청에 대한 대체
특정 HTTP 메서드를 사용하여 모든 요청에 대한 간단한 대체를 구현하려면(예: GET):
@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. 모호한 매핑 오류
모호한 매핑 오류는 Spring이 서로 다른 컨트롤러 메서드에 대해 동일한 두 개 이상의 요청 매핑을 평가할 때 발생합니다. 요청 매핑은 HTTP 메서드, URL, 매개변수, 헤더 및 미디어 유형이 동일한 경우 동일합니다.
예를 들어 다음은 모호한 매핑입니다.
@GetMapping(value = "foos/duplicate" )
public String duplicate() {
return "Duplicate";
}
@GetMapping(value = "foos/duplicate" )
public String duplicateEx() {
return "Duplicate";
}
throw된 예외에는 일반적으로 다음 행에 오류 메시지가 있습니다.
Caused by: java.lang.IllegalStateException: Ambiguous mapping.
Cannot map 'fooMappingExamplesController' method
public java.lang.String org.baeldung.web.controller.FooMappingExamplesController.duplicateEx()
to {[/ex/foos/duplicate],methods=[GET]}:
There is already 'fooMappingExamplesController' bean method
public java.lang.String org.baeldung.web.controller.FooMappingExamplesController.duplicate() mapped.
오류 메시지를 주의 깊게 읽으면 이미 매핑 된 org.baeldung.web.controller 와 충돌하는 매핑이 있기 때문에 Spring이 org.baeldung.web.controller.FooMappingExamplesController.duplicateEx() 메서드를 매핑할 수 없다는 사실을 나타냅니다. .FooMappingExamplesController.duplicate().
아래 코드 조각은 두 메서드가 서로 다른 콘텐츠 유형을 반환하므로 모호한 매핑 오류가 발생하지 않습니다 .
@GetMapping(value = "foos/duplicate", produces = MediaType.APPLICATION_XML_VALUE)
public String duplicateXml() {
return "<message>Duplicate</message>";
}
@GetMapping(value = "foos/duplicate", produces = MediaType.APPLICATION_JSON_VALUE)
public String duplicateJson() {
return "{\"message\":\"Duplicate\"}";
}
이러한 차별화를 통해 컨트롤러 는 요청에 제공된 Accept 헤더 를 기반으로 올바른 데이터 표현을 반환할 수 있습니다 .
이 문제를 해결하는 또 다른 방법은 관련된 두 가지 방법 중 하나에 할당된 URL을 업데이트하는 것입니다.
7. 새로운 요청 매핑 단축키
Spring Framework 4.3 은 @RequestMapping 을 기반으로 하는 몇 가지 새로운 HTTP 매핑 어노테이션을 도입했습니다 .
- @GetMapping
- @포스트매핑
- @PutMapping
- @DeleteMapping
- @패치매핑
이러한 새로운 어노테이션은 가독성을 향상시키고 코드의 장황함을 줄일 수 있습니다.
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. 스프링 구성
FooController 가 다음 패키지에 정의되어 있다는 점을 고려하면 Spring MVC 구성은 충분히 간단 합니다.
package org.baeldung.spring.web.controller;
@Controller
public class FooController { ... }
전체 MVC 지원을 활성화하고 컨트롤러에 대한 클래스 경로 스캔을 구성하려면 @Configuration 클래스가 필요합니다 .
@Configuration
@EnableWebMvc
@ComponentScan({ "org.baeldung.spring.web.controller" })
public class MvcConfig {
//
}
9. 결론
이 기사 는 Spring 의 @RequestMapping 어노테이션에 초점을 맞추고 , 간단한 사용 사례, HTTP 헤더 매핑, @PathVariable 을 사용하여 URI의 일부를 바인딩하고, URI 매개변수 및 @RequestParam 어노테이션으로 작업합니다.
Spring MVC에서 다른 핵심 어노테이션을 사용하는 방법을 배우고 싶다면 여기에서 @ModelAttribute 어노테이션을 탐색 할 수 있습니다 .
기사의 전체 코드는 GitHub에서 사용할 수 있습니다 .