6 Haziran 2018 Çarşamba

SpringMVC @InitBinder Anotasyonu - Custom Validation

Giriş
Şu satırı dahil ederiz.
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
Açıklaması şöyle
The @InitBinder annotation is used to customize the data binding process for web request parameters in a controller. It allows you to define methods that will be invoked before the actual request handler methods are called, giving you the opportunity to pre-process request data, validate it, or perform other necessary tasks.
1. @RequestParam İçin Validator
Örnek
Şöyle yaparız
@RestController
public class DemoController {

  @GetMapping("/isallok")
  public String allOk(@RequestParam("rangeParameter") String rangePara){

  }

  @InitBinder
  public void initbinder(@RequestParam(value = ("rangeParameter"), required = false)
    String rangePara){
    //here you can preform all task on your parameter
  }
}
Açıklaması şöyle
Always make @RequestParam in initbinder optional because this will get called for every controller present in DemoController class
2. DateTime Format
Örnek
Elimizde şöyle bir kod olsun
@ControllerAdvice
public class CustomBindingControllerAdvice {

  @InitBinder
  public void initBinder(WebDataBinder binder) {
    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
    dateFormat.setLenient(false);
    binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
  }
}
Elimizde şöyle bir kod olsun
@RestController
@RequestMapping("/users")
public class UserController {

  @PostMapping("/create")
  public String createUser(@RequestParam String name, @RequestParam Date dob) {
    ...
  }

  @GetMapping("/create")
  public String getUser(@RequestParam String name, @RequestParam Date dob) {
    ...
  }
}
Bu RestController şöyle çağrılmak zorunda. Çünkü @InitBinder ile sabit bir SimpleDateFormat örüntüsü atadık
POST /users/create?name=John&dob=1990-05-15
3. Validator İlave Etmek
Bu anotasyon ile Spring'e rest metodlarında kullanılacak validator tanıtılır
İzlenecek adımlar şöyle
1. Create a class that implements the Validator interface.
2. Add the validator reference in the Controller class
3. Bind the custom validator to the controller
4. Annotate the controller method parameter with @Valid or @Validated
@Valid ve @Validated anotasyonuna bakabilirsiniz. Açıklaması şöyle
The validators which are bound using @Initbinder will be applied by default to all endpoints of the controller irrespective of type.
Eğer hata varsa, @ControllerAdvice + MethodArgumentNotValidException ile yakalanır

Örnek - @Valid
Elimizde şöyle bir kod olsun. FieldTripForm bir POJO
@Component
public class FieldTripFormValidator implements Validator {
  @Override
  public boolean supports(Class clazz) {
    return FieldTripForm.class.isAssignableFrom(clazz);
  }
  @Override
  public void validate(Object target, Errors errors){
          
    FieldTripForm form = (FieldTripForm) target;
    if(errors.getErrors == 0){
      ValidationUtils.rejectIfEmptyOrWhitespace(errors, "age","error.age", 
        "Age is required.");
      ValidationUtils.rejectIfEmptyOrWhitespace(errors, "name","error.name", 
        "Name is required.");
 
      if(form.getAge() < 18){
        ValidationUtils.rejectIfEmptyOrWhitespace(errors, "guardian", "error.guardian", 
          "Guardian name is required.");
      }
    } 
  }
}
Şöyle yaparız
@RestController
@RequestMapping("/")
public class FieldTripController {

  @Autowired
  private FieldTripFormValidator ftfValidator;
  
  @InitBinder(value = "fieldTripForm")
  protected void initBinder(WebDataBinder binder) {
    binder.setValidator(ftfValidator);
  }
  
  @PostMapping(value = "/fieldtrip")
  public ResponseEntity<APIResponse> signUp(@Valid @RequestBody FieldTripForm ftf){
    ...   
  }
}
Örnek - @Validated
Elimizde şöyle bir kod olsun
public class UserValidate implements Validator {

  @Override 
  public boolean supports(Class<?> arg0) {
    return User.class.isAssignableFrom(arg0);
  }

  @Override 
  public void validate(Object target, Errors errors) {
    User user = (User) target;
    int length = user.getUserName().length();
    if (length > 20) {
      errors.rejectValue("userName", "user.userName.too_long",
        "Username cannot exceed {20} characters");
    }
    ...
  }
}
Şöyle yaparız. Validator rest noktasına @Validated ile bağlanır
@Controller
public class UserController {

  @PostMapping("/addUser")
  public String addBook(@Validated User user,BindingResult result, Model model) {

    if(result.hasErrors()){
      List<ObjectError> allErrors = result.getAllErrors();
      Builder<String, String> builder = ImmutableListMultimap.builder();
      allErrors.stream().forEach(new Consumer<ObjectError>() {

        @Override
        public void accept(ObjectError t) {
          builder.put(t.getObjectName(), t.getDefaultMessage());
        }
      });

      ImmutableListMultimap<String, String> build = builder.build();
      model.addAttribute("result",build);
    }else {
      model.addAttribute("result","success");
    }
    return "user";
  }

  @InitBinder
  public void initBinder(WebDataBinder binder) {
    binder.addValidators(new UserValidate());
  }

}

Hiç yorum yok:

Yorum Gönder