Você está na página 1de 32

3/16/23, 10:21 PM documentation/powersolution-academy-spring-boot-basics.

adoc at main · PowerSolution-Academy/documentation

PowerSolution-Academy / documentation Private

Code Issues Pull requests Actions Projects Security Insights

main

documentation / backend / spring-boot / powersolution-academy-spring-boot-basics.adoc

MarceloEliasM-PS documentation: Spring Boot Basics [fix - alt 5] … History

1 contributor

1069 lines (740 sloc) 38.4 KB

Spring Framework

Controlo de Versões
Table 1. Histórico de Versões
Data Autor Versão Descrição Validado

Marcelo Conceitos básicos para


17 de Janeiro
Monteiro 0.1 utilização de Spring
de 2023
Framework

Especificações Técnicas
Este manual destina-se a qualquer pessoa que deseje organizar e acolher informações
sobre a Spring Framework mas também tem a finalidade de servir de guião para iniciantes
e aprendizes.

Table of Contents

https://github.com/PowerSolution-Academy/documentation/blob/main/backend/spring-boot/powersolution-academy-spring-boot-basics.adoc?fbclid=I… 1/32
3/16/23, 10:21 PM documentation/powersolution-academy-spring-boot-basics.adoc at main · PowerSolution-Academy/documentation

O que é a Spring Framework?


A Spring Framework fornece um modelo abrangente de programação e configuração para
aplicações empresariais modernas baseadas em Java - em qualquer tipo de plataforma de
implementação. [1]

Spring Boot é uma extensão do Spring Framework, mais rápida e mais eficiente com
funcionalidades como: injeção de dependências iniciais para simplificar a configuração da
compilação e da aplicação, servidor incorporado para reduzir a complexidade da
implementação e configuração automática para funcionalidade Spring. As dependências
mais utilizadas são: JPA, Security, Test, Web e Thymeleaf. Todas as configurações de
dependências são automaticamente incluídas no processo de autoconfiguração.

Principais vantagens
O Spring Boot funciona bem com vários containers de servlet

O Spring Boot funciona bem com alguns dos containers de servlet incorporados mais
populares. O Spring Boot usa o Tomcat como padrão, mas pode-se trocá-lo facilmente por
Jetty, Undertow, Resin e Wildfly.

Bootstrapping economiza espaço de memória

O Spring Boot usa o Boot Initializer para compilar o idioma de origem. Essa técnica de
inicialização permite que aos utilizadores economizarem espaço nos seus dispositivos e
carreguem aplicações rapidamente.

Nenhuma configuração XML necessária

Os desenvolvedores de projetos Spring podem optar por usar anotações ou configurações


XML. A opção de evitar configurações XML atrai muitos engenheiros de software que não
desejam passar pelas etapas extras necessárias.

Ficheiros WAR não são necessários

Embora o Spring Boot possa usar ficheiros WAR (recurso de aplicativo da web), eles não
são necessários. Em vez disso, o Spring Boot pode contar com o JAR (recurso Java).

Gestão de dependências do POM

O Spring Boot não força o desenvolvidor usar um POM (project object model). Incluir o
artefato spring-boot-dependencies permite gerir dependências sem depender de um POM
ou arquivo XML.

https://github.com/PowerSolution-Academy/documentation/blob/main/backend/spring-boot/powersolution-academy-spring-boot-basics.adoc?fbclid=I… 2/32
3/16/23, 10:21 PM documentation/powersolution-academy-spring-boot-basics.adoc at main · PowerSolution-Academy/documentation

Uma grande comunidade de utilizadores

Como muitas ferramentas de código aberto, o Spring Boot possui uma grande
comunidade de utilizadores cheia de desenvolvedores que gostam de partilhar as suas
ideias e criações.

Ref.: [2]

Instalação Rápida
Passo 1 - Criar um novo projeto

Use este link para criar um projeto “web”. Na caixa de diálogo “Dependências”, procure e
adicione a dependência “web” conforme mostrado na captura de tela. Clique no botão
“Gerar”, baixe o zip e descompacte-o em uma pasta no seu computador.

Figure 1. Configurações necessárias para criar um projeto Spring Boot com Spring Initializr
online
Os projetos criados por start.spring.io contêm Spring Boot, uma estrutura que torna o
Spring pronto para funcionar dentro da sua aplicação, mas sem muito código ou
configuração necessária. O Spring Boot é a maneira mais rápida e popular de iniciar
projetos Spring.

Passo 2 - Adicionar o seu código

https://github.com/PowerSolution-Academy/documentation/blob/main/backend/spring-boot/powersolution-academy-spring-boot-basics.adoc?fbclid=I… 3/32
3/16/23, 10:21 PM documentation/powersolution-academy-spring-boot-basics.adoc at main · PowerSolution-Academy/documentation

Abra o projeto em seu IDE e localize o ficheiro DemoApplication.kt na pasta


/main/kotlin/com/powersolutioncv/demo . Agora altere o conteúdo do ficheiro
adicionando o método extra e as anotações mostradas no código abaixo. Pode copiar e
colar o código ou apenas digitá-lo.

Este é todo o código necessário para criar um serviço web simples “Hello World” no Spring
Boot.

import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RestController

@SpringBootApplication
@RestController
class DemoApplication {

@GetMapping("/hello")
fun hello(@RequestParam(value = "name", defaultValue = "World") name: String?) :
return "Hello $name!"
}

