인프런 영문 브랜드 로고
인프런 영문 브랜드 로고

Inflearn Community Q&A

ehdusdl3012555's profile image
ehdusdl3012555

asked

Spring MVC Part 2 - Backend Web Development Utilization Technology

Spring Interceptor - Request Log

인터셉처 2개 적용하기

Written on

·

374

1

안녕하세요!!!!

제목 그대로 인터셉터를 2개 등록해서 사용하려고 했더니

Error creating bean with name 'memberApiController' defined in file [/Users/gimnayeon/Desktop/GreenProject/GrinGreen/out/production/classes/com/grin/GrinGreen/api/MemberApiController.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'memberService': Unsatisfied dependency expressed through field 'passwordEncoder'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'webSecurityConfig': Unsatisfied dependency expressed through method 'setContentNegotationStrategy' parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration$EnableWebMvcConfiguration': Unsatisfied dependency expressed through method 'setConfigurers' parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'webConfig' defined in file [/Users/gimnayeon/Desktop/GreenProject/GrinGreen/out/production/classes/com/grin/GrinGreen/login/WebConfig.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'loginService': Unsatisfied dependency expressed through field 'passwordEncoder'; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'getPasswordEncoder': Requested bean is currently in creation: Is there an unresolvable circular reference?

위와 같은 오류가 발생합니다.

상황을 대략 적자면

  1. 1번 인터셉터로 로그인 제외 url을 설정

  2. 2번 인터셉터로 api 작동 전 로그인 후 세션 주입

이렇게 처리를 하려고 하는데 @Autowired 문제일까요?

구글링을 해보려고 했으니 지금 티스토리 등이 정상적으로 열리지 않아 이렇게 질문 남깁니다ㅠ.ㅠ

MemberApiController

@Slf4j
@RequiredArgsConstructor
@RequestMapping("/api")
@RestController
public class MemberApiController {

    private final MemberService memberService;
    private final LoginService loginService;

    /** 회원 등록 API **/
    @PostMapping("/members")
    public CreateMemberResponse saveMember(@RequestBody @Valid
                                               CreateMemberRequest request) {
        Member member = new Member();
        member.setNickname(request.nickname);
        member.setMail(request.mail);
        member.setPassword(request.password);
        member.setMember_type(request.member_type);
        member.setMember_status(request.member_status);
        member.setHint_password(request.hint_password);
        member.setAnswer_password(request.answer_password);
        member.setUpdated_at(now());
        member.setCreated_at(now());

        String mail = memberService.join(member);
        return new CreateMemberResponse(mail);

    }

    /** 회원 수정 API **/
    @PutMapping("/members/{mail}/edit")
    public UpdateMemberResponse updateMember(@PathVariable ("mail") String mail,
                                             @RequestBody @Valid UpdateMemberRequest request) {
        memberService.update(mail, request.getNickname(), request.getAnswer_password());
        Member findMember = memberService.findOne(mail);
        return new UpdateMemberResponse(findMember.getNickname(), findMember.getMail(),
                findMember.getHint_password(), findMember.getAnswer_password());
    }
    /** 회원 탈퇴 API **/
    @PutMapping("/members/{mail}/delete")
    public DeleteMemberResponse deleteMember(@PathVariable ("mail") String mail,
                                            @RequestBody @Valid DeleteMemberRequest request) {
        Member member = memberService.findOne(mail);
        memberService.delete(mail, request.getPassword());
        return new DeleteMemberResponse(member.getMail(), member.getMember_status());
    }

    /** 회원 로그인 API **/
    @PostMapping("/login")
    public LoginMemberResponse loginMember(@RequestBody @Valid LoginMemberRequest request) {
        Member login = loginService.login(request.getMail(), request.getPassword());
        return new LoginMemberResponse(login.getMail());
    }

MemberService

@Slf4j
@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class MemberService {

    @Autowired
    private final MemberRepository memberRepository;

    @Autowired
    private PasswordEncoder passwordEncoder;

    /** 회원가입 **/
    @Transactional
    public String join(Member member){
        //비밀번호 암호화 후 레포지토리에 넘기기
        String encodedPassword = passwordEncoder.encode(member.getPassword());
        member.setPassword(encodedPassword);

        validateDuplicateMember(member);//중복회원검증
        memberRepository.save(member);
        return member.getMail();
    }

    /** 중복회원검증 **/
    private void validateDuplicateMember(Member member) {
        List<Member> findMembers = memberRepository.findByMail(member.getMail());
        if (!findMembers.isEmpty()){
            throw new IllegalStateException("이미 존재하는 회원입니다");
        }
    }

    private void validateDuplicateNickname(Member member) {
        Member findMembers = memberRepository.findOndByMail(member.getMail());
        if (!findMembers.getNickname().equals(member.getNickname())){
            throw new IllegalStateException("이미 존재하는 회원입니다");
        }
    }

    /** 회원전체조회 **/
    public List<Member> findMembers(){
        return memberRepository.findAll();
    }

    public Member findOne(String mail) {
        return memberRepository.findOndByMail(mail);
    }

    /** 회원 수정 **/
    @Transactional
    public void update(String mail, String nickname, String answer_password){

        Member member = memberRepository.findOndByMail(mail);
        if(nickname.equals(member.getNickname())) {
            validateDuplicateNickname(member);
        }
        member.setNickname(nickname);
        member.setAnswer_password(answer_password);
        member.setUpdated_at(now());

    }

    /** 회원 탈퇴 **/
    @Transactional
    public String delete(String mail, String password){
        Member findUser = memberRepository.findOndByMail(mail);

        if(!passwordEncoder.matches(password,findUser.getPassword())){
            //throw new IllegalStateException("비밀번호가 맞지 않습니다.");
            System.out.println("암호 실패");
            return null;
        }
        findUser.setUpdated_at(now());
        findUser.setMember_status("D");

        return findUser.getPassword();
    }
}

LoginService

@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class LoginService {

    @Autowired
    private final MemberRepository memberRepository;

    @Autowired
    private PasswordEncoder passwordEncoder;

    public Member findOne(String mail){ return memberRepository.findOndByMail(mail);}

    /** 로그인 **/
    @Transactional
    //public String login(Member member){
    public Member login(String mail, String password){

        List<Member> findMember = memberRepository.findByMail(mail);
        Member findUser = memberRepository.findOndByMail(mail);

        if (findMember==null){
            //throw new IllegalStateException("해당 이메일의 유저가 존재하지 않습니다.");
            //System.out.println("이메일 실패");
            return null;
        }

        if(!passwordEncoder.matches(password,findUser.getPassword())){
            //throw new IllegalStateException("비밀번호가 맞지 않습니다.");
            return null;
        }
        System.out.println("로그인 완료 :"+findUser.getNickname());

        //세션 표시를 위해 닉네임값 넘기기
        return findUser;
    }

    /** 비밀번호 매치 **/
    @Transactional
    public String passwordMatches(Member member){
        Member findUser = memberRepository.findOndByMail(member.getMail());

        if(!passwordEncoder.matches(member.getPassword(),findUser.getPassword())){
            //throw new IllegalStateException("비밀번호가 맞지 않습니다.");
            System.out.println("암호 실패");
            return null;
        }

        return findUser.getPassword();
    }

    /** 비밀번호 변경 **/
    @Transactional
    public void updatePassword(String mail, String editPassword){

        Member member = memberRepository.findOndByMail(mail);

        if (editPassword.equals(member.getPassword())) {
            throw new IllegalStateException("이전 비밀번호와 동일합니다.");
        }

        member.setPassword(editPassword);
        member.setUpdated_at(now());
    }
}

WebConfig

@Configuration
@RequiredArgsConstructor
public class WebConfig implements WebMvcConfigurer {

    private final LoginService loginService;

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        resolvers.add(new LoginMemberArgumentResolver());
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginCheckInterceptor())
                .order(1)
                .addPathPatterns("/**")
                .excludePathPatterns("/", "/members/new",
                        //"/login", "/logout", "/css/**", "/*.ico", "/error", "/api/**");
                        "/login", "/logout", "/css/**", "/*.ico", "/error");
        registry.addInterceptor(new ApiLoginCheckInterceptor(loginService))
                .order(2)
                .addPathPatterns("/api/business")
                .excludePathPatterns("/api/members/**");

    }

}

