ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Spring boot 스프링 부트에서 request Validation 요청값 검증하기
    프로그래밍/서버 프로그래밍 2019. 2. 18. 14:22

    Spring boot 스프링 부트에서 request Validation 요청값 검증하기 @Valid이용

    안녕하세요. 오늘은 Spring boot 에서 request에 들어오는 요청값을 검증하는 법을 알아보겠습니다.
    현재 제가 공부로 진행중인 프로젝트에서 소스를 조금 가져오겠습니다.

    먼저 AccountController에 있는 createAccount메소드를 가져오겠습니다.

    @PostMapping
        public ResponseEntity createAccount(@RequestBody @Valid AccountDto dto, Errors errors) {
            if (errors.hasErrors()) {
                return ResponseEntity.badRequest().build();
            }
    
            Account account = accountService.save(dto);
    
            return ResponseEntity.ok(
                    AccountDto.builder()
                            .displayName(account.getDisplayName())
                            .email(account.getEmail())
                            .build()
            );
        }
    

    현재 소스코드에서 보면 @RequestBody@Valid 어노테이션이 AccountDto 요청값에 붙어있는데,

    @RequestBody 어노테이션은 @RequestMapping에 의해 POST 방식으로 전송된 HTTP 요청 데이터를 제가 지정해준 AccouontDto에 맞춰서 변환해주는 역할을 합니다.

    @Valid 어노테이션이 바로 요청데이터를 검증하는 어노테이션입니다.

    여기서 그냥 @Valid 어노테이션을 붙인다고해서 바로 검증을 할 수 있는 것은 아니고 실제 AccountDto에도 필드별로 검증하기 위해 다양한 어노테이션을 붙여줍니다.

    @Getter
    @Setter
    @Builder
    @AllArgsConstructor
    public class AccountDto {
    
        @NotEmpty @NotBlank
        private String displayName;
        @NotEmpty @NotBlank @Email
        private String email;
        @NotEmpty
        @NotBlank
        @JsonIgnore
        private String password;
    
        public Account toEntity(){
            return Account.builder()
                    .displayName(this.displayName)
                    .password(this.password)
                    .email(this.email)
                    .build();
        }
    }
    

    각 필드마다 위에 @NotEmpty, @Email, @NotBlank
    등 다양한 어노테이션이 보입니다.
    실제로 @javax.validation.constraints.까지 입력하시고, Ctrl + Space키를 눌러보시면 하단에

    이렇게 많은 어노테이션이 존재합니다.

    각 어노테이션은 이름에서도 대충 유추를 할 수 있지만, 더 자세히 알고 싶으시면 여기를 더 참고하시면 좋을 것 같습니다.

    이제 이런식으로 각 요청값을 @Valid 어노테이션을 이용하여서 걸러낼 수 있다는 것을 알아봤는데 , 만약 요청값이 @Email인데 이메일 형식이 아닌값이 들어오는 등, 요청값이 검증에 실패할 경우엔 어떻게 될까요?

    위의 컨트롤러 소스코드를 다시보시면 createAccount의 두번째 인자로 Errors를 받고 있는 것을 보실 수 있습니다.

    Validation 과정에서 실패하거나 에러가 발생하면 이 Errors에 에러들이 담기기 때문에 저같은 경우는 errors.hasErrors()를 이용해서 에러 발생시 예외처리를 해주고 있습니다.

    하지만 위에 javax.validation.constraints.*에 제가 필요한 검증이 어노테이션으로 존재하지 않는 경우에는 어떤 방식으로 검증을 해야할까요?

    최근 백기선님의 REST API강의를 하면서 배웠던 방식을 한번 보겠습니다. 예를 들기 위해 임의로 Event라는 객체를 아주 간단히 만들어 보겠습니다.

    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    @Getter @Setter
    @Entity
    public class Event {
        @Id
        @GeneratedValue
        private Long id;
        private String name;
        private String description;
        private LocalDate startDate;
        private LocalDate endDate;
    }
    

    이를 요청값으로 받을 때는 Entity클래스가 DTO클래스를 따로 생성하는게 좋기 때문에 이번에는 EventDto클래스를 만들어 보겠습니다.

    @Getter
    @Setter
    @Builder
    @NoArgsConstructor @AllArgsConstructor
    public class EventDto {
        @NotEmpty
        private String name;
        @NotEmpty
        private String description;
        @NotNull
        private LocalDate startDate;
        @NotNull
        private LocalDate endDate;

    현재는 위에 방식과 마찬가지로 @Valid를 사용한 방식만을 사용하고 있습니다.
    하지만 현재 만일 startDate 보다 endDate가 더 이른 날짜가 들어온다면 이를 검증할 수 없다는 문제가 있습니다.( startDate = 20190218, endDate = 20190201)

    이를 해결하기 위하여 저희는 EventValidator라는 클래스를 생성할 것입니다.

    @Component
    public class EventValidator {
        public void validate(EventDto eventDto, Errors errors){
             if(endDate.isBefore(startDate)){
                errors.rejectValue("endDate", "wrongValue", "endDate is wrong");
            }
        }

    이런식으로 EventValidator@Component로 등록해준 뒤,
    EventController에서 불러와 사용할 수 있습니다.

    @Autowired
    private EventValidator eventValidator;
    
    @PostMapping
        public ResponseEntity createEvent(@RequestBody @Valid EventDto eventDto, Errors errors) {
    
            if(errors.hasErrors()) {
                return ResponseEntity.badRequest().body(errors);
            }
    
            eventValidator.validate(eventDto, errors);
    
            if(errors.hasErrors()){
                return ResponseEntity.badRequest().body(errors);
            }
    
                ...이벤트 생성코드 작성...
    
            return ResponseEntity.ok().build();
    

    현재는 startDateendDate만 검증을 해봤는데, 실제로 필요한 검증을 직접 추가하시고 소스코드도 더 리팩토링하셔서 사용을 하시면 될 것 같습니다!

    이상으로 오늘은 스프링 부트에서 요청값을 검증하는 방법에 대하여 알아봤습니다!


    아직 모르는게 많아 게시글에 잘못된 정보가 있을 수 있습니다. 혹시 잘못된 정보가 있다면, 댓글 혹은 메일로 알려주시면 최대한 빨리 수정하겠습니다!

    댓글

Designed by Tistory.