Spring Boot Um Exemplo Completo - IMasters

Fazer download em pdf ou txt
Fazer download em pdf ou txt
Você está na página 1de 7

Fórum iMasters (h ps://forum.imasters.com.

br/)
we are developers
Certificações (h p://certificacao.imasters.com.br)

POWERED
(/)
BY:
(HTTP://DEVELOPERS.TOTVS.COM/) (h ps://www.facebook.com/PortaliMasters) (h ps://twi er.c

Back-End(https://imasters.com.br/back-end)
Mobile(https://imasters.com.br/mobile)
Front End(https://imasters.com.br/front-end)
DevSecOps(https://imasters.com.br/devsecops)
Design & UX(https://imasters.com.br/design-ux)
Data(https://imasters.com.br/data)
APIs e Microsserviços(https://imasters.com.br/apis-microsservicos)
IoT e Makers(https://imasters.com.br/iot-makers)

DESENVOLVIMENTO

1 AGO, 2017

Spring Boot um exemplo completo


100 visualizações
(h ps://www.facebook.com/sharer? (h ps://twi er.com/share? (h ps://www.linkedin.com/shareArticle?
u=h ps://imasters.com.br/desenvolvimento/spring- url=h ps://imasters.com.br/desenvolvimento/spring- url=h ps://imasters.com.br/desenvolvimento/spring-boot- COMPARTILHE!
boot-um-exemplo-completo) boot-um-exemplo-completo) um-exemplo-completo)

FELIPE ADORNO
(HTTPS://IMASTERS.COM.BR/PERFIL/FELIPEADORNO)
Tem 7 artigos publicados com 12692
visualizações desde 2017

PUBLICIDADE

FELIPE ADORNO (HTTPS://IMASTERS.COM.BR/PERFIL/FELIPEADORNO)

É engenheiro de so ware na Monkey Exchange, onde trabalha fortemente com Spring Cloud e possui mais de 10 anos de experiência no mundo da
tecnologia. É ativo na comunidade Java, onde sempre tem dado palestras e participado de debates sobre os mais variados assuntos. Além disso tem
contribuído em alguns frameworks como Apache Commons, FF4J, Netflix Ribbon e outros.

LEIA MAIS (HTTPS://IMASTERS.COM.BR/PERFIL/FELIPEADORNO)

22 AGO, 2017
Spring cloud contract – Trabalhando com microsserviços (h ps://imasters.com.br/apis-microsservicos/spring-cloud-contract-trabalhando-com-
microsservicos)

18 AGO, 2017
7Masters Spring – Spring Cloud Contract (h ps://imasters.com.br/desenvolvimento/7masters-spring-spring-cloud-contract)

25 JUL, 2017
Hystrix circuit breaker (h ps://imasters.com.br/desenvolvimento/hystrix-circuit-breaker)

O lá, hoje quero abordar um assunto que acho que vai tirar as dúvidas de muitas pessoas, pois sempre que criamos um projeto
surgem algumas perguntas:
Como vou criar o projeto?
Como vou organizar os pacotes?
Onde ficam as regras de negócio?
E, se for uma API RestFul, a coisa fica ainda pior e outras perguntas surgem:

Como faço o versionamento da API?


Vou devolver a minha entidade toda na API?
Onde eu coloco os links dos meus resource?
O que eu quero é criar um projeto e sanar todas essas dúvidas que assolam os desenvolvedores e também já me tiraram noites de
sono. A idéia aqui é realmente se preocupar com todas as regras de qualidade e separação do código e usar frameworks que nos
ajudem a fazer isso, então vamos lá!

Como vou criar o meu projeto?


Bom, essa é uma dúvida muito comum, eu hoje sempre acredito que você ganhará mais velocidade e produtividade se usar o
spring-boot, não estou nem falando sobre usar toda a stack do spring-cloud, que não é o foco aqui, mas criar um projeto spring-
boot com spring-data e pronto. Desta forma, você irá reduzir drasticamente a quantidade de código que terá que escrever. Então
crie um projeto utilizando o https://start.spring.io/ (https://start.spring.io/) como na imagem abaixo:

(https://static.imasters.com.br/wp-content/uploads/2017/08/01-
SpringBoot.jpg)
h ps://start.spring.io/

As dependências utilizadas são: Web, JPA, H2 (Para eu não configurar um banco de dados), Hateoas e Lombok. Pra quem não
conhece o Lombok, ele possui algumas anotações que evitam que tenhamos que escrever getters, setter, construtores, equals,
hashcode, builders e etc.

Como vou organizar os pacotes?

Agora que o projeto já está criado, é hora de começar a organizar as coisas. Já vi pessoas que gostam de dividir o projeto em
módulos, e isso normalmente deixa o projeto com o módulo de domain (ORM e acesso a dados), core (Classes de negócio) e um
módulo onde ficam os serviços web. A primeira vista isso parece legal, mas acaba onerando muito tendo que criar um pom pai e
orquestrar todas as dependências do maven e todos os plugins e etc.

Prefiro fazer apenas um projeto e separar tudo isso em pacotes, assim o meu projeto fica como exibido na imagem abaixo:

(https://static.imasters.com.br/wp-content/uploads/2017/08/02-SpringBoot.jpg)

E os pacotes ficaram assim:

 API: Todos os serviços RestFul, resources e assemblers.

 Configuration: Todas as classes de configuração do spring, caso sejam necessárias.


 Domain: Todo o acesso a dados fica aqui, ORM’s, repositories e specifications.

 Service: Todos os serviços onde estão as regras de negócio, validações e o que mais for preciso.

A classe de start do spring eu deixo fora de qualquer pacote, porque ela sempre é usada e não é legal ter que ficar procurado por
ela o tempo todo.

Onde ficam as regras de negócio?

As regras de negócio são o core do business e elas devem ser fáceis de alterar, fáceis de encontrar e fáceis de entender. Vejo
pessoas que divagam na abstração e fazem coisas que nem mesmo elas, depois de dois dias, são capazes de entender, então faça
um código que resolva o problema, e, caso ele precise ser mais abstrato ou mais extensível, aí então você se preocupa com isso.
Lembre-se que entregar funcionalidade ao usuário é o que mais importa, você é um desenvolvedor e quer que as pessoas usem
coisas que você criou.

Os serviços são @Service para o Spring e devem ter uma interface. Eu normalmente coloco o nome da interface como BookService
e o nome da implementação como BookServiceProvider. O serviço deve receber dados da api, passar pelas suas regras e armazenar
ou consultar na base de dados.

Os serviços acessam os repositories, ORM’s e Specifications que estão no pacote domain, então vamos criar uma ORM e um
repository, para isso crie um pacote orm e um pacote repository dentro do pacote domain e então crie as classes abaixo:

Book orm:

1 package br.com.sample.domain.orm;

2
3 import lombok.Builder;

4 import lombok.Getter;
5 import lombok.NoArgsConstructor;

6
7 import javax.persistence.GeneratedValue;

8 import javax.persistence.Id;
9
10 @Entity
11 @Getter

12 @Builder
13 @NoArgsConstructor

14 @AllArgsConstructor
15 public class Book {

16
17 @Id
18 @GeneratedValue
19 private Integer id;

20 private String title;


21 private String author;
22 private Integer pages;
23 }

Book Repository:

1 package br.com.sample.domain.repository;
2
3 import br.com.sample.domain.orm.Book;
4 import org.springframework.data.repository.CrudRepository;
5 import org.springframework.stereotype.Repository;
6
7 @Repository

8 public interface BookRepository extends CrudRepository<Book, Integer> {}

Perfeito, feito isso é hora de criar a interface e a implementação do serviço e elas devem ficar como o exemplo abaixo:

A interface:
1 package br.com.sample.service;

2
3 import br.com.sample.domain.orm.Book;
4
5 public interface BookService {
6
7 Book getById(Integer id);
8 Book save(Book book);
9 }

A implementação:

1 package br.com.sample.service;
2
3 import br.com.sample.domain.orm.Book;
4 import br.com.sample.domain.repository.BookRepository;
5 import lombok.AllArgsConstructor;
6 import org.springframework.stereotype.Service;

7
8 import static java.util.Objects.isNull;

9
10 @Service

11 @AllArgsConstructor
12 public class BookServiceImpl implements BookService {

13
14 private final BookRepository bookRepository;

15
16 @Override

17 public Book getById(Integer id) {


18 Book book = bookRepository.findOne(id);

19 if(isNull(book)) {
20 throw new RuntimeException("Book not found!");
21 }
22 return book;
23 }
24
25 @Override
26 public Book save(Book book) {
27 //QUALQUER REGRA DE NEGÓCIO OU VALIDAÇÃO ANTES DE SALVAR
28 return bookRepository.save(book);
29 }
30 }

Lembre-se todas as regras de negócio devem ficar no serviço e devem ser legíveis, bem escritas e bem testadas.

Como faço o versionamento da API?

Eu particularmente prefiro fazer o versionamento via URL, fica claro e fácil de saber qual a versão do resource você está acessando
então as urls ficam v1/books, v2/books e etc. E no projeto isso fica versionado em um pacote, então crie um pacote v1 dentro do
seu pacote api e pronto sua API já tem versionamento. Feito isso é hora de criar o endpoint RestFul, para isso crie uma classe
dentro do pacote api.v1 chamada BookResource e ela quem vai ser o retorno da API, justamente para não devolvermos a ORM, a
classe deve ficar como a do exemplo abaixo:
1 package br.com.sample.api.v1;
2 import lombok.Data;
3 import lombok.EqualsAndHashCode;
4 import org.springframework.hateoas.ResourceSupport;
5 import org.springframework.hateoas.core.Relation;
6 @Data
7 @EqualsAndHashCode(callSuper = true)
8 @Relation(value="book", collectionRelation="books")
9 class BookResource extends ResourceSupport {
10 private String title;
11 private String author;
12 private Integer pages;
13 }

Pode parecer estranho criar uma classe igual a ORM para ser devolvida via API, é estranho sim nesse nosso caso, mas e se você
colocar mais informações na ORM e não quer que elas sejam expostas como você vai fazer? Dessa maneira o seu problema já foi
solucionado antes de acontecer.

Criado o resource é hora de criar o endpoint serviço rest que vai receber as chamadas, para isso criar uma class chamada
BooRestService como a do exemplo abaixo:

1 package br.com.sample.api.v1;

2
3 import br.com.sample.service.BookService;

4 import lombok.AllArgsConstructor;
5 import org.springframework.http.HttpStatus;

6 import org.springframework.web.bind.annotation.*;
7 import sun.reflect.generics.reflectiveObjects.NotImplementedException;

8
9 @RestController

10 @AllArgsConstructor
11 @RequestMapping("v1/books")

12 public class BookRestService {


13
14 private final BookService bookService;
15
16 @ResponseStatus(HttpStatus.OK)
17 @RequestMapping(value = "/{id}", method = RequestMethod.GET)

18 public BookResource getById(@PathVariable Integer id) {


19 throw new NotImplementedException();
20 }
21
22 @ResponseStatus(HttpStatus.CREATED)
23 @RequestMapping(method = RequestMethod.POST)
24 public BookResource save(@RequestBody BookResource bookResource) {
25 throw new NotImplementedException();

26 }
27
28 }

Bom, você deve ter notado que a classe ainda não tem implementação dos métodos e isso acontece porque eu preciso criar o
assembler que ira resolver os próximos dois problemas que são “Onde eu coloco os links dos meus resource?” e “Vou devolver a
minha entidade toda na API?”.

O AssemblerResource é onde são adicionados os links e a conversão de Domain -> Resource e Resource -> Domain é realizada. O
resource deve ser como o exemplo abaixo:
1 package br.com.sample.api.v1;
2
3 import br.com.sample.domain.orm.Book;
4 import org.springframework.hateoas.Link;
5 import org.springframework.hateoas.mvc.ResourceAssemblerSupport;
6 import org.springframework.stereotype.Component;
7
8 @Component
9 public class BookResourceAssembler extends ResourceAssemblerSupport<Book, BookResource> {
10
11 public BookResourceAssembler() {
12 super(BookRestService.class, BookResource.class);
13 }
14
15 @Override
16 public BookResource toResource(Book book) {
17 BookResource bookResource = createResourceWithId(book.getId(), book);
18 bookResource.setAuthor(book.getAuthor());
19 bookResource.setPages(book.getPages());
20 bookResource.setTitle(book.getTitle());
21 addLinks(bookResource);
22 return bookResource;
23 }
24
25 public Book toDomain(BookResource bookResource) {
26 return Book.builder()
27 .author(bookResource.getAuthor())
28 .pages(bookResource.getPages())
29 .title(bookResource.getTitle())
30 .build();
31 }
32
33 private void addLinks(BookResource bookResource) {
34 //Links de exemplo você pode usar o linkTo(methodOn())
35 bookResource.add(new Link("http://localhost:8080/v1/foo", "foo"));
36 bookResource.add(new Link("http://localhost:8080/v1/bar", "bar"));
37 }
38 }

O assembler cria automaticamente o link self poupando o seu trabalho. Agora é possível terminar a implementação do rest service
e deve ficar como o exemplo:
1 package br.com.sample.api.v1;

2
3 import br.com.sample.service.BookService;
4 import lombok.AllArgsConstructor;
5 import org.springframework.http.HttpStatus;
6 import org.springframework.web.bind.annotation.*;
7
8 @RestController
9 @AllArgsConstructor
10 @RequestMapping("v1/books")
11 public class BookRestService {
12
13 private final BookService bookService;
14 private final BookResourceAssembler bookResourceAssembler;
15
16 @ResponseStatus(HttpStatus.OK)
17 @RequestMapping(value = "/{id}", method = RequestMethod.GET)
18 public BookResource getById(@PathVariable Integer id) {
19 return bookResourceAssembler.toResource(bookService.getById(id));
20 }
21
22 @ResponseStatus(HttpStatus.CREATED)
23 @RequestMapping(method = RequestMethod.POST)
24 public BookResource save(@RequestBody BookResource bookResource) {
25 return bookResourceAssembler.toResource(bookService.save(bookResourceAssembler.toDomain(bookResource)));
26 }
27
28 }

Pronto, agora temos um projeto bem organizado e de fácil manutenção. Para ver o projeto que foi criado é só acessar o link
(https://github.com/FelipeAdorno/spring-boot-sample).

Comentem as dúvidas, espero que tenham gostado e até a próxima.

De 0 a 10, o quanto você recomendaria este artigo para um amigo?

0 1 2 3 4 5 6 7 8 9 10

ARTIGOS PUBLICADOS POR ESTE AUTOR

FELIPE ADORNO (HTTPS://IMASTERS.COM.BR/PERFIL/FELIPEADORNO)


22 AGO, 2017

Spring cloud contract – Trabalhando com microsserviços (h ps://imasters.com.br/apis-microsservicos/spring-cloud-contract-trabalhando-com-


microsservicos)

FELIPE ADORNO (HTTPS://IMASTERS.COM.BR/PERFIL/FELIPEADORNO)


18 AGO, 2017

7Masters Spring – Spring Cloud Contract (h ps://imasters.com.br/desenvolvimento/7masters-spring-spring-cloud-contract)

FELIPE ADORNO (HTTPS://IMASTERS.COM.BR/PERFIL/FELIPEADORNO)


25 JUL, 2017

Hystrix circuit breaker (h ps://imasters.com.br/desenvolvimento/hystrix-circuit-breaker)

FELIPE ADORNO (HTTPS://IMASTERS.COM.BR/PERFIL/FELIPEADORNO)


19 JUL, 2017

Consumindo serviços de forma fácil com Spring-Cloud-Feign (h ps://imasters.com.br/apis-microsservicos/consumindo-servicos-de-forma-facil-com-


spring-cloud-feign)

FELIPE ADORNO (HTTPS://IMASTERS.COM.BR/PERFIL/FELIPEADORNO)


11 JUL, 2017

Buscando por todos os campos com reflexão (h ps://imasters.com.br/apis-microsservicos/buscando-por-todos-os-campos-com-reflexao)

Você também pode gostar