fun main(args: Array<String>) {


runApplication<DemoApplication>(*args)
}

O método hello() que adicionamos foi projetado para receber um parâmetro String
chamado name e, em seguida, combinar esse parâmetro com a palavra "Hello" no
código. Isso significa que, se definires seu nome como “Joana” na solicitação, a resposta
será “Hello Joana” .

A anotação @RestController informa ao Spring que este código descreve um endpoint


que deve ser disponibilizado na web. O @GetMapping(“/hello”) diz ao Spring para usar
nosso método hello() para responder às requisições que são enviadas para o endereço
http://localhost:8080/hello . Finalmente, o @RequestParam está a dizer ao Spring para
esperar um valor de name na solicitação, mas se não estiver lá, ele usará a palavra
“World” por padrão.

Passo 3 - Teste

https://github.com/PowerSolution-Academy/documentation/blob/main/backend/spring-boot/powersolution-academy-spring-boot-basics.adoc?fbclid=I… 4/32
3/16/23, 10:21 PM documentation/powersolution-academy-spring-boot-basics.adoc at main · PowerSolution-Academy/documentation

Vamos compilar e executar o programa. Se estiver a utilizar o Intellij como IDE, clique no
ícone 'Run' para iniciar a compilação e de seguida a execução

Figure 2. Clique no botão com o símbolo de "play" para executar o programa

Nota: Se não estiver a utilizar o Intellij ou o seu IDE não possui o botão
"Run", pode executar o código abaixo através do terminal:

./gradlew spring-boot:run (para MacOS ou Linux)


gradlew.bat spring-boot:run (para Windows)

Deve ver algo parecido a isto:

As últimas linhas aqui nos dizem que o Spring iniciou. O servidor Apache Tomcat
incorporado do Spring Boot atua como um servidor da Web e escuta as solicitações na
porta 8080 . Abra o seu browser e na barra de endereços na parte superior, digite
http://localhost:8080/hello . Deve obter um resultado semelhante a este:

O que acontece quando adicionar ?name=Joana no final da URL? Teste também este caso.

https://github.com/PowerSolution-Academy/documentation/blob/main/backend/spring-boot/powersolution-academy-spring-boot-basics.adoc?fbclid=I… 5/32
3/16/23, 10:21 PM documentation/powersolution-academy-spring-boot-basics.adoc at main · PowerSolution-Academy/documentation

Ref.: [3]

Iniciar um projeto através da IDE


Esta seção descreve como criar e executar um aplicativo Spring no IntelliJ IDEA. Essa é a
maneira mais rápida de criar um aplicativo Spring, e o IntelliJ IDEA fornece um assistente
de projeto dedicado para isso.

1. No menu principal, selecione File | New | Project.

2. No painel esquerdo do assistente New Project, selecione Spring Initializr.

3. Especifique um nome para o projeto. Neste exemplo deu-se o nome de demo

Escolha o caminho que irá guardar o projeto, e seleciona a linguagem como Kotlin , o
tipo como Gradle - Kotlin e atribua o nome ao grupo de com.powersolutioncv e o
artifacto como o nome do projeto tudo a minuscula com separações de palavras feitas
com hífen ( - )

Na lista JDK, selecione Download JDK e faça download da versão mais recente do Oracle
OpenJDK.

Selecione a versão mais recente do Java (17 ou superior).

https://github.com/PowerSolution-Academy/documentation/blob/main/backend/spring-boot/powersolution-academy-spring-boot-basics.adoc?fbclid=I… 6/32
3/16/23, 10:21 PM documentation/powersolution-academy-spring-boot-basics.adoc at main · PowerSolution-Academy/documentation

De seguida clique em Next


4. Busque pelas seguintes dependências e as selecione:

Spring Web

Spring Data JPA

H2 Database

Validation

Spring HATEOAS

Spring Boot DevTools

https://github.com/PowerSolution-Academy/documentation/blob/main/backend/spring-boot/powersolution-academy-spring-boot-basics.adoc?fbclid=I… 7/32
3/16/23, 10:21 PM documentation/powersolution-academy-spring-boot-basics.adoc at main · PowerSolution-Academy/documentation

Por fim clique em Create

Ref.: [4]

Estrutura do projeto
Normalmente o projeto é estruturado da seguinte forma:

▪ api: onde contém todos os pacotes com os elementos que fazem a gestão dos pedidos
e dos dados como controladores, conversores de modelos como assemblers, constantes,
exceções para tratamento de erros e os modelos de entrada e saída;

▪ config: onde estão presentes as classes de configuração da aplicação;

https://github.com/PowerSolution-Academy/documentation/blob/main/backend/spring-boot/powersolution-academy-spring-boot-basics.adoc?fbclid=I… 8/32
3/16/23, 10:21 PM documentation/powersolution-academy-spring-boot-basics.adoc at main · PowerSolution-Academy/documentation

▪ data: onde estão presentes os elementos da base de dados como modelos e


repositórios;

▪ domain: onde estão os modelos de negócios e também os serviços que serão


consumidos pelo cliente

Dentro do pacote api pode-se encontrar:

▪ assemblers: que contém classes que convertem os modelos da base de dados para um
modelo de saída, onde são definidos os campos em que o cliente pode receber nas
respostas dos pedidos.

▪ constants: contêm as variáveis que não mudam de valores em todo o sistema, como
mensagens de exceções e validações.

▪ controllers têm a função de gerir de todos os pedidos HTTP feitos pelo cliente e
retornar a resposta dado pelo sistema.

