
Quando você lê os requisitos para o próximo aplicativo Web corporativo para uso interno, geralmente (a julgar pela minha experiência), ele é o mesmo conjunto: um banco de dados relacional para armazenamento de dados, geralmente herdado da versão anterior do aplicativo, um grande número de formas de diferentes níveis de complexidade (mas ao mesmo tempo típico) para entrada de dados, uma variedade de formulários de relatórios, lógica de negócios complexa, integração com outros aplicativos - da contabilidade ao gerenciamento de suprimentos, vários milhares de usuários trabalhando simultaneamente. O que geralmente vem à mente?
"Então, vou pegar o DBMS que eu conheço e que se ajusta ao volume de dados, fixar o Hibernate / JPA, escrever o aplicativo no Spring Boot, expor a API REST e escrever o cliente na estrutura JS, provavelmente Angular / React".
“Sim, ainda precisamos ferrar a Spring Security. E escreva uma restrição no acesso aos dados para diferentes departamentos e funções - no nível das linhas do banco de dados ou objetos de dados. Como fazer isso? Submissão ou VPD, você precisará assistir. ”
"Ugh, eu tenho que escrever um monte de DAOs - eles são feitos rapidamente, mas existem muitos deles."
"E a conversão de Entidade para DTO - estou usando o ModelMapper ."
"O principal é não esquecer de lembrar o estagiário sobre os atributos preguiçosos e se unir para que não haja, como da última vez."
"Abetos, enquanto você inicia a lógica de negócios, precisa escrever muito código de serviço ..."
Este artigo é para aqueles que escreveram pelo menos alguns aplicativos corporativos do zero no Spring / Spring Boot e agora acham que seria bom acelerar o desenvolvimento de aplicativos tão diferentes, mas ao mesmo tempo similares. A seguir, veremos como se livrar de tarefas "típicas" usando a
plataforma CUBA .
Outra estrutura?

Pensamento número um, quando é oferecida ao desenvolvedor uma nova estrutura (e, em particular, CUBA), é: “Por que devo me preocupar com isso? Vou pegar o familiar e familiar Spring Boot e vou fazer tudo. " E isso é razoável. Uma nova estrutura é o estudo de novas abordagens de desenvolvimento, novas armadilhas e limitações que você aprendeu a evitar de maneira inteligente ao desenvolver uma estrutura familiar.
Mas, quando comecei a desenvolver no CUBA, não precisei mudar muito minhas habilidades com o Spring. Naturalmente, tive que gastar um pouco de tempo compreendendo a plataforma, mas isso não foi um colapso radical de todos os hábitos, mas uma pequena mudança nas habilidades de desenvolvimento.
Como resultado, o código para DTO, saída de dados página a página, filtragem de dados (análise dos parâmetros transferidos para a forma e compilação de solicitações) desapareceu. Ao mesmo tempo, quase não precisei mexer nas configurações do Spring Security e escrever o código do administrador, os formulários de login e a lógica de troca de idioma da interface do usuário.
Vamos começar desde o início e ver como o desenvolvimento do CUBA se compara à maneira usual de se desenvolver no Spring e como, usando sua experiência e aprendendo algumas coisas novas, você pode finalmente criar aplicativos mais rapidamente.
O foco principal do artigo é o desenvolvimento do lado do servidor, para não perder o foco e manter a quantidade de texto em um nível aceitável.
Arquitetura de aplicativos Spring
Em 90% dos casos, digitando no Google “Spring Application Architecture” ou “Spring application architecture”, você verá uma imagem semelhante. Um aplicativo clássico de três camadas com módulos comuns a algumas camadas.
Modelo de Domínio (Modelo de Domínio) - classes de entidade do domínio (Entidades), armazenadas, como regra, no banco de dados. As classes geralmente são criadas manualmente, mas você pode criar a estrutura automaticamente, com base no esquema do banco de dados.
Camada de Repositório (Camada de Repositório) - um conjunto de classes que fornecem trabalho com o armazém de dados. Normalmente, essa camada usa várias estruturas ORM e contém lógica para executar operações CRUD. Se falamos sobre Spring, os repositórios são bastante compactos, principalmente devido aos métodos JPA Query, mas geralmente é necessário escrever a lógica de seleção do banco de dados e mapear manualmente para o modelo de domínio.
Camada de serviço - uma camada de aplicativo que contém a implementação da lógica de negócios, algoritmos de processamento de informações específicos da área de assunto. Isso é útil no caso de algoritmos de processamento complexos, bem como para trabalhar com dados de várias fontes (bancos de dados, aplicativos externos, serviços da Internet etc.).
Camada da Web / controladores - classes responsáveis pela API REST. Também pode haver arquivos de modelo de página nessa camada se usarmos uma estrutura como Thymeleaf, Velocity, bem como classes responsáveis por renderizar e manipular eventos da interface do usuário se algo como GWT, Vaadin, Wicket etc. for usado.

