¿Qué hay de nuevo en CUBA 7?

¿Qué hay de nuevo en CUBA 7?


Hace tres años, anunciamos la segunda versión principal del marco disponible públicamente. CUBA 6 fue la versión que cambió el juego: la licencia pasó de ser propietaria a Apache 2.0. Esos días ni siquiera podíamos adivinar dónde iba a llevar el marco a largo plazo. La comunidad CUBA comenzó a crecer exponencialmente, por lo que hemos aprendido muchas formas posibles (y a veces imposibles) de cómo los desarrolladores usan el marco. Ahora nos complace anunciar CUBA 7 , que, esperamos, hará que el desarrollo sea más coherente y alegre para todos los miembros de la comunidad, desde aquellos que recién comienzan su viaje en CUBA y Java hasta desarrolladores empresariales expertos y expertos en Java.


cuba


Herramientas de desarrollo


Obviamente, una gran parte del éxito de CUBA se lo debemos a CUBA Studio . Se ha simplificado notablemente la rutina empresarial de Java sobrecargada, en muchos lugares se basa en hacer configuraciones triviales en los diseñadores visuales: no es necesario conocer Persistence API o Gradle o incluso Spring para desarrollar una aplicación CRUD completa y rica en funciones: Studio lo hará para ti


El Studio era una aplicación web separada y este hecho causó algunas limitaciones significativas:


  • En primer lugar, Studio no era un IDE con todas las funciones, por lo que los desarrolladores tuvieron que cambiar entre Studio e IntelliJ IDEA o Eclipse para desarrollar la lógica empresarial y beneficiarse de la navegación conveniente, la finalización del código y otras cosas esenciales, lo que era molesto.
  • En segundo lugar, esta simplicidad mágica se construyó sobre el análisis y generación masivos de código fuente. Mejorar las capacidades de generación de código significaría avanzar hacia el desarrollo de un IDE con todas las funciones, una tarea demasiado ambiciosa.

Decidimos apoyarnos en el hombro de otro gigante para superar estas limitaciones. Studio se fusionó con IntelliJ IDEA por JetBrains. Ahora puede instalarlo como un complemento para su IntelliJ IDEA o descargarlo como un paquete independiente por separado.


cuba1


Esto abre nuevos horizontes:


  • Soporte de otros idiomas JVM (y Kotlin en primer lugar)
  • Implementación en caliente mejorada
  • Navegación intuitiva por todo el proyecto.
  • Sugerencias más inteligentes y generadores de código

Actualmente, el nuevo Studio está en desarrollo activo: estamos transfiriendo características de la versión anterior. El plan a corto plazo también es volver a implementar diseñadores basados ​​en la web utilizando la interfaz de usuario nativa de IntelliJ y mejorar la experiencia de navegación del proyecto.


Actualización de pila


Tradicionalmente, la pila subyacente también se ha mejorado principalmente, por ejemplo, Java 8/11, Vaadin 8, Spring 5.


cuba2


Por defecto, los nuevos proyectos usan Java 8, pero puede especificar la versión de Java agregando la siguiente cláusula al archivo build.gradle:


subprojects { sourceCompatibility = JavaVersion.VERSION_11 targetCompatibility = JavaVersion.VERSION_11 } 

La actualización a Vaadin 8 fue un gran desafío debido a los cambios masivos en la API de enlace de datos de Vaadin. Afortunadamente, CUBA extrae desarrolladores de elementos internos de Vaadin envolviéndolos en su propia capa API. El equipo de CUBA hizo un gran trabajo reimplementando los componentes internos manteniendo intacta su propia API. Esto significa que la compatibilidad se guarda por completo y puede beneficiarse de Vaadin 8 justo después de migrar un proyecto a CUBA 7 sin ninguna refactorización.


La lista completa de dependencias actualizadas está disponible en las notas de la versión oficial.


Nueva API de pantallas


