프로그래밍에서 개선이 필요한 부분 중 대표적인것은 코드가 반복되는 부분입니다.
이전 포스팅에는 세션을 가져오는 부분이 여러번 반복되었습니다.
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";
}