SPRING/Spring MVC

[SpringMVC] ArgumentResolver 활용하기

IT록흐 2023. 8. 31. 23:08
반응형

 

 

[SpringMVC] HTTP 메시지 컨버터 동작원리

JSON 데이터를 JAVA 환경에서 사용하는 방법이다. HTTP Body 영역의 데이터를 InputStream 객체로 이진데이터를 가지고 온 후, 인코딩하고 문자열로 변환하면 JAVA 환경에서 사용가능한 데이터 타입이 된

lordofkangs.tistory.com

 

 

지난 포스팅에서 ArgumentResolver의 개념을 다루어보았다.

 

 

 

 

Controller는 비즈니스 로직을 처리하는 클래스로, 필요한 데이터를 파라미터로 요구한다. Controller(Handler)를 실행하는 주체는 HandlerAdapter인데, HandlerAdapter는 파라미터에 맞는 데이터를 넘겨야 한다. 그러므로 다양한 파라미터에 대응할 수 있는 모듈이 필요한데,  그것이 ArgumentResolver이다. 

 

 

 

핸들러 어댑터는 컨트롤러 메소드의 파라미터 객체를 생성할 수 있는 ArgumentResolver 구현체를 탐색한다. @ModelAttribute, @RequestBody, HttpEntity.. 등등 다양한 파라미터에 대응할 수 있는 ArgumentResolver 구현체가 이미 Spring에 구현되어 있다. 

 

이번 포스팅에서는 ArgumentResolver 구현체를 직접 만들어, Spring이 지원하지 않는 파라미터에 객체를 넘기어 보겠다.

 

 

ArgumentResolver 활용하기

 

 

@Login

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

}

Controller

@GetMapping("/")
public String login(@Login Member loginMember, Model model){

	// [ 비즈니스 로직 ]
    
}

 

@Login 어노테이션을 새로 만들었다. 그리고 Controller의 login 메소드 파라미터에 @Login 어노테이션을 선언하였고 파라미터로 Member 클래스를 정의하였다. @Login 어노테이션은 새로 만든 어노테이션이므로, Spring이 제공하는 ArgumentResolver 구현체로는 Member 객체를 생성하여 파라미터로 넘기지 못한다. 

 

그러므로 @Login 어노테이션이 선언되어 있을때 Member 객체를 넘겨 줄 수 있는 ArgumentResolver 구현체를 직접 만들어야 한다. 

 

LoginMemberArgumentResolver

public class LoginMemberArgumentResolver implements HandlerMethodArgumentResolver {
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        
        // 1) @Login 어노테이션이 선언되어 있는가?
        boolean hasLoginAnnotation = parameter.hasParameterAnnotation(Login.class); 
        
        // 2) 파라미터가 Member 클래스인가?
        boolean hasMemberType = Member.class.isAssignableFrom(parameter.getParameterType()); 
        
        // 1)과 2)가 TRUE이면 LoginMemberArgumentResolver 동작
        return hasLoginAnnotation && hasMemberType; 

    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
                
        // HttpServletRequest 객체로 형변환
        HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest();
        // 세션 조회하기 
        HttpSession session = request.getSession(false);
        
        // 세션이 없는 경우 
        if(session == null){
            return null;
        }
        
        // 세션에서 회원정보 추출하여 반환하기 ( Member 객체 )
        return session.getAttribute(SessionConst.LOGIN_MEMBER);
    }
}

 

 

LoginMemberArgumentResolver를 직접 만들어 보았다.

 

LoginMemberArgumentResolver는 HandlerMethodArgumentResolver 인터페이스의 구현체이다. HandlerMethodArgumentResolver는 @RequestMapping이 선언된 컨트롤러를 지원하는 ArgumentResolver이다. ArgumentResolver는 두 가지 메소드를 구현하면 된다.

 

1) supportsParameter 메소드

2) resolveArgument 메소드

 

핸들러 어댑터는 파라미터에 객체를 전달할 수 있는 ArgumentResolver를 탐색하는데, ArgumentResolver의 supportsParameter 메소드를 호출하여 적합 여부를 판단한다. 

 

그럼 위 코드를 보자. 

 

- supportsParameter 메소드

 

파라미터가 @Login 어노테이션을 가지고 있고(hasParameterAnnotation)

파라미터에 Member 클래스가 할당될 수 있다면(isAssignableFrom) 

 

메소드는 true를 반환한다. 핸들러 어댑터에게 자신이 파라미터에 적합한 객체를 생성하여 반환할 수 있음을 알리는 것이다. 그럼 핸들러 어댑터는 resolveAgument 메소드를 호출한다. 

 

- resolveArgument 메소드

 

resolveArgument 메소드는 실제 파라미터에 넘길 객체를 생성하는 메소드이다. 메소드의 파라미터를 보자.

 

MethodParameter parameter

ModelAndViewContainer mavContainer

NativeWebRequest webRequest

WebDataBinderFactory binderFactory

 

파라미터 데이터부터 웹 관련 데이터까지,  웹 환경에서 데이터를 추출하여 컨트롤러 파라미터에 넘길 객체를 만들 수 있도록 환경을 제공하고 있다. 우리는 그럼 HttpServletRequest 객체에서 세션 객체를 가져와보자. 세션객체에 key값을 넣어 회원정보(Member)를 추출한다. 그렇게 추출된 Member 객체를 핸들러 어댑터에 반환하면 핸들러 어댑터는 컨트롤러 메소드의 파라미터로 전달한다. 

 

Controller

@GetMapping("/")
public String login(@Login Member loginMember, Model model){

	// [ 비즈니스 로직 ]
    
}

 

그럼 Controller의 loginMember 객체에는 로그인 요청을 보내온 회원의 정보가 들어 있다. 정보를 토대로 로그인 비즈니스 로직을 처리하면 된다. 

 

그럼 직접 만든 ArgumentResolver를 Spring이 사용할 수 있도록 등록해보자. 

 

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        resolvers.add(new LoginMemberArgumentResolver()); // 등록!
    }
    
 }

 

WebMvcConfigurer 인터페이스는 Spring이 제공하는 각종 인터페이스에 커스터 마이징된 구현체들을 쉽게 등록할 수 있도록 기능을 제공하고 있다. WebMvcConfigurer 인터페이스의 addArgumentResolvers 메소드는 ViewReselover를 등록하는 기능을 제공하는 메소드이다.  위 코드처럼 간단히 등록할 수 있다. 

 

ArgumentResolver 등록을 완료하면, 다음과 같은 자동화가 이루어진다.

 

컨트롤러 메소드에 @Login과 Member 클래스로 구성된 파라미터가 있으면 Spring이 자동으로 세션에서 회원정보를 추출하여 파라미터로 넘겨준다. 그럼 다음부터 개발할때는 간단히 @Login으로 회원정보를 요청만하면 된다. 이렇게 ArgumentResolver 구현체를 직접 만들어 등록하면 Controller 메소드를 단순화시킬 수 있다.

 

 


 

 

참고자료

 

스프링 MVC 2편 - 백엔드 웹 개발 활용 기술 - 인프런 | 강의

웹 애플리케이션 개발에 필요한 모든 웹 기술을 기초부터 이해하고, 완성할 수 있습니다. MVC 2편에서는 MVC 1편의 핵심 원리와 구조 위에 실무 웹 개발에 필요한 모든 활용 기술들을 학습할 수 있

www.inflearn.com

 

 

 

반응형