Normalmente, os controladores trabalham com DTO, e não com classes da camada de domínio; portanto, a funcionalidade de converter DTO em Entidade e vice-versa é adicionada ao aplicativo.
Se tudo o que foi exposto acima é óbvio para você, ou mesmo a “capitania regular” é excelente. Então você pode começar a trabalhar com o CUBA sem problemas.Pedido de Referência - Pet Clinic
Vamos dar uma olhada em um exemplo específico e escrever um código. Para o Spring, existe um aplicativo de "referência" - Pet Clinic no
GitHub . Este aplicativo foi criado em diferentes versões usando diferentes ferramentas - do clássico Spring ao Kotlin e Angular. A seguir, veremos como fazer esse aplicativo no CUBA. Para aqueles que não estão familiarizados com a versão Spring, há um bom texto
aqui ; trechos dele serão usados neste artigo.
Modelo de dados

O diagrama ER é mostrado na figura acima. O modelo de domínio repete essa estrutura, várias classes com campos comuns são adicionadas a ela e as classes de entidade já são herdadas delas. UML pode ser encontrado na
apresentação que mencionei anteriormente.
Camada de repositório
Existem quatro repositórios no aplicativo que são responsáveis por trabalhar com as entidades Proprietário (Proprietário), Animal de estimação (Animal de estimação), Visita (Visita) e Veterinário (Veterinário). Os repositórios são gravados usando o Spring JPA e praticamente não contêm código, apenas declarações de método. No entanto, uma consulta foi adicionada ao repositório que funciona com a entidade Proprietária, que permite extrair proprietários e seus animais de estimação do banco de dados em uma amostra.
Interface do usuário
Pet Clinic tem nove páginas que permitem exibir uma lista de proprietários, seus animais de estimação e uma lista de veterinários. O aplicativo fornece uma funcionalidade CRUD simples: é possível editar alguns dados - proprietários, animais de estimação e você também pode adicionar visitas à clínica. Mas, como já mencionado, não discutiremos a interface do usuário em detalhes neste artigo.
Opcional
Além do código para manipulações simples com entidades, o aplicativo possui uma funcionalidade interessante, projetada para mostrar os recursos do Spring:
- Armazenamento em cache - a lista de veterinários é selecionada no banco de dados apenas uma vez e, em seguida, é armazenada no cache até o servidor de aplicativos reiniciar.
- Verificando o preenchimento dos campos obrigatórios ao inserir informações sobre um novo animal de estimação.
- Formatar o tipo de animal antes de exibi-lo.
- i18n - o aplicativo suporta inglês e alemão.
- Gerenciamento de transações - algumas transações são marcadas como somente leitura.
Notas marginais

