-
[Spring Boot] 2-6. Validation을 이용한 회원가입 구현 (jsp)프로젝트/도서 관리 시스템 2023. 7. 5. 20:53
검증 기능을 매번 코드로 작성하는 것은 상당히 번거롭다. 특히 특정 필드에 대한 검증 로직은 대부분 빈 값인지 아닌지, 특정 크기를 넘는지 아닌지와 같이 매우 일반적인 로직이다.
이런 검증 로직을 모든 프로젝트에 적용할 수 있게 공통화하고, 표준화한 것이 바로 Bean Validation이다. 이전 세션을 이용한 회원가입에서는 js 정규표현식을 이용해 유효성검사를 구현했었다. 이번엔 더 편리한 방법으로 유효성 검사를 진행해보려고 한다.
build.gradle에 아래 의존관계를 추가하면 라이버러리가 추가된다.
implementation 'org.springframework.boot:spring-boot-starter-validation
📑 검증 어노테이션 (domain)
package com.wish.library.security.domain; import lombok.*; import javax.validation.constraints.Digits; import javax.validation.constraints.NotBlank; import javax.validation.constraints.Pattern; import javax.validation.constraints.Size; import java.util.Date; @Getter @Setter @ToString @AllArgsConstructor @NoArgsConstructor //기본 생성자를 생성해준다. @Builder public class MemberSaveForm { @NotBlank(message = "아이디는 필수 입력 값입니다.") @Email(message = "이메일 형식이 올바르지 않습니다.") private String email; // 회원 아이디 @NotBlank(message = "비밀번호는 필수 입력 값입니다.") @Pattern(regexp = "(?=.*[0-9])(?=.*[a-zA-Z])(?=.*\\W)(?=\\S+$).{8,16}", message = "비밀번호는 8~16자 영문 대 소문자, 숫자, 특수문자를 사용하세요.") private String password; //비밀번호 @NotBlank(message = "이름은 필수 입력 값입니다.") @Pattern(regexp = "^[ㄱ-ㅎ가-힣a-z0-9-_]{2,20}$", message = "이름은 특수문자를 제외한 2~20자리여야 합니다.") private String name; @NotBlank(message = "닉네임은 필수 입력 값입니다.") @Pattern(regexp = "^[ㄱ-ㅎ가-힣a-z0-9-_]{2,30}$", message = "닉네임은 특수문자를 제외한 2~10자리여야 합니다.") private String nickname; private Sex mfCode; //성별 (men, female) @NotBlank(message = "핸드폰 번호는 필수 입력 값입니다.") @Pattern(regexp = "^[0-9]*$", message = "정수만 가능") @Size(min = 9, max = 11, message = "전화번호 길이에 부합해야함.") private String cellNo; }
📌 NotBlank : 빈값 + 공백만 있는 경우를 허용하지 않는다.
📌 NotNull : null을 허용하지 않는다.
📌 Pattern : 문자열이 지정한 패턴에 일치하는지 검사한다.
📌 Size : min부터 max 사이에 있는지 검사한다. 값이 null인 경우 유효한 것으로 판단한다.
📌 Email : 값이 email 주소인지 검사
📑 Controller 수정
package com.wish.library.security.controller; import com.wish.library.security.domain.MemberSaveForm; import com.wish.library.security.domain.UserDTO; import com.wish.library.security.service.CustomUserService; import com.wish.library.security.service.MemberService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; 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.annotation.*; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.support.RedirectAttributes; /** * GET 방식, 화면 조회시 */ @Controller @RequiredArgsConstructor @Slf4j public class UserController { private final CustomUserService customUserService; private final MemberService memberService; @GetMapping("/join") public String join(){ return "join"; } @PostMapping("/join") public String join(@Validated @ModelAttribute("memberSaveForm") MemberSaveForm memberSaveForm , BindingResult bindingResult , RedirectAttributes rttr) { log.info("=================join Controller"); if(bindingResult.hasErrors()){ log.info("errors={}", bindingResult); return "join"; } boolean saveResult = memberService.save(memberSaveForm); if(saveResult){ rttr.addFlashAttribute("result", "회원 가입 완료"); return "redirect:/login"; } return "join"; } }
스프링 부트가 spring-boot-starter-validation 라이브러리를 넣으면 자동으로 Bean Validator를 인지하고 스프링에 통합한다. 따라서 컨트롤러 객체 앞에 @Valid, @Validated만 적용해주면 된다.
@Validated는 반드시 BindingResult 앞에 적어준다. 만약 bindingResult에 에러값이 있는 경우 log를 출력하고 다시 join 페이지로 이동한다.
📑 join.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %> <!doctype html> <html lang="en" data-bs-theme="auto"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="description" content=""> <meta name="author" content="Mark Otto, Jacob Thornton, and Bootstrap contributors"> <meta name="generator" content="Hugo 0.111.3"> <meta name="_csrf" content="${_csrf.token}"/> <meta name="_csrf_header" content="${_csrf.headerName}"/> <title>회원가입</title> <link rel="canonical" href="https://getbootstrap.com/docs/5.3/examples/sign-in/"> <link href="assets/dist/css/sign-in.css" rel="stylesheet"> <jsp:include page="./includes/common_includes.jsp"></jsp:include> <%-- <script type="text/javascript" src="assets/dist/js/commonAjax.js"></script> <script type="text/javascript" src="assets/dist/js/member.js"></script>--%> <style> @media (min-width: 768px) { .bd-placeholder-img-lg { font-size: 3.5rem; } } .nav-scroller .nav { display: flex; flex-wrap: nowrap; padding-bottom: 1rem; margin-top: -1px; overflow-x: auto; text-align: center; white-space: nowrap; -webkit-overflow-scrolling: touch; } </style> </head> <script> </script> <body class="text-center"> <main class="form-signin w-100 m-auto"> <form:form name="join_form" action="/join" method="post" modelAttribute="memberSaveForm"> <%--<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />--%> <img class="mb-4" src="assets/brand/bootstrap-logo.svg" alt="" width="72" height="57" onclick="location.href='/'"> <h1 class="h3 mb-3 fw-normal">Please join in</h1> <div class="form-floating"> <input type="email" class="form-control" name="email" id="email" placeholder="name@example.com"> <label for="email">Email address</label><%--<button class="btn btn-light rounded-pill px-3" type="button" name="btn" id="btnEmailCheck">Duplicate check</button>--%> <%--<span id="id-check"></span>--%> <span class="text-danger"><form:errors path="email" /></span> </div> <div class="form-floating"> <input type="password" class="form-control" name="password" id="password" placeholder="Password" autoComplete="off"> <label for="password">Password</label> <span class="text-danger"><form:errors path="password" /></span> </div> <div class="form-floating"> <input type="text" class="form-control" name="name" id="name" placeholder="name"> <label for="name">name</label> <span class="text-danger"><form:errors path="name" /></span> </div> <div class="form-floating"> <input type="text" class="form-control" name="nickname" id="nickname" placeholder="nickname"> <label for="nickname">nickname</label> <%--<button class="btn btn-light rounded-pill px-3" type="button" name="btn" id="btnNicknameCheck">Duplicate check</button>--%> <%--<span id="nickname-check"></span>--%> <span class="text-danger"><form:errors path="nickname" /></span> </div> <div class="form-floating"> <div class="form-check"> <input id="men" name="mfCode" value="MEN" type="radio" class="form-check-input" checked> <label class="form-check-label" for="men">Men</label> </div> <div class="form-check"> <input id="female" name="mfCode" value="FEMALE" type="radio" class="form-check-input"> <label class="form-check-label" for="female">Female</label> </div> </div> <div class="form-floating"> <input type="text" class="form-control" name="cellNo" id="cellNo" placeholder="cellNo"> <label for="cellNo">cellNo</label> <span class="text-danger"><form:errors path="cellNo" /></span> </div> <button class="w-50 btn btn-lg btn-dark" type="button" onclick="history.back();" >이전페이지로가기</button> <%--<button class="w-50 btn btn-lg btn-primary" type="button" name="btn" id="btnSingUp" >Sign up</button>--%> <button type="submit" class="w-50 btn btn-lg btn-primary">Sign up</button> </form:form> </main> </body> </html>
jsp 페이지에서 중요한 점은 다음과 같다.
1. <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %> 추가
2. <form:form name="join_form" action="/join" method="post" modelAttribute="memberSaveForm">
form 태그 형식을 다음과 같이 수정한다. 마지막에 modelAttribute에서 지정한 객체의 이름을 입력해줘야한다.
3. <span class="text-danger"><form:errors path="email" /></span> 출력할 에러 메시지 태그를 요소 입력값 아래 위치한다.출력 결과는 아래와 같다. 간단하게 끝!!
반응형'프로젝트 > 도서 관리 시스템' 카테고리의 다른 글
[Spring Boot] 2-7. Validation 회원가입 중복 체크 (0) 2023.07.17 [Spring Boot] 2-5. 스프링 시큐리티, 로그인 실패시 메시지 출력 (0) 2023.07.05 [Spring Boot] 2-4. 스프링 시큐리티, 회원 가입 구현하기 (0) 2023.07.05 [Spring Boot] 2-3. 스프링 시큐리티, 로그인/로그아웃 구현 (0) 2023.07.05 [Spring Boot] 2-2. 세션을 사용하는 회원 가입, 회원 정보 수정 (1) 2023.06.19