Esta sección también podría llamarse "La primera API de pantallas", ya que CUBA nunca ha tenido una API oficialmente declarada en el nivel de cliente web. Proviene de la historia del marco y ciertos supuestos que se hicieron en la primera etapa:


  • Enfoque declarativo centrado: todo lo que se puede describir de manera declarativa, debe declararse en un descriptor de pantalla y no codificarse en su controlador
  • Las pantallas estándar (navegador y editor) proporcionan una funcionalidad genérica concreta y no es necesario modificarla.

Desde que los primeros mil miembros se unieron a nuestra comunidad, nos dimos cuenta de cuán amplia es la variedad de requisitos para pantallas CRUD "estándar", mucho más allá del conjunto de características inicialmente diseñado. Sin embargo, durante mucho tiempo pudimos manejar solicitudes de comportamiento personalizado incluso sin una capa API, gracias a otra suposición de la primera etapa: herencia abierta. La herencia abierta efectiva significa que puede anular cualquier método público o protegido de una clase subyacente para adaptar su comportamiento a lo que necesita. Esto puede sonar como una cura para todas las enfermedades, pero de hecho no le da ni siquiera un contrato a corto plazo: ¿qué pasa si el método anulado será renombrado, eliminado o simplemente nunca se usará en las futuras versiones del marco?


cuba3


Entonces, en respuesta a la creciente demanda de la comunidad, decidimos introducir una nueva API de pantallas. La API proporciona puntos de extensión claros y a largo plazo sin magia declarativa oculta, flexible y muy fácil de usar.


Declaración de pantalla


En CUBA 7, la declaración de pantalla es extremadamente simple:


 @UiController("new-screen") // screen id public class NewScreen extends Screen { } 

En el ejemplo anterior, podemos ver que el identificador de pantalla se define explícitamente justo encima de la clase de controlador. En otras palabras, la identificación de la pantalla y la clase de controlador ahora se corresponden entre sí de manera única. Entonces, buenas noticias, ahora las pantallas pueden ser abordadas directamente por su clase de controlador de una manera segura:


 @Inject private ScreenBuilders screenBuilders; @Subscribe private void onBeforeClose(BeforeCloseEvent event) { screenBuilders.screen(this) .withScreenClass(SomeConfirmationScreen.class) .build() .show(); } 

El descriptor de pantalla se convierte en una parte complementaria en lugar de obligatoria. El diseño puede crearse mediante programación o declararse como un descriptor de pantalla xml, que se define mediante la anotación @UiDescriptor sobre la clase de controlador. Esto hace que los controladores y el diseño sean mucho más fáciles de leer y comprender: este enfoque es muy similar al utilizado en el desarrollo de Android.


Antes, también era necesario registrar un descriptor de pantalla en el archivo web-Screens.xml y asignarle un identificador. En CUBA 7, este archivo se mantiene debido a razones de compatibilidad, sin embargo, la creación de pantallas de una nueva manera no requiere dicho registro.


Pantallas ciclo de vida


La nueva API presenta eventos de ciclo de vida de pantalla claros y autoexplicativos:


  • Init
  • Afterinit
  • Antes de
  • Después del espectáculo
  • Antes de cerrar
  • Afterclose

Todos los eventos relacionados con la pantalla en CUBA 7 se pueden suscribir de la siguiente manera:


 @UiController("new-screen") public class NewScreen extends Screen { @Subscribe private void onInit(InitEvent event) { } @Subscribe private void onBeforeShow(BeforeShowEvent event) { } } 

Al comparar la nueva API con el enfoque anterior, puede ver que no estamos anulando los métodos de enlace, que se denominan oscuramente en la jerarquía de las clases principales, sino que definen la lógica en puntos claros predefinidos del ciclo de vida de la pantalla.


Manejo de eventos y delegados funcionales


En la sección anterior aprendimos cómo suscribirse a los eventos del ciclo de vida, entonces, ¿qué pasa con otros componentes? ¿Deberíamos dispersar a todos los oyentes necesarios en la inicialización de la pantalla como en las versiones 6.x? La nueva API es muy uniforme, por lo que suscribirse a otros eventos es absolutamente similar a los del ciclo de vida.