Eu realmente gosto dessa foto. Ele reflete 100% dos meus sentimentos ao trabalhar com estruturas. Para usar a estrutura efetivamente, você deve entender como ela é construída dentro (não importa o que). Por exemplo, quantos de vocês já se perguntaram quantas classes são necessárias para fazer a interface JPA funcionar?
Mesmo em um aplicativo pequeno como o Pet Clinic, há um pouco da mágica do Spring Boot:
- Não há configuração para o cache (exceto para a anotação
@Caheable
), no entanto, o Spring Boot “sabe” como iniciar o cache desejado (neste caso, o EhCache). - Os repositórios CRUD não são marcados com a anotação
@Transactional
(e sua classe pai é org.springframework.data.repository.Repository
também), mas todos os métodos save()
funcionam conforme o esperado.
Mas, apesar de todos os "implícitos", o Spring Boot é muito popular. Porque É transparente e previsível. A boa documentação e o código-fonte aberto tornam possível entender os princípios e, se necessário, aprofundar nos detalhes da implementação. Parece-me que todo mundo adora essas estruturas, transparência e previsibilidade - a chave para a estabilidade e a manutenção do aplicativo.
Pet Clinic na plataforma CUBA
Bem, vejamos a Pet Clinic, que foi criada usando o CUBA, do ponto de vista do desenvolvedor do Spring e tente entender onde você pode salvar.O código fonte do aplicativo pode ser encontrado no
GitHub . Além disso, a plataforma CUBA possui uma
documentação decente em russo e inglês, o que explica em detalhes como se desenvolver adequadamente nessa plataforma. Muitos exemplos no
GitHub , incluindo vários tutoriais. No artigo, frequentemente vou me referir à documentação, para não escrever a mesma coisa duas vezes.
Arquitetura de aplicativos CUBA
O aplicativo CUBA consiste nos módulos mostrados no diagrama.
Global (módulo global) - contém classes de entidade, representações CUBA e interfaces de serviço usadas em diferentes módulos.
Núcleo (módulo de serviço) - é aqui que o código dos serviços que implementam a lógica de negócios, bem como o código para trabalhar com o data warehouse, são colocados. Deve-se notar que essas classes não estão disponíveis em outros módulos de aplicativos, isso é feito para fornecer
uma implantação separada para melhor escalabilidade. Para usar serviços em outros módulos de aplicativos, você precisa usar as interfaces declaradas no módulo global.
GUI, Web, Desktop, Portal - esses módulos contêm código para classes relacionadas ao processamento de eventos da interface com o usuário, bem como controladores REST adicionais se a
API REST CUBA
incorporada não
for suficiente.
Para economizar tempo do desenvolvedor, o CUBA possui um
estúdio - um pequeno ambiente gráfico de desenvolvimento que ajuda a realizar trabalhos de rotina, como gerar entidades, registrar serviços em arquivos de configuração etc. usando a interface gráfica. Para gerar a interface do aplicativo desenvolvido, existe um editor (quase) WYSIWYG.
Assim, o aplicativo baseado na plataforma CUBA consiste em dois módulos principais - Core e GUI, que podem ser implantados separadamente, além de um módulo comum - Global. Vamos dar uma olhada no design desses módulos.
Módulo global
Modelo de entidade
A modelagem de entidades em um aplicativo CUBA não é diferente do que os desenvolvedores do Spring estão acostumados. As classes de domínio são criadas e as anotações
@Table
,
@Entity
etc. são colocadas nelas. Essas classes são registradas no arquivo
persistence.xml
.
Ao escrever Pet Clinic, apenas copiei as classes do aplicativo original do Spring e as alterei um pouco. Aqui estão algumas pequenas adições que você precisa saber se escrever na plataforma CUBA:
- O CUBA introduz o conceito de " espaço para nome " para cada componente do aplicativo, a fim de evitar a duplicação de nomes de tabelas no banco de dados. É por isso que o prefixo "petclinic $" foi adicionado a cada entidade.
- É recomendável usar a anotação
@NamePattern
- um análogo do toString()
para exibição legível de entidades na interface do usuário.
Pergunta natural: "O que mais o CUBA adiciona além de prefixos e
toString()
declarativo?" Aqui está uma lista parcial de recursos adicionais:
- Classes base com IDs gerados automaticamente de Inteiro para UUIDs.
- Interfaces de marcadores úteis que fornecem recursos adicionais:
Versioned
- para oferecer suporte à versão de instâncias de entidade.SoftDelete
- para suportar a exclusão "lógica" de registros no banco de dados.Updatable
- são adicionados campos para registrar o fato de atualizar o registro, nome de usuário e hora.Creatable
- os campos são adicionados para registrar a criação de um registro.
Você pode ler mais sobre modelagem de entidades na documentação . - Os scripts para criar e atualizar o banco de dados são gerados automaticamente usando o CUBA Studio.
Assim, a criação de um modelo de dados para a Pet Clinic se resumiu a copiar classes de entidades e adicionar itens específicos de CUBA a eles, que mencionei acima.Visualizações
O conceito de "representações" em CUBA pode parecer um tanto incomum, mas é fácil de explicar. Uma visualização é uma maneira declarativa de declarar atributos cujos valores precisam ser recuperados do armazém de dados.
Por exemplo, você precisa extrair proprietários e seus animais de estimação do banco de dados (ou veterinários e sua profissão) - uma tarefa muito comum ao criar uma interface é quando você precisa mostrar dados dependentes da mesma forma que a principal. Na primavera, isso pode ser feito através de uma associação JPA ...
@Query("SELECT owner FROM Owner owner left join fetch owner.pets WHERE owner.id =:id") public Owner findById(@Param("id") int id);
... ou defina os atributos EAGER / LAZY para recuperar a coleção da entidade principal no contexto de uma única transação.
@ManyToMany(fetch = FetchType.EAGER) @JoinTable(name = "vet_specialties", joinColumns = @JoinColumn(name = "vet_id"), inverseJoinColumns = @JoinColumn(name = "specialty_id")) private Set<Specialty> specialties;
No CUBA, você pode fazer isso através do EntityManager e JPQL (todos sabem como) ou através da visualização e do DataManager:
- Formar uma apresentação (pode ser feita no CUBA Studio ou manualmente na configuração)
<view class="com.haulmont.petclinic.entity.Vet" extends="_minimal" name="vet-specialities-view"> <property name="specialities" view="_minimal"> </property> </view>
- E use o DataManager para buscar:
public Collection<Vet> findAll() { return dataManager.load(Vet.class) .query("select v from cubapetclinic$Vet v") .view("vet-specialities-view") .list(); }
Você pode criar diferentes visualizações para diferentes tarefas com o conjunto desejado de atributos e níveis de aninhamento de entidades. Há um excelente
artigo sobre as postagens no
blog de Mario David.
Seis submissões diferentes foram feitas para o aplicativo Pet Clinic. A maioria deles foi gerada "de forma semi-automática" ao criar a interface do usuário, e a exibição descrita acima foi implementada para o serviço de exportação de dados.Interfaces de serviço
Como o módulo global é usado por todos os outros módulos de aplicativos, as interfaces de serviço são declaradas nele, para que posteriormente possam ser usadas em outros módulos através do mecanismo de injeção de dependência (DI).
Além disso, você precisa registrar os serviços no
web-spring.xml
no módulo da Web. Ao inicializar o contexto, o CUBA criará classes de proxy para serializar e desserializar classes ao interagir com serviços no módulo Core. Isso apenas fornece uma implantação separada dos módulos Core e Web, enquanto o desenvolvedor não precisa fazer esforços adicionais, tudo é feito de forma transparente.
Portanto: ao criar classes de entidade no CUBA, a mesma quantidade de tempo é gasta como no Spring puro (se você não usa o CUBA Studio), mas não precisa criar classes base para gerar chaves primárias. Além disso, você não precisa escrever código para suportar o campo de versão da entidade, exclusão lógica e auditoria. Além disso, na minha opinião, as visualizações podem economizar um pouco de tempo na depuração da junção JPA e na manipulação de amostras EAGER / LAZY.Módulo principal
Este módulo contém as implementações das interfaces declaradas no módulo global. Cada serviço em um aplicativo CUBA é anotado pelo
@Service
, você pode usar outras anotações do Spring, mas é necessário considerar o seguinte:
- Se você deseja que o serviço esteja disponível em outros módulos, defina a anotação
@Service
. - É recomendável nomear o serviço para evitar duplicação se um componente aparecer no aplicativo que implementa a mesma interface.
- A amostragem de dados é feita de maneira um pouco diferente da do Spring, mais sobre isso na próxima seção.
Caso contrário, o módulo Core é um código Spring regular. Você pode selecionar dados do banco de dados, pode chamar serviços da Web externos; em geral, escrever código da maneira que está acostumado.
Gerenciador de entidades e DataManager
A plataforma CUBA usa seu próprio
EntityManager , que delega parte das chamadas ao familiar
javax.persistence.EntityManager
, mas não implementa essa interface. O EntityManager fornece principalmente operações de baixo nível e não oferece suporte completo ao modelo de segurança CUBA. A classe principal para trabalhar com dados é o
DataManager, que fornece a seguinte funcionalidade:
- Controle de acesso no nível da linha e do atributo.
- Usando visualizações ao buscar dados.
- Atributos dinâmicos.
Mais sobre o DataManager e o EntityManager estão escritos na
documentação . Não há necessidade de trabalhar explicitamente com essas classes para selecionar dados nos componentes da interface do usuário (tabelas, etc.), as
fontes de dados (fontes de dados) são usadas na GUI.
Se falarmos sobre o PetClinic - quase não há código no módulo Core, não há lógica de negócios complexa neste aplicativo.Funcionalidades adicionais de Pet Clinic para CUBA
Na seção anterior, funcionalidade adicional foi considerada no aplicativo de referência. Como o CUBA usa o Spring, a mesma funcionalidade também está disponível no desenvolvimento com base nesta plataforma, mas você precisará prescindir da mágica do Spring Boot. Além disso, o CUBA fornece uma funcionalidade pronta para uso semelhante.
Armazenamento em cache
A plataforma CUBA possui um cache de consulta e um cache de entidade. Eles são descritos em detalhes na
documentação e podem ser considerados como soluções prioritárias se você deseja usar o cache no aplicativo. As soluções incorporadas oferecem suporte à implantação e cluster distribuído de aplicativos. Bem, é claro, você pode usar a anotação
@Cacheable
, conforme descrito na
documentação do
Spring , se o cache
@Cacheable
não funcionar para algo.
Verificação de entrada
O CUBA usa
BeanValidation para validar os dados inseridos. Se as classes internas não fornecerem a funcionalidade necessária, você poderá escrever
sua própria lógica de verificações . Além disso, o CUBA fornece classes
Validator
, descritas
aqui .
Formatação de saída
A plataforma CUBA fornece vários
formatadores para os componentes da interface do usuário; você também pode criar o
seu , além do padrão. Você pode usar a anotação
@NamePattern
para representar instâncias de entidade como uma sequência
i18n
O CUBA suporta
saída em vários idiomas usando arquivos
message.properties
, nada de novo aqui. O CUBA Studio facilita e agiliza a criação e edição desses arquivos.
Gerenciamento de transações
Os seguintes tipos de gerenciamento de transações são suportados:
- Familiar para a anotação Spring
@Transactional
, - Interface de
Persistence
(e classe) se você precisar de gerenciamento de transações de baixo nível.
Quando escrevi Pet Clinic, eu precisava do gerenciamento de transações em apenas um lugar: quando desenvolvi um formulário de entrada que me permitiu editar várias entidades relacionadas em uma tela. Era necessário editar os donos e seus animais de estimação, além de adicionar visitas à clínica. Era necessário armazenar cuidadosamente os dados e atualizá-los em outras telas.Pet Clinic em algumas horas. Realmente
Fiz uma cópia do Pet Clinic com a interface CUBA padrão em seis horas. Para não dizer que sou especialista em CUBA (já passaram algumas semanas desde que comecei a trabalhar em Haulmont), mas tenho experiência com a Spring e isso me ajudou muito.
Vamos dar uma olhada no aplicativo CUBA em termos de arquitetura clássica:
Modelo de dados - classes de entidade no módulo Global. Criar um modelo é um procedimento conhecido e familiar. Agradecemos à classe BaseIntegerIdEntity por economizar o tempo que geralmente leva para mexer na geração de IDs.
A camada do repositório não é necessária. Eu criei várias visualizações, e é isso. Obviamente, o CUBA Studio me poupou um pouco de tempo, não tive que escrever manualmente arquivos XML.
Camada de serviço - o aplicativo possui apenas dois serviços para exportar dados para JSON e XML. Na versão atual do aplicativo Spring Boot, esse recurso foi removido, a propósito. Embora não funcionou para JSON. Na versão CUBA, declarei interfaces no módulo global e coloquei a implementação no Core. Nada de novo, exceto o DataManager, mas demorou muito pouco tempo para dominá-lo.
Camada do controlador - o CUBA Pet Clinic possui apenas um controlador REST para exportar para JSON e XML. Eu coloquei este controlador no módulo da Web. Novamente, nada de especial, as anotações são as mesmas, um controlador Spring regular.
A interface do usuário - criando formulários CRUD padrão, e mesmo com o CUBA Studio, não causou dificuldades. Não há necessidade de escrever código para transferir dados para componentes, sem análise de dados no formulário de filtragem de dados, sem problemas com paginação. Existem componentes para tudo isso. Demorou um pouco para que a interface parecesse com a criada na versão Spring Boot. Vaadin ainda não é HTML puro, e era mais difícil de estilizar.
A experiência pessoal tabulou:
Obviamente, o Pet Clinic não usa todos os recursos do CUBA, uma lista completa dos recursos da plataforma pode ser encontrada no
site . Também é possível encontrar exemplos de códigos para resolver problemas típicos que surgem no desenvolvimento de aplicativos corporativos.
Minha opinião pessoal é que o CUBA simplifica o desenvolvimento do lado do servidor do aplicativo e ajuda a economizar ainda mais tempo no desenvolvimento da interface do usuário se você usar componentes de usuário padrão e recursos de estilo. Mas, mesmo se você precisar de alguma interface de usuário especial, ainda haverá um ganho de tempo devido ao lado do servidor padrão.Uma vantagem! Existem desvantagens?
Claro que existem, não existem estruturas perfeitas. Eles não são críticos, mas no começo, quando eu comecei a trabalhar com o CUBA, havia algum desconforto. Mas o
valor de WTF / m não era proibitivo.
- Para a plataforma CUBA, existe um IDE que simplifica a criação inicial de um projeto. Alternar entre estúdio e IDEA é um pouco chato no começo. A boa notícia é que existe uma versão beta do CLI, você não precisa executar o estúdio para gerar a estrutura do projeto e também - a próxima versão do CUBA Studio será um plugin do Intellij IDEA. Não há mais troca.
- O CUBA possui mais arquivos XML que o aplicativo médio de Inicialização em Spring, isso ocorre porque a inicialização do contexto no CUBA é feita à sua maneira. Agora, a luta está em andamento para reduzir a quantidade de XML, recorremos às anotações sempre que possível.
- Não há URLs "legíveis" para os formulários da interface do usuário. É possível acessar formulários através de links para telas , mas eles não são muito amigáveis.
- Para trabalhar com dados, você precisa usar o DataManager, visualizações e EntityManager, não Spring JPA ou JDBC (mas essas APIs também estão disponíveis, se necessário).
- O CUBA funciona melhor com bancos de dados relacionais como um data warehouse. Quanto ao NoSQL, você terá que usar bibliotecas de acesso para esses repositórios e escrever sua própria camada de repositório. Mas é a mesma quantidade de trabalho que desenvolvi um aplicativo sem o CUBA, na minha opinião.
Total
Se houver uma tarefa de desenvolver um aplicativo que use um banco de dados relacional como um data warehouse e esteja focado em trabalhar com dados em um formato tabular, o CUBA pode ser uma boa opção, pois:
- CUBA é transparente. O código fonte está disponível, qualquer método pode ser depurado.
- CUBA é extensível (para limites conhecidos, é claro). Você pode herdar quase qualquer classe de utilitário e inseri-la na plataforma, criar sua própria API REST, usar sua estrutura favorita para a interface do usuário. O CUBA foi criado para que você possa adaptar facilmente soluções para qualquer cliente. Há um bom artigo sobre extensibilidade da plataforma.
- CUBA é primavera. 80% do código do servidor será apenas um aplicativo Spring.
- Início rápido. Você terá um aplicativo completo com um painel de administração após criar a primeira entidade e uma tela para trabalhar com ela.
- Muitas tarefas de rotina já foram resolvidas na plataforma.
Portanto, com o CUBA, você pode economizar tempo escrevendo um código monótono de "serviço" e se concentrar em escrever código para resolver problemas de negócios. E sim, nós da Haulmont usamos o CUBA para desenvolver produtos in a box e personalizados.