Класи з анотаціями @Controller або @ControllerAdvice можуть мати методи, позначені анотацією @InitBinder, які ініціалізують екземпляри WebDataBinder, а ті, у свою чергу, можуть:

  • Прив'язувати параметри запиту (тобто дані форми або запиту) до об'єкта моделі.

  • Перетворювати рядкові значення запиту (такі як параметри запиту, змінні шляхи, заголовки, дані cookie та ін.) на цільовий тип аргументів методу контролера.

  • Форматувати значення об'єктів моделі як String значення при відображенні HTML-форм.

Методи з анотацією @InitBinder можуть реєструвати специфічні для контролера компоненти java.beans.PropertyEditor або Converter та Formatter зі Spring. До того ж, можна використовувати конфігурацію MVC для реєстрації типів Converter і Formatter у глобально розділеній FormattingConversionService.

Методи, позначені анотацією @InitBinder, підтримують багато з тих же аргументів, що й методи з анотацією @RequestMapping, за винятком аргументів, анотованих @ModelAttribute (об'єкт команди). Зазвичай вони оголошуються з аргументом WebDataBinder (для процедур реєстрації) і значенням, що повертається, void. У наступному лістингу наведено приклад:

Java
@Controller
public class FormController {
    @InitBinder 
    public void initBinder(WebDataBinder binder) {
        SimpleDateFormat dateFormat = новий SimpleDateFormat("yyyy-MM-dd");
        dateFormat.setLenient(false);
        binder.registerCustomEditor(Date.class, новий CustomDateEditor(dateFormat, false));
    }
    // ...
}
  1. Визначення методу з анотацією @InitBinder.
Kotlin
@Controller
class FormController {
    @InitBinder 
    fun initBinder(binder: WebDataBinder) {
        val dateFormat = SimpleDateFormat("yyyy-MM-dd")
        dateFormat.isLenient = false
        binder.registerCustomEditor(Date::class.java, CustomDateEditor(dateFormat, false))
    }
    // ...
}
  1. Визначення методу з анотацією @InitBinder.

До того ж, якщо ти використовуєш налаштування на основі Formatter через загальну службу FormattingConversionService, можеш повторно використовувати той самий підхід і зареєструвати специфічні для контролера реалізації Formatter, як показано в наступному прикладі:

Java
@Controller
public class FormController {
    @InitBinder 
    protected void initBinder(WebDataBinder binder) {
        binder.addCustomFormatter(new DateFormatter("yyyy-MM-dd"));
    }
    // ...
}
  1. Визначення методу з анотацією @InitBinder для кастомного формату.
Kotlin
@Controller
class FormController {
    @InitBinder 
    protected fun initBinder(binder: WebDataBinder) {
        binder.addCustomFormatter(DateFormatter("yyyy-MM-dd"))
    }
    // ...
}
  1. Визначення методу з анотацією @InitBinder для кастомного формату.

Структура моделі

У контексті вебдодатків прив'язування даних передбачає прив'язку параметрів HTTP-запиту (тобто даних форми або параметрів запиту) до властивостей об'єкта моделі та його вкладених об'єктів.

Для прив'язки даних відкриваються лише public властивості, що відповідають угоді про ім'я JavaBeans. Наприклад, методи public String getFirstName() та public void setFirstName(String) для властивості firstName.

Об'єкт моделі та його вкладений граф об'єктів також іноді називають об'єктом команди, базовим об'єктом форми або POJO ("старий добрий Java-об'єкт").

За замовчуванням Spring дозволяє прив'язку до всіх публічних якостей у графі об'єктів моделі. Це означає, що необхідно ретельно продумувати, які публічні властивості є у моделі, оскільки клієнт може на меті будь-яку публічну властивість, навіть ті, які не передбачаються для цього випадку використання.

Наприклад, за наявності кінцевої точки даних HTTP-форми, шкідливий клієнт може передати значення для властивостей, які існують у графі об'єктів моделі, але не є частиною HTML-форми, представленої у браузері. Це може призвести до того, що до об'єкта моделі та будь-якого з його вкладених об'єктів будуть встановлені дані, оновлення яких не очікується.

Рекомендований підхід полягає у використанні спеціалізованого об'єкта моделі, який відкриває лише ті властивості, що стосуються відправки форми. Наприклад, у формі зміни адреси електронної пошти користувача об'єкт моделі повинен оголосити мінімальний набір властивостей, як у наступному ChangeEmailForm.

public class ChangeEmailForm {
    private String oldEmailAddress;
    private String newEmailAddress;
    public void setOldEmailAddress(String oldEmailAddress) {
        this.oldEmailAddress = oldEmailAddress;
    }
    public String getOldEmailAddress() {
        return this.oldEmailAddress;
    }
    public void setNewEmailAddress(String newEmailAddress) {
        this.newEmailAddress = newEmailAddress;
    }
    public String getNewEmailAddress() {
        return this.newEmailAddress;
    }
}

Якщо ти не можеш або не бажаєш використовувати спеціалізований об'єкт моделі для кожного випадку використання прив'язки даних, ти маєш обмежити властивості, які дозволені для прив'язування даних. В ідеалі це можна зробити, зареєструвавши шаблони допустимих полів за допомогою методу setAllowedFields() у WebDataBinder.

Наприклад, щоб зареєструвати допустимі шаблони полів у твоєму додатку, можна реалізувати метод, позначений анотацією @InitBinder, у компоненті з анотацією @Controller або @ControllerAdvice, як показано нижче:

@Controller
public class ChangeEmailController {
    @InitBinder
    void initBinder(WebDataBinder binder) {
        binder.setAllowedFields("oldEmailAddress", "newEmailAddress");
    }
    //Методи, анотовані @RequestMapping тощо.
}

На додаток до реєстрації шаблонів допустимих полів, можна також зареєструвати шаблони недопустимих полів за допомогою методу setDisallowedFields() у DataBinder та його підкласах. Однак зверни увагу, що "список, що допускає", безпечніший за "список, що забороняє". Отже, використанню setAllowedFields() слід віддати перевагу замість використання setDisallowedFields().

Зверни увагу, що зіставлення з шаблонами допустимих полів чутливе до регістру; у той час як зіставлення із забороненими шаблонами полів — ні. До того ж, поле, яке відповідає забороненому шаблону, не буде прийнято, навіть якщо воно також відповідає шаблону зі списку допустимих.

Дуже важливо правильно налаштувати шаблони допустимих і недопустимих полів при безпосередньому відкритті моделі предметної області для прив'язки даних. В іншому випадку це буде великий ризик для безпеки.

Також рекомендується не використовувати типи з твоєї моделі предметної області, як-от сутності JPA або Hibernate, як об'єкт моделі у сценаріях прив'язки даних.