Gidhub BE Developer

Spring MVC - @Valid와 @Validated 애노테이션

2019-09-13
goodGid

이 글의 코드 및 정보들은 강의를 들으며 정리한 내용을 토대로 작성하였습니다.

@Valid

Java에서 제공해주는 애노테이션이다.

package javax.validation;

/**
 * Marks a property, method parameter or method return type for validation cascading.
 * <p>
 * Constraints defined on the object and its properties are be validated when the
 * property, method parameter or method return type is validated.
 * <p>
 * This behavior is applied recursively.
 *
 * @author Emmanuel Bernard
 * @author Hardy Ferentschik
 */
@Target({ METHOD, FIELD, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
@Documented
public @interface Valid {
}
  • Java가 제공해주는

    @Valid 애노테이션에는

    특정 Validation 그룹으로

    검증을 시킬 수 있는 기능이 없다.


@Validated

Spring에서 제공해주는 애노테이션이다.

package org.springframework.validation.annotation;

@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Validated {
    Class<?>[] value() default {};
}
  • 특정 Validation 그룹으로

    검증 할 수 있는 @Validated 애노테이션을 제공한다.


Example Code

Domain

public class Event {

    interface ValidateName {};
    interface ValidateLimit {};
    
    private Integer id;

    @NotBlank(groups = ValidateName.class) // Validate`Name`
    private String name;

    @Max(value = 10, groups = ValidateLimit.class) // Validate`Limit`
    private Integer limit;
}

ValidateLimit.Class

Controller

@Controller
@RequestMapping
public class SampleController {

    @GetMapping("/events")
    @ResponseBody
    public Event hello(@Validated(Event.ValidateLimit.class) @ModelAttribute Event event,
                        BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            bindingResult.getAllErrors().forEach(c -> {
                System.out.println(c);
            });
        }
        return event;
    }
}
  • 특정 그룹으로 validate를 실시한다.

    (= @Validated(Event.ValidateLimit.class) )

TC

@Test
public void helloTest() throws Exception {
    mockMvc.perform(get("/events")
                            .param("name", "goodGid")
                            .param("limit", "11"))
            .andDo(print())
            .andExpect(status().isOk());
}

Result

Field error in object 'event' on field 'limit': rejected value [11]; codes [Max.event.limit,Max.limit,Max.java.lang.Integer,Max]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [event.limit,limit]; arguments []; default message [limit],10]; default message [must be less than or equal to 10]

...

MockHttpServletResponse:
           Status = 200
    Error message = null
          Headers = [Content-Type:"application/json;charset=UTF-8"]
     Content type = application/json;charset=UTF-8
             Body = {"id":null,"name":"goodGid","limit":11}
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

ValidateName.Class

Controller

@Controller
@RequestMapping
public class SampleController {

    @GetMapping("/events")
    @ResponseBody
    public Event hello(@Validated(Event.ValidateName.class) @ModelAttribute Event event,
                        BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            bindingResult.getAllErrors().forEach(c -> {
                System.out.println(c);
            });
        }
        return event;
    }
}

TC

@Test
public void helloTest() throws Exception {
    mockMvc.perform(get("/events")
                            .param("name", "goodGid")
                            .param("limit", "11"))
            .andDo(print())
            .andExpect(status().isOk());
}

Result

MockHttpServletResponse:
           Status = 200
    Error message = null
          Headers = [Content-Type:"application/json;charset=UTF-8"]
     Content type = application/json;charset=UTF-8
             Body = {"id":null,"name":"goodGid","limit":11}
    Forwarded URL = null
   Redirected URL = null
          Cookies = []
  • Event.ValidateName.class 그룹으로

    Validate를 하였기 때문에 Error Log가 출력되지 않는다.

    (= 정상 케이스다.)


Summary

  • @Valid와 @Validated 애노테이션에 대해 알아봤다.

    각 어노테이션의 특징 및 두 개의 차이점에 대해 이해하고 적재적소에 잘 활용하자.


Reference


Recommend

Index