
Cuando lee los requisitos para la próxima aplicación web corporativa para uso interno, generalmente (a juzgar por mi experiencia) es uno y el mismo conjunto: una base de datos relacional para almacenar datos, a menudo heredada de la versión anterior de la aplicación, una gran cantidad de formas de diferentes niveles de dificultad (pero al mismo tiempo, típico) para la entrada de datos, una variedad de formularios de informes, lógica empresarial compleja, integración con otras aplicaciones, desde contabilidad hasta gestión de suministros, varios miles de usuarios que trabajan simultáneamente. ¿Qué suele venir a la mente?
"Por lo tanto, tomaré el DBMS que conozco y que se ajusta a sus volúmenes de datos, fijaré Hibernate / JPA, escribiré la aplicación en Spring Boot, expondré la API REST y escribiré al cliente en el marco JS, probablemente Angular / React".
“Sí, todavía necesitamos atornillar Spring Security. Y escriba una restricción en el acceso a los datos para diferentes departamentos y roles, a nivel de filas de bases de datos u objetos de datos. Como hacerlo Presentación o VPD, tendrá que mirar ".
"Ugh, tengo que escribir un montón de DAO, se hacen rápidamente, pero hay muchos de ellos".
"Y la conversión de Entity a DTO: estoy usando ModelMapper ".
"Lo principal es no olvidar recordarle al alumno sobre los atributos perezosos y las uniones para que no haya, como la última vez".
"Los abetos, mientras inicia la lógica de negocios, necesita escribir tanto código de servicio ..."
Este artículo es para aquellos que han escrito al menos un par de aplicaciones empresariales desde cero en Spring / Spring Boot y ahora piensan que sería bueno acelerar de alguna manera el desarrollo de aplicaciones tan diferentes, pero al mismo tiempo similares. A continuación, veremos cómo deshacerse de las tareas "típicas" utilizando la
plataforma CUBA .
Otro marco?

Pensamiento número uno, cuando se ofrece al desarrollador un nuevo marco (y, en particular, CUBA), es: “¿Por qué debería molestarme con esto? Tomaré el Spring Boot familiar y familiar y lo haré todo ". Y esto es razonable. El nuevo marco es el estudio de nuevos enfoques de desarrollo, nuevas trampas y limitaciones que ha aprendido a evitar de manera inteligente cuando se desarrolla en un marco familiar.
Pero, cuando comencé a desarrollar en CUBA, no tuve que cambiar mucho mis habilidades con Spring. Naturalmente, tuve que pasar un poco de tiempo entendiendo la plataforma, pero esto no fue un desglose radical de todos los hábitos, sino un pequeño cambio en las habilidades de desarrollo.
Como resultado, el código para DTO, salida de datos página por página, filtrado de datos (análisis de los parámetros transferidos al formulario y compilación de solicitudes) desapareció. Al mismo tiempo, casi no tuve que jugar con la configuración de Spring Security y escribir código de administrador, formularios de inicio de sesión y lógica de cambio de idioma de la interfaz de usuario.
Comencemos desde el principio y veamos cómo el desarrollo de CUBA se compara con la forma habitual de desarrollar en Spring y cómo, utilizando su experiencia y aprendiendo algunas cosas nuevas, puede crear aplicaciones más rápido.
El enfoque principal del artículo está en el desarrollo del lado del servidor para no perder el foco y mantener la cantidad de texto en un nivel aceptable.
Arquitectura de aplicaciones de primavera
En el 90% de los casos, escribiendo en Google "Spring Application Architecture" o "Spring application architecture", verá una imagen similar. Una aplicación clásica de tres capas con módulos comunes a algunas capas.
Modelo de dominio (Modelo de dominio) : clases de entidad del dominio (Entidades), almacenadas, por regla general, en la base de datos. Las clases generalmente se crean manualmente, pero puede construir la estructura automáticamente, en función del esquema de la base de datos.
Repository Layer (Repository Layer) : un conjunto de clases que proporcionan trabajo con el almacén de datos. Por lo general, esta capa utiliza varios marcos ORM y contiene lógica para realizar operaciones CRUD. Si hablamos de Spring, entonces los repositorios son bastante compactos, principalmente debido a los métodos de consulta JPA, pero a menudo hay que escribir la lógica de selección de la base de datos y asignarla al modelo de dominio manualmente.
Capa de servicio : una capa de aplicación que contiene la implementación de la lógica de negocios, algoritmos de procesamiento de información específicos del área temática. Esto es útil en el caso de algoritmos de procesamiento complejos, así como para trabajar con datos de varias fuentes (bases de datos, aplicaciones externas, servicios de Internet, etc.).
Web / Controllers Layer : clases responsables de la API REST. También puede haber archivos de plantilla de página en esta capa si usamos un marco como Thymeleaf, Velocity, así como clases responsables de representar y manejar eventos de interfaz de usuario si se usa algo como GWT, Vaadin, Wicket, etc.