Tomemos un ejemplo simple con dos elementos de la interfaz de usuario: un botón y un campo de moneda, para que su descriptor xml se vea así:


 <?xml version="1.0" encoding="UTF-8" standalone="no"?> <window xmlns="http://schemas.haulmont.com/cuba/screen/window.xsd" caption="msg://caption" messagesPack="com.company.demo.web"> <layout> <hbox spacing="true"> <currencyField id="currencyField" currency="$" currencyLabelPosition="LEFT"/> <button id="calcPriceBtn" caption="Calculate Price"/> </hbox> </layout> </window> 

Al hacer clic en el botón, llamamos al servicio de middleware que devuelve un número, que va al campo de moneda. El campo de moneda debería cambiar su estilo dependiendo del valor del precio.


 @UiController("demo_MyFirstScreen") @UiDescriptor("my-first-screen.xml") public class MyFirstScreen extends Screen { @Inject private PricingService pricingService; @Inject private CurrencyField<BigDecimal> currencyField; @Subscribe("calcPriceBtn") private void onCalcPriceBtnClick(Button.ClickEvent event) { currencyField.setValue(pricingService.calculatePrice()); } @Subscribe("currencyField") private void onPriceChange(HasValue.ValueChangeEvent<BigDecimal> event) { BigDecimal price = pricingService.calculatePrice(); currencyField.setStyleName(getStyleNameByPrice(price)); } private String getStyleNameByPrice(BigDecimal price) { ... } } 

En el ejemplo anterior, podemos ver dos controladores de eventos: uno se invoca cuando se hace clic en el botón y otro se ejecuta cuando el campo de moneda cambia su valor, tan simple como eso.


Ahora, imaginemos que necesitamos validar nuestro precio y verificar que su valor sea positivo. La forma más sencilla sería agregar un validador mientras se inicializa la pantalla:


 @UiController("demo_MyFirstScreen") @UiDescriptor("my-first-screen.xml") public class MyFirstScreen extends Screen { @Inject private CurrencyField<BigDecimal> currencyField; @Subscribe private void onInit(InitEvent event) { currencyField.addValidator(value -> { if (value.compareTo(BigDecimal.ZERO) <= 0) throw new ValidationException("Price should be greater than zero"); }); } } 

En las aplicaciones del mundo real, un punto de entrada de pantalla generalmente se llena de este tipo de inicializadores de elementos de pantalla. Para abordar este problema, CUBA proporciona la anotación útil @Install . Veamos cómo puede ayudar en nuestro caso:


 @UiController("demo_MyFirstScreen") @UiDescriptor("my-first-screen.xml") public class MyFirstScreen extends Screen { @Inject private CurrencyField<BigDecimal> currencyField; @Install(to = "currencyField", subject = "validator") private void currencyFieldValidator(BigDecimal value) { if (value.compareTo(BigDecimal.ZERO) <= 0) throw new ValidationException("Price should be greater than zero"); } } 

De hecho, delegamos la lógica de validación de nuestro campo de moneda al método currencyFieldValidator en nuestra pantalla. Esto puede parecer un poco complicado, sin embargo, los desarrolladores adoptan esta característica sorprendentemente rápido.


Creadores de pantalla / Notificaciones / Diálogos


cuba4


