@Component
public class LoginUserArgumentResolver implements HandlerMethodArgumentResolver {
@Autowired
private UserService userService;
@Override
public boolean supportsParameter(MethodParameter parameter) {
// @LoginUser 어노테이션이 붙은 파라미터만 처리하도록 설정
return parameter.hasParameterAnnotation(LoginUser.class);
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
// 세션에서 로그인된 사용자 정보 가져오기
ServletWebRequest servletWebRequest = (ServletWebRequest) webRequest;
HttpServletRequest request = servletWebRequest.getRequest();
HttpSession session = request.getSession(false);
if (session == null || session.getAttribute("userId") == null) {
throw new RuntimeException("로그인 해주세요.");
}
Long userId = (Long) session.getAttribute("userId");
// UserService를 사용하여 DB에서 사용자 정보 조회
User user = userService.findById(userId);
return user; // 로그인된 사용자 객체를 반환
}
}
Spring MVC 프로젝트를 하다 보면 로그인한 사용자 정보를 컨트롤러에서 자주 받아와야 할 때가 많습니다.
HttpSession에서 직접 값을 꺼내 쓰는 방식도 있지만, 매번 반복해서 쓰기보다는 깔끔하게 커스텀 어노테이션을 만들어 자동으로 처리되게 할 수 있습니다.
이번 글에서는 @LoginUser라는 커스텀 어노테이션을 만들어 로그인된 사용자 정보를 컨트롤러 메서드 파라미터에 자동 주입하는 방법을 소개합니다.
구조 : 요청 → DispatcherServlet → ArgumentResolver(@LoginUser) → 세션에서 userId 꺼냄 → DB 조회 → User 객체 반환
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface LoginUser {
}
@Component : 스프링이 자동으로 이 클래스를 빈으로 등록하게 해줌.
HandlerMethodArgumentResolver 인터페이스 : 컨트롤러 메서드에서 특정 조건에 맞는 파라미터가 있을 때 원하는 값을 바인딩해주는 인터페이스
-> 컨트롤러 메서드의 파라미터에 값을 넣어주는 로직을 우리가 직접 정의할 수 있도록 해주는 확장 포인트
-> 이걸 활용해서 @LoginUser 어노테이션이 붙은 파라미터에 로그인된 사용자 정보를 자동 주입하게 만듬
@Autowired : 필요한 의존 객체의 "타입"에 해당하는 빈을 찾아 주입.
@LoginUser 어노테이션 붙은 파라미터에만 설정
@Override
public boolean supportsParameter(MethodParameter parameter) {
// @LoginUser 어노테이션이 붙은 파라미터만 처리하도록 설정
return parameter.hasParameterAnnotation(LoginUser.class);
}
webRequest는 NativeWebRequest타입인데 웹 요청을 추상화한 객체, ServletWebRequest로 다운캐스팅 한 것.
request.getSession(false)은 세션이 있으면 가져오고, 없으면 null을 리턴
(true를 넣으면 세션이 없으면 새로 생성해버림, false는 세션이 있을 때만 가져오도록 제한)
// 1. Spring 추상화된 요청(webRequest)을 실제 ServletRequest로 다운캐스팅
ServletWebRequest servletWebRequest = (ServletWebRequest) webRequest;
// 2. 진짜 HttpServletRequest 꺼냄
HttpServletRequest request = servletWebRequest.getRequest();
// 3. 세션이 있으면 가져옴 (없으면 null)
HttpSession session = request.getSession(false);
// 4. 세션이 없다면 예외 처리
if (session == null) {
throw new RuntimeException("로그인 해주세요.");
}