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에서 사용할 수 있습니다 .

Generic footer banner