Escolar Documentos
Profissional Documentos
Cultura Documentos
Matera Systems
Direito Autoral
Matera Systems
Informações
IMPORTANTES
✔ Dê a sua opinião e contribua com a melhoria do projeto Matera BootCamp, e
garantimos que sua resposta será anônima!
Acesse agora: https://forms.gle/2SX4jFdfkmaV5yF47
✔ O certificado de participação será enviado aos alunos que tiverem 55% ou mais de
presença, na semana dos dias 13/03 à 17/03/23 via email.
✔ Faremos um sorteio de uma caneca exclusiva para os participantes que completarem
😉
no mínimo 80% de presença. Fique de olho em seu email, o resultado sai no dia
17/03/2023!
✔ Convidamos a todos a participar da nossa comunidade do Matera BootCamp. É o
ambiente perfeito para você participar e garantir que receberá todos os comunicados.
Entre no grupo:
Recursos Necessários
JAVA: https://www.java.com/pt-BR/download/ie_manual.jsp?locale=pt_BR
GIT: https://git-scm.com/downloads
Maven: https://maven.apache.org/download.cgi
JUnit: https://github.com/junit-team/junit4/wiki/Download-and-Install
Lombok: https://mvnrepository.com/artifact/org.projectlombok/lombok
Direito Autoral
Matera Systems
Conceitos Básicos
Encapsulamento
Herança
Herança é um princípio da programação orientada a objetos que permite
que classes sejam criadas a partir de outras. Desse modo, temos superclasses
(classes que dão origem às demais) e subclasses. Com isso, criamos um
esquema de hierarquia entre elas.
Composição
Composição apresenta um comportamento parecido com a da herança,
mas na composição podemos mudar o comportamento dos métodos
personalizando-os para cada subclasse em tempo de execução.
Na herança, criamos métodos que serão comuns às classes filhas e as
Direito Autoral
Matera Systems
Polimorfismo
Basicamente, o polimorfismo é o que permite que classes abstratas
tenham seus comportamentos alterados pelas classes concretas que as
estendem.
Classes Abstratas
Classes abstratas são classes bases que servem de modelo para classes
derivadas. Os métodos definidos na classe abstrata devem ser sobrescritos nas
classes derivadas. Classes abstratas não são instanciáveis, apenas suas
derivadas.
Interfaces
Interfaces são padrões definidos (como especificações ou “contratos”) para
as classes que as implementam. Elas definem o formato, e quais métodos
devem ser, obrigatoriamente, implementados.
Uma interface deve ter todos os métodos abstratos, sendo que nenhuma
implementação é permitida.
Sobreescrita e Sobrecarga
definição para ele, um código pré-definido, mas que este teve seu código
substituído pelo código definido na classe derivada que a estende.
Direito Autoral
Matera Systems
Equals vs ==
valores das propriedades uma por uma. Retornará true se todas as propriedades
tiverem o mesmo valor.
Por outro lado, o == irá retornar true apenas se os dois objetos
referenciarem o mesmo endereço em memória, isto é, sejam a mesma
instância.
Modificadores de Acesso
Modificadores de acesso procuram limitar o acesso à cada parte da classe
para serem mais adequadas para cada propósito. São definidos sempre em
letras maiúsculas como FINAL, NATIVE, STATIC SYNCHRONIZED e VOLATILE, e
podem ser utilizados em conjunto.
Quando o atributo recebe os modificadores STATIC FINAL quer dizer que
sua inicialização poderá ser realizada apenas na declaração do atributo ou em
algum bloco de inicialização estático.
Os modificadores Final e Static, os mais utilizados, serão apresentados
com mais detalhes a seguir.
Final
atributo uma constante que só pode ser inicializada uma única vez, diretamente
na declaração da classe ou no construtor.
Final é utilizado em criação de properties ou variáveis que já terão seus
valores definidos desde o começo. Com tipos primitivos, como integer e string,
esse valor será imutável.
Direito Autoral
Matera Systems
Figura 22: Classe utilizada como exemplo para o teste de modificador final.
Direito Autoral
Matera Systems
No caso acima, quer dizer que a propriedade final irá manter a referência
a este objeto, mas que seus atributos poderão ser modificados posteriormente.
Quando aplicado a métodos, o modificador FINAL garante que este não
será sobreescrito.
Por último, o modificador FINAL pode ser aplicado em parâmetros, sendo
que estes não poderão ser modificados no corpo do método.
Static
Economiza memória e a possibilita a troca de informações entre objetos
da classe. Torna o atributo possível de ser inicializado em qualquer parte da
classe, mas uma vez que recebe valor, todos os objetos da classe podem o
acessar.
Atributos STATIC são “atributos de classe''. Isso significa que todos os
objetos instanciados dessa classe compartilham esse atributo. É parecido com
Direito Autoral
Matera Systems
Estruturas e Funcionalidades
Classe Anônima
Classes anônimas são classes que não são declaradas explicitamente no
código, mas são internas à outra classe
Direito Autoral
Matera Systems
Não é possível criar um método numa classe anônima que não existe na
classe pai.
Ainda podemos utilizar classes anônimas com Interfaces.
Direito Autoral
Matera Systems
Figura 30: Interface utilizada para exemplo de classe anônima com interface.
Lambdas
As funções lambda tem como objetivo adicionar características de
linguagens funcionais ao JAVA. Foi introduzida no JAVA 8. Uma das grandes
vantagens é a diminuição de código necessário para a utilização e escrita de
funções.
Assim como as Classes Anônimas, as funções lambda nada mais são que
funções sem definição. Não é necessário declarar uma função lambda, por isso
podem ser declaradas já no mesmo ponto do código em que serão utilizadas.
A sintaxe das funções lambdas em JAVA é (argumento) -> (corpo), sendo
que uma função lambda por ter 0 ou N parâmetros e seus parâmetros podem
ou não ter declaração de tipos. Nos casos onde os tipos dos parâmetros não são
informados, o JAVA é capaz de inferi-los.
Ainda existe outro modo de usar as funções lambda que é passá-las como
parâmetro. Essa possibilidade abre oportunidade para que o método seja mais
flexível e customizável.
Direito Autoral
Matera Systems
Streams
Stream é um meio de trabalhar com coleções de modo que a
manipulação dessas fique mais fácil e seja realizada com menos código.
Também é uma das vantagens da adição de paradigmas funcionais ao JAVA 8.
Com streams é possível realizar buscas, mapeamentos e operações sobre
coleções.
Direito Autoral
Matera Systems
A maior parte das funções da stream facilita o loop realizado nos itens
desta. Por exemplo, a função filter() irá iterar na stream utilizando como critério
a função lambda informada.
Direito Autoral
Matera Systems
Filter
A função Filter já foi mencionada anteriormente quando estávamos
falando de Streams. É uma função bastante útil que serve para filtrar itens de
uma coleção baseado num predicado. Esse predicado, usualmente, é uma
função lambda.
Já vimos exemplos de como aplicá-lo em uma Stream, mas podemos
utilizá-lo também em Maps.
Direito Autoral
Matera Systems
Interface Funcional
Interfaces funcionais são interfaces que possuem um método abstrato. O
diferencial dessas interfaces é que elas permitem que sejam utilizadas com
expressões lambda.
São definidas pela anotação @FunctionalInterface.
Direito Autoral
Matera Systems
LocalDateTime
É a nova classe de manipulação de datas do JAVA 8. Abaixo algumas das
funcionalidades oferecidas pela biblioteca.
Direito Autoral
Matera Systems
Podemos obter dados das datas de modo muito mais simples e fácil do
que foi apresentado até o JAVA 8.
Outra classe que é importante mencionar é a Instant. É utilizada para
calcular durações, em sua maioria.
Direito Autoral
Matera Systems
Optional
A intenção do Optional é encapsular retorno de métodos <T> prevenir o
erro NullPointerException. Isso porque com Optional saberemos se o valor está
ou não presente. Para criar um Optional podemos usar o método estático of.
Caso exista a possibilidade de criação de Optional de objetos nulos, usa-se
o ofNullable.
O código acima recupera a conta e, caso ela não seja nula, a imprime.
Direito Autoral
Matera Systems
Podemos ainda, criar uma cadeia de métodos que irão manipular e filtrar
um optional, sem corrermos o risco de criarmos código que não sabem lidar
com itens nulos.
Collections
É um framework de um conjunto de interfaces que representam grupos
de dados. Coleções podem ser manipuladas através de interfaces,
implementações e algortimos já fornecidos pela Collections Framework.
Ainda temos uma segunda hierarquia relacionada à mapas que não são
derivadas da Collection, mas podem ser manipuladas de forma muito
semelhante.
Set
Um Set é uma interface que define uma coleção que não permite
List
É uma coleção ordenada, mas que pode conter elementos duplicados.
Fornece mais controle ao programador do que um Set e é possível acessar cada
elemento através de índices.
Existem duas implementações da interface List que são ArrayList e
LinkedList.
ArrayList oferece acesso aleatório rápido através de índice, ao contrário da
Direito Autoral
Matera Systems
LinkedList que possui acesso aleatório mais lento e necessita de um objeto “nó”
para cada elemento. Este nó possui o conteúdo e a referência para um próximo
elemento, sendo assim, ela ocupa mais memória.
LinkedLists são úteis para quando precisamos inserir ou remover algum
elemento do meio da lista, sem perder a ordenação. Ainda assim, o uso de
ArrayLists é mais comum, devido à sua adaptatividade.
A classe Collections fornece o método sort() que classifica conforme a
ordem natural (números crescentes ou ordem alfabética) ou ainda baseado na
implementação da interface Comparator.
Map e HashCode
Map são coleções que utilizam hashcode. Dispõe de um mecanismo de
criação de índices para armazenar uma grande quantidade de dados e facilitar a
busca.
A interface Map do JAVA mapeia valores para as chaves que serão
utilizadas como índices. Chaves essas que não podem ser repetidas na mesma
coleção. Essa interface faz parte do java.util e não possui os métodos da
interface Collection.
Direito Autoral
Matera Systems
Por último, ainda vale mencionar que existe a classe HashTable, que
funciona de modo bastante similar à HashMap, mas possui funções extras de
controle de concorrência e não aceita valores nulos.
Figura 75: Objeto que será utilizado para teste com MapTable.
Direito Autoral
Matera Systems
Iterator
Possibilita percorrer uma coleção e remover seus elementos. As interfaces
da Collections herdam o método iterator, que retorna uma interface Iterator.
Direito Autoral
Matera Systems
Testes Unitários
TDD
É o conceito que define que antes de criarmos um código novo, devemos
escrever testes para ele. Isso garante que o código que está sendo escrito já terá
testes automáticos que o cobrem. Estes testes serão utilizados como métrica
durante toda a vida do projeto.
O que são?
Testes unitários se concentram em testar a menos unidade de um projeto
de software. É realizado em cima de uma unidade lógica, com dados o
suficiente para testar apenas essa unidade. Em JAVA, normalmente uma
unidade lógica é um método.
O que testar?
Cada método deve ser uma unidade de negócio mínima, portanto, cada
método deve ser testado. É importante imaginar diversos cenários para cada
teste e escrevê-los. Quanto mais cenários, melhor.
Métodos get e set, normalmente, não são testados.
Direito Autoral
Matera Systems
JUnit
JUnit é um framework que facilita o desenvolvimento e execução de
testes unitários em JAVA. Fornece uma API para construir testes e aplicações
gráficas e em modo console para executar os testes criados.
Facilita a criação, execução automática e apresentação de resultados.
Fazer download do junit.jar em
https://github.com/junit-team/junit4/wiki/Download-and-Install e adicionar o jar
ao classpath do projeto.
Exemplo
Vamos criar uma classe Conta que possui os métodos: sacar e depositar.
Direito Autoral
Matera Systems
GIT
É um gerenciador de versões bastante utilizado em projetos. A maior
parte das operações é feita localmente primeiro, como commits e criação de
branches.
Fluxo de Trabalho
O GIT trabalha com uma área temporária de arquivos entre as alterações
locais e as que estão no servidor. Portanto, temos o Diretório de Trabalho
(Working Directory) que mantém todas as alterações vigentes realizadas
localmente, o Index que é a área temporária onde as alterações ainda não estão
no servidor. Por último, a HEAD que aponta para o último commit realizado.
Adicionar e Confirmar
Quando mudanças são realizadas, primeiro as adicionamos ao Index
usando git add <arquivo> ou git add .
Para realmente confirmar essas mudanças, é necessário fazer commit
com o comando git commit -m “Comentario do commit”. Isso quer dizer que
suas mudanças estarão no HEAD, mas ainda não estarão acessíveis no
repositório remoto.
Criando branches
Branches são utilizados para desenvolver atividades isoladamente, de
modo que os commits e envios dessa atividade não afete o branch master. Eles
sempre são criados a partir de um branch “oficial” e, ao final do
desenvolvimento, são reintegrados ao branch principal.
Para criar um novo branch execute git checkout -b <nome_branch>.
Desse modo, seu espaço de trabalho estará nesse branch. Caso queira retornar
para a master execute git checkout master.
O checkout faz com que todos os arquivos locais que se tenha na
máquina fiquem de acordo com o branch de qual foi feito checkout. Qualquer
alteração que não tenha sido commitada poderá ser perdida.
O branch criado ficará disponível apenas localmente até que você o envie
para o servidor com o comando git push origin <nome_banch>. Para apagar o
branch criado execute git branch -d <nome_branch>.
Squash Merge
Durante o desenvolvimento, é recomendado realizar commits frequentes.
Isso pode poluir a timeline de um branch. Nesse caso, seria muito melhor
termos apenas um commit com todas as alterações realizadas durante todo o
desenvolvimento. Para isso utilizamos o comando rebase.
O rebase é parecido com o merge e atualiza o branch atual com os
commits do branch de referência, porém, ao invés dele criar um commit de
“merge”, ele usa como base o branch de destino, colocando por cima todos os
commits realizados na branch atual, reescrevendo seu histórico.
Isso significa que o último commit do histórico não será o commit de
merge, e sim o último commit realizado na branch atual.
Para facilitar ainda mais, podemos condensar todos os commits realizados
até então em um único commit, despoluindo o log de commits e facilitando a
integração desse branch em outros.
Primeiro, encontramos o hash do último commit que foi realizado antes
de todos os que queremos condensar. Imagine que temos 3 commits que
iremos agrupar, desse modo, temos que pegar o hash do quarto commit. Com o
hash em mãos, executamos o comando git rebase -i <hash>. Isso irá abrir o
modo interativo do rebase, e todos os commits a partir desse poderão ser
alterados.
Direito Autoral
Matera Systems
O rebase irá retornar alguns commits que poderão ser agrupados. Para
marcar quais deverão sofrer o squash, troque o pick por squash.
Maven
É uma ferramenta de automação e gerenciamento de projetos JAVA.
Fornece um meio de automatizar e padronizar a construção e publicação de
software.
Padroniza as versões e quais bibliotecas são utilizadas em cada projeto,
deste modo, o ambiente de construção do ambiente irá sempre utilizar essas
bibliotecas, não dependendo de cada desenvolvedor em separado.
Direito Autoral
Matera Systems
Instalação
Antes de instalar o maven, é necessário ter o JAVA instalado. Para fazer o
download do maven acesse http://maven.apache.org/download.html e escolha o
arquivo compatível com seu ambiente.
Então, descompacte o arquvivo em um diretório com o nome no formato
maven-[versão] (sem espaços).
Criar as variáveis de ambiente JAVA_HOME e M2_HOME. A primeira deve
conter a localização do diretório do JDK que está sendo utilizado e a segunda
deve conter a localização do diretório maven. Também deve-se alterar a variável
Path, adicionando a localização do diretório bin do maven.
Segue link com tutorial de instalação completo:
https://dicasdejava.com.br/como-instalar-o-maven-no-windows/ .
Dependências
As dependências são gerenciadas pelo arquivo pom.xml. Aqui são listadas
as dependências que o projeto utiliza, quais suas versões, quais plugins e quais
perfis existem para esse projeto.
Direito Autoral
Matera Systems
Figura 93: Jar gerado a partir da execução do mvn clean install na pasta target.
Lombok
É um framework que permite escrever código menos verboso. Isso
significa que será necessário escrever menos código para conseguir o resultado
desejado.
Basicamente, gera uma compilação dos métodos GET e SET, construtores
e padrão builder.
Instalação
Para utilizar o Lombok é necessário instalar o plugin do Lombok na sua
IDE.
IntelliJ: Para instalar, vá na parte de instalação de pugin do IntelliJ e
instale o Lombok Plugin.
Eclipse: Baixe e instale o .jar do Lombok na versão desejada em
https://mvnrepository.com/artifact/org.projectlombok/lombok.
Após instalar o plugin na IDE, adicionamos o lombok no projeto.
Direito Autoral
Matera Systems
Utilização
Arquitetura MVC
(Model-View-Controller)
Possibilita a divisão do projeto em camadas. Cada uma delas, Model, View
e Controller possui finalidades específicas e cada uma executa apenas o que lhe
é definido.
Direito Autoral
Matera Systems
Model
É a camada responsável pelas regras de negócio, persistência no banco de
dados e classes de entidades. Ela recebe as requisições vindas da Controller e
gera respostas para essas requisições.
View
É a camada de visualização. Contém as interfaces com o usuário. Não
contém nenhuma lógica de negócio, apenas tabelas, grids, formulários e outras
formas de interface.
Essa camada aciona a Controller.
Controller
Serve como um intermediário que organiza os eventos da interface e os
direciona para a camada de modelo. Assim, é possível o reaproveitamento da
camada de modelo em outros sistemas, já que não existe dependência entre a
visualização e as regras de negócio.
Direito Autoral
Matera Systems
Vantagens
● Separação clara entre camadas;
● Manutenção facilitada;
● Reaproveitamento de código;
● Isolamento da camada de interface, sendo que qualquer alteração
realizada em telas não afeta o negócio.
Desvantagens
● Em projetos mais simples, acaba criando uma complexidade
desnecessária;
● Requer um tempo maior de modelagem de sistema;
● Exige bastante disciplina dos desenvolvedores envolvidos para manter a
organização do projeto.
Tratamento de Exceção
Exceções acontecem quando algo imprevisto ocorre, podem ser resultado
de erros de lógica ou acesso a recursos que não estejam disponíveis, como
tentar abrir um arquivo inexistente, ou acessar alguma posição em memória
que ainda não criada, ou ainda tentar conectar em algum servidor ou banco de
dados que não esteja disponível.
Por isso, em todos os locais onde identificamos que algum erro, seja de
lógica ou de acesso possam ocorrer, criamos o tratamento de exceções. Para
isso usamos os comando try e catch no JAVA.
Direito Autoral
Matera Systems
Nesse caso, mesmo que a exceção tenha sido capturada, o finally ainda
será executado como demonstrado no resultado abaixo.
Sistemas Web
Com a facilidade do acesso à internet, os sistemas web vêm dominando
cada vez mais o mercado. Além da praticidade ao usuário do sistema, de poder
acessá-lo de qualquer dispositivo, também facilita a manutenção. Com um
sistema web, não é necessário dar manutenção, atualizando máquina por
máquina, mas apenas uma única aplicação em um servidor.
Um servidor fica disponível para acesso em um endereço e pode ser
utilizado por pessoas, através de uma interface gráfica, ou até mesmo por outros
sistemas.
Existe mais de uma forma de se desenvolver um sistema web.
Inicialmente, uma única aplicação no servidor era responsável por devolver ao
usuário uma página com os recursos do front-end. Em algumas linguagens,
frameworks foram desenvolvidos para trazer uma maior dinamicidade para
essas páginas. Porém, ficava sob responsabilidade do servidor que montasse a
página com os resultados e entregasse prontas ao cliente. Cabia a mesma
aplicação conhecer o back-end e o front-end. Era o servidor que devolvia pronto
todo o HTML de tabelas com respostas de consultas.
Recurso
Um recurso é a representação de algo do mundo real para um elemento
acessível via web por meio de uma URI (Uniform Resource Identifier). Por
exemplo:
http://www.matera.com/bootcamp-for-girls-matera/alunas
Hipoteticamente se essa URI existisse ao acessá-la poderíamos ver, por
exemplo, os nomes das alunas aprovadas.
Direito Autoral
Matera Systems
Constraints do Rest
Iremos conhecer agora as regras (constraints) definidas pelo Rest. São
elas:
● Cliente-Servidor: Essa regra define que precisamos de uma aplicação
cliente (um app, uma outra aplicação, um frontend e etc.) que consome
(faz requisições) para uma aplicação servidora (que disponibiliza um
serviço ou recurso). Além disso, essas aplicações cliente e servidor podem
evoluir de maneira totalmente independentes.
● Stateless: A aplicação servidora não pode guardar o “estado”
(informações) do cliente que fez a requisição. Ou seja, todas as
informações necessárias para o processamento da requisição devem ser
enviadas no momento da requisição.
● Cache: Uma API pode fazer cache da resposta de uma requisição. Por
exemplo, uma API que retorna os bairros de uma cidade não precisa
processar a todo momento a requisição uma vez que os bairros de uma
cidade não mudam com alta frequência. Isso facilita a escalabilidade das
aplicações, melhora o tempo de resposta e de performance.
Direito Autoral
Matera Systems
Rest X Restful
É comum termos dúvidas quanto a diferença entre Rest e Restful. Mas, a
diferença entre os dois é “simples”. Rest é o padrão arquitetural (especificação)
com suas constraints e Restful é uma API desenvolvida seguindo essas
constraints definidas pelo Rest.
Existem alguns estudos sobre o nível de maturidade das API’s Rest
mediante as constraints aplicadas por elas. Para saber mais acesse:
https://martinfowler.com/articles/richardsonMaturityModel.html
e https://www.brunobrito.net.br/richardson-maturity-model/
Direito Autoral
Matera Systems
Status Code
Os Status Code são códigos que representam o status de processamento
de uma requisição. Isso ajuda o cliente que fez a requisição “agir” de maneira
adequada mediante a resposta da mesma. Assim como temos a semântica em
relação aos verbos HTTP, temos também uma semântica para os Status Code,
ou seja, devemos usar as famílias de maneira adequada.
Essas são as famílias de status code:
1XX – Informações Gerais (100 a 199)
2XX – Sucesso (200 a 299)
3XX – Redirecionamento (300 a 399)
4XX – Erro no cliente (400 a 499)
5XX – Erro no servidor (500 a 599)
Para conhecer mais sobre os status code acesse:
https://developer.mozilla.org/pt-BR/docs/Web/HTTP/Status
Direito Autoral
Matera Systems
Request
Uma requisição é composta por:
● Método Http (também conhecido como Verbos Http): GET, POST, DELETE,
PUT, PATH e outros.
● URI: é o que recursos que desejamos dentro do servidor
● Versão do protocolo http: Atualmente estamos na versão 2.0 do protocolo
http, entretanto a versão mais utilizada é a versão 1.1
● Cabeçalhos: Os cabeçalhos são informações do formato chave: valor. Essas
informações ajudam o servidor a processar adequadamente a requisição.
O protocolo http já define alguns cabeçalhos. Entretanto, podemos criar
nossos próprios cabeçalhos caso necessário.
● Corpo: O corpo da requisição não é obrigatório, dependendo do verbo
http utilizado. O mesmo serve para enviar informações para o servidor.
Por exemplo:
Verbo: POST
URI: /api/v1/bootcamp-for-girls-matera/alunas
Versão do protocolo: HTTP/1.1
Cabeçalho: Content-Type: aplication/json (significa que estamos enviando um corpo no
formato json)
Corpo: { “nome”: “Maria Joaquina”}
Response
Uma resposta é composta por:
● Versão
● Status Code
Direito Autoral
Matera Systems
● Cabeçalhos
● Corpo
Por exemplo:
Java e Spring
O Java possui diversos frameworks para desenvolvimento web. Nos
modelos antigos, quando o servidor respondia toda a página renderizada com
os dados preenchidos, frameworks como JSF e JSP eram amplamente
utilizados. Porém, com a chegada de ferramentas front-end como o Angular e
React, a maior parte das aplicações Java web que são desenvolvidas (e de
quaisquer outras linguagens de programação), são pensadas apenas como
servidores back-end.
Dos frameworks backend Java o Spring é o que mais se sobressai e
atualmente é o “padrão” de mercado.. O Spring não é apenas um framework, na
realidade ele é todo um ecossistema. São vários módulos com utilidades em
diversas áreas, abstraindo grande parte de configuração que precisaria ser feita
para o uso mais comum de cada um desses módulos. Alguns exemplos entre os
módulos mais comuns são Spring Data JPA, Spring Security e Spring Web.
Direito Autoral
Matera Systems
O Spring trabalha com um conceito de Beans. Beans são objetos que são
gerenciados pelo Spring através de um container de Inversão de Controle (IoC).
Inversão de Controle é o processo responsável por verificar as dependências dos
Beans sem precisar, de fato, criá-los. Após essa análise, os Beans são criados pelo
container de IoC, baseado nas suas dependências. Em outras palavras inversão
de controle é delegar para o Spring a instanciação dos nossos objetos que ele
gerencia e todo esse processo fica encapsulado pelo framework.
A forma mais simples de se trabalhar com Spring é através do uso de
anotações. Para se criar um Bean no Spring, basta anotar a classe criada com
@Component. Algumas outras variações estão disponíveis para uso, como
@Controller, @RestController, @Service e @Repository, porém a única diferença
entre elas é tentar facilitar a leitura do código (semântica).
Como dito anteriormente, uma vez que uma classe foi anotada com
alguma anotação do Spring (@Component, @Service e etc.) o container de IoC
faz o gerenciamento da criação desses Beans, portanto, para utilizá-los, não é
necessária a instanciação. Para isso será utilizado um outro conceito
fundamental do Spring que é a injeção de dependências. Isso indicará ao Spring
que uma classe A depende da classe B. Nesse caso o container de IoC criará
primeiro a classe B e utilizará esse objeto criado para criar a classe A. Esse
conceito é amplamente utilizado em sistemas web. Dessa forma é possível fazer
um melhor gerenciamento de memória e concorrência entre as requisições.
Para indicar ao Spring que uma classe depende de outra, é possível fazer de três
maneiras diferentes. Usando a anotação @Autowired diretamente no atributo,
com @Autowired usando o método setter para o atributo ou através do
construtor do objeto (caso a classe tenha mais de um construtor que receba
parâmetros o @Autowired deve sinalizar qual construtor o Spring deve utilizar
na inicialização).
Direito Autoral
Matera Systems
Spring na prática
Nesta seção nós veremos um pouco mais do spring na prática além
conhecermos o Spring boot, Spring Data JPA e um pouco sobre transações.
Spring Boot
O Spring Boot é um dos projetos dentro do ecossistema Spring. Ele tem
como principal missão facilitar o uso dos demais módulos do Spring, abstrair e
Direito Autoral
Matera Systems
Perfis de execução
Você verá que sua aplicação foi gerada com uma pasta “resources”, com
alguns arquivos dentro. Neste momento, apenas o arquivo
“application.properties” importa, os demais podem ser excluídos. O Spring é
capaz de entender tanto arquivos “properties” como arquivos “yaml”. Por
motivos de verbosidade, utilizaremos no projeto um arquivo do tipo “yaml”. Para
isso, exclua o arquivo “application.properties” e crie um arquivo com o nome
“application.yaml”. Nesse arquivo algumas configurações fixas podem ser
pré-definidas para a execução da aplicação. Através dele podemos definir
diferentes perfis de execução do Spring. Vários perfis podem estar ativos
simultaneamente. Para criar um novo perfil, basta criar um arquivo
“application-nome-do-perfil.yaml”. Um bom exemplo de uso é quando a
aplicação desenvolvida suporta diferentes tipos de banco de dados. Dessa
Direito Autoral
Matera Systems
Configurações em código
O Spring dá também a possibilidade de fazer configurações via linhas de
código. Isso pode ser útil quando alguma informação precisa ser obtida, ou um
objeto instanciado, para que a configuração seja feita. Para criar uma classe de
configuração no Spring basta anotá-la com @Configuration, como no exemplo
abaixo. Classes de configuração geralmente são instanciadas antes dos demais
componentes.
Direito Autoral
Matera Systems
Na figura 16, caso um usuário não seja encontrado em uma busca pelo
código recebido em “UsuarioCrud.java”, uma exceção “RuntimeException” será
lançada com uma mensagem personalizada. A classe
“ExceptionHandlerConfig.java” configura que para qualquer exceção lançada no
sistema (pois todas derivam de Exception), o método
“defaultExceptionHandler(Exception excecao)” será chamado. Esse método cria
um objeto do tipo “ErroViewModel”, preenche com os dados da exceção
ocorrida, e recebida por parâmetro, e devolve com um status 404 (valor da
constante HttpStatus.NOT_FOUND) uma mensagem JSON com título e detalhe
preenchidos, de acordo com o exemplo.
Direito Autoral
Matera Systems
Figura 115: Criando um conversor customizado entre objetos java e valores no BD.
A interface JpaRepository
O Spring possui uma interface que apenas de utilizá-la, todos os métodos
principais de um CRUD (criação, atualização, deleção e busca) são gerados
automaticamente, sem qualquer implementação necessária.
Conforme demonstrado na figura 19, para utilizar a interface
JpaRepository, basta criar uma interface de repositório para a classe de entidade
que deseja, no exemplo a classe @Entity utilizada é a “Usuario”, e fazer com que
a interface criada extenda a interface JpaRepository. Dois parâmetros serão
necessários para isso funcionar. O primeiro será o tipo da entidade desse
repositório, no caso “Usuario”, e o segundo deve ser o tipo do Id dessa entidade,
que nesse caso é Long. Nenhuma outra implementação será necessária. Para
ter acesso a todos os métodos disponíveis na interface JpaRepository, basta a
interface que acabou de criar no Bean onde deseja utilizá-la.
Os principais métodos utilizados serão findById, findAll, deleteById, save e
saveAndFlush. A diferença entre save e saveAndFlush é que para o método save
o framework decidirá qual o melhor momento de executar o script no banco de
dados, enquanto saveAndFlush fará com que o método seja imediatamente
executado.
Direito Autoral
Matera Systems
Sempre que possível, o método save deve ser a melhor opção, porém há
casos em que imediatamente precisamos do valor alterado no banco de dados
devido a concorrência, para esses casos deve ser usado saveAndFlush. Ambos os
métodos fazem tanto a inserção de novos registros, quanto a atualização dos
que já existem, se diferenciando apenas pelo id ter sido informado ou não.
Transações
As integrações do Spring com o JPA também permitem que transações
sejam criadas usando anotações. Caso em um processo seja necessário que
uma transação seja criada, basta anotá-lo com @Transactional. Ao serem
executados uma nova transação será imediatamente aberta. O commit
também será feito automaticamente após a conclusão do método. Se uma
exceção não tratada for lançada durante a execução do método, o rollback da
transação será executado imediatamente e toda a transação será desfeita. Mas
valem alguns pontos de atenção:
1. Consultas que sejam do tipo lazy-load, como objetos com listas de outros
objetos no banco de dados, devem obrigatoriamente estar dentro de uma
transação caso os campos com lazy-load precisem ser executados. Caso
os campos que são configurados como lazy-load não sejam utilizados, não
é necessário criar uma transação.
2. Transações só funcionam através de proxies do Spring. Isso significa que
chamadas do tipo self-invocations (quando um objeto chama ele mesmo,
ou algum método herdado), mesmo que anotados como @Transactional,
não terão transações iniciadas. Isso não gera nenhum tipo de alerta ou
erro, e cabe ao desenvolvedor se atentar a isso.
3. Por consequência do item 2, métodos protected e private nunca iniciam
transações.
4. Alterações em objetos consultados dentro de transações serão aplicadas
mesmo que não seja chamado o método save.
Direito Autoral
Matera Systems
API’s Rest
O Spring abstrai e facilita bastante o desenvolvimento de API’s Rest. Por
conta disso precisamos escrever pouco código para criar um cadastro (CRUD)
completo. A figura 120 mostra o código necessário para criar 5 API’s para
cadastrar, atualizar, apagar e buscar um ou todos os usuários.
Direito Autoral
Matera Systems
Vamos entender agora o que foi feito, o que é enviado em cada requisição,
etc.
Na linha 13 temos a anotação @RequestMapping. Essa anotação é
utilizada para definir qual é o recurso que está sendo criado. No caso, é o
“/api/v1/usuarios”.
Direito Autoral
Matera Systems
Figura 122: Request, response e status code da requisição GET para /api/v1/usuarios
Direito Autoral
Matera Systems
Na figura 122 podemos ver o Json de retorno com dois usuários e Status
Code 200 da requisição GET.
Figura 124: Request, response e status code da requisição GET para /api/v1/usuarios/5
{
"agencia": "5678",
"conta": "928563"
}
Figura 126: Request, response e status code da requisição POST para /api/v1/usuarios
Figura 128: Request, response e status code da requisição PUT para /api/v1/usuarios/5
Figura 130: Request, response e status code da requisição DELETE para /api/v1/usuarios/5
Teste Integrado
Já vimos de maneira bastante detalhada o que são testes unitários, TDD e
a importância dos mesmos. Entretanto, existem cenários onde é de suma
importância escrever um teste que cubra um fluxo como um todo e não apenas
um comportamento em específico. Nesses casos se faz necessário escrevermos
Testes Integrados. Você pode saber mais sobre o assunto clicando no link: TDD na
prática com Java usando @MockBean