강의

멘토링

커뮤니티

인프런 커뮤니티 질문&답변

김철준님의 프로필 이미지
김철준

작성한 질문수

스프링 MVC 2편 - 백엔드 웹 개발 활용 기술

Validator 분리2

InitBinder 질문드립니다.

해결된 질문

작성

·

108

0

학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.

1. 강의 내용과 관련된 질문을 남겨주세요.
2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.
(자주 하는 질문 링크: https://bit.ly/3fX6ygx)
3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.
(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)

질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.
=========================================
[질문 템플릿]
1. 강의 내용과 관련된 질문인가요? 예
2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예
3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예

[질문 내용]

복습겸 개인 프로젝트를 하고 있는데요, 로그인과 회원가입을 각각 검증기를 넣어주려고 하는데, 두 가지 검증기를 넣으니 다른 한 쪽에서는 오류가 발생합니다. 예를 들어, 로그인 페이지에 들어갈 경우에는

 

java.lang.IllegalStateException: Invalid target for Validator [com.weblibrary.domain.user.validation.JoinValidator@135416b2]: LoginUserDto(username=null, password=null)

 

이런 식입니다. supports에 해당하지 않으면 무시하는 게 아니라, 예외가 발생하는 걸까요? 이런 경우 어떻게 해결하는 게 좋을까요?

 

package com.weblibrary.domain.user.controller;

import com.weblibrary.domain.user.model.JoinUserDto;
import com.weblibrary.domain.user.model.LoginUserDto;
import com.weblibrary.domain.user.model.User;
import com.weblibrary.domain.user.service.UserService;
import com.weblibrary.domain.user.validation.JoinValidator;
import com.weblibrary.domain.user.validation.LoginValidator;
import jakarta.servlet.http.HttpSession;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;

/**
 * 유저 회원가입 컨트롤러, GET, POST에 따라 다르게 동작.
 */
@Controller
@RequiredArgsConstructor
@Slf4j
public class AccountController {

    private final UserService userService;
    private final LoginValidator loginValidator;
    private final JoinValidator joinValidator;

    @InitBinder
    public void initLoginBinder(WebDataBinder dataBinder) {
        dataBinder.addValidators(loginValidator);
        dataBinder.addValidators(joinValidator);
    }

    /* join form 보여주기 */
    @GetMapping("/join")
    public String joinForm(Model model) {
        model.addAttribute("user", new JoinUserDto());
        return "home/join";
    }

    /* 회원가입 처리하기 */
    @PostMapping("/join")
    public String join(@Validated @ModelAttribute("user") JoinUserDto user, BindingResult bindingResult) {

        log.debug("objectName={}", bindingResult.getObjectName());
        log.debug("target={}", bindingResult.getTarget());

        log.debug("Input User DTO: {}", user);

        if (bindingResult.hasErrors()) {
            log.debug("errors={}", bindingResult);
            return "home/join";
        }

        // 회원가입 후에 홈으로 리다이렉트
        return "redirect:/";
    }

    @GetMapping("/login")
    public String loginForm(Model model) {
        model.addAttribute("user", new LoginUserDto());
        return "home/login";
    }

    /* 로그인 처리하기 */
    @PostMapping("/login")
    public String login(@Validated @ModelAttribute("user") LoginUserDto user, BindingResult bindingResult) {

        log.debug("objectName={}", bindingResult.getObjectName()); // loginUserDto로 나오고 있었다. @ModelAttribute("user")로 해결
        log.debug("target={}", bindingResult.getTarget()); // 정상적으로 LoginUserDto 인스턴스를 찾아옴.

        log.debug("Input User DTO: {}", user);

        if (bindingResult.hasErrors()) {
            log.debug("errors={}", bindingResult);
            return "home/login";
        }

        // 로그인 후에 홈으로 리다이렉트

        return "redirect:/";

    }

    @PostMapping("/signout")
    public ResponseEntity<String> signOut(HttpSession session) {

        User user = (User) session.getAttribute("user");

        log.debug("login user={}", user);

        if (user == null) {
            return new ResponseEntity<>("로그인되지 않았습니다.", HttpStatus.FORBIDDEN);
        }

        session.setAttribute("user", null);

        return new ResponseEntity<>("로그아웃 되었습니다.", HttpStatus.OK);
    }

}

답변 2

1

김영한님의 프로필 이미지
김영한
지식공유자

안녕하세요. 김철준님

다음을 참고해주세요.

https://www.inflearn.com/community/questions/280541

감사합니다.

0

안녕하세요, 인프런 AI 인턴입니다.

김철준님, 올려주신 예외는 특정 Validator가 해당 객체 타입에 대해 예외를 던지는 경우에 발생할 수 있습니다. 모든 Validator의 supports() 메서드는 해당 Validator가 유효성을 검사할 수 있는 객체 타입을 명확히 지정해야 합니다. InitBinder 메서드에서 여러 Validator를 등록할 경우, 각 Validator의 supports() 메서드가 호출되어 특정 객체에 대해 실행 가능 여부를 판단하게 됩니다.

로그인과 회원가입에 각각 다른 DTO를 사용하시기 때문에, 각 Validator의 supports() 메서드가 DTO 타입에 대해 올바르게 설정되었는지 확인해보세요. 예를 들어, JoinValidatorJoinUserDto만, LoginValidatorLoginUserDto만 지원해야 합니다.

JoinValidator의 예시:

@Override
public boolean supports(Class<?> clazz) {
    return JoinUserDto.class.isAssignableFrom(clazz);
}

LoginValidator의 예시:

@Override
public boolean supports(Class<?> clazz) {
    return LoginUserDto.class.isAssignableFrom(clazz);
}

이렇게 설정되면, Spring MVC는 각 DTO에 대해 적절한 Validator를 연결하여 사용하게 됩니다. 이렇게 적절하게 설정하시면 예외 상황 없이 각 페이지에서 객체를 검증할 수 있습니다. 추가로 InitBinder 설정을 각 컨트롤러 메서드에 따라 분리하여 사용해볼 수도 있습니다.

문제가 해결되길 바랍니다. 추가적인 질문이 있으시면 언제든지 말씀해 주세요. 감사합니다!

내용과 관련된 정보를 확인하시려면 여기 링크를 참고해주세요.

김철준님의 프로필 이미지
김철준

작성한 질문수

질문하기