[SpringBoot] 회원가입 기능시 필요한 @Valid / @ControllerAdvice (예외처리, 유효성 검사 설정)
회원가입을 진행할 시에 처리해야 하는 유효성 검사와 예외처리들이 있다.
기본적으로 체크가 필요한 사항은
- 가입시 ID의 길이 제한
- ID 중복 여부 체크
가 있다.
만일 위에 2가지의 요구사항이 있을 경우 ID 길이 체크는 DB를 다녀가지 않아도 체크가 가능한 사항이다. 따라서 Spring에서 제공하는 Valid와 Validation을 통하여 사용자에서 넘어오는 값들의 유효성을 체크할 수 있다.
Spring Validation 을 활용한 유효성 검사
1. 디펜던시 추가
기존에는 boot에 기본적으로 가지고 있었으나 최근에는 따로 디펜던시를 잡아줘야한다고 한다.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<version>2.4.4</version>
</dependency>
2. 제약조건을 설정할 DTO 객체 클래스에 validation 어노테이션 설정
어노테이션 종류
Anotation | 제약조건 |
@NotNull | Null 불가 |
@Null | Null만 입력 가능 |
@NotEmpty | Null, 빈 문자열 불가 |
@NotBlank | Null, 빈 문자열, 스페이스만 있는 문자열 불가 |
@Size(min=,max=) | 문자열, 배열등의 크기가 만족하는가? |
@Pattern(regex=) | 정규식을 만족하는가? |
@Max(숫자) | 지정 값 이하인가? |
@Min(숫자) | 지정 값 이상인가 |
@Future | 현재 보다 미래인가? |
@Past | 현재 보다 과거인가? |
@Positive | 양수만 가능 |
@PositiveOrZero | 양수와 0만 가능 |
@Negative | 음수만 가능 |
@NegativeOrZero | 음수와 0만 가능 |
이메일 형식만 가능 | |
@Digits(integer=, fraction = ) | 대상 수가 지정된 정수와 소수 자리 수 보다 작은가? |
@DecimalMax(value=) | 지정된 값(실수) 이하인가? |
@DecimalMin(value=) | 지정된 값(실수) 이상인가? |
@AssertFalse | false 인가? |
@AssertTrue | true 인가? |
package com.cos.photogramstart.web.dto.auth;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
import com.cos.photogramstart.domain.user.User;
import lombok.Data;
@Data //getter setter
public class SignupRequestDTO {
@Size(min=5, max=20)
private String username;
@NotBlank
private String password;
@NotBlank
private String email;
@NotBlank
private String name;
public User toEntity(){
return User.builder()
.username(username)
.password(password)
.email(email)
.name(name)
.build();
}
}
3. 넘어오는 파라미터(인자)에 @Valid 어노테이션 설정 과 BindingResult 넣기
Controller 클래스에서 요청된 파라미터에 유효성 검사를 할 객체 앞에 @Valid를 작성 하고, 바로 뒤이어 BindingResult 를 작성하면 유효성 검사를 통한 결과를 담게된다.
- @Valid 어노테이션을 통해 SignupRequestDTO가 유효한 객체인지 검사
- SignupRequestDTO 객체가 유효하지 않으면 bindingResult.hasErrors() 메소드에서 true 값이 반환
- SignupRequestDTO가 유효하지 않다면, 예외를 발생시켜 따로 처리하도록 설정 (이후 ControllerAdvice를 통해 예외처리 할 예정)
/**
* 회원가입 요청
* @return 로그인 페이지
*/
@PostMapping(value="/auth/signup")
public String signup(@Valid SignupRequestDTO signupRequestDTO,BindingResult bindingResult) {
if(bindingResult.hasErrors()){
Map<String,String> errorMap = new HashMap<>();
for(FieldError error: bindingResult.getFieldErrors()){
errorMap.put(error.getField(),error.getDefaultMessage());
System.out.println("#################################################################");
System.out.println(error.getDefaultMessage());
System.out.println("#################################################################");
}
throw new CustomValidationException("유효성 실패",errorMap);
}else{
//User <- SignupDto
User user = signupRequestDTO.toEntity();
User userEntity = authService.signup(user);
log.info("massage",userEntity);
return "auth/signin";
}
@ControllerAdvice 를 통한 예외처리
- @Controller나 @RestController에서 발생한 예외를 한 곳에서 관리하고 처리할 수 있게 도와주는 어노테이션
1. 새로운 클래스 생성 후 @ControllerAdvice 어노테이션 설정
- @ControllerAdvice 설정 이후, 설정할 예외에 @ExceptionHandler 설정
- @ExceptionHandler(처리할 예외.class) ( 안에 value 를 적지않으면 모든 예외를 catch해 처리함 )
package com.cos.photogramstart.handler;
import java.util.Map;
import com.cos.photogramstart.handler.ex.CustomValidationException;
import com.cos.photogramstart.utils.Script;
import com.cos.photogramstart.web.dto.CRMRespDto;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestController;
@RestController
@ControllerAdvice // 모든 exception을 가로채온다.
public class ControllerExceptionHandler {
/*
@ExceptionHandler(CustomValidationException.class)
public CRMRespDto<?> validationException(CustomValidationException e){
return new CRMRespDto<Map<String,String>>(-1,e.getMessage(),e.getErrorMap());
}*/
/**
* 예외처리 상황에서 스크립트로 응답
* 1. 클라이언트 응답시엔 script
* 2. Ajax 통신에는 위의 방법이 나음
* @param e
* @return 에러메세지 스크립트로 반환
*/
@ExceptionHandler(CustomValidationException.class)
public String validationException(CustomValidationException e){
return Script.back(e.getErrorMap().toString());
}
}
2. 사용자 정의 Exception 처리
- 처리할 RuntimeException을 상속받은 클래스를 생성한다.
- 원하는 형태의 데이터로 반환 받기 위함 (회원가입시 여러 파트에서 예외가 발생한 경우)
- 요구사항에 따라 데이터 형식이 아닌 script를 반환해 사용자에게 직접 알림을 보낼 수도 있다.(비권장방식)
package com.cos.photogramstart.handler.ex;
import java.util.Map;
public class CustomValidationException extends RuntimeException{
private static final long serialVersionUID = 1L;
private String message;
private Map<String,String> errorMap;
public CustomValidationException(String message, Map<String,String> errorMap){
super(message); // 부모의 클래스에 전달해준다.
this.errorMap= errorMap;
}
public Map<String,String> getErrorMap(){
return errorMap;
}
}
반환 데이터
{
"code": -1,
"message": "유효성 실패",
"data": {
"username": "크기가 5에서 20 사이여야 합니다"
}
}
package com.cos.photogramstart.utils;
public class Script {
public static String back(String msg){
StringBuffer sb = new StringBuffer();
sb.append("<script>");
sb.append("alert('"+msg+"');");
sb.append("history.back();");
sb.append("</script>");
return sb.toString();
}
}
'Framework > SpringBoot' 카테고리의 다른 글
[SpringBoot] Spring Security 설정 (url 제한 및 로그인 페이지 설정 ) (0) | 2022.02.13 |
---|
댓글