전 시간에 Controller에서 Session을 가져오는 데 있어서 중복 코드가 있었습니다. 해당 코드를 ArgumentResolver로 해결해보겠습니다. 

 

ArgumentResolver란? 

컨트롤러의 메소드의 인자로 사용자가 임의의 값을 전달하는 방법을 제공할 때 사용합니다. 저희가 활용할 부분은 세션에 저장되어 있는 것을 메소드의 파라미터로 넘겨주는 역할을 하게 됩니다.


1. argumentresolver 패키지 먼저 만듭니다. 

SessionConst와 SessionDto를 사용하므로 Dto에 있던 것을 옮겨줍니다.

2. ArgumentResolver에 사용될 LoginUser Annotation만들기

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface LoginUser {
}
  • @Target: Annotation을 사용할 수 있는 곳을 정의합니다. Class, Parameter,Method,Field 등등 여러 가지 있습니다.
  • @Retention: Annotation의 설정으로 Annotation의 라이프 사이클을 정의합니다. Source, Class, Runtime이 있습니다. 보통 Runtime을 사용하여 프로젝트가 실행 중에도 사용할 수 있도록 Annotation의 라이프 사이클을 정해줍니다. 

3. ArgumentResolver

public class ArgumentResolver implements HandlerMethodArgumentResolver {

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        parameter.hasParameterAnnotation(LoginUser.class);
        boolean hasLoginAnnotation = parameter.hasParameterAnnotation(LoginUser.class);
        boolean hasOwnerType = SessionDto.class.isAssignableFrom(parameter.getParameterType());

        return hasLoginAnnotation && hasOwnerType;
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest();
        HttpSession session = request.getSession(false);
        if(session==null){
            return null;
        }
        return session.getAttribute(SessionConst.LOGIN_MEMBER);
    }
}

 

  • supportsParameter: 우리가 받고자 파라미터가 조건을 만족하는지 확인합니다. 조건을 만족시키지 못할 시 false를 반환하며, resolveArgument()를 실행하지 않습니다.

     1. @LoginUser Annotation이 붙었는지 확인합니다. 

     2. 정보를 넣고자 하는 SessionDto 클래스인지 확인합니다. 

 

  • resolveArgument: supportsParameter에서 true가 넘어올 시 실행됩니다.

     1. NativeWebRequest를 HttpServletRequest로 형변환 합니다.

     2. request.getSession(false)로 하여 session이 없다면 생성하지 않습니다. 

     3. session이 있다면 로그인을 기존에 한 user이므로 session.getAttribute(SessionConst.LOGIN_MEMBER)를 실행하여 SessionDto에 정보를 넣어주는 역할을 하게 됩니다.

 

4. MVC에서 사용할 수 있도록 WebConfig에 등록해줍니다.

 패키지와 WebConfig를 생성해줍니다. 

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        resolvers.add(new ArgumentResolver());
    }
}
  • WebMvcConfigurer를 상속받고, addArugmentResolvers를 Override 하여 저희가 만든 ArgumentResolver를 추가해줍니다. 

5. MemberController변경

@RestController
@RequiredArgsConstructor
@RequestMapping("/member")
public class MemberController {
    private final MemberService memberService;

    @PostMapping("/request/{teamId}")
    public Long requestTeam(@PathVariable(name = "teamId")Long teamId,@LoginUser SessionDto sessionUser){
        Long okId = memberService.requestTeam(teamId,sessionUser.getId());
        return okId;
    }

    @GetMapping("/request")
    public List<RequestTeamDto> requestList(@LoginUser SessionDto sessionUser){
        return memberService.findRequestList(sessionUser.getId());
    }

    @DeleteMapping("/request/{teamId}")
    public String deleteRequest(@PathVariable(name = "teamId") Long teamId,@LoginUser SessionDto sessionUser){
        memberService.WithdrawalTeamRequest(sessionUser.getId(),teamId);
        return "ok";
    }

    @DeleteMapping("/request")
    public String leavingTeam(@LoginUser SessionDto sessionUser){
        memberService.leavingTeam(sessionUser.getId());
        return "ok";
    }
}

6. Postman을 이용해서 테스트해보겠습니다.

 

회원 가입을 진행해줍니다.

로그인을 하기 전에는 Session이 없기 때문에 Cookies에 아무런 내용이 없습니다. 

로그인 요청을 보낸 후 성공했습니다. 그리고 Session이 생성된 것을 알 수 있습니다.

 

ArgumentResolver가 잘 작동하는지 알아보기 위해서 Member가 팀 가입 신청한 리스트를 찾는 로직을 실행합니다. Team이 아직 생성되지 않아도 가능하므로 잘 작동한다면 [] 비어있는 List를 받으며 

  1. Get localhost/member/request 요청 보냅니다.
  2. Team이 아직 생성되지 않아도 가능하므로 잘 작동한다면 [] 비어있는 List를 받습니다.
  3. 작동하지 않는다면 Member를 찾을 수 없는 오류를 터뜨릴 것입니다.

ArgumentResolver가 잘 작동하여 빈 List를 받은 것을 확인할 수 있습니다. 

 

지금까지 Annotation을 활용한 ArgumentResolver를 만들어봤습니다. 저희는 로그인만 성공하면 Member에 관한 모든 로직을 사용할 수 있는 형태였습니다. 하지만 TeamFounder나 LeagueHost의 역할을 가진 다른 User는 사용하지 못하도록 Interceptor를 만들어보겠습니다. 감사합니다. 

 

모든 코드는 아래 링크에서 확인 가능합니다.

https://github.com/rlaehdals/blogProject

 

GitHub - rlaehdals/blogProject

Contribute to rlaehdals/blogProject development by creating an account on GitHub.

github.com