728x90
반응형
유효성 검증
- 입력 값이나 데이터가 정해진 규칙에 부합하는지 검증하는 과정
- 보안측면에서 중요하다.
- 유효하지 않은 악의적인 코드 필터가 가능하다.
@Valid VS @Validated
- @Valid : java.validation 패키지에서 제공하는 유효성 검사 어노테이션
- @Validated : spring-boot-starter-validation으로 추가 하여 사용
- 두 어노테이션은 기능적으로는 차이는 없다.
- 참고 : https://mangkyu.tistory.com/174
- @Valid : ArgumentResolver에 의해 처리
- 예외 : MethodArgumentNotValidException 발생
- 메소드 레벨에서 주로 사용
- @Validated : AOP기반으로 처리
- 예외 : ConstraintViolationException 발생
- 클래스 레벨에서 주로 사용
- 유효성 검사 그룹 지정
- @Validated의 유효성 검증 그룹 (코드의 복잡성때문에 거의 사용하지 않음 -> 두 어노테이션이 같은 동작을 수행한다고 생각하면 된다.)
- 동일한 클래스에 요청에 따라 제약조건이 달라질 수 있다.
- ex) 동일한 UserRequestDto 객체에서 일반 유저와 관리자 유저 분리
- 동일한 클래스에 요청에 따라 제약조건이 달라질 수 있다.
Spring Boot Validation
dependency 추가
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-validation'
}
자주 유효성 검사에 사용되는 어노테이션
@NotNull // null 불가 / "", " " 허용
@NotEmpty // null, "" 불가 / " " 허용
@NotBlank // null, "", " " 불가
@Email
@Pattern(regexp="") // 정규식
@Size(min=, max=) // 문자길이 제한
@Max(), @Min() // 최대/최소 값 지정
모델 정의
UserRequestDto
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class UserRequestDto {
@NotNull(message = "이름은 null일 수 없습니다.")
private String name;
@Email(message = "email 형식으로 입력해주세요.")
@NotBlank(message = "eamil을 입력해주세요.")
private String email;
@Range(min = 1, max = 150, message = "1~150살 이내로 입력하세요.")
private Integer age;
@Pattern(regexp = "^\\d{2,3}-\\d{3,4}-\\d{4}$", message = "핸드폰 번호의 양식과 맞지 않습니다. 01x-xxx(x)-xxxx")
private String phoneNumber;
}
컨트롤러
- 3가지 케이스로 알아보기
1. 유효성 검증에 대한 예외를 처리하지 않은 경우
- 400 Bad Request 에러를 발생하여 어떤 에러인지 명확하지 않다.
@RestController
@RequestMapping("/user")
public class UserController {
@PostMapping("/add")
public ResponseEntity add(@Valid @RequestBody UserRequestDto userRequestDto
){
return ResponseEntity.ok("addUser");
}
}
2. BindingResult 이용
- https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/validation/BindingResult.html
- Spring에서 제공하는 바인딩 결과를 저장하고 있는 객체
- Validator를 적용한다.
=> Spring에서 Validate 오류 발생시 바인딩하여 결과값을 저장하고 있는 객체로 사용된다.
@RestController
@RequestMapping("/user")
public class UserController {
@PostMapping("/add")
public ResponseEntity add(@Valid @RequestBody UserRequestDto userRequestDto
, BindingResult bindingResult
){
if (bindingResult.hasErrors()) {
List<String> errors = bindingResult.getAllErrors().stream().map(e -> e.getDefaultMessage()).collect(Collectors.toList());
return ResponseEntity.badRequest().body(errors);
}
return ResponseEntity.ok("addUser");
}
}
3. 공통 예외처리로 개선
- BindingResult를 유효성 검증을 하는 메소드마다 넣기는 번거롭기 때문에 공통 예외로 처리한다.
- @RestControllerAdvice로 개선
- GlobalException
@RestControllerAdvice
public class GlobalException {
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(MethodArgumentNotValidException.class)
public Map<String, String> handleValidationExceptions(
MethodArgumentNotValidException ex) {
Map<String, String> errors = new HashMap<>();
ex.getBindingResult().getAllErrors().forEach((error) -> {
String fieldName = ((FieldError) error).getField();
String errorMessage = error.getDefaultMessage();
errors.put(fieldName, errorMessage);
});
return errors;
}
}
- controller
@RestController
@RequestMapping("/user")
public class UserController {
@PostMapping("/add")
public ResponseEntity add(@Valid @RequestBody UserRequestDto userRequestDto
){
return ResponseEntity.ok("addUser");
}
}
파트너스 활동을 통해 일정액의 수수료를 제공받을 수 있음
반응형
'Spring' 카테고리의 다른 글
Spring boot Slack 채널 연동 (0) | 2024.04.19 |
---|---|
[에러] java.util.zip.ZipException: invalid code lengths set (1) | 2024.01.04 |
Mustache로 템플릿 메일 발송 (0) | 2022.04.26 |
[Spring Boot] docker-compose로 mysql컨테이너 생성 및 Spring Boot 연결 (0) | 2021.09.13 |
[Spring AOP] AOP를 이용한 Decode (0) | 2021.08.28 |