Por lo general, los controladores funcionan con DTO y no con clases de la capa de dominio, por lo que la funcionalidad de convertir DTO a Entity y viceversa se agrega a la aplicación.
Si todo lo anterior es obvio para usted, o incluso la "capitanía regular" es excelente. Para que pueda comenzar a trabajar con CUBA sin ningún problema.Solicitud de referencia - Clínica de mascotas
Veamos un ejemplo específico y escriba un código. Para Spring, hay una aplicación de "referencia": Pet Clinic en
GitHub . Esta aplicación fue creada en diferentes versiones utilizando diferentes herramientas, desde el clásico Spring hasta Kotlin y Angular. A continuación veremos cómo hacer esta aplicación en CUBA. Para aquellos que no están familiarizados con la versión Spring, hay un buen texto
aquí ; extractos de la misma se utilizarán en este artículo.
Modelo de datos

El diagrama ER se muestra en la figura anterior. El modelo de dominio repite esta estructura, se le agregan varias clases con campos comunes y las clases de entidad ya se heredan de ellos. UML se puede encontrar en la
presentación que mencioné anteriormente.
Capa de repositorio
Hay cuatro repositorios en la aplicación que son responsables de trabajar con las entidades Propietario (Propietario), Mascota (Mascota), Visita (Visita) y Veterinario (Veterinario). Los repositorios se escriben usando Spring JPA y prácticamente no contienen código, solo declaraciones de métodos. Sin embargo, se ha agregado una consulta al repositorio que funciona con la entidad Propietario, lo que permite extraer propietarios y sus mascotas de la base de datos en una muestra.
Interfaz de usuario
Pet Clinic tiene nueve páginas que le permiten ver una lista de propietarios, sus mascotas y una lista de veterinarios. La aplicación proporciona una funcionalidad CRUD simple: es posible editar algunos datos: propietarios, mascotas, y también puede agregar visitas a la clínica. Pero, como ya se mencionó, no discutiremos la interfaz de usuario en profundidad en este artículo.
Opcional
Además del código para manipulaciones simples con entidades, la aplicación tiene una funcionalidad interesante que está diseñada para mostrar las capacidades de Spring:
- Almacenamiento en caché: la lista de veterinarios se selecciona de la base de datos solo una vez, luego se almacena en la memoria caché hasta que se reinicia el servidor de aplicaciones.
- Verificación de la finalización de los campos obligatorios al ingresar información sobre una nueva mascota.
- Formatear el tipo de animal antes de mostrarlo.
- i18n: la aplicación admite inglés y alemán.
- Gestión de transacciones: algunas transacciones están marcadas como de solo lectura.
Notas marginales

