스프링 부트로 블로그 서비스 개발하기

회원가입 기능 - 컨트롤러단 인풋 검증

exena 2025. 11. 27. 01:56

로그인과 회원가입 화면 html(타임리프) 파일을 만들어서 resources에 넣어주고 컨트롤러를 만들어서 연결시켜주자.

스프링 시큐리티의 필터체인에서 회원가입 url은 permitAll에 넣어줘야 한다.

@Controller
@RequiredArgsConstructor
@RequestMapping("/member")
public class MemberPage {
    private final MemberRegister memberRegister;

    @GetMapping("/login")
    public String login(){
        return "member/login";
    }

    @GetMapping("/register")
    public String register(Model model){
        // record의 경우 불변 객체이기 때문에 빈 생성자는 불가능하지만 빌더를 쓰면 빈 생성자와 같은 효과를 낼 수 있다.
        // 대신 NonNullApi에 위배된다.
        model.addAttribute("registerRequest", new MemberRegisterRequest());
        return "member/register";
    }

    @PostMapping("/register")
    public String register(@Validated @ModelAttribute("registerRequest") MemberRegisterRequest request,
                           BindingResult bindingResult){
        if(bindingResult.hasErrors()){
            return "/member/register";
        }
        memberRegister.register(request);
        return "redirect:/";
    }
}

컨트롤러는 이렇다. 이전에 JSON으로 요청받고 응답하는 API 컨트롤러와는 별개의 클래스로 만들었다.

일단 로그인 화면을 띄우는 GET "/member/login" 맵핑. 너무 단순해서 설명할 게 없다.

POST "/member/login" 요청을 받는 부분은 구현하지 않아도 스프링 시큐리티가 알아서 해준다.

회원가입 화면을 띄우는 부분에서 model에 가입 요청 DTO를 담는 것을 볼 수 있다.

이후 해당 요청을 받는 부분에서 @ModelAttribute로 해당 DTO를 받는다.

 

인풋 검증의 결과는 BindingResult 패러미터에 담긴다.

 

DTO를 받는 패러미터 앞에 @Valid가 붙어있다. 즉, 인풋 검증은 DTO의 어노테이션이 수행한다.

만약 에러가 있다면 첫번째 if문에서 /member/register.html 을 띄운다. 가입 요청 DTO는 @ModelAttribute가 붙어있기에 모델에 자동으로 들어간다. BindingResult도 모델에 같이 들어간다.

에러가 없다면 홈 화면으로 리다이렉트한다.

프론트엔드단은 코드를 따로 적지는 않겠다. 나는 인풋 검증에서 걸린 경우 타임리프의 th:errors를 써서  BindingResult에 담긴 에러 메시지가 나타나도록 하였다.

회원가입 화면으로 들어가보자. 위에서 말했다시피 스프링 시큐리티에서 열어놔야 한다.
이렇게 써서 회원가입 요청을 보내보자.

회원가입에 실패하고 메시지가 출력되는 것을 볼 수 있다. 이메일 형식에 맞지 않는다는 듯 하다.

이는 이전에 만든 가입 신청 DTO에 @Email 어노테이션을 붙여놨기 때문이다.

이 이외에도 여러가지 검증용 어노테이션이 제공된다. 이를 써서 인풋 검증을 철저하게 하도록 하자.

 

추가)

서비스 단에서도 인풋 검증을 할 수 있다. 컨트롤러에서 검증한걸 또 검증하냐고 생각할 수 있지만 어플리케이션 단이 방어막 역할을 해주는 것이 좋다.

public interface MemberRegister {
    Member register(@Valid MemberRegisterRequest registerRequest);
}

회원 등록 인터페이스의 DTO 패러미터를 받는 부분에 @Valid를 넣어주고 이 인터페이스를 상속받는 서비스 클래스에 @Validated를 붙여주면 된다.