ApiLoginCheckInterceptor

public class ApiLoginCheckInterceptor implements HandlerInterceptor {
    private final LoginService loginService;

    public ApiLoginCheckInterceptor(LoginService loginService) {
        this.loginService = loginService;
    }


    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        Member loginMember = loginService.login("test2@test.com", "test1234!");
        HttpSession session = request.getSession();
        session.setAttribute(SessionConst.LOGIN_MEMBER, loginMember);

        return true;
    }
}

 

springMVC

Answer 1

0

안녕하세요. 김도연님, 공식 서포터즈 David입니다.

코드로는 안 올려주셨는데 스프링 시큐리티를 사용중이신 걸로 보입니다.

시큐리티 설정 클래스, PasswordEncoder 클래스 등과 관련된 의존관계 주입이 순환참조 형태를 띄고 있는 건 아닌지 확인해주세요.

감사합니다.

ehdusdl3012555님의 프로필 이미지
ehdusdl3012555
Questioner

안녕하세요!

PasswordEncoder 의존 주입에 static을 붙이니 해결 됐습니다. 감사합니다!!!

혹시 이유를 알 수 있을까요?

코드 전체를 볼 수 없어서 이유를 알려드리기 어렵네요^^;;

ehdusdl3012555's profile image
ehdusdl3012555

asked

Ask a question