Saltar al contenido principal

Validating and Binding Data

Abrir en ChatGPT

Tu aplicación de Observers y Parámetros de Ruta puede usar FormView para editar datos de clientes existentes. Este paso utiliza Vinculación de Datos, que conecta componentes de la interfaz de usuario directamente al modelo de datos para la sincronización automática de valores. Esto reduce el código repetitivo en tu aplicación y permite agregar comprobaciones de validación a la entidad de Spring Customer, haciendo que tus usuarios proporcionen información completa y precisa al completar los formularios. Este paso cubre los siguientes conceptos:

Completar este paso crea una versión de 5-validando-y-vinculando-datos.

Ejecución de la aplicación

A medida que desarrollas tu aplicación, puedes usar 5-validando-y-vinculando-datos como referencia. Para ver la aplicación en acción:

  1. Navega al directorio de nivel superior que contiene el archivo pom.xml, este es 5-validando-y-vinculando-datos si estás siguiendo la versión en GitHub.

  2. Usa el siguiente comando de Maven para ejecutar la aplicación de 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 debe incluir validación. Las comprobaciones de validación ayudan a mantener datos significativos y precisos enviados por los usuarios. Si se las deja sin chequear, esto podría generar problemas, por lo que es importante detectar los tipos de errores que los usuarios pueden cometer al completar 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 no es vá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 cadenas nulas y vacías, mientras que @Pattern verifica 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 nombre como el apellido sean obligatorios y contengan solo letras, mientras que el nombre de la empresa es opcional y permite letras, números y espacios, aplica las siguientes anotaciones a la entidad Customer:

Customer.java

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

@NotEmpty(message = "Se requiere el apellido del cliente")
@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 comprobaciones de validación en Customer para la interfaz de usuario en FormView, crearás un BindingContext para la vinculación de datos. Antes de la vinculación de datos, cada campo en FormView requería un oyente de eventos para sincronizarse manualmente con la entidad de Spring Customer. Crear un BindingContext en FormView vincula y sincroniza automáticamente el modelo de datos Customer a 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, usa 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 a utilizar para la vinculación.
  • true : El tercer parámetro habilita la validación de Jakarta, permitiendo que el contexto use las validaciones que configuraste para Customer. Hacer esto cambiará el estilo de los componentes inválidos y mostrará los mensajes establecidos.

Todo junto, se verá como la siguiente línea de código:

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

Haciendo el formulario receptivo

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

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

Eliminando oyentes 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 oyentes de eventos de cada campo:

Antes

FormView.java
// Sin vinculación de datos
TextField firstName = new TextField("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("Nombre");
TextField lastName = new TextField("Apellido");
TextField company = new TextField("Empresa");
ChoiceBox country = new ChoiceBox("País");

Vinculando por nombres de propiedad

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

@UseProperty("firstName")
TextField firstNameField = new TextField("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, como estás usando un BindingContext, puedes usar 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);

// Eliminados cada setValue() para los componentes de la interfaz

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 usando el método write().

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

Usa el método write() para escribir en la copia de Customer usando los componentes vinculados en FormView. Luego, si el ValidationResult devuelto es válido, actualiza la base de datos H2 usando 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 soporta vinculación de datos y validación utilizando Spring Boot y webforJ. Las entradas de formulario se sincronizan automáticamente con el modelo y se comprueban contra las reglas de validación.

FormView.java
@Route("customer/:id?<[0-9]+>")
@FrameTitle("Formulario del 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("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(

Próximo paso

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