▪ exceptions contém classes que fazem o tratamento de erros e retornam uma mensagem
apropriada para que o utilizador entenda quais são as possíveis causas do erro e corrigir o
pedido caso o erro seja da parte do utilizador.

▪ models contém os modelos de entrada, que são o corpo JSON que deve ser enviado
pelo cliente com os campos requisitados, e os modelos de saída que são modelos que
contém os campos que devem ser retornados pelo servidor.

No pacote config podem se encontrar as classes que são responsáveis pela definição dos
parâmetros de configuração e também pelo carregamento de ficheiros de configuração
caso existirem.

No pacote data encontram-se todas as entidades JPA que são representação da tabela em
que os dados serão persistidos na base de dados no pacote entities ou models. Também
contém as interfaces dos repositórios que dá o acesso aos dados no pacote repositories.

No pacote domain estão: ▪ Os adapters que convertem os modelos da base de dados


para modelos de negócio.

▪ Em exceptions estão as classes que fazem o tratamento de erros e retornam mensagens


com a descrição dos erros.

▪ As classes auxiliares estão presentes no pacote helpers, que contêm métodos que
ajudam na implementação de serviços

▪ Os modelos do negócio estão contidos no pacote models.


https://github.com/PowerSolution-Academy/documentation/blob/main/backend/spring-boot/powersolution-academy-spring-boot-basics.adoc?fbclid=I… 9/32
3/16/23, 10:21 PM documentation/powersolution-academy-spring-boot-basics.adoc at main · PowerSolution-Academy/documentation

▪ Em repositories estão todas as especificações dos parâmetros que filtram os dados de


acordo com os parâmetros passados no URL da requisição.

▪ Em services estão todos os serviços a serem consumidos pela API.

Entidades
As entidades no JPA nada mais são do que POJOs que representam dados que podem ser
persistidos no banco de dados. Uma entidade representa uma tabela armazenada em um
banco de dados. Cada instância de uma entidade representa uma linha na tabela.

As entidades são definidas no pacote data\models .

Para definir uma entidade, cria-se uma classe Kotlin com o nome da entidade iniciado
sempre a maíuscula.

Temos um exemplo de uma aplicação de gestão de uma escola. Um exemplo de entidade


é um aluno. Pode-se criar uma classe que represente essa entidade com o nome de
Student :

