Desenvolvimento rápido de aplicativos Web em Vaadin e Spring Boot

CPAP


O objetivo deste artigo é sistematizar o processo de desenvolvimento de um aplicativo Web no Vaadin 14 usando o Spring Boot.


Antes de ler este artigo, recomendo a leitura do seguinte material:



Impressões


O Vaadin 14 é uma ferramenta bastante conveniente para projetar aplicativos da Web. Antes de conhecê-lo, ele desenvolveu interfaces gráficas apenas em JavaFX, Android e até J2ME e, ao mesmo tempo, evitou o desenvolvimento de front-end (conhecimentos básicos de HTML, CSS e JS estão disponíveis) porque não pensava. meu.


Isenção de responsabilidade


Aqueles que ainda não trabalharam com o Spring Boot recomendam pular rapidamente o Spring Initializr, retornar ao material recomendado e tentar configurar tudo por conta própria, tendo encontrado muitos problemas diferentes; caso contrário, no futuro, haverá lacunas na compreensão de várias coisas.


Início rápido


Crie um projeto para nosso aplicativo Web usando o Spring Initializr , as dependências necessárias para nosso pequeno aplicativo Web:


  • Spring Data JPA (para trabalhar com o banco de dados)
  • Vaadin (para desenvolvimento de aplicativos da web)
  • Lombok (para reduzir o código da placa da caldeira)
  • Driver MySQL (eu uso o mariadb, na primavera inicializr'e não é)

Configurando application.properties e banco de dados


O projeto criado no Spring Initializr está quase pronto para execução, só podemos configurar o application.properties especificando o caminho do banco de dados, nome de usuário e senha


spring.datasource.url = jdbc:mariadb://127.0.0.1:3306/test spring.datasource.username=user spring.datasource.password=password spring.jpa.hibernate.ddl-auto=update 

Cuidado: ddl-auto

Não use ddl-auto com o valor de atualização em um banco de dados ativo ou ao desenvolver um projeto, pois ele atualiza automaticamente o esquema do banco de dados.
Opções existentes para ddl-auto:
create - criará uma tabela no banco de dados, excluindo anteriormente a versão antiga da tabela (perda de dados em caso de alteração do esquema)
validate - verifica a tabela no banco de dados, se não corresponder à entidade, o hibernate emitirá uma exceção
update - verifica a tabela e a atualiza automaticamente sem remover campos inexistentes da entidade
create-drop - verifica a tabela, cria ou atualiza e, em seguida, a exclui, destinada ao teste de unidade


Com o conjunto de valores ddl-auto: update, o hibernate cria automaticamente uma tabela no banco de dados com base em nossa essência, porque criamos um catálogo de endereços simples e criamos uma classe de contato.


Contact.class
 @Entity(name = "Contacts") @Getter @Setter @EqualsAndHashCode public class Contact { @Id @GeneratedValue(strategy = GenerationType.AUTO) private int id; private String firstName; private String secondName; private String fatherName; private String numberPhone; private String email; } 

Vamos criar uma interface para trabalhar com o banco de dados e adicionar um método que retorne List desde Por padrão, o Spring Data JPA retorna Iterable em vez de List.

ContactRepository.class
 public interface ContactRepository extends CrudRepository<Contact, Integer> { List<Contact> findAll(); } 

O desenvolvimento da interface no Vaadin inclui adicionar componentes de entrada, visualização e formas de interação aos objetos de layout para o posicionamento necessário dos elementos. Uma lista de todos os componentes pode ser encontrada no site oficial da estrutura.


A página principal do nosso aplicativo será ContactList. Herdaremos todos os objetos das páginas criadas do AppLayout - este é um layout típico de um aplicativo da Web composto por:


  • Navbar (cabeçalho)
  • Gaveta (barra lateral)
  • Conteúdo
    Ao mesmo tempo, os componentes são adicionados à Navbar e ao Drawer e um componente é definido como Conteúdo como Conteúdo, por exemplo, VerticalLayout, no qual os elementos do usuário serão colocados em uma disposição vertical.

A página para editar e criar contatos será ManageContact, e implementaremos a interface HasUrlParameter nela para transferir o ID do contato. Quando essa interface está ativada, o parâmetro deve ser passado para a página.
Para vincular uma página a um URL específico, a anotação de Rota é usada:


 @Route("contacts") public class ContactList extends AppLayout {} @Route("manageContact") public class ManageContact extends AppLayout implements HasUrlParameter<Integer> {} 

Crie uma lista de contatos


No construtor do objeto ContactList, especifique os componentes usados, primeiro tornando-os os campos do objeto. Como os dados serão retirados do banco de dados, é necessário conectar o repositório ao campo do objeto.


 @Route("contacts") public class ContactList extends AppLayout { VerticalLayout layout; Grid<Contact> grid; RouterLink linkCreate; @Autowired ContactRepository contactRepository; public ContactList(){ layout = new VerticalLayout(); grid = new Grid<>(); linkCreate = new RouterLink(" ",ManageContact.class,0); layout.add(linkCreate); layout.add(grid); addToNavbar(new H3(" ")); setContent(layout); } } 

Sobre conexão automática (atualizado)

Não tente acessar contactRepository do construtor de um objeto; isso certamente causará uma NullPointerException, acesso de métodos com anotação PostConstruct ou métodos de um objeto já criado.
Em uma dica de zesetup : contactRepository , você pode injetar através do construtor:


 ContactRepository contactRepository; @Autowired public ContactList(ContactRepository contactRepository){ this.contactRepository = contactRepository; 

Como dica de markellg : Também vale a pena notar que, ao usar o Spring versão 4.3 e superior, a anotação com fio automático no construtor é opcional se a classe contiver um único construtor.


O componente VerticalLayout foi adicionado à classe ContactList para a organização vertical dos elementos no conteúdo; adicionaremos o RouterLink a ele (para acessar a página de criação de contatos) e o Grid para exibir a tabela. A grade é digitada pelo objeto Contact, para que possamos carregar dados da lista e eles aparecem automaticamente quando o método setItems () é chamado;


 Grid<Contact> grid; public ContactList(){ grid = new Grid<>(); //      grid = new Grid<>(Contact.class); //      ,       } 

O comportamento da criação automática de colunas não é interessante para nós, porque na estrutura do artigo, vale a pena mostrar a adição de colunas e a exibição de botões para excluir ou editar contatos.


Para preencher a tabela, obteremos os dados de contactRepository, para isso criaremos um método com a anotação PostConstruct


Preenchendo uma Tabela com FillGrid ()
  @PostConstruct public void fillGrid(){ List<Contact> contacts = contactRepository.findAll(); if (!contacts.isEmpty()){ //     grid.addColumn(Contact::getFirstName).setHeader(""); grid.addColumn(Contact::getSecondName).setHeader(""); grid.addColumn(Contact::getFatherName).setHeader(""); grid.addColumn(Contact::getNumberPhone).setHeader(""); grid.addColumn(Contact::getEmail).setHeader("E-mail"); //     grid.addColumn(new NativeButtonRenderer<Contact>("", contact -> { UI.getCurrent().navigate(ManageContact.class,contact.getId()); })); grid.addColumn(new NativeButtonRenderer<Contact>("", contact -> { Dialog dialog = new Dialog(); Button confirm = new Button(""); Button cancel = new Button(""); dialog.add("     ?"); dialog.add(confirm); dialog.add(cancel); confirm.addClickListener(clickEvent -> { contactRepository.delete(contact); dialog.close(); Notification notification = new Notification(" ",1000); notification.setPosition(Notification.Position.MIDDLE); notification.open(); grid.setItems(contactRepository.findAll()); }); cancel.addClickListener(clickEvent -> { dialog.close(); }); dialog.open(); })); grid.setItems(contacts); } } 

NativeButtonRenderer é usado para adicionar colunas com botões de edição e exclusão, passamos o nome do botão para os argumentos do construtor e um manipulador de cliques de botão.


 grid.addColumn(new NativeButtonRenderer<Contact>("", contact -> { //DO SOMETHING })); grid.addColumn(new NativeButtonRenderer<Contact>("", new ClickableRenderer.ItemClickListener<Contact>() { @Override public void onItemClicked(Contact contact) { //DO SOMETHING }})); 

Resultado

Lista de contatos


Criando uma página de edição de contato


A página de edição de contato aceita o parâmetro como o ID do contato, portanto, precisamos implementar o método setParameter ():


  @Override public void setParameter(BeforeEvent beforeEvent, Integer contactId) { id = contactId; if (!id.equals(0)){ addToNavbar(new H3(" ")); } else { addToNavbar(new H3(" ")); } fillForm(); //  } 

A adição de componentes é semelhante ao ContactList, apenas neste caso não usamos VerticalLayout, mas usamos a marcação especial FormLayout para exibir esses formulários. Nós preenchemos o formulário com dados que não usam mais o método com a anotação PostConstruct, mas depois de obter o número de contato da URL, porque a cadeia: Construtor de objetos -> @PostConstruct -> Substituir


Managecontact.class
 @Route("manageContact") public class ManageContact extends AppLayout implements HasUrlParameter<Integer> { Integer id; FormLayout contactForm; TextField firstName; TextField secondName; TextField fatherName; TextField numberPhone; TextField email; Button saveContact; @Autowired ContactRepository contactRepository; public ManageContact(){ //    contactForm = new FormLayout(); firstName = new TextField(""); secondName = new TextField(""); fatherName = new TextField(""); numberPhone = new TextField(" "); email = new TextField(" "); saveContact = new Button(""); //     contactForm.add(firstName, secondName,fatherName,numberPhone,email,saveContact); setContent(contactForm); } @Override public void setParameter(BeforeEvent beforeEvent, Integer contactId) { id = contactId; if (!id.equals(0)){ addToNavbar(new H3(" ")); } else { addToNavbar(new H3(" ")); } fillForm(); } public void fillForm(){ if (!id.equals(0)){ Optional<Contact> contact = contactRepository.findById(id); contact.ifPresent(x -> { firstName.setValue(x.getFirstName()); secondName.setValue(x.getSecondName()); fatherName.setValue(x.getFatherName()); numberPhone.setValue(x.getNumberPhone()); email.setValue(x.getEmail()); }); } saveContact.addClickListener(clickEvent->{ //       Contact contact = new Contact(); if (!id.equals(0)){ contact.setId(id); } contact.setFirstName(firstName.getValue()); contact.setSecondName(secondName.getValue()); contact.setFatherName(fatherName.getValue()); contact.setEmail(email.getValue()); contact.setNumberPhone(numberPhone.getValue()); contactRepository.save(contact); Notification notification = new Notification(id.equals(0)? "  ":"  ",1000); notification.setPosition(Notification.Position.MIDDLE); notification.addDetachListener(detachEvent -> { UI.getCurrent().navigate(ContactList.class); }); contactForm.setEnabled(false); notification.open(); }); } } 

Resultado

Edição de contatos


Resultados: O Vaadin 14 é uma estrutura bastante conveniente para a criação de aplicativos da Web simples. Usando-o, você pode criar rapidamente um aplicativo apenas com conhecimento de Java na bagagem e funcionará. Infelizmente, porém, toda a interface é criada no servidor e os recursos são muito mais necessários do que usar HTML5 + JS. Essa estrutura é mais adequada para pequenos projetos que precisam ser realizados rapidamente, sem estudar tecnologias front-end.


Este artigo mostrou como você pode criar rápida e facilmente um aplicativo da Web sem projetar um banco de dados de antemão, evitar configurações XML longas e com que rapidez você pode desenvolver uma interface da Web. Na maioria das vezes, o Spring Boot e o Spring Data JPA facilitam a vida dos desenvolvedores e simplificam o desenvolvimento. O artigo não revelará nada de novo aos desenvolvedores já estabelecidos, mas ajudará o iniciante a dominar a estrutura do Spring.


Repositório com projeto


Os erros de gramática e pontuação são possíveis no artigo; após a detecção, envie um

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


All Articles