Controller에서 사용되는 @RequestMapping에 대해서 알아보겠습니다.

@RequestMapping

RequestHandlerMappingHandler에서 컨트롤러를 선택할 때 사용되는 어노테이션입니다. 메서드 단위까지 세분화하여 적용할 수 있습니다. Get, Post, Put 등 HTTP 메서드와 관계없이 매핑됩니다. 

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {

   String name() default "";

   @AliasFor("path")
   String[] value() default {};

   @AliasFor("value")
   String[] path() default {};

   RequestMethod[] method() default {};

   String[] params() default {};

   String[] headers() default {};

   String[] consumes() default {};

   String[] produces() default {};
}

@RequestMapping name 속성

@RequestMapping을 구분하기 위한 이름으로 사용됩니다. Spring JSP에서 URL로 넘길 수 있습니다.

@RestController
@RequestMapping(value = "/hi",name = "parent")
public class ParentController {

    @GetMapping
    public String one() {
        return "parent";
    }
}
  • @RequestMapping name = parent 를 부여해줬습니다.
<%@ taglib uri="http://www.springframework.org/tags" prefix="s" %>

<a href="${s:mvcUrl('ParentController#parent').build()}">Get Parent</a>
  • mvcUrl을 통해서 URL을 빌드할 수 있습니다.

@RequestMapping path, value 속성

value는 path의 별칭입니다. 따라서 같은 역할을 수행합니다. 

@RequestMapping(path = "/hi")
public String hi(){
    return "ok";
}

@RequestMapping(value = "/hi")
public String hi2(){
    return "ok";
}

@RequestMapping("/hi")
public String hi3(){
    return "ok";
}

// 3개 모두 같은 경로를 가집니다.
  • 따라서 위의 코드는 한 경로에 두 개가 Mapping되므로 오류가 발생합니다.
  • value값이 디폴트로 설정되었기에 value = 생략하고 작성이 가능합니다.

URL을 배열로 넘길 수 있습니다. 

@RequestMapping({"/hi","/bye"})
public String hi3(){
    return "ok";
}
  • hi3()는 /hi 와 /bye url에 모두 동작합니다.

@RequestMapping method 속성

method는 HTTP 메서드를 의미합니다. (GET, POST, PUT, PATCH, DELETE) 이것을 통해서 같은 경로라 하여도 HTTP 메서드의 차이로 Mapping이 달라집니다.

@RequestMapping(value = "/hi",method = RequestMethod.GET)
public String get(){
    return "get";
}

@GetMapping("/hi")
public String getPlus() {
    return "getPlus";
}

@RequestMapping(value = "/hi", method = RequestMethod.POST)
public String post(){
    return "post";
}

@PostMapping("/hi")
public String postPlus(){
    return "postPlus";
}
  • /hi라는 같은 URL이 들어와도 method의 차이로 다르게 매핑되는 것을 확인하실 수 있습니다.
  • method를 일일히 지정하는 것보다 @GetMapping = @RequestMapping(method = RequestMethod.GET)은 같은 것을 의미하므로 보통 @GetMapping을 바로 사용합니다.
@RestController
@RequestMapping("/good")
public class ParentController {

    @RequestMapping(value = "/hi",method = RequestMethod.GET)
    public String get(){
        return "get";
    }

    @GetMapping("/hi")
    public String getPlus() {
        return "getPlus";
    }

    @RequestMapping(value = "/hi", method = RequestMethod.POST)
    public String post(){
        return "post";
    }

    @PostMapping("/hi")
    public String postPlus(){
        return "postPlus";
    }
}
  • 하지만 메소드 단위가 아닌 클래스 단위에 붙이는 것은 @RequestMapping을 사용하여 prefix를 지정합니다. 

@RequestMapping param 속성

URL이 같을지라도 쿼리 파라미터의 유형으로 매핑을 다르게 할 수 있습니다.

@GetMapping(value = "/param", params = "myValue=my")
public String param1() {
    return "param1";
}

@GetMapping(value = "/param", params = "myValue=you")
public String param2(){
    return "param2";
}
  • URL = /param?myValue=my 일 때 param1이 실행되고, /param? myValue=you일 때 param2가 실행됩니다.
  • 긍정 표현뿐만 아니라 부정도할 수 있습니다. params = "myValue!=you" 라면 you가 아닌 경우에 매핑됩니다.

@RequestMapping headers 속성

Header를 지정하여, 매핑을 더욱 좁힐 수 있습니다. 단 header는 지정한 것만 있어야 합니다.(equal)

GetMapping(value = "/header", headers = "text/html")
public String header1() {
    return "header1";
}

@GetMapping(value = "/header", headers = "application/json")
public String header2() {
    return "header2";
}
  • header가 text/html일 경우 header1 호출되며, application/json일 경우 header2가 호출됩니다.

Accept 속성을 이용해서 equal이 아닌 contain으로 변경할 수 있습니다. 

@GetMapping(value = "/header", headers = "Accept=application/json")
public String header2() {
    return "header2";
}
  • Accept가 없었다면 application/json만 있을 경우 매핑됐지만, Accept가 있다면 application/json을 header로 가지고 있을 경우 매핑이 됩니다.

@ReqeustMapping consume 속성

consumes 속성은 Client가 요청을 보낼 때 특정한 데이터 타입만 처리할 수 있게 해주는 속성입니다. 

@GetMapping(value = "/consume", consumes = MediaType.APPLICATION_JSON_VALUE) // "application/json" 의미
public String consume1() {
    return "consume2";
}

@GetMapping(value = "/consume", consumes = MediaType.TEXT_HTML_VALUE) // "text/html" 의미
public String consume2() {
    return "consume2";
}
  • 요청이 들어오는 데이터 타입이 application/json이라면 consume1이 실행되며, text/html이라면 consume2가 실행됩니다.
  • 같은 URL이라도 요청하는 데이터 타입에 따라 다르게 매핑되는 것을 볼 수 있습니다.

@RequestMapping produce 속성

consume과 반대로 응답하는 데이터 타입을 지정하는 것입니다. 

client가 요청을 보낼 때 accept header에 있을 경우 매핑됩니다. 

@GetMapping(value = "/produce", produces = MediaType.APPLICATION_JSON_VALUE) // "application/json" 의미
public String produce1() {
    return "produce2";
}

@GetMapping(value = "/produce", produces = MediaType.TEXT_HTML_VALUE) // "text/html" 의미
public String produce2() {
    return "produce2";
}
  • accept header가 /* 이라면 오류를 일으키고, application/json이나 text/html이라고 지정됐을 경우 매핑이 각각 됩니다.
  • produce를 통해서 매핑을 더 좁게 지정이 가능합니다.

지금까지 Controller 계층에서 사용되는 @RequestMapping의 속성들에 대해서 알아봤습니다. 감사합니다.