class Student (

Para que o Spring reconheça esta classe como uma entidade, deve-se definir a anotação
@Entity .

https://github.com/PowerSolution-Academy/documentation/blob/main/backend/spring-boot/powersolution-academy-spring-boot-basics.adoc?fbclid=… 10/32
3/16/23, 10:21 PM documentation/powersolution-academy-spring-boot-basics.adoc at main · PowerSolution-Academy/documentation

@Entity
class Student (

Cada entidade JPA deve ter uma chave primária que a identifique exclusivamente. A
anotação @Id define a chave primária. Podemos gerar os identificadores de diferentes
formas, que são especificadas pela anotação @GeneratedValue .

Podemos escolher entre quatro estratégias de geração de id com o elemento strategy. O


valor pode ser AUTO, TABLE, SEQUENCE ou IDENTITY.

Também pode-se escolher o tipo de id com o formato UUID. Para isto define-se um
generador genérico com estratégia uuid com o nome de system-uuid através da
anotação @GenericGenerator , como pode-se ver no exemplo a seguir:

@Entity
class Student (

@Id
@GeneratedValue(generator = "system-uuid")
@GenericGenerator(name = "system-uuid", strategy = "uuid")
val id: String = "",

De seguida pode-se definir outros campos do tipo var por serem mutáveis de acordo
com os atributos da entidade. Por exemplo no caso da entidade Student , campos como
código ou número de estudante, nome, idade, ano, curso, faculdade e universidade podem
ser utilizadas.

@Entity
class Student (

@Id
@GeneratedValue(generator = "system-uuid")
@GenericGenerator(name = "system-uuid", strategy = "uuid")
val id: String = "",

var code: Long = 0L,

var name: String = "",

var age: Int = 18,


https://github.com/PowerSolution-Academy/documentation/blob/main/backend/spring-boot/powersolution-academy-spring-boot-basics.adoc?fbclid=I… 11/32
3/16/23, 10:21 PM documentation/powersolution-academy-spring-boot-basics.adoc at main · PowerSolution-Academy/documentation

var course: Course = Courses.TIC,

var faculty: Faculty = Faculty.TECH,

@ManyToOne
var university: University? = null

Neste exemplo podemos notar que todas as variáveis foram inicializadas com o valor
padrão, e em alguns casos como o caso de course , faculty , utilizaram os tipo Course e
Faculty , que podem ser definidos como uma classe de enumerados. As classes de
enumerados contêm valores constantes e padronizados para um determinado tipo num
determinado contexto. Por exemplo, podemos definir a classe Faculty que contém as
faculdades existentes numa universidade.

enum class Faculty {

TECH, SOCIAL, BIO

Também podemos notar relações com uma outra entidade como o caso de university .
Existem vários tipos de relações como OneToOne, OneToMany, ManyToOne e
ManyToMany. Para mais detalhes podes consultar [6]

Ainda nas classes das entidades, pode-se definir o nome da tabela na base de dados
através da anotação @Table , onde no campo name pode-se escolher o nome da tabela.
Convencionalmente, o nome é definido tudo em minúscula.

@Entity
@Table(name = "students")
class Student (
// fields
)

Também existe a anotação de colunas, onde contém várias formas de customizar a coluna,
como o seu nome, o comprimento da entrada, se for nulável ou não, ou se for único.

@Entity
@Table(name = "students")

https://github.com/PowerSolution-Academy/documentation/blob/main/backend/spring-boot/powersolution-academy-spring-boot-basics.adoc?fbclid=… 12/32
3/16/23, 10:21 PM documentation/powersolution-academy-spring-boot-basics.adoc at main · PowerSolution-Academy/documentation

class Student (

// ...

@Column(name="student_num", length=6, nullable=false, unique=true)


var code: Long = 0L,

// ...
)

O nome da coluna passa a ser student_num na tabela na base de dados. Ao definir


tamanho 6, não será aceite números com mais de 6 dígitos. Com nullable como false
a coluna tem de ter um valor obrigatoriamente. O campo unique como true , significa
que não pode haver nenhuma outra entrada na coluna com o valor igual a uma já
existente.

Mais detalhes podem ser encontrados em [5]

Repositórios
Cada repositório no Spring Data estende a interface do repositório genérico, mas além
disso, cada um deles tem uma funcionalidade diferente. Existem diferentes tipos de
interfaces de repositório Spring Data e suas funcionalidades, tais como:

CrudRepository

PagingAndSortingRepository

JpaRepository

Normalmente utiliza-se o JpaRepository porque contém a API completa de


CrudRepository e PagingAndSortingRepository , devido ao relacionamento de herança.

Considerando o exemplo da secção anterior, a entidade Student , para implementar o seu


repositório deve ser feito da seguinte forma:

@Repository
interface StudentRepository : JpaRepository<Student, String>

Ao definir a anotação @Repository o Spring Data Repository gerará automaticamente a


implementação com base no nome que fornecemos.

Para o tipo JpaRepository devemos indicar a entidade e também o tipo de Id. Neste
exemplo, a entidade é Student e o Id é do tipo String . [7]
https://github.com/PowerSolution-Academy/documentation/blob/main/backend/spring-boot/powersolution-academy-spring-boot-basics.adoc?fbclid=… 13/32
3/16/23, 10:21 PM documentation/powersolution-academy-spring-boot-basics.adoc at main · PowerSolution-Academy/documentation

Essa interface declara métodos úteis para trabalhar com especificações. Para usá-los,
precisamos que nosso repositório estenda
org.springframework.data.jpa.repository.JpaSpecificationExecutor<T> .

Por exemplo, agora podemos encontrar todas as instâncias de Student com o código de
estudante especificado:

@Repository
interface StudentRepository : JpaRepository<Student, String>, JpaSpecificationExecut

fun findStudentByCode (code: Long) : Optional<Student>

Na secção Serviços pode-se encontrar o uso do método.

Modelos de Entrada e Saída + Hypermedia (Spring HATEOAS)


Os modelos de saída são a representação dos dados quando o servidor retorna a resposta
para o cliente. Os assemblers são conversores que fazem a conversão dos dados que vem
da base de dados para os modelos de saída.

A baixo temos um exemplo para a entidade Student . Normalmente os campos de id não


são expostos nos modelos de saída. Também entidades com qual haja relações, são
definidos a partir de links de relação, que está detalhado na secção Assemblers.

class StudentOutputModel (

val code: Long,

val name: String,

val age: Int,

val course: Course,

val faculty: Faculty

) : RepresentationModel<StudentOutputModel>()

https://github.com/PowerSolution-Academy/documentation/blob/main/backend/spring-boot/powersolution-academy-spring-boot-basics.adoc?fbclid=… 14/32
3/16/23, 10:21 PM documentation/powersolution-academy-spring-boot-basics.adoc at main · PowerSolution-Academy/documentation

O modelo de saída pode ser definido por uma classe que estende a classe
RepresentationModel do HATEOAS que herda o método add() que serve para adicionar
links de relações da entidade com outras entidades ou com ele próprio.

Um exemplo de corpo JSON pode ser encontrado a baixo. Onde pode-se ver a estrutura
de resposta é retornado pelo servidor:

{
"code" : 123456,
"name" : "Joana Patricia Pereira",
"age" : 19,
"course" : "MEDICINE",
"faculty" : "BIO",
"_links" : {
"self" : {
"href" : "http://localhost:8080/students/5a7cc6d9-cc26-4db7-8365-aee937cd0173"
},
"university": {
"href" : "http://localhost:8080/universities/36127889-bf8e-472f-b88f-bda84b27e
}
}
}

No exemplo acima, temos um exemplo de um JSON retornado pelo servidor, onde pode-
se observar os campos com os dados e também links de relação com a própria entidade
representada por self , onde contém o link para realizar operações para aquela entidade
como GET , PUT , DELETE . Na secção Teste de API encontram-se mais informações destas
operações de forma detalhada. Também o link de relação com a entidade University
onde pode-se efetuar também operações para aquela entidade.

Modelos de Entrada
O modelo de entrada é um corpo JSON que serve para enviar dados para o servidor para
fazer operações de edição na base de dados. Normalmente é passado no corpo de uma
requisição POST ou PUT .

O modelo é definido por uma classe de dados com os campos necessários para o sucesso
da operação requisitada.

São utilizadas anotações de validação que realizam validações como de campo vazio
NotBlank, e de campo anulável NotNull que garantem que os dados necessários sejam
enviados para o sistema. Caso não tenha os dados é retornado uma resposta de erro de
validação.
https://github.com/PowerSolution-Academy/documentation/blob/main/backend/spring-boot/powersolution-academy-spring-boot-basics.adoc?fbclid=… 15/32
3/16/23, 10:21 PM documentation/powersolution-academy-spring-boot-basics.adoc at main · PowerSolution-Academy/documentation

A definição do modelo de entrada pode ser feita da seguinte forma:

class StudentInputModel (

@field:NotNull(message = "É obrigatório indicar o código de estudante")


@field:Positive
@field:Digits(integer = 6, fraction = 0)
val code: Long,

@field:NotBlank(message = "O nome não pode ser vazio")


val name: String,

@field:NotNull(message = "É obrigatório indicar a idade do estudante")


@field:Positive(message = "A idade deve ser indicada por um número natural")
@field:Digits(integer = 2, fraction = 0, message = "A idade não pode ultrapa
val age: Int,

@field:NotNull(message = "É obrigatório indicar o curso")


val course: Course,

@field:NotNull(message = "É obrigatório indicar a faculdade")


val faculty: Faculty,

@field:NotBlank(message = "É obrigatório indicar o id da universidade")


@field:Size(max = 36, min = 36)
val universityId: String

A anotação @field:NotNull indica que o campo deve ser obrigatório, @field:NotBlank


indica que o campo não pode ser vazio. É utilizado para campos do tipo String , também
este valida a nulabilidade do campo String .

A anotação @field:Digits normalmente é utilizado para indicar o limite máximo dos


digitos, tanto inteiros (integer) como decimais ou fracionários (fraction). Deve ser usado
para campos numéricos. Para campos String deve-se utilizar a anotação @field:Size
para limitar o comprimento máximo ou mínimo. Também nestas anotações pode-se
indicar mensagens personalizadas, através do campo message . Sabe dizer qual validação
é feita com a anotação @field:Positive ?

Pode encontrar mais detalhes em [8].

Assemblers

https://github.com/PowerSolution-Academy/documentation/blob/main/backend/spring-boot/powersolution-academy-spring-boot-basics.adoc?fbclid=… 16/32
3/16/23, 10:21 PM documentation/powersolution-academy-spring-boot-basics.adoc at main · PowerSolution-Academy/documentation

O assembler permite conversão da entidade para seu modelo de representação com a


extensão da classe RepresentationModelAssemblerSupport , através do método toModel() .

O assembler é anotado por @Component . E estende da classe


RepresentationModelAssemblerSupport onde se indica o modelo e o modelo de
representação. Continuando com o exemplo de Student o modelo seria Student e o seu
modelo de representação StudentOutputModel . No construtor, indica-se o controlador e
também o modelo de saída. Neste exemplo o controlador seria StudentController . Faz-
se um override da função toModel() onde indica-se o modelo e retorna-se o modelo de
saída.

Ainda utiliza-se o método apply() para que seja feitas outras operações dentro do
modelo. Neste caso através do método add() do RepresentationModel adiciona-se um
link de relação de entidades. Com o método linkTo() de WebMvcLinkBuilder
( org.springframework.hateoas.server.mvc.WebMvcLinkBuilder ) pode-se criar um link. Para
mapear para um dos métodos do controlador que normalmente é o GET , utiliza-se o
methodOn() também da WebMvcLinkBuilder onde é indicado o controlador, e pode-se
acessar o método getStudentById por exemplo que existe no controlador e indicar o id
acessando a partir do modelo ( entity.id ).

Ainda no método linkTo() pode-se indicar a relação com os métodos withRel() onde
indica-se um parâmetro String o nome da relação, mas em caso de relação com a
própria entidade pode-se utilizar o método withSelfRel() sem a necessidade de passar
parâmetro "self" .

@Component
class StudentAssembler : RepresentationModelAssemblerSupport<Student, StudentOutputM
StudentController::class.java, StudentOutputModel::class.java
) {

override fun toModel (entity: Student) : StudentOutputModel {

return StudentOutputModel (
code = entity.code,
name = entity.name,
age = entity.age,
course = entity.course,
faculty = entity.faculty,
).apply {

this.add(
WebMvcLinkBuilder.linkTo(
WebMvcLinkBuilder.methodOn(StudentController::class.java
.getOneStudentById(entity.id)
).withSelfRel()
https://github.com/PowerSolution-Academy/documentation/blob/main/backend/spring-boot/powersolution-academy-spring-boot-basics.adoc?fbclid=… 17/32
3/16/23, 10:21 PM documentation/powersolution-academy-spring-boot-basics.adoc at main · PowerSolution-Academy/documentation

if(entity.university != null)
this.add(
WebMvcLinkBuilder.linkTo(
WebMvcLinkBuilder.methodOn(UniversityController::cla
.getUniversityById(entity.university!!.id)
).withRel("university")
)

Serviços
Componentes de serviço são classes que contêm a anotação @Service . Esses classes são
usadas para escrever a lógica de negócios em uma camada diferente, separada do ficheiro
de classe @RestController .

A lógica para criar a classe de componente de serviço é mostrada a baixo:

@Service
class StudentService () {

Seguindo o exemplo ainda com o caso de Gestão de Estudantes, irá se criar métodos que
servirão para obter, guardar, atualizar e eliminar estudantes.

@Service
class StudentService () {

fun getStudents () {

fun getStudentById () {

https://github.com/PowerSolution-Academy/documentation/blob/main/backend/spring-boot/powersolution-academy-spring-boot-basics.adoc?fbclid=… 18/32
3/16/23, 10:21 PM documentation/powersolution-academy-spring-boot-basics.adoc at main · PowerSolution-Academy/documentation

fun createStudent () {

fun updateStudent () {

fun deleteStudent () {

Normalmente nos serviços são injetados os repositórios por onde se tem acesso aos
dados, para fazer isto no construtor da classe StudentService indica-se o repositório de
estudantes.

Também nota-se que o assembler é utilizado para converter o modelo guardado para o
modelo de representação. O assembler também deve-se ser injetado no serviço:

@Service
class StudentService (
var assembler : StudentAssembler,
var repository : StudentRepository,
) {

// methods
}

Para definir a lógica de obtenção dos estudantes, dentro do corpo da função


getStudents , define-se uma variável onde dados obtidos do repositório é armazenado.
Para obter dados de todos os estudantes presentes no repositório, utiliza-se o método
findAll() presente na interface do repositório e este retorna uma lista de estudantes
( List<Student> ). Posteriormente, deve-se converter cada elemento da lista para o seu
modelo de representação. Para isto utiliza-se o método map{} que irá realizar a operação
em cada elemento da lista identificado como it . Por fim retorna-se a lista do tipo
List<StudentOutputModel> :

fun getStudents () : List<StudentOutputModel> {

val students = repository.findAll()

val studentsOut = students.map { assembler.toModel(it) }

https://github.com/PowerSolution-Academy/documentation/blob/main/backend/spring-boot/powersolution-academy-spring-boot-basics.adoc?fbclid=… 19/32
3/16/23, 10:21 PM documentation/powersolution-academy-spring-boot-basics.adoc at main · PowerSolution-Academy/documentation

return studentsOut

Para definir a lógica de obtenção de um estudante através do id, dentro do construto da


função getStudentById , define-se uma variável onde dados obtidos do repositório é
armazenado. Para obter dados de um estudante presente no repositório através do seu id,
utiliza-se o método findById() presente na interface do repositório e este ao ser
indicado um id, retorna o estudante se este estiver presente. O método orElseThrow() é
utilizado para que se o estudante com aquele id não estiver presente no repositório, seja
lançado uma exceção do tipo EntityNotFoundException indicando que o estudante não
foi encontrado. Posteriormente faz-se a conversão para o modelo de representação
utilizando o método toModel() definido no assembler:

fun getStudentById (id: String) : StudentOutputModel {

val student = repository.findById(id)


.orElseThrow { EntityNotFoundException("O estudante identificado por $id

val studentOut = assembler.toModel(student)

return studentOut

Também pode-se buscar um estudante através de um outro campo que não seja id. Como
apresentado na secção de Repositórios com o JpaSpecificationExecutor pode-se definir
métodos que buscam a entidade através de campos específicos. Podemos definir no
serviço um método getStudentByCode onde ao passar o código de estudante, pode-se
obter aquele estudante. É feito da mesma forma que o id, com a diferença do uso do
método findStudentByCode para buscar o estudante.

fun getStudentByCode (code: Long) : StudentOutputModel {

val student = repository.findStudentByCode(code)


.orElseThrow { EntityNotFoundException("O estudante identificado por $id

val studentOut = assembler.toModel(student)

return studentOut

https://github.com/PowerSolution-Academy/documentation/blob/main/backend/spring-boot/powersolution-academy-spring-boot-basics.adoc?fbclid=… 20/32
3/16/23, 10:21 PM documentation/powersolution-academy-spring-boot-basics.adoc at main · PowerSolution-Academy/documentation

Para definir a lógica de criação do estudante, dentro do construtor da função


createStudent define-se o modelo de entrada da entidade de Student que é o
StudentInputModel , onde possui os dados introduzidos pelo utilizador. No corpo cria-se
um novo objeto do tipo Student e introduz-se os valores vindos no modelo de entrada
nos seus respetivos campos. De seguida através do método save() existente na interface
do repositório, passa-se este objeto para que seja guardado na base de dados uma
entrada com os dados do estudante. A baixo pode-se ver o código que faz o descrito
acima.

fun createStudent (inputModel : StudentInputModel) : StudentOutputModel {

val university = universityRepository.findById(inputModel.universityId)


.orElseThrow { EntityNotFoundException("A universidade identificada por

val student = Student(


code = inputModel.code,
name = inputModel.name,
age = inputModel.age,
course = inputModel.course,
faculty = inputModel.faculty,
university = university
)

val savedStudent = repository.save(student)

val studentOutput = assembler.toModel(savedStudent)

return studentOutput

Note que ao indicar a universidade foi utilizado o id que o identifica. Sendo assim deve-se
buscar a universidade através do seu id recorrendo ao repositório para a universidade,
para isto define-se também no construtor do serviço o universityRepository que irá ser
utilizado para acessar dados sobre as universidades. Após isto, a entidade do estudante
tem uma relação com a entidade da universidade.

@Service
class StudentService (
var assembler : StudentAssembler,
https://github.com/PowerSolution-Academy/documentation/blob/main/backend/spring-boot/powersolution-academy-spring-boot-basics.adoc?fbclid=… 21/32
3/16/23, 10:21 PM documentation/powersolution-academy-spring-boot-basics.adoc at main · PowerSolution-Academy/documentation

var repository : StudentRepository,


var universityRepository : UniversityRepository,
) {

// methods
}

Para definir a lógica de atualização do estudante, dentro do construtor da função


updateStudent define-se o modelo dos novos dados com o tipo StudentInputModel ou
então se caso haja dados que não podem ser alterados como por exemplo o nome e o
número de estudante, define-se um novo modelo StudentUpdateInputModel no mesmo
pacote de StudentInputModel , onde possui apenas dados que podem ser atualizados
pelo utilizador. As validações também devem ser feitas.

class StudentUpdateInputModel (

@field:NotNull(message = "É obrigatório indicar a idade do estudante")


@field:Positive(message = "A idade deve ser indicada por um número natural")
@field:Digits(integer = 2, fraction = 0, message = "A idade não pode ultrapa
val age: Int,

@field:NotNull(message = "É obrigatório indicar o curso")


val course: Course,

@field:NotNull(message = "É obrigatório indicar a faculdade")


val faculty: Faculty,

@field:NotBlank(message = "É obrigatório indicar o id da universidade")


@field:Size(max = 36, min = 36)
val universityId: String

Ainda no construtor deve-se indicar o id do Student que se quer atualizar.

No corpo, através do repositório busca-se o estudante pelo seu id, e de seguida guarda-se
numa variável. De seguida através do método apply , introduz-se os valores vindos no
modelo com os novos dados nos seus respetivos campos. Por fim utiliza-se o método
save() para guardar as alterações. A baixo pode-se ver o código que faz o descrito acima.

fun updateStudent (updateInputModel : StudentUpdateInputModel) : StudentOutputModel

val university = universityRepository.findById(updateInputModel.universityId)

https://github.com/PowerSolution-Academy/documentation/blob/main/backend/spring-boot/powersolution-academy-spring-boot-basics.adoc?fbclid=… 22/32
3/16/23, 10:21 PM documentation/powersolution-academy-spring-boot-basics.adoc at main · PowerSolution-Academy/documentation

.orElseThrow { EntityNotFoundException("A universidade identificada por

val student = repository.findById(id)


.orElseThrow { EntityNotFoundException("O estudante identificado por $id

student.apply {
age = updateInputModel.age
course = updateInputModel.course
faculty = updateInputModel.faculty
university = university
}

val updatedStudent = repository.save(student)

val studentOutput = assembler.toModel(updatedStudent)

return studentOutput

Para o caso de eliminação busca-se o estudante pelo seu id, e utiliza-se o método
delete() para eliminar o estudante da base de dados.

fun deleteStudent (id: String) : Boolean {

val student = repository.findById(id)


.orElseThrow { EntityNotFoundException("O estudante identificado por $id

repository.delete(student)

return true

Controladores
Os controladores servem para fazer a gestão das requisições HTTP feitas pelos clientes e
retornar uma resposta do servidor para os clientes definido por uma classe que é anotada
por @RestController . Os controladores são definidos pelo contexto do negócio, mas
também podem ser definidos de acordo com as entidades.

O endpoint para cada controlador é indicado pela anotação @RequestMapping , e a


anotação @CrossOrigin , dá permissão para requisição para qualquer cliente, ou seja,
qualquer host pode enviar requisições para o sistema.
https://github.com/PowerSolution-Academy/documentation/blob/main/backend/spring-boot/powersolution-academy-spring-boot-basics.adoc?fbclid=… 23/32
3/16/23, 10:21 PM documentation/powersolution-academy-spring-boot-basics.adoc at main · PowerSolution-Academy/documentation

Os métodos contêm anotações que indicam para qual método HTTP e para qual endpoint
deve ser feita a requisição para que seja invocada a função específica para aquela ação.
Por exemplo, para métodos GET ou DELETE , é utilizado a anotação @GetMapping ou
@DeleteMapping respetivamente. É indicado um endpoint caso haja um específico, em que
também pode ser passado parâmetros como um ID, que é indicado pela anotação
@PathVariable . Em casos onde os parâmetros são passados por query, é utilizado a
anotação @RequestParam para identificar a variável.

Para métodos POST e PUT são utilizadas anotações como @PostMapping e @PutMapping ,
onde no corpo é indicado uma anotação @RequestBody em que normalmente é precedido
por uma anotação @Valid para que seja validada os campos de entrada, como
mencionado na secção dos Modelos de Entrada.

No controlador são injetados serviços, que são invocados quando é enviado uma
requisição para o seu respetivo endpoint.

O controlador retorna como resposta para o cliente, lista de modelos de saída em caso de
vários dados ou um modelo de saída com a estrutura referida na secções Modelos de
Saída, ou a indicação de que o pedido foi recebido com sucesso, em casos onde não há
necessidade de retornar dados. Utiliza-se o ResponseEntity para retornar dados
juntamente com o status. Possue status como ok, badRequest, entre outros.

@RestController
@CrossOrigin
@RequestMapping("students")
class StudentController (
var service : StudentService
) {

@GetMapping
fun getAllStudents () : ResponseEntity<List<StudentOutputModel>> {

val studentsList = service.getStudents()

return ResponseEntity.ok(studentsList)

@GetMapping("/{id}")
fun getOneStudentById (@PathVariable id: String) : ResponseEntity<StudentOutputM

val student = service.getStudentById(id)

return ResponseEntity.ok(student)

https://github.com/PowerSolution-Academy/documentation/blob/main/backend/spring-boot/powersolution-academy-spring-boot-basics.adoc?fbclid=… 24/32
3/16/23, 10:21 PM documentation/powersolution-academy-spring-boot-basics.adoc at main · PowerSolution-Academy/documentation

@GetMapping("/one")
fun getOneStudentByCode (@RequestParam("code") code: Long? = null) : ResponseEnt

if(code != null) {

val student = service.getStudentByCode(code)

return ResponseEntity.ok(student)

return ResponseEntity.badRequest()

@PostMapping
fun createStudent (@RequestBody body: StudentInputModel) : ResponseEntity<Studen

val student = service.createStudent(body)

return ResponseEntity.ok(student)

@PutMapping("/{id}")
fun updateStudent (@PathVariable id: String, @RequestBody body: StudentUpdateInp
: ResponseEntity<StudentOutputModel> {

val student = service.updateStudent(id, body)

return ResponseEntity.ok(student)

@DeleteMapping("/{id}")
fun deleteStudent (@PathVariable id: String) : ResponseEntity<Boolean> {

val deleted = service.deleteStudent(id)

return ResponseEntity.ok(deleted)

https://github.com/PowerSolution-Academy/documentation/blob/main/backend/spring-boot/powersolution-academy-spring-boot-basics.adoc?fbclid=… 25/32
3/16/23, 10:21 PM documentation/powersolution-academy-spring-boot-basics.adoc at main · PowerSolution-Academy/documentation

Desafio: No controlador, crie um método HTTP para atualizar uma entidade através de
Por exemplo atualizar os dados do estudante através do seu código de estudante.

Teste de API
Vamos compilar e executar o programa. Clique no ícone 'Run' para iniciar a compilação e
de seguida a execução

Figure 3. Clique no botão com o símbolo de "play" para executar o programa


Com a ferramenta Postman, comece a enviar requisições para o endpoints que foram
definidos nos controladores, utilizando os diferentes métodos. Para aprender a utilizar o
Postman consulte [9]

Deve obter algo parecido a isto:

Figure 4. Obter todos os estudantes

https://github.com/PowerSolution-Academy/documentation/blob/main/backend/spring-boot/powersolution-academy-spring-boot-basics.adoc?fbclid=… 26/32
3/16/23, 10:21 PM documentation/powersolution-academy-spring-boot-basics.adoc at main · PowerSolution-Academy/documentation

Figure 5. Obter estudante pelo ID

https://github.com/PowerSolution-Academy/documentation/blob/main/backend/spring-boot/powersolution-academy-spring-boot-basics.adoc?fbclid=… 27/32
3/16/23, 10:21 PM documentation/powersolution-academy-spring-boot-basics.adoc at main · PowerSolution-Academy/documentation

Figure 6. Obter estudante pelo número de estudante

https://github.com/PowerSolution-Academy/documentation/blob/main/backend/spring-boot/powersolution-academy-spring-boot-basics.adoc?fbclid=… 28/32
3/16/23, 10:21 PM documentation/powersolution-academy-spring-boot-basics.adoc at main · PowerSolution-Academy/documentation

Figure 7. Criar um estudante

https://github.com/PowerSolution-Academy/documentation/blob/main/backend/spring-boot/powersolution-academy-spring-boot-basics.adoc?fbclid=… 29/32
3/16/23, 10:21 PM documentation/powersolution-academy-spring-boot-basics.adoc at main · PowerSolution-Academy/documentation

Figure 8. Atualizar um estudante

https://github.com/PowerSolution-Academy/documentation/blob/main/backend/spring-boot/powersolution-academy-spring-boot-basics.adoc?fbclid=… 30/32
3/16/23, 10:21 PM documentation/powersolution-academy-spring-boot-basics.adoc at main · PowerSolution-Academy/documentation

Figure 9. Eliminar um estudante

Glossary

A
AOP

Aspect oriented programming

C
Commons DBCP

Commons DataBase Connection Pools - Library of the Apache foundation offering pooling
implementations of the DataSource interface.

CRUD

Create, Read, Update, Delete - Basic persistence operations

D
DAO

Data Access Object - Pattern to separate persisting logic from the object to be persisted

Dependency Injection

Pattern to hand a component’s dependency to the component from outside, freeing the
component to lookup the dependant itself. For more information see
http://en.wikipedia.org/wiki/Dependency_Injection.

H
Hibernate

Object relational mapper implementing JPA - http://www.hibernate.org

J
JPA

Java Persistence Api

https://github.com/PowerSolution-Academy/documentation/blob/main/backend/spring-boot/powersolution-academy-spring-boot-basics.adoc?fbclid=… 31/32
3/16/23, 10:21 PM documentation/powersolution-academy-spring-boot-basics.adoc at main · PowerSolution-Academy/documentation

S
Spring

Java application framework - http://projects.spring.io/spring-framework

Referências
[1] Spring Framework - Spring.io

[2] Advantages of Spring Boot - ADSERVIO

[3] Spring Quickstart Guide - Spring.io

[4] Tutorial: Create your first Spring application - Intellij IDEA

[5] Defining JPA Entities - Baeldung

[6] Working with Relationships in Spring Data REST - Baeldung

[7] CrudRepository, JpaRepository, and PagingAndSortingRepository in Spring Data -


Baeldung

[8] Validating Form Input - Spring.io

[9] Postman Learning - Postman

Give feedback

https://github.com/PowerSolution-Academy/documentation/blob/main/backend/spring-boot/powersolution-academy-spring-boot-basics.adoc?fbclid=… 32/32

Você também pode gostar