Saltar al contenido principal

Validating and Binding Data

Abrir en ChatGPT

Tu aplicación de Observers and Route Parameters puede utilizar FormView para editar datos de clientes existentes. Este paso utiliza Data binding, que conecta componentes de la interfaz de usuario directamente con el modelo de datos para una sincronización automática de valores. Esto reduce el código repetitivo en tu aplicación y te permite agregar verificaciones de validación a la entidad de Spring Customer, haciendo que tus usuarios proporcionen información completa y precisa al llenar formularios. Este paso cubre los siguientes conceptos:

Completar este paso crea una versión de 5-validating-and-binding-data.

Ejecutando la aplicación

A medida que desarrollas tu aplicación, puedes usar 5-validating-and-binding-data como comparación. Para ver la aplicación en acción:

  1. Navega al directorio de nivel superior que contiene el archivo pom.xml, que es 5-validating-and-binding-data si estás siguiendo la versión en GitHub.

  2. Usa el siguiente comando de Maven para ejecutar la aplicación Spring Boot localmente:

    mvn

Ejecutar la aplicación abre automáticamente un nuevo navegador en http://localhost:8080.

Definiendo reglas de validación

Desarrollar una aplicación con datos editables debería incluir validación. Las verificaciones de validación ayudan a mantener datos significativos y precisos enviados por los usuarios. Si se dejan sin control, podría llevar a problemas, por lo que es importante detectar los tipos de errores que los usuarios pueden cometer al llenar un formulario en tiempo real.

Dado que lo que se considera válido puede diferir entre propiedades, necesitarás definir qué hace que cada propiedad sea válida e informar al usuario si hay algo que es inválido. Afortunadamente, puedes hacer esto fácilmente con Validación de Jakarta. La validación de Jakarta te permite agregar restricciones a las propiedades como anotaciones.

Este tutorial utiliza dos anotaciones de Jakarta, @NotEmpty y @Pattern. @NotEmpty verifica si hay cadenas nulas o vacías, mientras que @Pattern comprueba si la propiedad coincide con una expresión regular que estableces. Ambas anotaciones te permiten agregar un mensaje para mostrar cuando la propiedad se vuelve inválida.

Para requerir que tanto el primer nombre como el apellido sean obligatorios y contengan solo letras, mientras que el nombre de la empresa sea opcional y permita letras, números y espacios, aplica las siguientes anotaciones a la entidad Customer:

Customer.java

@NotEmpty(message = "El nombre del cliente es requerido")
@Pattern(regexp = "[a-zA-Z]*", message = "Caracteres inválidos")
private String firstName = "";

@NotEmpty(message = "El apellido del cliente es requerido")
@Pattern(regexp = "[a-zA-Z]*", message = "Caracteres inválidos")
private String lastName = "";

@Pattern(regexp = "[a-zA-Z0-9 ]*", message = "Caracteres inválidos")
private String company = "";

private Country country = Country.UNKNOWN;

public enum Country {
UNKNOWN,

Consulta la referencia de restricciones de Validación de Bean de Jakarta para obtener una lista completa de validaciones, o aprende más en el artículo de Validación de Jakarta de webforJ.

Vinculando los campos

Para usar las verificaciones de validación en Customer para la interfaz de usuario en FormView, deberás crear un BindingContext para la vinculación de datos. Antes de la vinculación de datos, cada campo en FormView requería un listener de eventos para sincronizar manualmente con una entidad de Spring Customer. Crear un BindingContext en FormView vincula y sincroniza automáticamente el modelo de datos Customer con los componentes de la interfaz de usuario.

Creando un BindingContext

Una instancia de BindingContext necesita el bean de Spring con el que se sincronizan las vinculaciones. En FormView, declara un BindingContext usando la entidad Customer:

FormView.java
public class FormView extends Composite<Div> implements WillEnterObserver {
private final CustomerService customerService;

private BindingContext<Customer> context;

Customer customer = new Customer();

Luego, para vincular automáticamente los componentes de la interfaz de usuario a las propiedades del bean según sus nombres, utiliza BindingContext.of() con los siguientes parámetros:

