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

  • 반복되는 같은 코드 해결하기
    • 커스텀 어노테이션(@LoginUser) 만들기
    • ArgumentResolver

커스텀 어노테이션 생성

  • 세션 처리를 위한 @LoginUser 어노테이션 생성
    1. @Target(ElementType.PARAMETER)
      • 어노테이션이 생성될 수 있는 위치를 지정
      • PARAMETER로 지정하므로써 메서드의 파라미터로 선언된 객체에서만 사용될 수 있다.
      • 이 외에도 클래스 선언시 사용할 수 있는 TYPE 등이 있다.
    2. @Interface
      • 해당 파일을 어노테이션 클래스로 지정
      • LoginUser라는 이름을 가진 어노테이션을 사용할 수 있다.
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface LoginUser {
}

LoginUserArgumentResolver

  • ArgumentResolver 생성

    • HandlerMethodArgumentResolver 인터페이스를 구현한 클래스
    • 조건에 맞는 경우 메서드가 있다면, HandlerMethodArguementResolver의 구현체가 지정한 값으로 해당 메서드의 파리미터로 넘길 수 있다.
    1. supportParameter()
      • 컨트롤러 메서드의 특정 파라미터를 지원하는지 판단
      • 파라미터에 @LoginUser 어노테이션이 붙어있고, 파라미터 클래스 타입이 SessionUser.class인 경우 true를 반환
    2. resolveArgument()
      • 파라미터에 전달할 객체를 생성
      • 해당 코드에서는 세션에서 객체를 가져온다.
@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");
    }
}

ArgumentResolver 설정

  • WebConfig
    • 스프링에서 LoginUserArgumentResolver를 인식할 수 있도록 WebMvcConfigurer를 구현한 WebConfig 클래스에 설정한다.
    • WebMvcConfigurer의 addArgumentResolvers()를 추가한다.
    • 다른 HandlerMethodArgumentResolver가 필요한 경우 같은 방식으로 추가한다.
@RequiredArgsConstructor
@Configuration
public class WebConfig implements WebMvcConfigurer {
    private final LoginUserArgumentResolver loginUserArgumentResolver;

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

Controller 수정

  • 세션을 사용하는 부분 수정

    • @LoginUser를 파라미터로 받아 사용할 수 있도록 수정
    1. @LoginUser SessionUser user
      • 기존 (SessionUser) httpSession.getAttribute("user")로 가져오던 세션 정보 값을 개선
      • 다른 컨트롤러에서 세션이 필요한 경우 @LoginUser를 사용하여 세션 정보를 가져올 수 있다.
@RequiredArgsConstructor
@Controller
public class IndexController {

    private final PostsService postsService;
    private final HttpSession httpSession;

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

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

    @GetMapping("/posts/save")
    public String postsSave() {
        return "posts-save";
    }

    @GetMapping("/posts/update/{id}")
    public String postsUpdate(@PathVariable Long id, Model model) {
        PostsResponseDto dto = postsService.findById(id);
        model.addAttribute("post", dto);
        return "posts-update";
    }
}

어노테이션 기반으로 변경하여 다시 세션 체크

  • 글 작성 테스트

  • 글 등록 확인

+ Recent posts