로그인 사용자에 대한 기능들을 구현하다보면 로그인 사용자의 Session 정보를 활용할 일이 정말 많다.
그렇다 보니 Session 정보를 가져오는 코드마다 아래의 코드가 반복될 것이다.
SessionUser user = (SessionUser) httpSession.getAttribute("loginUser");
이 같은 코드가 반복되는 것을 방지하고자 Spring의 argument resolver를 활용하여
메서드 파라미터의 SessionUser 앞에 @Login 어노테이션을 붙여 세션값을 바로 받아 올 수 있도록 구현할수 있다.
또한 사용자별 세션 정보를 갖고 있으므로, 사용자별로 서로 다른 페이지 내용을 볼 수 있다. ( ex: 마이페이지 )
SessionUser 클래스
세션에 저장할 사용자의 정보를 담을 클래스로 민감한 부분은 제거하고 필요한 부분만을 선언하였다.
(만약 소셜 로그인을 구현한다면 email, picture 필드가 추가로 들어갈수 있다.)
@Getter
public class SessionUser implements Serializable {
private String name;
public SessionUser(User user) {
this.name = user.getName();
}
}
세션에 저장하기 위해 직렬화를 구현해야 한다.
@Login 어노테이션 생성
SessionUser 클래스 앞에 붙여 로그인 여부를 판별할 @Login 어노테이션을 만들어준다.
@Target(ElementType.PARAMETER) // 어노테이션 생성 위치
@Retention(RetentionPolicy.RUNTIME) // 어노테이션 유지 기간
public @interface Login {
}
@Target은 정의한 어노테이션이 붙을 수 있는 타입을 정의하는 부분이다.
ElementType.PARAMETER 옵션을 넣어 파라미터에 붙을 수 있는 어노테이션으로 정의 하였다.
@Retention은 어노테이션의 생명주기를 설정하는 것이다.
RetentionPolicy.RUNTIME 옵션을 넣어 실행될 때까지 어노테이션을 유효하도록 설정하였다.
해당 어노테이션은 HandlerMethodArgumentResolver 를 통해 어떠한 기능을 할지 구현할 예정이다.
LoginUserArgumentResolver
HandlerMethodArgumentResolver 인터페이스를 구현하는 구현체로 각각의 오버라이딩 메소드인 supportsParameter와 resolveArgument를 구현해준다.
이 클래스를 통해 @Login 어노테이션이 어떠한 역할을 할지 설정해주는 것이다.
/**
* 사용자의 세션 정보를 컨트롤러 메서드의 파라미터로 전달하기 위해 사용되는 클래스
*/
public class LoginUserArgumentResolver implements HandlerMethodArgumentResolver {
/**
* 컨트롤러 메서드의 특정 파라미터를 지원하는지 판단
* 파라미터에 @Login 어노테이션이 붙어 있고, 파라미터 클래스 타입이 SessionUser.class인 경우 true를 반환.
*/
@Override
public boolean supportsParameter(MethodParameter parameter) {
boolean isLoginUserAnnotation = parameter.getParameterAnnotation(Login.class) != null;
boolean isSessionClass = SessionUser.class.equals(parameter.getParameterType());
return isLoginUserAnnotation && isSessionClass;
}
/**
* 파라미터에 전달할 객체를 생성한다.
* 여기선 세션에서 객체를 가져온다.
*/
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) {
HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest();
HttpSession session = request.getSession(false);
if (session == null) {
return null;
}
return session.getAttribute(LOGIN_USER);
}
}
supportsParameter
주석의 설명과 같다.
@Login 어노테이션이 붙어있고, 메소드 파라미터가 SessionUser 클래스 타입이라면 true를 반환한다.
resolveArgument
만일 supportsParameter의 리턴값이 false라면, 해당 메소드는 실행되지 않는다.
true 인경우에만 실행되며 HttpSession에서 세션 값이 있을 경우 "LOGIN_USER"로 저장된 객체 반환한다.
(세션 값이 없을 경우 null을 반환하며 비 로그인 사용자인 것을 알 수 있다.)
WebConfig
LoginUserArgumentResolver 클래스가 인식될 수 있도록 다음과 같이 설정클래스에서 추가해줘야한다.
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(new LoginUserArgumentResolver());
}
}
오버라이딩한 메서드에 LoginUserArgumentResolver 객체를 추가하면, 스프링 MVC가 HTTP 요청 처리 시 해당 Resolver를 사용하여 매개변수를 해석하게 된다.
@Login 어노테이션을 사용한 로그인 정보 활용 예시
다음은 장바구니컨트롤러에서 로그인 한 사용자인지 비 로그인 사용자인지 판별 하여 view에 data를 넘겨주는 코드이다.
로그인한 사용자의 경우 장바구니에 저장한 상품들을 view에 전달해주고, 비 로그인 사용자의 경우에는 바로 view를 반환한다.
(비 로그인 사용자는 LocalStorage에 담긴 장바구니 정보를 보여주도록 하였다.)
@Controller
@RequiredArgsConstructor
public class CartController {
private final CartService cartService;
@GetMapping("/user/cart")
public String loginUserCart(@Login SessionUser sessionUser, Model model) {
if (sessionUser != null) {
List<CartAndImageDto> cartAndImages = cartService.selectCartAndImageByUserId(sessionUser.getUserIdNo());
model.addAttribute("cartAndImages", cartAndImages);
}
return "user/cart";
}
}
이 처럼 HttpSession에서 일일이 세션정보를 꺼내오는 코드없이 @Login 어노테이션을 붙임으로서 간편하게 로그인 사용자 정보를 가져올 수 있다.
'◼ Spring' 카테고리의 다른 글
[Spring] 아임포트(import)로 결제 취소, 환불 기능 구현하기 (6) | 2023.09.05 |
---|---|
[Spring] 아임포트(import)로 결제 기능 구현하기 (클라이언트 + 서버 코드 포함) (7) | 2023.09.01 |
[Spring] Cookie(쿠키)를 활용한 최근 본 상품 기능 구현 (Session과 비교) (0) | 2023.08.30 |
[Spring] 공통 기능을 @Aspect를 사용해 적용하기 (0) | 2023.08.30 |
[Spring] GET요청으로 url 쿼리 파라미터에 포함된 JSON 데이터 사용하기 (0) | 2023.08.30 |