  • this : Anteriormente, declaraste context como el BindingContext. El primer parámetro establece qué objeto contiene los componentes vinculables.
  • Customer.class : El segundo parámetro es la clase del bean que se utilizará para la vinculación.
  • true : El tercer parámetro habilita la validación de Jakarta, permitiendo que el contexto utilice las validaciones que estableciste para Customer. Hacer esto cambiará el estilo de los componentes inválidos y mostrará los mensajes establecidos.

En conjunto, se verá como la siguiente línea de código:

context = BindingContext.of(this, Customer.class, true);

Haciendo el formulario sensible

Con la vinculación de datos, tu aplicación ahora realiza automáticamente las verificaciones de validación. Al agregar un listener de eventos a las verificaciones, puedes prevenir que los usuarios envíen un formulario inválido. Agrega lo siguiente para que el botón de enviar esté activo solo cuando el formulario sea válido:

context = BindingContext.of(this, Customer.class, true);
context.onValidate(e -> submit.setEnabled(e.isValid()));

Eliminando listeners de eventos para componentes

Cada cambio en la interfaz de usuario ahora se sincroniza automáticamente con el BindingContext. Esto significa que ahora puedes eliminar los listeners de eventos de cada campo:

Antes

FormView.java
// Sin vinculación de datos
TextField firstName = new TextField("Primer Nombre", e -> customer.setFirstName(e.getValue()));
TextField lastName = new TextField("Apellido", e -> customer.setLastName(e.getValue()));
TextField company = new TextField("Empresa", e -> customer.setCompany(e.getValue()));
ChoiceBox country = new ChoiceBox("País",
e -> customer.setCountry(Country.valueOf(e.getSelectedItem().getText())));

Después

FormView.java
// Con vinculación de datos
TextField firstName = new TextField("Primer Nombre");
TextField lastName = new TextField("Apellido");
TextField company = new TextField("Empresa");
ChoiceBox country = new ChoiceBox("País");

Vinculación por nombres de propiedades

Dado que el nombre de cada componente coincide con el modelo de datos, webforJ aplicó Vinculación Automática. Si los nombres no coincidieran, podrías usar la anotación @UseProperty para mapearlos.

@UseProperty("firstName")
TextField firstNameField = new TextField("Primer Nombre");

Leyendo datos en el método fillForm()

Anteriormente, en el método fillForm(), inicializabas el valor de cada componente recuperando manualmente los datos de la copia de Customer. Pero ahora, dado que estás usando un BindingContext, puedes utilizar el método read(). Este método llena cada componente vinculado con la propiedad asociada de los datos en la copia de Customer.

En el método fillForm(), reemplaza los métodos setValue() con read():

FormView.java
public void fillForm(Long customerId) {
customer = customerService.getCustomerByKey(customerId);

// Removed each setValue() method for the UI components

context.read(customer);
}

Agregando validación a submitCustomer()

El último cambio en FormView para este paso será agregar una salvaguarda al método submitCustomer(). Antes de confirmar cambios en la base de datos H2, la aplicación realizará una validación final sobre los resultados del contexto vinculado utilizando el método write().

El método write() actualiza las propiedades de un bean utilizando los componentes de la interfaz de usuario vinculados en el BindingContext y devuelve un ValidationResult.

Usa el método write() para escribir en la copia de Customer utilizando los componentes vinculados en FormView. Luego, si el ValidationResult devuelto es válido, actualiza la base de datos H2 con los datos escritos.

FormView.java
private void submitCustomer() {
ValidationResult results = context.write(customer);
if (results.isValid()) {
if (customerService.doesCustomerExist(customerId)) {
customerService.updateCustomer(customer);
} else {
customerService.createCustomer(customer);
}
navigateToMain();
}
}

FormView completado

Con estos cambios, así es como se ve FormView. La aplicación ahora admite la vinculación de datos y la validación utilizando Spring Boot y webforJ. Las entradas del formulario se sincronizan automáticamente con el modelo y se verifican contra las reglas de validación.

FormView.java
@Route("customer/:id?<[0-9]+>")
@FrameTitle("Formulario de Cliente")
public class FormView extends Composite<Div> implements WillEnterObserver {
private final CustomerService customerService;
private BindingContext<Customer> context;
private Customer customer = new Customer();
private Long customerId = 0L;
private Div self = getBoundComponent();
private TextField firstName = new TextField("Primer Nombre");
private TextField lastName = new TextField("Apellido");
private TextField company = new TextField("Empresa");
private ChoiceBox country = new ChoiceBox("País");
private Button submit = new Button("Enviar", ButtonTheme.PRIMARY, e -> submitCustomer());
private Button cancel = new Button("Cancelar", ButtonTheme.OUTLINED_PRIMARY, e -> navigateToMain());
private ColumnsLayout layout = new ColumnsLayout(

Siguiente paso

El siguiente paso, Integrando un Diseño de Aplicación, se centra en utilizar un AppLayout para agregar un menú lateral que esté disponible para los usuarios tanto en las páginas de la tabla de clientes como en las páginas de formulario de clientes. También aprenderás sobre otra herramienta de diseño, el componente FlexLayout.