슬기로운 개발생활

커스텀 어노테이션을 통해 중복코드 개선

by coco3o
반응형

Spring Boot 게시판 Security 회원가입,로그인 구현 에서 세션 유무에 따라 로그인/로그아웃 버튼을 보여주는 코드를 작성했었다.

@GetMapping("/")
public String index(Model model, ...) {
   ...
   UserSessionDto user = (UserSessionDto) session.getAttribute("user");
    if(user != null) {
    	model.addAttribute("user", user.getNickname());
    }
   ...
}

UserSessionDto user = (UserSessionDto) session.getAttribute("user"); 는 세션 정보를 가져오는 코드인데,

이 코드는 Controller의 각 메소드마다 동일하게 존재하고 있다.

이러한 중복코드는 추후에 수정이 필요한 경우 모든 부분을 하나씩 수정해야한다.

이렇게 될 경우 유지보수성이 떨어지고, 다른 문제가 생길 수도 있을 것이다.

그래서 위 부분을 각 메소드의 파라미터로 세션 값을 바로 받을 수 있게 커스텀 어노테이션을 만들어 보도록 하겠다.


1. LoginUser 생성

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

@LoginUser를 사용할 수 있도록 어노테이션을 생성했다.

@Target(ElementType.PARAMETER)

- @LoginUser 어노테이션이 생성될 수 있는 위치를 지정한다.


@Retention(RetentionPolicy.RUNTIME)

- 런타임까지 보존한다.


@interface

- 어노테이션 클래스로 지정한다.


2. LoginUserArgumentResolver 생성

ArgumentResolver : 사용자가 컨트롤러의 메소드 인자값으로 임의의 값을 전달하려 할 때 사용된다.

@RequiredArgsConstructor
@Component
public class LoginUserArgumentResolver implements HandlerMethodArgumentResolver {

    private final HttpSession session;

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

        boolean isUserClass = UserSessionDto.class.equals(parameter.getParameterType());

        return isLoginUserAnnotation && isUserClass;
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
                                  NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {

        return session.getAttribute("user");
    }
}

HandlerMethodArgumentResolver를 implements하여 메소드 오버라이딩 하였다.

supportsParameter

- @LoginUser 어노테이션이 붙어 있고, 파라미터 클래스 타입이 UserSessionDto인가 판단 후 true를 반환

resolveArgument

- 파라미터에 전달할 객체 생성 ( 세션에서 객체를 가져옴 )


3. WebConfig

@RequiredArgsConstructor
@Configuration
public class WebConfig implements WebMvcConfigurer {

    private final LoginUserArgumentResolver loginUserArgumentResolver;

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

LoginUserArgumentResolver가 스프링에서 인식될 수 있도록 WebMvcConfigurer에 추가


4. Controller

@LoginUser 어노테이션으로 중복 코드를 다음과 같이 개선하였다.

@GetMapping("/")
public String index(Model model, @LoginUser UserSessionDto user, ...) {
   ...
    if(user != null) {
    	model.addAttribute("user", user.getNickname());
    }
    ...
}

참고

반응형

블로그의 정보

슬기로운 개발생활

coco3o

활동하기