일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 백준#boj#16932#모양만들기
- 백준#BOJ#8012#한동이는영업사원
- 백준#BOJ#12865#평범한배낭
- 백준#BOJ#2615#오목
- 백준#BOJ#1939#중량제한
- 백준#BOJ#14501#퇴사#브루트포스
- 백준#boj#12755
- Today
- Total
순간을 성실히, 화려함보단 꾸준함을
MultipartFile 은 어떻게 validation 체크를 해야할까?(ConstraintValidator.class) 본문
MultipartFile 은 어떻게 validation 체크를 해야할까?(ConstraintValidator.class)
폭발토끼 2023. 9. 3. 17:25안녕하세요. 폭발토끼입니다.
오늘은 ConstraintValidator 를 사용한 경험에 대해서 공유하려고 글을 작성했습니다. 사실 구글에 너무나도 많은 블로그글들이 많아서 써야할까 고민했지만, 블로그에 기록해두면 앞으로 개발하면서 비슷한 문제를 마주했을때 빠르게 해결할 수 있을 것 같아서 이렇게 기록을 남깁니다.
배경
request dto 객체들에 대해서 validation 체크를 해줄때는 @Valid 어노테이션을 사용해서 편하게 체킹할 수 있습니다. 그러나 안타깝게 file class 들에 대해서는 마땅히 체킹할 수 있는 기능이 없습니다. @Valid 의 @NotNull 은 말 그대로 null 인 경우 체킹을 하지만 file 의 경우 아무값이 없을때 null 이 아닌 빈값으로 값이 들어와 필터링을 해줄 수 없기 때문입니다.
그래서 어떻게 하면 controller 에 도달하기 전에 validation 체킹을 할 수 있을지 열심히 서칭해보았습니다.
해결
바로 ConstraintValidator 를 사용하여 해결할 수 있었습니다.
스프링 사용자가 custom 하게 데이터들을 필터링 할 수 있게끔 기능을 제공해주는 클래스 입니다.
사용방법은 아래와 같습니다.
public class ValidFileValidator implements ConstraintValidator<ValidFile, MultipartFile> {
@Override
public boolean isValid(MultipartFile file, ConstraintValidatorContext context) {
return file != null && !file.isEmpty();
}
}
'MultipartFile 에 대해서 ValidFile 어노테이션의 제약을 준수했는지 체크한다' 라고 받아들이면 될 것 같아요.
저는 MultipartFile 에 대해서 유효성을 체크할 것이기 때문에 file 이 null 이 아니거나 비어있지 않으면 true 를 리턴하게끔 코드를 작성하였습니다.
@Target(value = ElementType.FIELD)
@Retention(value = RetentionPolicy.RUNTIME)
@Constraint(validatedBy = ValidFileValidator.class)
public @interface ValidFile {
String message() default "Invalid File";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
저는 ValidFile 라는 커스텀 어노테이션 정의해주어 위와 같이 사용했습니다.
@Setter
@Getter
@ToString
public class PostSaveRequestDTO {
private String content;
@ValidFile(message = "이미지 파일은 필수입니다.")
private MultipartFile image;
/**
* json 형태의 데이터를 객체형태로 변환하는데 JackSon Library 가 사용된다.
* 이때, 객체에는 '기본 생성자' 가 반드시 존재해야한다.
* 이유는 JackSon Library가 기본생성자를 이용하여 객체로 변환시켜주기 때문이다. => 역직렬화
*/
public PostSaveRequestDTO(){
}
@Builder
public PostSaveRequestDTO(String content, MultipartFile image) {
this.content = content;
this.image = image;
}
public void validate(){
if(image.isEmpty()){
throw new ImageFileArgumentNotValidation("image","이미지 파일은 필수입니다.");
}
}
}
결과
해당 api 에 대해 test code를 작성해 볼까요?
@Test
@DisplayName("게시글 업로드 : 게시글 업로드시 Image 파일은 필수입니다")
void uploadPostImageTest() throws Exception {
//given
Member member = createMember();
memberRepository.save(member);
UserSessionDTO sessionDTO = UserSessionDTO.builder()
.id(member.getId())
.email(member.getMemberEmail())
.nickname(member.getNickname())
.build();
String accessToken = jwtManager.makeAccessToken(sessionDTO.getId());
PostSaveRequestDTO postSaveRequestDTO = createPostRequestDTO();
postSaveRequestDTO.setImage(null);
//when
mockMvc.perform(multipart(COMMON_URL + "/upload")
.file("image", null)
.header(HttpHeaders.AUTHORIZATION,accessToken)
.param("content", postSaveRequestDTO.getContent())
)
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.code").value("I001"))
.andExpect(jsonPath("$.message").value("이미지 파일이 존재하지 않습니다"))
.andExpect(jsonPath("$.validation.image").value("이미지 파일은 필수입니다."))
.andDo(print());
}
다행이 통과를 했네요 ㅎㅎㅎ
오늘은 ContraintValidator 를 사용하여 커스텀한 validation 체크를 수행할 수 있는 방법에 대해서 알아보았는데요.
이렇게 직접 무엇인가를 만들어봐야지 벽을 느끼고 그걸 하나씩 뿌셔가면서 배울 수 있는 것 같습니다.
앞으로도 어떤 문제를 마주하게 될지 궁금하네요 ㅎㅎㅎ
감사합니다.
'나의 개발 메모장' 카테고리의 다른 글
[Docker] docker-compose 첫 사용기! (0) | 2023.12.24 |
---|---|
동시성 문제에 관하여... (0) | 2023.12.10 |
인텔리제이 .http 파일로 MultipartFile 전송해보기 (0) | 2023.08.19 |
글또 8기를 마치며 (4) | 2023.07.16 |
wsl+docker 를 사용한 spring boot + Redis 사용하기!! (0) | 2023.06.11 |