29
Trilha Java EE Emmanuel Neri CONSTRUINDO APIS DE FORMA PRODUTIVA COM SPRING BOOT, SPRING DATA E SPRING MVC

Construindo APIs de forma produtiva com Spring Boot, Spring Data e Spring MVC

Embed Size (px)

Citation preview

Page 1: Construindo APIs de forma produtiva com Spring Boot, Spring Data e Spring MVC

Trilha Java EE

Emmanuel Neri

CONSTRUINDO APIS DE FORMA PRODUTIVA COM SPRING BOOT, SPRING DATA E SPRING MVC

Page 2: Construindo APIs de forma produtiva com Spring Boot, Spring Data e Spring MVC

EMMANUEL NERI

‣ Mestre em Desenvolvimento de Tecnologia

‣ Desenvolvedor desde 2010

‣ Atualmente desenvolvedor back-end na Navita

)(

Page 3: Construindo APIs de forma produtiva com Spring Boot, Spring Data e Spring MVC

PROBLEMA

Quais os obstáculos da construção de APIs?

Ambiente Objeto <—> JSON Acessos aos dados

Page 4: Construindo APIs de forma produtiva com Spring Boot, Spring Data e Spring MVC

AGENDA

Spring Boot

Spring MVC Spring Data

Page 5: Construindo APIs de forma produtiva com Spring Boot, Spring Data e Spring MVC

SPRING BOOT

Spring Boot

AUTO CONFIGURAÇÃO

EMBEDDED SERVLET

CONTAINERS

GERENCIAMENTO DE DEPENDÊNCIAS

Page 6: Construindo APIs de forma produtiva com Spring Boot, Spring Data e Spring MVC

GERENCIAMENTO DE DEPENDÊNCIAS

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <version>1.5.3.RELEASE</version> </dependency>

<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>1.5.3.RELEASE</version> </plugin> </plugins> </build>

Page 7: Construindo APIs de forma produtiva com Spring Boot, Spring Data e Spring MVC

GERENCIAMENTO DE DEPENDÊNCIAS

Page 8: Construindo APIs de forma produtiva com Spring Boot, Spring Data e Spring MVC

AUTO CONFIGURAÇÃO

@SpringBootApplication public class AppConfig { public static void main(String[] args) { SpringApplication.run(AppConfig.class, args); } }

@EnableAutoConfiguration

@AutoConfigureTestDatabase

@AutoConfigureMockMvc

Page 9: Construindo APIs de forma produtiva com Spring Boot, Spring Data e Spring MVC

AUTO CONFIGURAÇÃO

========================= AUTO-CONFIGURATION REPORT =========================

Positive matches: ----------------- EmbeddedServletContainerAutoConfiguration matched: ... DataSourceConfiguration.Tomcat matched: ... Negative matches: ----------------- ActiveMQAutoConfiguration: Did not match:

RedisAutoConfiguration: Did not match:

mvn spring-boot:run -Ddebug

Page 10: Construindo APIs de forma produtiva com Spring Boot, Spring Data e Spring MVC

AUTO CONFIGURAÇÃO

/src/main/resources/application.properties

spring.profiles.active=dev

server.port=8090 server.context-path=/api

spring.http.encoding.charset=UTF-8

spring.datasource.url=jdbc:postgresql://localhost:5432/db spring.datasource.username=postgres spring.datasource.password=postgres spring.datasource.driver-class-name=org.postgresql.Driver

spring.jpa.show-sql=true

Page 11: Construindo APIs de forma produtiva com Spring Boot, Spring Data e Spring MVC

AUTO CONFIGURAÇÃOspring.profiles.active=

spring.mail.host=

spring.sendgrid.api-key=

flyway.enabled=true # Enable flyway

liquibase.enabled=true

spring.data.cassandra.cluster-name=

spring.data.elasticsearch.cluster-name=

spring.data.mongodb.database=test

spring.data.redis.repositories.enabled=true

spring.activemq.broker-url=

…. https://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html

Page 12: Construindo APIs de forma produtiva com Spring Boot, Spring Data e Spring MVC

EMBEDDED SERVLET CONTAINERS

mvn spring-boot:run

s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8080 (http)

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>

Page 13: Construindo APIs de forma produtiva com Spring Boot, Spring Data e Spring MVC

SPRING MVC

Spring MVC

FACILIDADE NA LEITURA DE

PARÂMETROS

ABSTRAÇÃO NA SERIALIZAÇÃO / DESERIALIZAÇÃO

SIMPLICIDADE NA EXPOSIÇÃO DE APIS

CONSTRUÇÃO SIMPLES

ESTRUTURA DE RETORNO

TRATAMENTO DE ERROS

Page 14: Construindo APIs de forma produtiva com Spring Boot, Spring Data e Spring MVC

SIMPLICIDADE NA EXPOSIÇÃO DE APIS

@RestController @RequestMapping("/customers") public class CustomerController {

@RequestMapping(method = RequestMethod.GET) public List<Customer> findAll() { return customerService.findAll(); } }

http://localhost:8080/customers

Page 15: Construindo APIs de forma produtiva com Spring Boot, Spring Data e Spring MVC

ABSTRAÇÃO NA SERIALIZAÇÃO / DESERIALIZAÇÃO

@RequestMapping(method = RequestMethod.GET) public List<Customer> findAll() {

return customerService.findAll(); }

@RequestMapping(method = RequestMethod.POST) public void save(@RequestBody BillDTO billDTO) { billService.save(billDTO); }

Page 16: Construindo APIs de forma produtiva com Spring Boot, Spring Data e Spring MVC

ABSTRAÇÃO NA SERIALIZAÇÃO / DESERIALIZAÇÃO

import com.fasterxml.jackson.annotation.JsonFormat;

public final class BillDTO { @JsonFormat(pattern = "yyyy-MM") private YearMonth yearMonth;

Page 17: Construindo APIs de forma produtiva com Spring Boot, Spring Data e Spring MVC

FACILIDADE NA LEITURA DE PARÂMETROS

@RequestMapping(value = "/byUk/{customerId}/{identifier}/{yearMonth}", method = RequestMethod.GET)

public Bill findByUk(@PathVariable("customerId") Long customerId, @PathVariable("identifier") String identifier, @PathVariable("yearMonth") YearMonth yearMonth) { return billService.findByUk(customerId, identifier, yearMonth); }

@RequestMapping(value = "/search", method = RequestMethod.GET) public List<Customer> search(

@RequestParam(value = "id", required = false) Long id, @RequestParam(value = "name", required = false) String name){

return customerService.search(new CustomerSearchTO(id, name)); }

Page 18: Construindo APIs de forma produtiva com Spring Boot, Spring Data e Spring MVC

CONSTRUÇÃO SIMPLES ESTRUTURA DE RETORNO

ResponseEntity.ok(bill);

ResponseEntity.badRequest().build();

@RequestMapping(method = RequestMethod.GET) public ResponseEntity ok() {

return ResponseEntity.ok().build(); }

200

400

200

{      "id":1,    "customer":{         "name":"Customer"    },    "carrier":{         "name":"TIM"    },    "identifier":"23326",    “yearMonth”:"2017/06"  }

ResponseEntity.status(UNAUTHORIZED).build(); 401

Page 19: Construindo APIs de forma produtiva com Spring Boot, Spring Data e Spring MVC

TRATAMENTO DE ERROS

@ControllerAdvice public class GlobalExceptionHandler {

@ExceptionHandler(BusinessException.class) public ResponseEntity<Set<ExceptionTO>> handleError(BusinessException ex) { return ResponseEntity.status(HttpStatus.BAD_REQUEST) .body(Collections.singleton(new ExceptionTO(ex.getMessage()))); }

@ExceptionHandler(ConstraintViolationException.class) public ResponseEntity<Set<ExceptionTO>> handleError(ConstraintViolationException ex) { final Set<ExceptionTO> erros = ex.getConstraintViolations().stream() .map(c -> new ExceptionTO(c.getMessage())) .collect(Collectors.toSet()); return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(erros); }

@ExceptionHandler(Exception.class) public ResponseEntity handleError(Exception ex) { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) .body("O sistema se encontra indisponível”); }

Page 20: Construindo APIs de forma produtiva com Spring Boot, Spring Data e Spring MVC

SPRING DATA

Spring Data

SUPORTE A DIFERENTE FONTES DE

DADOS

ABSTRAÇÃO NO ACESSO AOS

DADOS

IMPLEMENTAÇÕES PADRÕES

CACHE

Page 21: Construindo APIs de forma produtiva com Spring Boot, Spring Data e Spring MVC

IMPLEMENTAÇÕES PADRÕES

public interface BillRepository extends JpaRepository<Bill, Long> {

‣ findAll()

‣ save(T object)

‣ save(Iterable<T> objects)

‣ flush()

‣ getOne(ID id)

‣ delete(ID id)

‣ deleteInBatch(Iterable<T> objects)

Page 22: Construindo APIs de forma produtiva com Spring Boot, Spring Data e Spring MVC

ABSTRAÇÃO NO ACESSO AOS DADOS

public Customer save(Customer customer) { return customerRepository.save(customer); }

public List<Customer> findAll() { return customerRepository.findAll(); }

public Page<Customer> findPaginable(int page, int size) { final Sort sort = new Sort(Sort.Direction.DESC, "name"); return customerRepository.findAll(

new PageRequest(page, size, sort)); }

Page 23: Construindo APIs de forma produtiva com Spring Boot, Spring Data e Spring MVC

ABSTRAÇÃO NO ACESSO AOS DADOS

Bill findByCustomerIdAndIdentifierAndYearMonth(Long customerId, String identifier, YearMonth yearMonth);

@Modifying @Query("delete from BillItem where bill.id = :#{#billId}") void deleteByBillItem(@Param("billId") Long billId);

Hibernate: select bill… from bill bill0_ where bill0_.customer_id=? and bill0_.identifier=? and bill0_.year_month=?

Hibernate: delete from bill where id=?

Page 24: Construindo APIs de forma produtiva com Spring Boot, Spring Data e Spring MVC

ABSTRAÇÃO NO ACESSO AOS DADOS

‣ Integração com QueryDSL

public interface BillRepository extends JpaRepository<Bill, Long>, QueryDslPredicateExecutor<Bill> {

public Page<Bill> search(BillSearchTO searchTO) { return billRepository.findAll(searchTO.toPredicate(), new PageRequest(searchTO.getPage(), searchTO.getSize(),

new Sort(Sort.Direction.DESC, "id"))); }

public class BillSearchTO {

public BooleanBuilder toPredicate() { final QBill qBill = QBill.bill; final BooleanBuilder predicate = new BooleanBuilder();

if(!Strings.isNullOrEmpty(identifier)) { predicate.and(qBill.identifier.eq(identifier)); }

if(initYearMonth != null) { predicate.and(qBill.yearMonth.goe(initYearMonth)); } ....

Page 25: Construindo APIs de forma produtiva com Spring Boot, Spring Data e Spring MVC

ACESSO AOS DADOS

‣ Repositorios customizadospublic interface BillRepositoryCustom {

Page<BillDTO> findAll(BillSearchTO searchTO); }

public interface BillRepository extends JpaRepository<Bill, Long>, QueryDslPredicateExecutor<Bill>, BillRepositoryCustom { ...

public class BillRepositoryImpl implements BillRepositoryCustom {

@PersistenceContext private EntityManager entityManager;

@Override public Page<BillDTO> findAll(BillSearchTO searchTO) { final JPQLQuery jpaQuery = new JPAQuery(entityManager) .from(qBill) .join(qBill.carrier).fetchJoin() .join(qBill.customer).fetchJoin() .join(qBill.items).fetchJoin(); ...

Page 26: Construindo APIs de forma produtiva com Spring Boot, Spring Data e Spring MVC

SUPORTE A DIFERENTE FONTES DE DADOS

‣ Módulos da Spring

‣ Módulos da comunidade

JPA LDAP

REST

Page 27: Construindo APIs de forma produtiva com Spring Boot, Spring Data e Spring MVC

SUPORTE A DIFERENTE FONTES DE DADOS

public interface BillFileRepository extends MongoRepository<BillFile, String> { }

import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.mapping.Document;

@Document(collection = "bill_file") @Getter public class BillFile {

@Id private String id; private String date; private String content

Page 28: Construindo APIs de forma produtiva com Spring Boot, Spring Data e Spring MVC

CACHE

@SpringBootApplication @EnableCaching public class AppConfig {

@Cacheable("carriers") public List<Carrier> findAll() { return carrierRepository.findAll(); }

‣ JSR-107

‣ Caffeine

‣ Guava cache

‣ EhCache

‣ GemFire

Page 29: Construindo APIs de forma produtiva com Spring Boot, Spring Data e Spring MVC

FIM …

OBRIGADO! https://github.com/emmanuelneri/productivity-with-spring

[email protected]

https://github.com/emmanuelneri

@emmanuelnerii

www.emmanuelneri.com.br