어노테이션 기반으로 개선하기

nn·2022년 2월 4일
0
post-custom-banner

프로그래밍에서 개선이 필요한 부분 중 대표적인것은 코드가 반복되는 부분입니다.

이전 포스팅에는 세션을 가져오는 부분이 여러번 반복되었습니다.

SessionUser user = (SessionUser) httpSession.getAttribute("user");

컨트롤러나 여러 다른 메소드들은 세션값이 필요할 때마다 직접 세션에서 값을 꺼내와야하기 때문에 비효율적입니다.

세션값을 메소드 인자로 받을 수 있도록 변경해보겠습니다.


config 패키지에 다음과 같이 @LoginUser라는 어노테이션을 만들어보겠습니다.

LoginUser.java

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

@LoginUser 어노테이션이 생성될 수 있는 위치를 지정합니다.
PARAMETER는 메소드의 파라메어로 선언된 객체에서만 사용할 수 있게 해줍니다.

  • @interface

어노테이션 클래스를 지정할 때 사용합니다.


같은 위치에 HandlerMethodArgumentResolver인터페이스를 구현한 클래스를 만들겠습니다.

HandlerMethodArgumentResolver는 조건에 맞는 경우 메소드가 있다면 이 구현체가 지정한 값으로 해당 메소드의 파라메터로 넘길 수 있는 기능을 지원합니다.

LoginUserArgumentResolver.java

@RequiredArgsConstructor
@Component
public class LoginUserArgumentResolver implements HandlerMethodArgumentResolver {

    private final HttpSession httpSession;

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        boolean isLoginUserAnnotation = parameter.getParameterAnnotation(LoginUser.class) != null;
        boolean isUserClass = SessionUser.class.equals(parameter.getParameterType());
        return isLoginUserAnnotation && isUserClass;
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
                                  NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        return httpSession.getAttribute("user");
    }
}
  • supportsParameter()
    컨트롤러 메소드의 특정 파라메터를 지원하는지 판단합니다.
    @LoginUser 이 붙어있고, 파라메터 클래스 타입이 LoginUser.class인 경우에 참을 반환합니다.

  • resolveArgument()
    파라메터에 전달 할 객체를 생성합니다.
    여기서는 세션에서 객체를 가져오게됩니다.

어노테이션 적용

@LoginUser 을 사용하기위해 설정을 추가하겠습니다.
config 패키지에 다음과 같은 파일을 만들겠습니다.

WebConfig.java

@RequiredArgsConstructor
@Configuration
public class WebConfig implements WebMvcConfigurer {
    private final LoginUserArgumentResolver loginUserArgumentResolver;

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolver) {
        argumentResolver.add(loginUserArgumentResolver);
    }
}

이렇게 생성하면 LoginUserArgumentResolver가 스프링에서 인식될 수 있습니다.

HandlerMethodArgumentResolver는 항상 addArgumentResolvers를 거쳐서 추가해야합니다.


개선

@LoginUser를 만들었으니 이 어노테이션을 세션값을 직접 가져오는 부분에 대신 사용하겠습니다.

 @GetMapping("/")
    public String index(Model model){
        model.addAttribute("posts", postsService.findAllDesc());

        SessionUser user = (SessionUser) httpSession.getAttribute("user");
        // 로그인 성공 시 세션 값

        if (user != null) {
            model.addAttribute("userName", user.getName());
        }
        return "index";
    }

위의 코드를 개선하면 아래와 같습니다.

 @GetMapping("/")
    public String index(Model model, @LoginUser SessionUser user){
        model.addAttribute("posts", postsService.findAllDesc());
        
        if (user != null) {
            model.addAttribute("userName", user.getName());
        }
        return "index";
    }
profile
내가 될 거라고 했잖아
post-custom-banner

0개의 댓글