ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Spring Boot] 유효성 검사 처리 (Custom Validation)
    Spring Boot/기타 2022. 6. 6. 18:46
    반응형

    1. DateValid 구현

    DateValid.java

    package com.example.customvalidation.annotiaon;
    
    import com.example.customvalidation.validator.DateValidator;
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    import javax.validation.Constraint;
    import javax.validation.Payload;
    
    @Documented
    @Constraint(validatedBy = DateValidator.class)
    @Target({ElementType.METHOD, ElementType.FIELD})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface DateValid {
    
      String message() default "6자리의 yyyyMMdd 형식이어야 합니다.";
    
      Class<?>[] groups() default {};
    
      Class<? extends Payload>[] payload() default {};
    
      String pattern() default "yyyyMMdd";
    }

     

    2. DateValidator 구현

    DateValidator.java

    package com.example.customvalidation.validator;
    
    import com.example.customvalidation.annotiaon.DateValid;
    import java.time.LocalDate;
    import java.time.format.DateTimeFormatter;
    import java.time.format.DateTimeParseException;
    import javax.validation.ConstraintValidator;
    import javax.validation.ConstraintValidatorContext;
    import lombok.extern.slf4j.Slf4j;
    
    @Slf4j
    public class DateValidator implements ConstraintValidator<DateValid, String> {
    
      private String pattern;
    
      @Override
      public void initialize(DateValid constraintAnnotation) {
        this.pattern = constraintAnnotation.pattern();
      }
    
      @Override
      public boolean isValid(String value, ConstraintValidatorContext context) {
    
        try {
          LocalDate.from(LocalDate.parse(value, DateTimeFormatter.ofPattern(this.pattern)));
        } catch (DateTimeParseException e) {
          log.error("DateValidator : {}", e);
          return false;
        }
        return true;
      }
    }

     

    3. ValidatedController 구현

    ValidatedController.java 

    package com.example.customvalidation.controller;
    
    import com.example.customvalidation.dto.ValidatedDto;
    import javax.validation.Valid;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RestController;
    
    @Slf4j
    @RestController
    public class ValidatedController {
    
      @PostMapping("/validated/date")
      public String validatedDate(
          @Valid @RequestBody ValidatedDto.Request validationRequest
      ) {
        log.info("validationRequest: {}", validationRequest);
        return "postValidation";
      }
    }

     

    4. ValidatedDto 구현

    ValidatedDto.java

    package com.example.customvalidation.dto;
    
    import com.example.customvalidation.annotiaon.DateValid;
    import com.fasterxml.jackson.annotation.JsonProperty;
    import javax.validation.constraints.AssertFalse;
    import javax.validation.constraints.NotBlank;
    import lombok.AllArgsConstructor;
    import lombok.Builder;
    import lombok.Getter;
    import lombok.NoArgsConstructor;
    import lombok.Setter;
    import lombok.ToString;
    
    public class ValidatedDto {
    
      @Getter
      @Setter
      @Builder
      @AllArgsConstructor
      @NoArgsConstructor
      @ToString
      public static class Request {
    
        @JsonProperty("id")
        private Long id;
    
        @NotBlank
        @JsonProperty("title")
        private String title;
    
        @NotBlank
        @JsonProperty("description")
        private String description;
    
        @AssertFalse
        @JsonProperty("completed")
        private Boolean completed;
    
        @DateValid(message = "8자리의 yyyy-MM-dd 형식이어야 합니다.", pattern = "yyyy-MM-dd")
        @JsonProperty("created_date")
        private String createdDate;
    
        @DateValid(message = "8자리의 yyyy-MM-dd 형식이어야 합니다.", pattern = "yyyy-MM-dd")
        @JsonProperty("updated_date")
        private String updateDate;
      }
    
      @Getter
      @Setter
      @AllArgsConstructor
      @NoArgsConstructor
      @ToString
      public class Response {
    
        @JsonProperty("id")
        private Long id;
    
        @JsonProperty("title")
        private String titile;
    
        @JsonProperty("description")
        private String description;
    
        @JsonProperty("completed")
        private Boolean completed;
    
        @JsonProperty("created_date")
        private String createdDate;
    
        @JsonProperty("updated_date")
        private String updateDate;
      }
    }

     

    5. ValidatedControllerTest 구현

    ValidatedControllerTest.java

    package com.example.customvalidation.controller;
    
    import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
    import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
    import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
    import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
    
    import com.example.customvalidation.dto.ValidatedDto;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import org.junit.jupiter.api.Disabled;
    import org.junit.jupiter.api.DisplayName;
    import org.junit.jupiter.api.MethodOrderer;
    import org.junit.jupiter.api.Test;
    import org.junit.jupiter.api.TestMethodOrder;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.http.MediaType;
    import org.springframework.test.web.servlet.MockMvc;
    import org.springframework.test.web.servlet.ResultActions;
    
    @TestMethodOrder(MethodOrderer.OrderAnnotation.class)
    @AutoConfigureMockMvc
    @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
    @Disabled
    class ValidatedControllerTest {
    
      @Autowired
      MockMvc mockMvc;
    
      @Autowired
      ObjectMapper objectMapper;
    
      @DisplayName("validatedDate_유효성 검증 성공_응답 코드:200")
      @Test
      void testValidatedDate() throws Exception {
    
        // Given & When
        String url = "/validated/date";
        ValidatedDto.Request validatedRequest = ValidatedDto.Request.builder()
            .title("title")
            .description("description")
            .completed(false)
            .createdDate("2022-06-06")
            .updateDate("2022-06-06")
            .build();
    
        ResultActions resultActions = mockMvc.perform(
            post(url)
                .contentType(MediaType.APPLICATION_JSON)
                .content(objectMapper.writeValueAsString(validatedRequest))
        );
    
        // Then
        resultActions
            .andExpect(status().isOk())
            .andDo(print());
      }
    
      @DisplayName("validatedDate_유효성 검증 실패_응답 코드:400")
      @Test
      void testValidatedDateFail() throws Exception {
    
        // Given & When
        String url = "/validated/date";
        ValidatedDto.Request validatedRequest = ValidatedDto.Request.builder()
            .title("title")
            .description("description")
            .completed(false)
            .createdDate("20220606")
            .updateDate("20220606")
            .build();
    
        ResultActions resultActions = mockMvc.perform(
            post(url)
                .contentType(MediaType.APPLICATION_JSON)
                .content(objectMapper.writeValueAsString(validatedRequest))
        );
    
        // Then
        resultActions
            .andExpect(status().isBadRequest())
            .andDo(print());
      }
    }

     

    소스 코드는 Github Repository - https://github.com/tychejin1218/custom-validation 를 참조하세요.

    참고 : https://www.baeldung.com/spring-mvc-custom-validator

    반응형

    댓글

Designed by Tistory.