Argument Resolver

이한수·2022년 6월 2일

Spring

목록 보기
1/1

프로젝트에서도 간단히 사용해보았고 , 강의를 보면서 공부한 내용을 정리해보고자 한다.

Controller를 사용하면서 @ModelAttribute , @RequestParam , @ResponseBody 등 다양한 어노테이션을 이용하여 , 값을 주입받고 사용한다.

그것을 가능하게 해주는 것이 ArgumentResolver 이며 , 이에 대해서 적어보고자 한다.

먼저 , 어디서 사용되는지 알기 위해서 MVC패턴을 간단하게 짚고 넘어가려 한다.

MVC 패턴

Model , View , Controller의 약자이며 ,디자인 패턴 중 하나다.
과거 view에는 비즈니스 로직까지 같이 적었다고 한다.

그로 인해 , 방대해진 코드양과 더불어 , 유지보수를 하기에도 힘들었는데 , 이를 보완하기 위해서 사용한 것이 MVC 패턴이다.

순서

Dispatcher -> HandlerMapping -> HandlerAdaptor -> Handler -> viewResolver -> view 순서로 실행 된다.

DispatcherServlet

  • FrontController의 패턴으로 구현되었다.
  • 클라이언트의 요청을 DispatcherServlet 이 받는다.

HandlerMapping

  • 사용하고자 하는 Handler를 찾아 온다.

    HandlerAdaptor

  • HandlerMapping를 통해 찾은 Handler를 실행시킬 Adaptor를 찾아온다.

viewResolver

  • HandlerAdator를 통하여 Handler로부터 얻어온 논리 뷰 이름을 가지고 view를 반환한다.

view

  • view를 render해서 클라이언트에게 반환한다.

한가지 더 알고 넘어가야할 것이 있다.
바로 HTTP Header다.

HTTP Header

Content-Type

  • 표현 데이터의 형식을 설명한다.
  • 미디어 타입 , 문자 인코딩

즉 , HTTP Message Body에 들어가는 데이터 타입을 명시해준다고 보면 된다.

Accept

  • 클라인언트가 요청 메세지를 보낼 때 , 자신이 선호하는 미디어 타입을 전달할 때 사용한다.

즉 , 서버에게 나는 이런 데이터 타입을 받을 수 있다고 알려준다고 보면 된다.


Argument Resolver

HandlerAdaptor를 얻어올 때 , Handler가 어느 기반이냐에 따라 얻어오는 HandlerAdaptor가 달라진다.

Argument Resolver는 어노테이션 기반 컨트롤러를 처리할 때 사용하는 RequestMappingHandler에서 동작한다.

즉 , HandlerAdaptor과 Handler의 사이에는 사실
HandlerAdaptor -> ArgumentResolver -> (Message converter)-> Handler -> ReturnValueHandler ->HandlerAdaptor 라는 일련의 과정이 숨겨져 있다.

ReturnValueHandler도 ArgumentResolver와 비슷하다.
String 으로 뷰이름을 반환해도 동작되는것이 이 덕분이다.

이러한 일련의 과정을 통해서 우리는 Controller에서 사용할 데이터를 쉽게 파싱하여 사용할 수 있다.

public Class Board{
	Long id;
    String writer;
    String content;
}

@GetMapping("/board")
public String board(@ModelAttribute Board board){
		
}

위와 같은 예시가 있을때 , 넘어오는 데이터중에 이름이 같은 것이 있으면 Board라는 객체에 주입을 해주는데 , 이를 중간에서 해준다고 보면 된다.

ArgumentResolver의 진짜 이름은 HandlerMethodArgumentResolver 인데 줄여서 ArgumentResolver라고 한다고 한다.

ArgumentResolver는 인터페이스이며 , 이를 구현한 많은 클래스들이 있다.
Controller의 파라미터 타입에 따라 사용되는 ArgumentResolver가 다르다.


public interface HandlerMethodArgumentResolver {

	boolean supportsParameter(MethodParameter 	parameter);

	@Nullable
	Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;
}
  • supportsParameter -> 해당 타입을 지원하는지. (지원하면 true 반환되고 ,resolverArgument 메소드 실행)

  • resolverArgument -> 파라미터 데이터를 Object로 생성하여 반환.

위 2가지 메소드를 이용하여 지원하는 ArgumentResovler를 찾아내고 사용 한다.

HTTP 메세지 컨버터

위 방식만으로 해결이 안되는 것들이 있다.
바로 HTTP 메세지를 처리하는 경우인데 , @RequestBody 혹은 HttpEntity를 사용하는 경우다.

응답의 경우 : @ResponseBody , HttpEntity 등

해당 파라미터 혹은 어노테이션을 처리하는 ArgumentResolver는
내부적으로 HTTP 메세지 컨버터라는 것을 호출 하여 사용할 데이터를 생성하여 반환 해준다..

Argument Resolver 만들기


@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface Custom {
}

@GetMapping("/board")
public String board(@Custom Board board){
		
}

위와 같이 어노테이션과 그것을 사용한 Handler가 있다고 가정해보자.


//구현

public class CustomBoardArgumentResolver implements HandlerMethodArgumentResolver {

    //파라미터가 Login 어노테이션을 가지고 있는지
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        boolean hasCustom = parameter.hasParameterAnnotation(Custom.class);
        //해당 어노테이션을 가지고 있는지 확인.

        boolean isBoard = Board.class.isAssignableFrom(parameter.getParameterType());
        //어노테이션을 가지고 있는 클래스의 타입이 Board인지

        return hasCustom && isBoard;
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        
        HttpServletRequest request =(HttpServletRequest) webRequest.getNativeRequest();
        
        String writer = request.getParameter("writer");
		String content = request.getParamter("content");
        
       
        return new Board(writer,content);
        //이런식으로 본인이 Binding을 원하는 객체를 생성하여 반환해주면 된다.
    }
}

HandlerMethodArgumentResolver를 상속받고 메소드를 구현해주면 된다.

//등록
@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
       resolvers.add(new CustomBoardArgumentResolver());
    }
}

참고 :
https://6161990src.tistory.com/124

https://velog.io/@gillog/Spring-HandlerMethodArgumentResolver-PathVariable-RequestHeader-RequestParam

김영한님의 MVC1,2강의를 이용하여 학습.

profile
성실하게

0개의 댓글