티스토리 뷰

Spring에서 제공하는 HandlerMethodArgumentResolver는 컨트롤러의 메서드에 조건에 맞는 파라미터 및 어노테이션이 정의되있다면 원하는 값을 주입해주는 인터페이스 입니다.

 

메서드 매개변수에 @RequestBody 어노테이션이 정의되었으면 HandlerMethodArgumentResolver의 구현체인

RequestResponseBodyMethodProcessor가 동작하여

request body에 있는 Json 포맷의 데이터를 Java 객체에 바인딩을 해줍니다.

 

세션을 이용하여 로그인 기능을 구현하게되면 로그인 시 입력된 값으로 DB에 사용자를 조회후 조회한 값을 세션에저장할 것 이고 사용자의 정보가 필요할 경우 HttpSession을 컨트로러 메서드 매개변수에 주입받아 사용자의 정보를 꺼내올 것이다. 아래사진을 보자

세션에서 사용자 정보 꺼내기

예를들어 A 서비스와 B 서비스에서 사용자의 정보가 필요하다면 저렇게 session.getAttribute(key)로 사용자의 정보를 조회할 것이다.

근데 만일 A, B 서비스뿐만 아니라 다른쪽에서도 사용자의 정보가 필요할 경우 해당 서비스를 호출하는 컨트롤러쪽에는 HttpSession을 매번 주입받고 session.getAttribute(key)로 꺼낸뒤 casting을 해줘야하는 번거로움이 있다.

컨트롤러의 메서드가 호출될 때 매개변수로 사용자의 정보가 담긴 객체를 한번에 받아올 수 있으면 위의 작업을 굳이 매번하지 않아도되며 중복된 코드를 방지할 수 있다. HandlerMethodArgumentResolver를 커스텀하여 간단하게 처리할 수 있다.

Annotation 생성

import java.lang.annotation.*;

/**
 * Get the login user information
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface LoginUser {
}

컨트롤러 메서드 매개변수에 @LoginUser 어노테이션이 있을 해당 객체에 사용자의 정보를 넣어줄 것 이다.

HandlerMethodArgumentResolver 커스텀

import com.example.loginuser.annotation.LoginUser;
import com.example.loginuser.util.CommonUtil;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import javax.servlet.http.HttpServletRequest;

public class LoginUserArgumentResolver implements HandlerMethodArgumentResolver {

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.getParameterAnnotation(LoginUser.class) != null;
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest,WebDataBinderFactory binderFactory) throws Exception {
        HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
        return request.getSession().getAttribute(CommonUtil.LOGIN_USER);
    }

}

HandlerMethodArgumentResolver 인터페이스를 구현하면 두개의 메서드를 오버라이딩 해줘야한다.
supportsParameter 메서드에 특정조건을 정의하고 그 결과가 true를 반환하면 resolveArgument 메서드가 실행되며 해당resolveArgument 메서드에서 return하는 값이 매개변수에 저장된다.

컨트롤러 메서드 매개변수중에 @LoginUser 어노테이션이 정의된 매개변수가 존재하면 session에 저장된 유저정보를 반환한다.

Web 설정

import com.example.loginuser.resolver.LoginUserArgumentResolver;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.List;

@Configuration
public class WebConfig implements WebMvcConfigurer {

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

}

WebMvcConfigurer 인터페이스의 addArgumentResolvers 메서드를 오버라이딩하여 커스텀한 resolver를 등록해준다.

User 클래스 생성

public class User {
    private String id;
    private String pwd;

    public String getId() {
        return id;
    }
    public String getPwd() {
        return pwd;
    }
}

세션에 저장할 객체

Controller 생성

해당코드의 흐름은 다음과 같다.

  • 로그인 페이지로 이동
  • ID, PWD 입력후 로그인 API 호출
  • 사용자 정보조회후 조회한 데이터를 세션에 저장
  • index 페이지 진입 시 콘솔에 사용자 아이디 출력

결과

정상적으로 값이 잘 받아와졌다.


여러곳에서 동일한 데이터를 조회해서 사용할 때 해당기능을 응용하면 중복된 코드를 걷어낼 수 있겠지만 예시코드를 보면 resolveArgument에서 return하는 데이터의 타입과 컨트롤러 메서드 매개변수의 타입이 맞지않으면 예외가 발생될 수 있으니 이점은 주의하면서 사용하자

728x90
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함