본문 바로가기
공부/프로그래밍

[springboot] 자주쓰는 정보 파라미터에 설정해 자동 주입하여 받기(resolver 사용)

by demonic_ 2021. 1. 11.
반응형

Spring Security Oauth2 를 이용해 로그인을 할 경우, Principal를 이용해 name을 조회할 수 있는데, 여기서 한단계 더 나아가 유저정보를 가지고 있어야 할때가 있다.

 

이럴때 아마 principal.getName()을 이용해 유저정보를 조회한 후 회원정보를 불러올 것이다.

...
    public String testUser(Principal principal) {
        User findUser = loginMapper.findUserInfoByUserEmail(principal.getName());
        ...
    }
...

 

아마 로그인을 이용한 정보는 거의 대부분의 비지니스 로직에서 쓸텐데 그렇다면 위 코드를 매번 삽입해야 한다. 이부분을 생략하고자 설정하는 것이다.

 

일전에 AOP를 이용해 어노테이션으로 설정, 조회하도록 했는데 매 메서드마다 어노테이션을 설정하는 것도 귀찮아 Resolver를 추가하게 되었다.

 

이전글:

lemontia.tistory.com/940

 

[springboot, aop] 반복적인 작업은 이제 그만, AOP로 해결하기

특정 정보의 코드나 key를 통해 value값을 로드해야 할때, 매번 코드마다 똑같은 코드를 복사하는 것도 꽤나 힘든 작업이다. 스프링을 사용하면 AOP를 이용해 한번에 해결이 가능하다. ​ 실제로 최

lemontia.tistory.com

 

 

그럼 이제 시작해보자.

 

우선 구현하는 방법은 파라미터 내용중 특정 클래스가 있으면 체크하도록 한다.

예를들어 이런 클래스를 추가한다.

@Getter
@ToString
@AllArgsConstructor
public class UserDto {
    private Long userNo;
    private String userEmail;
}

 

그리고 위 클래스가 등록된 Parameter의 경우만 가로채 데이터를 삽입한다. 다음같은 경우가 그렇다.

...
    @GetMapping("/test/user/resolver")
    @ResponseBody
    public String testUserResolver(UserDto userDto) {
        System.out.println("userDto = " + userDto);
        return userDto.getUserEmail();
    }
...

 

WebMvcConfigurer를 구현한 WebConfig 라는 파일을 만든다. 이 파일에서 Resolver를 등록할 수 있다.

@Configuration
@RequiredArgsConstructor
public class WebConfig implements WebMvcConfigurer {
    private final LoginMapper loginMapper;
    
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        resolvers.add(new CustomUserResolver(loginMapper));
    }
}

 

addArgumentResolvers를 오버라이드 하여 구현한다. CustomUserResolver를 resolver에 추가등록한다.

 

LoginMapper 는 로그인을 조회하기 위한 Mapper 역할을 한다. JPA로 구성되어 있다면 Repository를 주입받으면 된다. 여기서 주입받는 이유는 CustomUserResolver에서 실질적으로 수행할건데, 해당 클래스는 빈으로 등록할 것이 아니기 때문이다.

 

그럼 이제 CustomUserResolver 구현체를 만든다.

public class CustomUserResolver implements HandlerMethodArgumentResolver {
    private final LoginMapper loginMapper;

    public CustomUserResolver(LoginMapper loginMapper) {
        this.loginMapper = loginMapper;
    }

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        // userDto 가 파라미터에 포함되어 있는지 체크하여 true를 리턴한다.
        if(parameter.getParameterType() == UserDto.class){
            return true;
        }
        return false;
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        // 인증된 정보를 가져와 getName() 을 호출한다. 여기서 호출은 principal.getName() 과 동일하다
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        String email = authentication.getName();
        // username 을 이용해 정보를 조회한다.(여기서는 email이 username 이다)
        User findUser = loginMapper.findUserInfoByUserEmail(email);
        // 조회한 정보를 UserDto에 담은 후 리턴한다
        UserDto userDto = new UserDto(findUser.userNo(), findUser.getEmail());

        return userDto;
    }
}

 

이제 설정이 끝났다. 그럼 이전에 등록한 컨트롤러인 /test/user/resolver 를 호출한 후 로그를 확인해보자

...
    @GetMapping("/test/user/resolver")
    @ResponseBody
    public String testUserResolver(UserDto userDto) {
        System.out.println("userDto = " + userDto);
        return userDto.getUserEmail();
    }
...
userDto = userDto(userNo=1, userEmail=test@test.com)

의도한대로 잘 나온다.

 

 

끝.

 

반응형

댓글