SPRING/Spring MVC

[SpringMVC] @RequestMapping, @Controller

IT록흐 2023. 8. 10. 21:01
반응형

 

 

[SpringMVC] HandlerAdapter

[SpringMVC] MVC 패턴 구현하기(4) - Adapter [SpringMVC] MVC 패턴 구현하기(1) - View [SpringMVC] 응답(Response)의 종류 ( Text, Html, Json ) [SpringMVC] 요청(Request)의 종류 ( GET, POST, JSON ) [SpringMVC] 웹서비스에서 Request(요

lordofkangs.tistory.com

 

지난 포스팅에서 HandlerAdapter를 다루면서 @RequestMapping으로 선언된 Handler를 알아보았다. 

 

 

DispatcherServlet은 4가지 HandlerAdapter에 접근 가능하다. 그중 우선순위가 가장 높은 HandlerAdapter는 RequestMappingHandlerAdapter이다. RequestMappingHandlerAdapter는 @RequestMapping 어노테이션으로 선언된 Handler(Controller)를 지원하는 Adapter이다. 

 

@Component // Bean으로 등록!
@RequestMapping // 핸들러임을 명시!
public class SpringController {

    @RequestMapping("/springmvc/new-form")
    public ModelAndView process(){
    
   		// [ 비즈니스 로직 중략 ... ] 
       
        return new ModelAndView("new-form"); 
    }
    
}

 

예시 Controller를 하나 만들어 보았다. 단순한 클래스가 Controller로 동작하려면 2가지 어노테이션이 필요하다. 

 

1. @Component

2. @RequestMapping

 

@Component는 Spring Bean으로 등록하기 위한 어노테이션이다. Bean 객체로 생성되어 있어야 요청이 들어왔을 때 사용할 수 있다. 

 

 

@RequestMapping

 

@RequestMapping은 해당 Controller가  RequestMappingHandlerAdapter가 지원하는 Handler임을 명시한다. 지난 포스팅에서 말했듯, DispatcherServlet은 Controller의 비즈니스 로직을 실행할 권리를 Adapter에게 위임했다. Handler를 지원하는 적합한 HandlerAdapter가 있어야 Controller의 비즈니스 로직이 실행될 수 있다. 그러므로 Controller는 어노테이션으로 RequestMappingHandlerAdapter가 실행할 수 있는 Controller임을 표시해야 한다. 이때 사용되는 어노테이션이 바로, @RequestMapping이다. 

 

@RequestMapping의 가장 큰 장점은 하나의 Controller에 여러 개의 비즈니스 로직을 처리하는 메소드를 둘 수 있다는 점이다. 과거에 요청을 처리하는 Handler 역할을 하던 HandlerFunction 인터페이스, HttpRequestHandler 인터페이스, Controller 인터페이스는 모두 함수형 인터페이스이다. 메소드가 단 하나뿐이다. 그래서 구현체로 생성된 Handler도 메소드가 하나 뿐이라 하나의 비즈니스 로직만 처리 가능했다.  

 

@RequestMapping을 사용하면 하나의 핸들러에 다수의 메소드를 선언할 수 있다.

 

@Component
@RequestMapping("/springmvc/members")
public class SpringController {

    private final MemberRepository memberRepository = MemberRepository.getInstance();

    @RequestMapping(value = "/new-form") 
    public String newForm(){
    
    	// [ 비즈니스 로직 1 ]
        
        return "new-form";
    }

    @RequestMapping
    public String members(Model model){
    
    	// [ 비즈니스 로직 2 ]

        return "members";
    }

    @RequestMapping(value = "/save")
    public String save(@RequestParam("username") String username, @RequestParam("age") int age, Model model){
		
        // [ 비즈니스 로직 3 ]
        
        return "save-result";
    }

}

 

위 코드처럼 @RequestMapping을 메소드에 선언하고 세부URL을 명시하면 된다.

 

정리하면, 요청URL이 들어오면 DispatcherServlet은 URL에 매핑되는 Handler를 가져온다. DispatcherServlet은 Handler를 지원하는 HandlerAdapter를 가져오고 Handler 실행을 명령한다. HandlerAdapter는 요청에 맞는 비즈니스 로직을 실행을 위해 @RequestMapping으로 선언된 메소드의 세부URL을 확인하여 요청URL과 일치하는 메소드를 실행한다. 이와같은 원리로, Handler는 실행가능한 여러 개의 메소드를 가질 수 있게 되었다. 이런 장점으로 현재 가장 많이 사용되고 있는 Controller 유형이기도 하다.

 

 

@Controller 

 

다시 한번 말하면, 단순한 클래스가 Controller로 동작하려면 두 가지 어노테이션이 필요하다

 

1. @Component

2. @RequestMapping

 

Bean으로 등록되어야 하고 Handler임을 명시해야 한다. 이 두 가지를 한번에 하는 어노테이션이 있다. 그것이 @Controller이다. 

 

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component // @Component 가지고 있음
public @interface Controller {
	//중략...
}

 

@Controller 어노테이션 소스를 열어보면 @Component가 등록되어 있음을 확인할 수 있다. 그러므로 @Controller로 선언된 클래스도 Bean으로 등록 가능해진다. 그런데 Handler임을 명시하는 @RequestMapping이 없다. 앞서, @RequestMapping이 선언되어야 하는 이유는 RequestMappingHandlerAdapter가 처리할 수 있는 Handler임을 나타내기 위함이라 말했다.

 

public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMapping
		implements MatchableHandlerMapping, EmbeddedValueResolverAware {
              
    //중략...
    
    @Override
    protected boolean isHandler(Class<?> beanType) { // Handler가 아래 유형인지 확인
        return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) || //Controller 어노테이션
                AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class)); //RequestMapping 어노테이션
    }
    
    //중략...
    
}

 

 

