Классы с аннотациями @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 = new SimpleDateFormat("yyyy-MM-dd");
dateFormat.setLenient(false);
binder.registerCustomEditor(Date.class, new 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, в качестве объекта модели в сценариях привязки данных.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