CUBA 7 también presenta un conjunto de componentes útiles con API fluidas:


  • ScreenBuilders combina fábricas fluidas para generar búsquedas estándar, editores y pantallas personalizadas. El siguiente ejemplo muestra cómo puede abrir una pantalla desde otra. Tenga en cuenta que el método build () devuelve la instancia de pantalla del tipo correcto, sin necesidad de emitirlo de forma insegura.


    CurrencyConversions currencyConversions = screenBuilders.screen (this)
    .withScreenClass (CurrencyConversions.class)
    .withLaunchMode (OpenMode.DIALOG)
    .build ();
    currencyConversions.setBaseCurrency (Currency.EUR);
    currencyConversions.show ();


  • El componente Pantallas proporciona una abstracción de nivel inferior para crear y mostrar pantallas en lugar de ScreenBuilders . También proporciona acceso a la información sobre todas las pantallas abiertas en su aplicación CUBA ( Screens # getOpenedScreens ) en caso de que necesite recorrerlas.


  • Los componentes de notificaciones y cuadros de diálogo presentan interfaces convenientes que se explican por sí mismas. Aquí hay un ejemplo para crear y mostrar un diálogo y una notificación:


    dialogs.createOptionDialog ()
    .withCaption ("Mi primer diálogo")
    .withMessage ("¿Quieres agradecer al equipo de CUBA?")
    .withActions (
    nuevo DialogAction (DialogAction.Type.YES) .withHandler (e ->
    notificaciones.create ()
    .withCaption ("¡Gracias!")
    .withDescription ("Agradecemos a todos los miembros de la comunidad")
    .withPosition (Notificaciones.Position.MIDDLE_CENTER)
    .withHideDelayMs (3000)
    .show ()),
    nuevo DialogAction (DialogAction.Type.CANCEL)
    )
    .show ();



Enlace de datos


CUBA permite el desarrollo extremadamente rápido de interfaces de usuario de backoffice no solo al proporcionar herramientas visuales avanzadas con amplias capacidades de generación de código, sino también mediante un amplio conjunto de componentes conscientes de los datos disponibles de inmediato. Dichos componentes solo necesitan saber con qué datos trabajan y el resto se administrará automáticamente, por ejemplo, listas de búsqueda, campos de selección, varias cuadrículas con operaciones CRUD, etc.


Antes de la versión 7, el enlace de datos se implementaba a través de los llamados orígenes de datos, objetos que envuelven una sola entidad o una colección de entidades para vincularlos reactivamente con componentes conscientes de los datos. Este enfoque funcionó muy bien, sin embargo, en cuanto a la implementación, fue un monolito. La arquitectura monolítica generalmente causa problemas con su personalización, por lo que en CUBA 7 esta roca sólida se dividió en 3 componentes de datos:


  • El cargador de datos es un proveedor de datos para contenedores de datos. Los cargadores de datos no guardan datos, simplemente pasan todos los parámetros de consulta necesarios a un almacén de datos y alimentan los contenedores de datos con el conjunto de datos resultante.
  • El contenedor de datos mantiene los datos cargados (una sola entidad o varias entidades) y los proporciona a los componentes conscientes de los datos de manera reactiva: todos los cambios de las entidades envueltas se exponen a los componentes de la interfaz de usuario correspondientes y viceversa, todos los cambios en Los componentes de la IU conducirán a los cambios correspondientes en su contenedor de datos.
  • El contexto de datos es un poderoso administrador de modificación de datos que rastrea los cambios y confirma todas las entidades modificadas. Una entidad puede fusionarse en un contexto de datos, por lo que proporcionará una copia de la entidad original con la única, pero muy importante diferencia: todas las modificaciones de la entidad resultante y todas las entidades a las que hace referencia (incluidas las colecciones) serán rastreados, almacenados y comprometido en consecuencia.

Los componentes de datos se pueden declarar en descriptores de pantalla o instanciarse mediante programación utilizando una fábrica especializada: DataComponents .


Misceláneo


Ufff, se describen las partes más importantes de las nuevas pantallas API, así que permítanme enumerar brevemente otras características importantes en el nivel de cliente web:


  • Historial de URL y navegación . Esta característica resuelve un problema muy común de SPA con el botón "volver" en un navegador web, proporciona una manera fácil de asignar rutas a las pantallas de aplicaciones y permite que una API refleje el estado actual de una pantalla en su URL.
  • Formulario en lugar de FieldGroup . FieldGroup es un componente de datos para mostrar y modificar campos de una sola entidad. Infiere la IU real que se muestra para un campo en tiempo de ejecución. En otras palabras, si tiene un campo Fecha en su entidad, se mostrará como DateField . Sin embargo, si desea operar con este campo mediante programación, necesitará inyectar este campo en el controlador de pantalla y emitirlo al tipo correcto manualmente ( DateField en nuestro ejemplo ). Más adelante cambiamos nuestro tipo de campo a otro y nuestra aplicación se bloquea en tiempo de ejecución ... El formulario aborda este problema mediante una declaración explícita de tipo de campo. Encuentre más información sobre este nuevo componente aquí .
  • La integración de componentes JavaScript de terceros se simplifica significativamente, siga la documentación para integrar componentes JavaScript personalizados en una aplicación CUBA.
  • Los atributos HTML / CSS ahora se pueden definir fácilmente desde el descriptor de pantalla xml o establecer mediante programación. Encuentra más información aquí .

Funciones de middleware


El bloque anterior sobre las nuevas pantallas API era más grande de lo que esperaba, ¡así que en esta sección intentaré estar ordenado!


Evento modificado de entidad


Entity Changed Event es un evento de aplicación de Spring que se activa cuando su entidad se dirigió a un almacén de datos, se insertó físicamente y está a una pulgada de su confirmación. Aquí puede proporcionar algunos controles adicionales (por ejemplo, verificar la disponibilidad del producto en stock antes de confirmar un pedido) y modificarlo (por ejemplo, volver a calcular los totales) justo antes de que sea visible para otras transacciones (por supuesto, con un nivel de aislamiento de lectura confirmada). También puede usar este evento como la última oportunidad para interrumpir la confirmación de la transacción lanzando una excepción, lo que podría ser útil en algunos casos de esquina.


También hay una manera de detectar el Evento de Entidad Cambiada justo después de que se haya realizado la confirmación.


Siga este capítulo de la documentación para ver un ejemplo.


Administrador de datos transaccionales


Al desarrollar una aplicación, normalmente operamos con entidades separadas, aquellas que no son administradas por ninguna transacción. Sin embargo, no siempre es posible trabajar con entidades separadas, especialmente cuando se trata de cumplir con los requisitos de ACID; este es el caso cuando puede usar el administrador de datos transaccionales. Se ve muy similar al administrador de datos ordinario, pero difiere en los siguientes aspectos:


  • Puede unirse a una transacción existente (en caso de que se llame en contexto transaccional) o crear su propia transacción.
  • No tiene método de confirmación , pero existe el método de guardar, que no conduce a una confirmación inmediata, sino que espera hasta que se confirme la transacción adjunta.

Encuentre un ejemplo de uso aquí .


JPA Lifecycle Callbacks


Finalmente, CUBA 7 admite devoluciones de llamada de ciclo de vida JPA. Para no replicar una información bien escrita sobre para qué se pueden usar estas devoluciones de llamada, permítanme compartir este enlace , que cubre completamente el tema.


¿Qué pasa con la compatibilidad?


cuba5


¡Una pregunta justa para cualquier lanzamiento importante, especialmente cuando hay tantos cambios aparentemente importantes! Hemos diseñado todas estas nuevas funciones y API teniendo en cuenta la compatibilidad con versiones anteriores:


  • La antigua API de pantallas es compatible con CUBA 7 y se implementa a través de la nueva bajo el capó :)
  • También hemos proporcionado adaptadores para el enlace de datos antiguo, que siguen funcionando para las pantallas antiguas.

Entonces, buenas noticias, la ruta de migración de la versión 6 a la 7 debería ser bastante sencilla.


Conclusión


Concluyendo esta descripción técnica, me gustaría mencionar que hay otras innovaciones importantes, especialmente con las licencias:


  • El límite de 10 entidades para Studio ahora se ha ido
  • Los complementos de informes, BPM, gráficos y mapas y búsqueda de texto completo ahora son gratuitos y de código abierto.
  • La versión comercial de Studio brinda comodidad de desarrollo adicional con diseñadores visuales para entidades, pantallas, menús y otros elementos de la plataforma, mientras que la versión gratuita se enfoca en trabajar con código
  • ¡Tenga en cuenta que para las versiones 6.xy anteriores de los términos de licencia de Platform y Studio siguen siendo los mismos!

Finalmente, permítanme agradecer nuevamente a los miembros de la comunidad por todo el apoyo y los comentarios. ¡Espero que te encante la versión 7! La lista completa de cambios está tradicionalmente disponible en las notas de la versión .

Source: https://habr.com/ru/post/444558/


All Articles