Класи з анотаціями @Controller
або @ControllerAdvice
можуть мати методи, позначені
анотацією @InitBinder
, які ініціалізують екземпляри WebDataBinder
, а ті, у свою чергу,
можуть:
-
Прив'язувати параметри запиту (тобто дані форми або запиту) до об'єкта моделі.
-
Перетворювати рядкові значення запиту (такі як параметри запиту, змінні шляхи, заголовки, дані cookie та ін.) на цільовий тип аргументів методу контролера.
-
Форматувати значення об'єктів моделі як
String
значення при відображенні HTML-форм.
Методи з анотацією @InitBinder
можуть реєструвати специфічні для контролера компоненти java.beans.PropertyEditor
або Converter
та Formatter
зі Spring. До того ж, можна використовувати конфігурацію MVC
для реєстрації типів Converter
і Formatter
у глобально розділеній FormattingConversionService
.
Методи, позначені анотацією @InitBinder
, підтримують багато з тих же аргументів, що й методи з анотацією
@RequestMapping
, за винятком аргументів, анотованих @ModelAttribute
(об'єкт команди).
Зазвичай вони оголошуються з аргументом WebDataBinder (для процедур реєстрації) і значенням, що повертається, void.
У наступному лістингу наведено приклад:
@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));
}
// ...
}
- Визначення методу з анотацією
@InitBinder
.
@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))
}
// ...
}
- Визначення методу з анотацією
@InitBinder
.
До того ж, якщо ти використовуєш налаштування на основі Formatter
через загальну службу FormattingConversionService
,
можеш повторно використовувати той самий підхід і зареєструвати специфічні для контролера реалізації
Formatter
, як показано в наступному прикладі:
@Controller
public class FormController {
@InitBinder
protected void initBinder(WebDataBinder binder) {
binder.addCustomFormatter(new DateFormatter("yyyy-MM-dd"));
}
// ...
}
- Визначення методу з анотацією
@InitBinder
для кастомного формату.
@Controller
class FormController {
@InitBinder
protected fun initBinder(binder: WebDataBinder) {
binder.addCustomFormatter(DateFormatter("yyyy-MM-dd"))
}
// ...
}
- Визначення методу з анотацією
@InitBinder
для кастомного формату.
Структура моделі
У контексті вебдодатків прив'язування даних передбачає прив'язку параметрів HTTP-запиту (тобто даних форми або параметрів запиту) до властивостей об'єкта моделі та його вкладених об'єктів.
Для прив'язки даних відкриваються лише public
властивості, що відповідають угоді про ім'я
JavaBeans. Наприклад, методи public String getFirstName()
та public void
setFirstName(String)
для властивості firstName
.
За замовчуванням 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, як об'єкт моделі у сценаріях прив'язки даних.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