위 코드를 보면 알 수 있듯이, RequestMappingHandlerAdapter가 처리할 수 있는 Handler의 종류는 2가지가 있다. 

 

1) @RequestMapping으로 선언된 클래스

2) @Controller로 선언된 클래스  

 

두 어노테이션 중 하나로 선언된 Handler는 RequestMappingHandlerAdapter가 처리할 수 있는 Handler인 것이다. 그러므로 굳이 @RequestMapping으로 선언되어 있지 않아도 @Controller로 선언되어 있으면 RequestMappingHandlerAdapter가 처리 가능한 것이다.

 

@Controller
public class SpringController {

    @RequestMapping("/springmvc/new-form")
    public ModelAndView process(){
    
   		// [ 비즈니스 로직 중략 ... ] 
       
        return new ModelAndView("new-form"); 
    }
    
}

 

그러므로 매번 두 개의 어노테이션을 사용할 필요가 없다. @Controller 하나면 두 가지 기능을 모두 수행할 수 있다. 그리고 메소드는 @RequestMapping로 선언하여 RequestMappingHandlerAdapter가 처리할 수 있도록 하면 된다. 

 

정리하면 단순 클래스가 Controller로 동작하려면 두 가지가 명시되어야 한다.

 

1) Bean임을 명시

2) Handler임을 명시

 

두 가지를 한번에 명시할 수 있는 어노테이션이 @Controller이다. @Controller에 @ResponseBody를 합친 @RestController도 존재하는데, 이에 대해서는 나중에 다루어 보도록 하겠다.

 

 

 


 

 

참고자료

 

스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 - 인프런 | 강의

웹 애플리케이션을 개발할 때 필요한 모든 웹 기술을 기초부터 이해하고, 완성할 수 있습니다. 스프링 MVC의 핵심 원리와 구조를 이해하고, 더 깊이있는 백엔드 개발자로 성장할 수 있습니다., 원

www.inflearn.com

 

반응형