Realmente me gusta esta foto. Refleja 100% mis sentimientos cuando trabajo con frameworks. Para utilizar el marco de manera efectiva, debe comprender cómo se construye en su interior (pase lo que pase). Por ejemplo, ¿cuántos de ustedes se han preguntado cuántas clases se necesitan para que la interfaz JPA funcione?
Incluso en una aplicación pequeña como Pet Clinic, hay un poco de magia Spring Boot:
- No hay configuración para el caché (a excepción de la anotación
@Caheable
), sin embargo, Spring Boot "sabe" cómo iniciar el caché deseado (EhCache en este caso). - Los repositorios CRUD no están marcados con la anotación
@Transactional
(y su clase principal es org.springframework.data.repository.Repository
), pero todos los métodos save()
funcionan como se espera.
Pero, a pesar de todo lo "implícito", Spring Boot es muy popular. Por qué Es transparente y predecible. La buena documentación y el código fuente abierto permiten comprender los principios y, si es necesario, profundizar en los detalles de la implementación. Me parece que a todos les encantan estos marcos, la transparencia y la previsibilidad, la clave para la estabilidad y el mantenimiento de la aplicación.
Pet Clinic en la plataforma CUBA
Bueno, echemos un vistazo a la Clínica de mascotas, que se hizo con CUBA, desde el punto de vista del desarrollador de Spring e intentemos entender dónde puede ahorrar.El código fuente de la aplicación se puede encontrar en
GitHub . Además, la Plataforma CUBA tiene
documentación muy decente en ruso e inglés, que explica en detalle cómo desarrollarse adecuadamente en esta plataforma. Muchos ejemplos en
GitHub , incluidos varios tutoriales. En el artículo a menudo me referiré a la documentación, para no escribir lo mismo dos veces.
Arquitectura de aplicaciones CUBA
La aplicación CUBA consta de los módulos que se muestran en el diagrama.
Global (módulo global) : contiene clases de entidad, representaciones CUBA e interfaces de servicio que se utilizan en diferentes módulos.
Core (módulo de servicio) : aquí es donde se ubica el código de servicios que implementa la lógica de negocios, así como el código para trabajar con el almacén de datos. Cabe señalar que estas clases no están disponibles en otros módulos de aplicación, esto se hace para proporcionar
una implementación separada para una mejor escalabilidad. Para usar servicios en otros módulos de aplicación, debe usar las interfaces declaradas en el módulo global.
GUI, Web, Escritorio, Portal : estos módulos contienen código para clases relacionadas con el procesamiento de eventos de la interfaz de usuario, así como controladores REST adicionales si la
API CUBA
REST incorporada no
es suficiente.
Para ahorrar tiempo al desarrollador, CUBA tiene un
estudio , un pequeño entorno de desarrollo gráfico que ayuda a realizar trabajos de rutina, como generar entidades, registrar servicios en archivos de configuración, etc. utilizando la interfaz gráfica. Para generar la interfaz de la aplicación desarrollada, hay un editor (casi) WYSIWYG.
Por lo tanto, la aplicación basada en la Plataforma CUBA consta de dos módulos principales: Core y GUI, que se pueden implementar por separado, así como un módulo común: Global. Echemos un vistazo más de cerca al diseño de estos módulos.
Módulo global
Modelo de entidad
El modelado de entidades en una aplicación CUBA no es diferente de lo que los desarrolladores de Spring están acostumbrados. Las clases de dominio se crean y se
@Table
anotaciones
@Table
,
@Entity
, etc. Estas clases se registran en el archivo
persistence.xml
.
Al escribir Pet Clinic, simplemente copié las clases de la aplicación Spring original y las cambié un poco. Aquí hay un par de pequeñas adiciones que debe conocer si escribe en la plataforma CUBA:
- CUBA introduce el concepto de " espacio de nombres " para cada componente de la aplicación con el fin de evitar la duplicación de nombres de tablas en la base de datos. Es por eso que se agregó el prefijo "petclinic $" a cada entidad.
- Se recomienda utilizar la anotación
@NamePattern
, un análogo del método toString()
para la visualización legible de entidades en la interfaz de usuario.
Pregunta natural: "¿Qué más agrega CUBA además de prefijos y declarative
toString()
?" Aquí hay una lista parcial de características adicionales:
- Clases base con ID generados automáticamente desde Integer hasta UUID.
- Interfaces útiles para marcadores que proporcionan características adicionales:
Versioned
: para admitir el control de versiones de instancias de entidad.SoftDelete
: para admitir la eliminación "lógica" de registros en la base de datos.Updatable
: se agregan campos para registrar el hecho de actualizar el registro, el nombre de usuario y la hora.Creatable
: se agregan campos para registrar la creación de un registro.
Puede leer más sobre el modelado de entidades en la documentación . - Las secuencias de comandos para crear y actualizar la base de datos se generan automáticamente con CUBA Studio.
Por lo tanto, crear un modelo de datos para Pet Clinic se redujo a copiar clases de entidad y agregarles cosas específicas de CUBA, que mencioné anteriormente.Vistas
El concepto de "representaciones" en CUBA puede parecer algo inusual, pero es bastante fácil de explicar. Una vista es una forma declarativa de declarar atributos cuyos valores deben recuperarse del almacén de datos.
Por ejemplo, debe extraer los propietarios y sus mascotas de la base de datos (o los veterinarios y su profesión): una tarea muy común al crear una interfaz es cuando necesita mostrar datos dependientes en la misma forma que la principal. En primavera, esto se puede hacer a través de una unión JPA ...
@Query("SELECT owner FROM Owner owner left join fetch owner.pets WHERE owner.id =:id") public Owner findById(@Param("id") int id);
... o establecer atributos EAGER / LAZY para recuperar la colección de la entidad principal en el contexto de una transacción única.
@ManyToMany(fetch = FetchType.EAGER) @JoinTable(name = "vet_specialties", joinColumns = @JoinColumn(name = "vet_id"), inverseJoinColumns = @JoinColumn(name = "specialty_id")) private Set<Specialty> specialties;
En CUBA, puede hacerlo a través de EntityManager y JPQL (todo el mundo sabe cómo hacerlo) o mediante la vista y DataManager:
- Forme una presentación (se puede hacer en CUBA Studio o manualmente en la configuración)
<view class="com.haulmont.petclinic.entity.Vet" extends="_minimal" name="vet-specialities-view"> <property name="specialities" view="_minimal"> </property> </view>
- Y use el DataManager para buscar:
public Collection<Vet> findAll() { return dataManager.load(Vet.class) .query("select v from cubapetclinic$Vet v") .view("vet-specialities-view") .list(); }
Puede crear diferentes vistas para diferentes tareas con el conjunto deseado de atributos y niveles de anidamiento de entidades. Hay un excelente
artículo sobre las publicaciones en el
blog de Mario David.
Se realizaron seis presentaciones diferentes para la aplicación Pet Clinic. La mayoría de ellos se generaron "semiautomáticamente" al crear la interfaz de usuario, y la vista descrita anteriormente se implementó para el servicio de exportación de datos.Interfaces de servicio
Dado que el módulo global es utilizado por todos los demás módulos de aplicación, las interfaces de servicio se declaran en él, para que luego puedan usarse en otros módulos a través del mecanismo de inyección de dependencia (DI).
Además, debe registrar los servicios en el
web-spring.xml
en el módulo web. Al inicializar el contexto, CUBA creará clases proxy para serializar y deserializar clases al interactuar con los servicios en el módulo Core. Esto solo proporciona una implementación separada de los módulos Core y Web, mientras que el desarrollador no necesita hacer esfuerzos adicionales, todo se hace de manera transparente.
Entonces: al crear clases de entidad en CUBA, se pasa la misma cantidad de tiempo que en Spring puro (si no usa CUBA Studio), pero no necesita crear clases base para generar claves primarias. Además, no necesita escribir código para admitir el campo de versión de entidad, la eliminación lógica y la auditoría. Además, en mi opinión, las vistas pueden ahorrar un poco de tiempo en la depuración de la unión JPA y la manipulación de muestras EAGER / LAZY.Módulo de núcleo
Este módulo contiene las implementaciones de las interfaces declaradas en el módulo global. Cada servicio en una aplicación CUBA está anotado por
@Service
, puede usar otras anotaciones de Spring, pero debe tener en cuenta lo siguiente:
- Si desea que el servicio esté disponible en otros módulos, debe configurar la anotación
@Service
. - Se recomienda nombrar el servicio para evitar la duplicación si aparece un componente en la aplicación que implementa la misma interfaz.
- El muestreo de datos se realiza de manera un poco diferente que en primavera, más sobre eso en la siguiente sección.
De lo contrario, el módulo Core es un código Spring normal. Puede seleccionar datos de la base de datos, puede llamar a servicios web externos, en general, escribir código de la forma en que está acostumbrado.
Entity Manager y DataManager
La plataforma CUBA usa su propio
EntityManager , que delega parte de las llamadas al conocido
javax.persistence.EntityManager
, pero no implementa esta interfaz. EntityManager proporciona principalmente operaciones de bajo nivel y no es totalmente compatible con el modelo de seguridad CUBA. La clase principal para trabajar con datos es el
DataManager, que proporciona la siguiente funcionalidad:
- Control de acceso a nivel de fila y atributo.
- Usar vistas al recuperar datos.
- Atributos dinámicos.
Más sobre DataManager y EntityManager está escrito en la
documentación . No es necesario trabajar explícitamente con estas clases para seleccionar datos en los componentes de la interfaz de usuario (tablas, etc.), las
fuentes de datos (Fuentes de datos) se utilizan en la GUI.
Si hablamos de PetClinic: casi no hay código en el módulo Core, no hay lógica empresarial compleja en esta aplicación.Funcionalidad adicional de Pet Clinic a CUBA
En la sección anterior, se consideró la funcionalidad adicional en la aplicación de referencia. Dado que CUBA usa Spring, la misma funcionalidad también está disponible cuando se desarrolla sobre la base de esta plataforma, pero tendrá que prescindir de la magia de Spring Boot. Además de esto, CUBA proporciona una funcionalidad similar lista para usar.
Almacenamiento en caché
La plataforma CUBA tiene un caché de consultas y un caché de entidad. Se describen en detalle en la
documentación y pueden considerarse soluciones prioritarias si desea utilizar el almacenamiento en caché en la aplicación. Las soluciones integradas admiten la distribución distribuida de aplicaciones y la agrupación en clúster. Bueno, por supuesto, puede usar la anotación
@Cacheable
, como se describe en la
documentación de Spring , si el almacenamiento en caché incorporado no funciona para algo.
Comprobación de entrada
CUBA usa
BeanValidation para validar los datos ingresados. Si las clases integradas no proporcionan la funcionalidad necesaria, puede escribir
su propia lógica de comprobaciones . Y, además de esto, CUBA proporciona clases
Validator
, que se describen
aquí .
Formato de salida
La plataforma CUBA proporciona varios
formateadores para los componentes de la interfaz de usuario, también puede hacer
los suyos además del estándar. Puede usar la anotación
@NamePattern
para representar instancias de entidad como una cadena
i18n
CUBA admite
salida en varios idiomas utilizando archivos
message.properties
, nada nuevo aquí. CUBA Studio hace que crear y editar dichos archivos sea rápido y fácil.
Gestión de transacciones
Se admiten los siguientes tipos de gestión de transacciones:
- Familiarizado con la anotación Spring
@Transactional
, - Interfaz de
Persistence
(y clase) si necesita una gestión de transacciones de bajo nivel.
Cuando escribí Pet Clinic, necesitaba la administración de transacciones en un solo lugar: cuando desarrollé un formulario de entrada que me permitió editar varias entidades relacionadas en una pantalla. Era necesario editar a los dueños y sus mascotas, así como agregar visitas a la clínica. Era necesario almacenar cuidadosamente los datos y actualizarlos en otras pantallas.Clínica de mascotas en pocas horas. Realmente
Hice una copia de Pet Clinic con la interfaz estándar de CUBA en seis horas. No quiere decir que soy un experto en CUBA (han pasado un par de semanas desde que comencé a trabajar en Haulmont), pero tengo experiencia con Spring y me ayudó mucho.
Echemos un vistazo a la aplicación CUBA en términos de arquitectura clásica:
Modelo de datos : clases de entidad en el módulo Global. Crear un modelo es un procedimiento conocido y conocido. Gracias a la clase BaseIntegerIdEntity por ahorrar el tiempo que generalmente se tarda en jugar con la generación de ID.
La capa de repositorio no es necesaria. Creé varias vistas, y eso es todo. Por supuesto, CUBA Studio me ahorró un poco de tiempo, no tuve que escribir manualmente archivos XML.
Capa de servicio : la aplicación tiene solo dos servicios para exportar datos a JSON y XML. Por cierto, en la versión actual de la aplicación Spring Boot, esta característica se eliminó. Aunque no funcionó para JSON. En la versión CUBA, declaró interfaces en el módulo global y puse la implementación en Core. Nada nuevo excepto el DataManager, pero tardó muy poco tiempo en dominarlo.
Capa de controlador : CUBA Pet Clinic solo tiene un controlador REST para exportar a JSON y XML. Coloqué este controlador en el módulo web. Una vez más, nada especial, las anotaciones son las mismas, un controlador Spring normal.
La interfaz de usuario : la creación de formularios CRUD estándar, e incluso con CUBA Studio, no causó ninguna dificultad. No es necesario escribir código para transferir datos a los componentes, no hay análisis de datos desde el formulario de filtrado de datos ni complicaciones con la paginación. Hay componentes para todo esto. Tomó tiempo hacer que la interfaz se viera como la que se hizo en la versión Spring Boot. Vaadin todavía no es HTML puro, y fue más difícil de diseñar.
La experiencia personal ha tabulado:
Por supuesto, Pet Clinic no usa todas las características de CUBA, puede encontrar una lista completa de las características de la plataforma en el
sitio , allí también puede encontrar ejemplos de código para resolver problemas típicos que surgen al desarrollar aplicaciones empresariales.
Mi opinión personal es que CUBA simplifica el desarrollo del lado del servidor de la aplicación y ayuda a ahorrar aún más tiempo en el desarrollo de la interfaz de usuario si utiliza componentes de usuario estándar y capacidades de diseño. Pero, incluso si necesita una interfaz de usuario especial, seguirá habiendo una ganancia de tiempo debido al lado del servidor estándar.Uno más! ¿Hay alguna desventaja?
Por supuesto que sí, no hay marcos perfectos. No son críticos, pero al principio, cuando comencé a trabajar con CUBA, sentí algunas molestias. Pero el
valor de WTF / m no era prohibitivo.
- Para la plataforma CUBA, hay un IDE que simplifica la creación inicial de un proyecto. Cambiar entre estudio e IDEA es un poco molesto al principio. La buena noticia es que hay una versión beta de CLI, no necesita ejecutar el estudio para generar la estructura del proyecto y, además, la próxima versión de CUBA Studio será un complemento Intellij IDEA. No más cambios.
- CUBA tiene más archivos XML que la aplicación Spring Boot promedio, esto se debe a que la inicialización de contexto en CUBA se realiza a su manera. Ahora que la lucha está en marcha para reducir la cantidad de XML, recurrimos a las anotaciones cuando sea posible.
- No hay URL "legibles" para los formularios de interfaz de usuario. Es posible acceder a los formularios a través de enlaces a pantallas , pero no son muy fáciles de usar.
- Para trabajar con datos, debe usar DataManager, vistas y EntityManager, no Spring JPA o JDBC (pero estas API también están disponibles si es necesario).
- CUBA funciona mejor con bases de datos relacionales como un almacén de datos. En cuanto a NoSQL, tendrá que usar bibliotecas de acceso para estos repositorios y escribir su propia capa de repositorio. Pero esta es la misma cantidad de trabajo que cuando se desarrolla una aplicación sin CUBA, en mi opinión.
Total
Si hay una tarea de desarrollar una aplicación que use una base de datos relacional como un almacén de datos y se concentre en trabajar con datos en formato tabular, entonces CUBA puede ser una buena opción, porque:
- CUBA es transparente. El código fuente está disponible, cualquier método puede ser depurado.
- CUBA es extensible (hasta límites conocidos, por supuesto). Puede heredar casi cualquier clase de utilidad y colocarla en la plataforma, crear su propia API REST, usar su marco favorito para la interfaz de usuario. CUBA fue creado para que pueda adaptar fácilmente las soluciones para cualquier cliente. Hay un buen artículo sobre la extensibilidad de la plataforma.
- CUBA es primavera. El 80% de su código de servidor será solo una aplicación Spring.
- Inicio rápido Tendrá una aplicación completa con un panel de administración después de crear la primera entidad y una pantalla para trabajar con ella.
- Muchas tareas rutinarias ya se han resuelto en la plataforma.
Por lo tanto, con CUBA puede ahorrar tiempo en escribir un código de "servicio" monótono y concentrarse en escribir código para resolver problemas comerciales. Y sí, nosotros en Haulmont utilizamos CUBA para desarrollar productos en caja y personalizados.