ballqs 님의 블로그
[Spring] @Valid 유효성 검사 , @ExceptionHandler , MethodArgumentNotValidException 본문
[Spring] @Valid 유효성 검사 , @ExceptionHandler , MethodArgumentNotValidException
ballqs 2024. 8. 12. 17:10받아오는 Parameter에 따라 유효성 검사를 할수 있다는 기능이 있다고 해서 알아보았다.
@Valid 라는 기능이다. 이건 어떻게 사용하는지 작성해보겠다.
의존성 추가
build.gradle 파일을 찾아서 추가하자.
implementation 'org.springframework.boot:spring-boot-starter-validation'
사용방법
@RestController
@RequestMapping("/api/schedule")
public class ScheduleController {
private final ScheduleService scheduleService;
@Autowired
ScheduleController(ScheduleService scheduleService) {
this.scheduleService = scheduleService;
}
@PostMapping("/create")
public ResponseEntity<ResponseDto<ScheduleSelectDto>> createSchedule(@Valid @RequestBody ScheduleInsertDto scheduleInsertDto) {
return ResponseEntity
.status(HttpStatus.OK)
.body(new ResponseDto<>(HttpStatus.OK.value(), scheduleService.createSchedule(scheduleInsertDto) , "성공적으로 등록완료했습니다."));
}
}
createSchedule 메서드를 살펴보면 @Valid 와 @RequestBody 가 쓰여져 있다.
@RequestBody는 클라이언트에서 body에 담아서 요청보낸 것들이라는 의미이다.
@Valid는 받은 값들의 유효성 검사를 하겠다는 의미이다.
ScheduleInsertDto에는 @Valid가 쓰여져있어서 아래와 같이 작성되었다.
만약! @Valid가 없는 곳에서 ScheduleInsertDto에 담는 것이라면 @Size , @NotNull , @NotBlank 등이 동작하지 않는다.
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Getter;
@Getter
public class ScheduleInsertDto {
@Size(max=200, min=1)
@NotNull
private String content;
@NotNull
private Long managerIdx;
@NotBlank
private String pw;
}
종류
빈 문자열 = ""
공백 = " "
Annotation | Comment |
@NotNull | 빈 문자열, 공백은 허용하지만 Null은 허용안함 |
@NotBlank | Null, 빈 문자열, 공백 모두 허용하지 않음! 한 글자라도 쓰여져 있어야 함 |
@NotEmpty | 공백은 허용하지만 Null과 빈 문자열은 허용하지 않음 |
@Size(max=,min=) | 길이를 제한한다. min이 최소값이고 max가 최대값 |
이메일 형식을 검사 | |
@Pattern(regexp=) | 정규식 검사 |
@Null | Null만 허용 |
@Max(value=) | value 이하의 값만 허용 |
@Min(value=) | value 이상의 값만 허용 |
@Positive | 값을 양수로 제한 |
@PositiveOrZero | 값을 양수와 0만 가능하도록 제한 |
@Negative | 값을 음수로 제한 |
@NegativeOrZero | 값을 음수와 0만 가능하도록 제한 |
@Future | 현재 시간보다 미래의 날짜 , 시간이어야 함 |
@FutureOrPresent | 현재 시간이거나 미래의 날짜 , 시간이어야 함 |
@Past | 현재 시간보다 과거의 날짜 , 시간이어야 함 |
@PastFutureOrPresent | 현재 시간이거나 과거의 날짜 , 시간이어야 함 |
MethodArgumentNotValidException 에러
@Valid 유효성 검사에 의해 발생되는 에러이다.
해당 에러는 어떤 값을 가져오는지 알기 위해 @ExceptionHandler 라는 어노테이션을 사용했다.
@ExceptionHandler
이 Annotation은 Controller에서만 사용이 가능하다고 한다. Service나 Repository에서 에러를 발생하면 Controller로 와서 해당 메서드에 들어가 실행문을 실행한다.
예를 들어 아래와 같이 동작한다.
public ScheduleSelectDto selectSchedule(Long idx) {
Schedule schedule = scheduleRepository.findById(idx);
if (Objects.nonNull(schedule)) {
return new ScheduleSelectDto(schedule);
} else {
throw new NullPointerException("존재하지 않는 일정 정보입니다.");
}
}
throw new NullPointerException() 를 통해 Controller에 있는 @ExceptionHandler가 선언되어 있는 곳을 찾아간다.
@ExceptionHandler(value = NullPointerException.class)
public ResponseEntity<ResponseDto<String>> nullPointerHandle(NullPointerException e) {
// 실행 내용...
return null;
}
@ExceptionHandler 에는 value값을 작성할 수 있는데 온갖 예외처리 부분을 작성해 넣을 수 있다.
그러면 value에 작성되어 있는 에러가 발생하면 해당 메서드로 들어와 내용물을 실행하게 되는 것이다.
MethodArgumentNotValidException 또한 @ExceptionHandler를 통해 작성되었고 내부가 어떤 내용이 있는지 살펴보자.
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public ResponseEntity<ResponseDto<String>> methodArgumentNotValidHabdle(MethodArgumentNotValidException e) {
List<String> msgList = new ArrayList<>();
for (int i = 0; i < e.getBindingResult().getFieldErrors().size(); i++) {
String msg = e.getBindingResult().getFieldErrors().get(i).getField() + "는 " + e.getBindingResult().getFieldErrors().get(i).getDefaultMessage();
msgList.add(msg);
}
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ResponseDto<>(HttpStatus.BAD_REQUEST.value() , "" , String.join(" , " , msgList)));
}
e 라는 변수를 통해 내용을 살펴보니 BindingResult가 있다.
깊게 파고 들어오니까 저부분이 List라는 것을 알수 있었고 그래서 size() 함수와 get()이 사용이 가능했던것이다.
getDefaultMessage()
기본 메세지만 가져오고 싶을 때
e.getBindingResult().getFieldErrors().get(i).getDefaultMessage()
getField()
필드 명을 가져오고 싶을 때
e.getBindingResult().getFieldErrors().get(i).getField()
이 이외에 자세하게 다룰라면 완전 뜯어봐야하는데 내가 그럴 재량이 아직 부족하다...
좀 더 자세하게 다룬 글은 여기에 있었다.
https://my-codinglog.tistory.com/56#check2
나중에 자주 들릴 예정이라 링크만 첨부 해두자!
마무리
코드를 작성하면서 진짜 많이 어려웠고 Spring은 이제 시작이라는 생각이 든다.
모르는걸 점점 블로그 글로 메모하듯이 적어두자...
'코딩 공부 > Spring' 카테고리의 다른 글
[Spring] PasswordEncoder 암호화 및 bcrypt 암호화 (0) | 2024.08.23 |
---|---|
[Spring] Naver Open API 사용방법 (0) | 2024.08.20 |
[Spring] JWT(Json Web Tokens)란? (0) | 2024.08.19 |
[Spring] JPA(Java Persistence API)란? (0) | 2024.08.14 |
[Spring] Lombok이란? (0) | 2024.08.09 |