728x90
1. ArgumentResolver 개념 및 동작 과정
- ArgumentResolver 는 Controller 에서 들어오는 데이터(파라미터)를 가공하여 필요한 데이터만 뽑는 로직이 필요할 때 사용한다.
- 보통 @ModelAttribute 나 @Param 를 사용해서 이러한 처리를 하게 되는데 문제는 이렇게 받았을 때 내가 필요한 정보만 있는게 아니라 다른 정보가 함께 있어서 추가적으로 데이터를 파싱하여 필요한 정보를 뽑아내는 등 추가 작업이 필요한 경우도 있다.
- 이를 위해서 사용하는 것이 바로 ArgumentResolver 이다! ArgumentResolver 는 HandlerMethodArgumentResolver 를 구현한 구현 클래스를 사용해서 애플리케이션에 맞는 새로운 Resolver 를 만들고, 실행 시 Resolver 리스트에 내가 만든 Resolver 을 추가함으로써 적용할 수 있다
- ArgumentResolver 가 동작되기까지의 구체적인 순서는 다음과 같다.
- 사실 ArgumentResolver 은 SpringIntercepter 보다 뒤에 실행되기 때문에 굳이 argumentResolver 을 사용하지 않고 Spring Intercepter 에서 처리해도 된다고 한다. 다만, 보다 구체적인 적용을 해야하는 경우에는 Resolver 이 사용하는게 원하는 로직을 구현하는데 더 좋다나 뭐라나…
사용자 요청 -> DispatcherServlet 동작 -> 요청한 URI 를 HandlerMapping 에서 검색 ->
SpringIntercepter 처리 -> ArgumentResolver 처리 -> MessageConverter 처리
그래서 ArgumentResolver 가 정확히 뭘 위해 만드는건데?
ArgumentResolver 는 넘어오는 파라미터에서 내가 원하는 로직으로 내가 원하는 정보를 위해 사용한다.
즉 기존에 스프링에서 이미 만들어진 어노테이션을 사용하는 것뿐만 아니라 내가 직접 만든 커스텀 어노테이션을 사용해서 파라미터 안에서 데이터를 분리, 로직 처리가 가능하다!
ArgumentResolver 사용하기 : @Login 어노테이션 만들기, 로그인 세션 처리하기
기존에 사용하던 SessionAttribute 가 아닌 @Login 이라는 커스텀 어노테이션을 생성 후 세션 처리를 해보자!
1) Controller
- 세션 처리를 위해 기존의 SessionAttribute 가 아닌 @Login 을 사용한다.
// ArgumentResolver 을 사용하면 @Login 어노테이션 뒤에 오는 Member 매개변수,
// 즉 Argument 에 대해서 해당 매개변수에 대한 정보가
// 세션에 담아져 있으면 로그인 사용자로 취급하여 로그인 사용자에 맞는 요청을 처리하고
// 아니면 로그인 사용자로 처리하지 않는다.
// 이때 @Login 어노테이션은 커스텀 어노테이션 - 사용자 정의 어노테이션 - 에 해당한다 => 직접 만들어야한다
@GetMapping(value = {"/home"}) // 스프링이 지원하는 세션 기능 : @SessionAttribute
public String LoginHomeV3ArgumentResolver(
@Login Member loginMember, Model model) {
// 로그인 안했을 시 => 세션이 없을 때
// 스프링이 알아서 처리해줌 만세!
/* 로그인 시도 시 */
// 각각 로그인을 시도했으나 회원 코드가 없는 경우, 회원코드가 0 인 경우, 회원 코드가 0 이 아닌 경우
if (loginMember == null) {
return "newspringhome";
} else if (loginMember.getMEMBERCODE() == 0) {
model.addAttribute("member", loginMember);
System.out.println("관리자 로그인 성공");
return "newspringhome_admin";
} else {
model.addAttribute("member", loginMember);
System.out.println("일반 회원 로그인 성공");
return "newspringhome_login";
}
}
2) Login : 커스텀 어노테이션 생성
package HJproject.Hellospring.argumentResolver;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
// 내가 만드는 사용자 정의 어노테이션
@Target(ElementType.PARAMETER) // 어떤 방식으로 적용할 건지? => 파라미터에 적용
@Retention(RetentionPolicy.RUNTIME) // 동작하는 시간? 동작하기까지 어노테이션이 살아있는 시간? => 즉 런타임까지 어노테이션 정보가 살아있음
public @interface Login {
}
3) LoginMemberArgumentResolver : HandlerMethodArgumentResolver 구현 클래스 생성
- 여기서는 parameter 메서드를 사용해서 내가 원하는 어노테이션이 붙어있는지, 해당 파라미터 안에 있는 값이 내가 원하는 타입인지 확인 후 로직 처리를 실행한다 ⇒ hasLoginAnno && isMemberType 부분
- 만약 두 가지 - hasLoginAnno && isMemberType - 가 모두 true 인 경우에만 resolveArgument 가 실행되며 이 안에서 HttpServletRequest 를 통해 확인했을 때 세션 정보가 있다면 해당 정보를 return 하고, 아니라면 null 을 return 한다.
package HJproject.Hellospring.argumentResolver;
import HJproject.Hellospring.Session.SessionConst;
import HJproject.Hellospring.domain.member.Member;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
@Slf4j
public class LoginMemberArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
log.info("############# LoginMemberArgumentResolver 실행 ############");
// hasParameterAnnotation 는 해당 메서드의 매개변수로 오는 어노테이션이 붙어있는지 여부를 반환
// 붙어있으면 true, 아니면 false
boolean hasLoginAnno = parameter.hasParameterAnnotation(Login.class);
// 파라미터의 클래스 타입이 isAssignableFrom 클래스와 매개변수에 해당하는 arameter.getParameterType() 가
// 동일한 클래스(타입)인지 여부 확인 => true, false
boolean isMemberType = Member.class.isAssignableFrom(parameter.getParameterType());
// hasLoginAnno 와 isMemberType 가 모두 true 일 때만 아래의 resolveArgument 가 실행됨
return hasLoginAnno && isMemberType;
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
log.info("############# resolveArgument 실행 ############");
// HttpServletRequest 를 가져와야함
HttpServletRequest req = (HttpServletRequest)webRequest.getNativeRequest();
// HttpServletRequest 에서 세션을 가져왔을 때 null 이면 그대로 null 을 return
HttpSession session = req.getSession();
if(session == null){
return null;
}
// 세션이 있다면 해당 세션의 내용을 return
return session.getAttribute(SessionConst.LOGIN_MEMBER);
}
}
4) Config : Config 파일에 ArgumentResolver 를 등록
- Config 클래스는 WebMvcConfigurer 를 구현한 구현 클래스여야 하며, addArgumentResolvers 를 어보라이드해서 ArgumentResolver 를 Bean 으로 등록 할 수 있다.
// ArgumentResolver 를 등록하기 위한 override
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(new LoginMemberArgumentResolver());
}
- 코드 확인
- Reference
'Java - Spring &&n SpringBoot' 카테고리의 다른 글
Spring - 예외 상황 처리 1) Servlet 예외 처리 : 404 error, 500 error (0) | 2022.08.19 |
---|---|
웹 네트워크 기본 공부 2) HTTP 알아보기 (0) | 2022.08.17 |
Spring - 스프링 인터셉터(3) 스프링 인터셉터 개념과 로그 남기기 (0) | 2022.08.13 |
Spring - 서블릿 필터 다루기(2) : 로그인 여부 체크, 로그인 여부에 따른 페이지 접근 (0) | 2022.08.12 |
Spring - 서블릿 필터와 스프링 인터셉터(1) 서블릿필터, 서블릿 필터를 사용한 로그 찍기 (0) | 2022.08.11 |
댓글