Las clases con las anotaciones @Controller o @ControllerAdvice pueden tener métodos marcados con la anotación @InitBinder que inicializan WebDataBinder código de instancias>, y ellos, a su vez, pueden:

  • Vincular parámetros de solicitud (es decir, datos de formulario o solicitud) a un objeto modelo.

  • Convierta los valores de la cadena de solicitud (como parámetros de solicitud, variables de ruta, encabezados, datos de cookies, etc.) al tipo de destino de los argumentos del método del controlador.

  • Formatee los valores de los objetos del modelo como valores String al mostrar formularios HTML.

Los métodos con la anotación @InitBinder pueden registrar java.beans.PropertyEditor o Converter y Formateador específicos del controlador. > componentes > de Spring. Además, puede utilizar la configuración MVC para registrar los tipos Converter y Formatter en un FormattingConversionService compartido globalmente.

Los métodos marcados con la anotación @InitBinder admiten muchos de los mismos argumentos que los métodos con la anotación @RequestMapping, con la excepción de los argumentos anotados con @ModelAttribute (objeto de comando). Normalmente se declaran con un argumento WebDataBinder (para procedimientos de registro) y un valor de retorno nulo. El siguiente listado es un ejemplo:

Java
@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));
    }
    // ...
}
  1. Definir un método con la anotación @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. Definir un método con la anotación @InitBinder.

Además, si utiliza la configuración basada en Formatter a través del FormattingConversionService genérico, puede reutilizar el mismo enfoque y registrar implementaciones de Formatter específicas del controlador. , como se muestra en el siguiente ejemplo:

Java
@Controller
public class FormController {
    @InitBinder 
    protected void initBinder(WebDataBinder binder) {
        binder.addCustomFormatter(new DateFormatter("yyyy-MM-dd"));
    }
    // ...
}
  1. Definir un método con la anotación @InitBinder para un formateador personalizado.
Kotlin
@Controller
class FormController {
    @InitBinder 
    protected fun initBinder(binder: WebDataBinder) {
        binder.addCustomFormatter(DateFormatter("yyyy-MM-dd"))
    }
    // ...
}
  1. Definir un método con la anotación @InitBinder para un formateador personalizado.

Estructura del modelo

En el contexto de las aplicaciones web, el enlace de datos implica vincular parámetros de solicitud HTTP (es decir, datos de formulario o parámetros de solicitud) a las propiedades del objeto modelo y sus objetos anidados.

Para el enlace de datos, solo las propiedades public correspondientes a están expuestas convenciones de nomenclatura de JavaBeans; por ejemplo, los métodos public String getFirstName() y public void setFirstName(String) para firstName propiedad.

El objeto modelo y su gráfico de objetos anidados también se denominan a veces objeto de comando, objeto de formulario base, o POJO("buen viejo objeto Java").

De forma predeterminada, Spring permite vincular todas las propiedades públicas en el gráfico de objetos del modelo. Esto significa que debe pensar detenidamente qué propiedades públicas tiene un modelo, ya que un cliente puede apuntar a cualquier propiedad pública, incluso aquellas que no están destinadas a un caso de uso determinado.

Por ejemplo, dado un punto final de datos de formulario HTTP, un cliente malintencionado podría pasar valores para propiedades que existen en el gráfico de objetos del modelo pero que no forman parte del formulario HTML presentado en el navegador. Esto puede dar como resultado que el objeto del modelo y cualquiera de sus subobjetos se establezcan en datos que no se espera que se actualicen.

El enfoque recomendado es utilizar un objeto modelo especializado que exponga sólo aquellas propiedades que son relevantes para el envío del formulario. Por ejemplo, en un formulario para cambiar la dirección de correo electrónico de un usuario, el objeto modelo debe declarar un conjunto mínimo de propiedades, como en el siguiente 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;
    }
}

Si no puede o no desea utilizar un objeto de modelo especializado para cada caso de uso de enlace de datos, entonces debe restringir las propiedades permitidas para el enlace de datos. . Idealmente, esto se puede hacer registrando patrones de campos permitidos usando el método setAllowedFields() en WebDataBinder.

Por ejemplo, para registrar patrones de campo válidos en su aplicación, puede implementar un método marcado con la anotación @InitBinder en un componente con @Controller o anotación @ControllerAdvice como se muestra a continuación:


@Controller
public class ChangeEmailController {
    @InitBinder
    void initBinder(WebDataBinder binder) {
        binder.setAllowedFields("oldEmailAddress", "newEmailAddress");
    }
    // métodos anotados con @RequestMapping, etc.
}

Además de registrar patrones de campo válidos, también puede registrar patrones de campo no permitidos utilizando el método setDisallowedFields() en DataBinder y sus subclases. . Sin embargo, tenga en cuenta que la "lista de permitidos" es más segura que la "lista de denegados". Por lo tanto, se debe preferir usar setAllowedFields() a setDisallowedFields().

Tenga en cuenta que la coincidencia de patrones de campos válidos distingue entre mayúsculas y minúsculas; mientras que comparar con patrones de campos prohibidos no lo es. Además, no se aceptará un campo que coincida con un patrón prohibido, incluso si también coincide con un patrón de la lista permitida.

Es muy importante configurar correctamente las plantillas de campos válidos e inválidos al abrir directamente el modelo de dominio para el enlace de datos. De lo contrario, será un gran riesgo para la seguridad.

Además, se recomienda encarecidamente no no utilizar tipos de su modelo de dominio, como entidades JPA o Hibernate, como objeto de modelo en escenarios de enlace de datos.