도도한 개발자

[@MVC 미션] @Controller(value) vs @RequestMapping(value) 본문

우아한테크코스

[@MVC 미션] @Controller(value) vs @RequestMapping(value)

Kiara Kim 2023. 9. 14. 17:59

본 게시물은 우아한테크코스 미션을 하면서 작성한 글입니다.

 

🐈‍⬛ @RequestMapping을 사용하면서...

MVC 미션 코드리뷰 하면서 헷갈리는 개념을 발견했습니다. 

HandlerKey를 만들 때 생성자에 RequestMapping 어노테이션의 value와 http method를 인자로 넘겨줘야 하는데 이때 value는 요청이 처리되는 url 경로입니다.

public static List<HandlerKey> keysByAnnotation(RequestMapping annotation) {
    List<HandlerKey> handlerKeys = new ArrayList<>();
    String value = annotation.value(); // 여기
    RequestMethod[] requestMethods = annotation.method();

    for (RequestMethod requestMethod : requestMethods) {
        handlerKeys.add(new HandlerKey(value, requestMethod));
    }
    return handlerKeys;
}

“여기”를 보시면 annotation의 value를 가져옵니다. 어떤 값이 들어있을까요?

 

@Controller
public class MyController {

    @RequestMapping(value = "/request-url", method = RequestMethod.GET)
    public String sayHello() {
        return "hello";
    }
}

임시로 만든 컨트롤러 클래스입니다. 여기서 value와 method는 @RequestMapping 옆에 있는 속성 값인 것을 확인할 수 있습니다.

그러면 value가 “/request-url”이 되겠죠.

 

🐾 만약 컨트롤러 클래스가 다음과 같이 생겼으면 어떨까요?

@Controller("test")
@RequestMapping("/test")
public class MyController {

    @RequestMapping(value = "/request-url", method = RequestMethod.GET)
    public String sayHello() {
        return "hello";
    }
}

@Controller 어노테이션에 value의 값으로 "test"를 지정했고 (@Controller 어노테이션엔 value 속성밖에 없습니다.)

바로 밑에 @RequestMapping 어노테이션의 value 값으로 “/test”를 지정했습니다.(속성이 하나면 value가 디폴트 속성이 됩니다.)

 

 

🐾이때 매핑 url을 /test/request-url로 지정하고 싶으면 어떻게 해야 할까요?

@Controller의 속성이 사용될까요 아님 @RequestMapping의 속성이 사용될까요?

이를 알기 위해선 이 둘의 value 속성이 어떤 역할을 하는지 알아야 할 필요가 있어보입니다.

스프링 프레임워크에서 @Controller의 value와 @RequestMapping의 value는 서로 다른 목적을 가지고 있습니다.

 

🐾@Controller의 value

@Controller은 클래스 레벨에서 사용되며, 해당 클래스가 컨트롤러 클래스임을 나타냅니다. 이 어노테이션은 일반적으로 패키지 스캔 및 컴포넌트 스캔을 통해 스프링 애플리케이션 컨텍스트에 빈으로 등록되어 관리됩니다. @Controller의 value 속성은 해당 컨트롤러 빈의 이름을 지정할 때 사용됩니다.

 

예를 들어, 위의 컨트롤러 클래스에서 "test" MyController 클래스의 빈 이름으로 사용됩니다. 이것은 주로 빈의 이름을 명시적으로 설정하고 싶을 때 사용됩니다. 만약 value 속성을 지정하지 않으면 스프링은 기본적으로 클래스 이름의 첫 글자를 소문자로 바꾼 이름을 사용합니다.

 

🐾 @RequestMapping의 value:

@RequestMapping은 메서드 레벨에서 사용되며, 해당 메서드가 요청을 처리하는 URL 경로를 지정합니다. @Controller 클래스 내부의 메서드에 적용되며, 해당 메서드가 어떤 URL 경로에 대한 요청을 처리할지를 정의합니다. @RequestMapping의 value 속성은 요청을 어떤 경로에 매핑할 것인지를 지정하며, 클라이언트가 해당 경로로 요청을 보낼 때 이 메서드가 호출됩니다.

 

예를 들어, 위의 코드에서 @RequestMapping("/test")는 /test 경로에 대한 요청을 처리하고, @RequestMapping("/request-url")은 /request-url 경로에 대한 요청을 처리합니다.

 

그래서 이 둘의 경로를 더한 /test/request-url을 경로로 요청하고 싶다면 다음과 같이 클래스를 찾아내 그 클래스 단의 @RequestMapping의 value값을 추출하고, 메소드 단의 @ReqeustMapping의 value값을 추출해 합치면 됩니다.

private void initHandlerExecutions() {
        Reflections reflections = new Reflections(basePackage);
        Set<Class<?>> typesAnnotatedWith = reflections.getTypesAnnotatedWith(Controller.class);
        for (Class<?> aClass : typesAnnotatedWith) {
            String rootUrl = aClass.getAnnotation(RequestMapping.class).value();
            for (Method method : aClass.getDeclaredMethods()) {
                String url = method.getAnnotation(RequestMapping.class).value();
                String requestUrl = rootUrl + url;
            }
        }
    }

(위 코드는 이해를 돕기 위해 메서드 분리를 하지 않았습니다.)

 

🐈‍⬛ 요약하면 

@Controller 어노테이션의 **value**는 컨트롤러 빈의 이름을 지정하고, @RequestMapping 어노테이션의 **value**는 메서드가 처리할 URL 경로를 지정합니다.

 

그런데 1단계 미션에선 컨트롤러 클래스에 rootUrl을 지정해주는 @RequestMapping이 없어서 쓸 일이 아직은 없는 것 같네요. 감사합니다.