06 Spring Boot
06 Spring Boot
Baseadas em Spring
Spring
Framework para construção de aplicações
Baseado no conceito de inversão de controle (Inversion of Control) e na Injeção de Dependência
(Dependency Injection)
Inversion of Control (IoC)
O fluxo é baseado nos objetos criados e não o contrário
Dependendecy Injection (DI)
Um objeto recebe os objetos que ele depende (dependências) assim o comportamento pode ser
“injetado” em outros objetos
Atualmente é o framework mais popular na linguagem Java
Composto por vários módulos divididos em projetos (https://spring.io/projects)
Spring Framework
Suporte básico para injeção de dependência, gestão de transações, web apps, acesso a dados e mensagens
Spring Boot
Permite a criação rápida de aplicações baseadas no Framework Spring
Spring Data
Acesso a dados em banco de dados relacionais e não relacionais
Spring Cloud, Spring Cloud Data Flow, Spring Security, Spring Session, etc.
https://docs.spring.io/spring-framework/docs/current/reference/html/
//setter Injection
void setWheel(Wheel wh) {
this.wh = wh;
}
}
Servidor Http
Spring
Framework
+ Embutido = Spring Boot
(Tomcat, Jetty)
@SpringBootApplication
public class HelloSpringBootApplication {
public static void main(String[] args) {
SpringApplication.run(HelloSpringBootApplication.class, args);
}
}
@SpringBootApplication
Anotação básica que indica o ponto de entrada de uma aplicação baseada no Spring
É uma combinação de três anotações
@Configuration – indica que trata-se de uma classe de configuração do Spring
@ComponentScan – permite que o controller busque pelos componentes no código o pacote
da aplicação (java package), facilitando a configuração
@EnableAutoConfiguration – permite a autoconfiguração e registro dos componentes
existentes
/BOOT-INF
/classes classes
No caso de aplicações baseadas no Spring MANIFEST.MF
https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/repository/CrudRepository.html
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class AccessingDataMysqlApplication {
@ExceptionHandler
@ExceptionHandler em uma
classe com anotação
@ControllerAdvice
Pode envolver a anotação
@ResponseSatus ou não
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(MethodArgumentNotValidException.class)
public Map<String, String> handleMethodArgumentNotValid(MethodArgumentNotValidException ex) {
Map<String, String> errors = new HashMap<>();
ex.getBindingResult().getFieldErrors().forEach(error ->
errors.put(error.getField(), error.getDefaultMessage()));
return errors;
}
O Código acima permite tratar exceções do tipo MethodArgumentNotValidException
A anotação ExceptionHandler indica o método que trata um determinado tipo de exceção
Um objeto do tipo BindingResult encapsula as mensagens de erro retornadas na exceção
O método pode ser utilizado para retornar no objeto HTTP as mensagens de erro em um
formato JSON
Controller
FrontEnd
Mobile App
{json} Model
// Service Logic
}
@PostMapping
public Employee saveEmployee(@Validated @RequestBody Employee employee) {
// Service Logic
}
@DeleteMapping("/{id}")
public ResponseEntity<String> deleteEmployeeById(@PathVariable(value = "id") long id) {
// Service Logic
}
} Programação para Internet 214
Prof. Flávio de Oliveira Silva, Ph.D.
REST API
Entidade (Employee)
package com.example.modernREST;
import ...
@Entity
class Employee {
private @Id @GeneratedValue Long id; private String name; private String role;
Employee() {}
Employee(String name, String role) {this.name = name; this.role = role;}
import org.springframework.data.jpa.repository.JpaRepository;
@Configuration
class EmployeeLoadDatabase {
@Bean
CommandLineRunner initDatabase(EmployeeRepository repository) {
{
"account": {
"account_number": 12345,
"balance": { Dados
"currency": "usd",
"value": 100.00
},
"links": {
"deposits": "/accounts/12345/deposits",
"withdrawals": "/accounts/12345/withdrawals",
"transfers": "/accounts/12345/transfers", Hypermedia
"close-requests": "/accounts/12345/close-requests"
}
}
}
Neste caso a resposta indica que a única operação possível é realizar o depósito,
indicando que a conta não possui mais saldo
A resposta muda conforme o estado da aplicação
HTTP/1.1 200 OK
{
"account": {
"account_number": 12345,
"balance": {
"currency": "usd",
"value": -25.00
},
"links": {
"deposits": "/accounts/12345/deposits"
}
}
}
@Component
class EmployeeModelAssembler implements RepresentationModelAssembler<Employee,
EntityModel<Employee>> {
@Override
public EntityModel<Employee> toModel(Employee employee) {
return EntityModel.of(employee, //
linkTo(methodOn(EmployeeController.class).one(employee.getId())).withSelfRel(),
linkTo(methodOn(EmployeeController.class).all()).withRel("employees"));
}
}
@RestController
@RequestMapping("/api2")
public class EmployeeController {
Programação para Internet 226
private final EmployeeRepository repository;
Prof. Flávio de Oliveira Silva, Ph.D.
REST API
Controller HATEOAS – Código Completo
@RestController
@RequestMapping("/api2")
public class EmployeeController {
private final EmployeeRepository repository;
private final EmployeeModelAssembler assembler;
@GetMapping("/employees")
CollectionModel<EntityModel<Employee>> all() {
List<EntityModel<Employee>>
employees = repository.findAll().stream().map(assembler::toModel).collect(Collectors.toList());
@PostMapping("/employees")
Programação para Internet 227
ResponseEntity<?> newEmployee(@RequestBody Employee
Prof. Flávio de Oliveira Silva, newEmployee) {
Ph.D.
REST API
Controller HATEOAS – Código Completo
@PostMapping("/employees")
ResponseEntity<?> newEmployee(@RequestBody Employee newEmployee) {
EntityModel<Employee> entityModel = assembler.toModel(repository.save(newEmployee));
return
ResponseEntity.created(entityModel.getRequiredLink(IanaLinkRelations.SELF).toUri()).body(entityModel);
}
@GetMapping("/employees/{id}")
EntityModel<Employee> one(@PathVariable Long id) {
Employee employee = repository.findById(id).orElseThrow(() -> new EmployeeNotFoundException(id));
return assembler.toModel(employee);
}
@PutMapping("/employees/{id}")
ResponseEntity<?> replaceEmployee(@RequestBody Employee newEmployee, @PathVariable Long id) {
Employee updatedEmployee = repository.findById(id).map(employee -> {
employee.setName(newEmployee.getName());
employee.setRole(newEmployee.getRole());
return repository.save(employee);
}).orElseGet(() -> {
newEmployee.setId(id);
Programação para Internet 228
return repository.save(newEmployee);
Prof. Flávio de Oliveira Silva, Ph.D.
REST API
Controller HATEOAS – Código Completo
@PutMapping("/employees/{id}")
ResponseEntity<?> replaceEmployee(@RequestBody Employee newEmployee, @PathVariable Long id) {
Employee updatedEmployee = repository.findById(id).map(employee -> {
employee.setName(newEmployee.getName());
employee.setRole(newEmployee.getRole());
return repository.save(employee);
}).orElseGet(() -> {
newEmployee.setId(id);
return repository.save(newEmployee);
});
EntityModel<Employee> entityModel = assembler.toModel(updatedEmployee);
return
ResponseEntity.created(entityModel.getRequiredLink(IanaLinkRelations.SELF).toUri()).body(entityModel);
}
@DeleteMapping("/employees/{id}")
ResponseEntity<?> deleteEmployee(@PathVariable Long id) {
repository.deleteById(id);
return ResponseEntity.noContent().build();
}
}
Programação para Internet 229
Prof. Flávio de Oliveira Silva, Ph.D.
Sessões em Aplicações Web
O protocolo HTTP é stateless, ou seja, não existe para o protocolo a
manutenção do estado da troca de mensagens
Um conceito comum em aplicações web é o conceito de Sessão de usuário
Na sessão do usuário o estado da aplicação é mantido ao longo do tempo e
informações são compartilhadas entre diferentes requisições
Como o protocolo HTTP não possui este suporte os servidores de aplicações
baseadas em HTTP possuem esta funcionalidade
Através de Sessão é possível por exemplo:
Manter um carrinho de compras em uma aplicação de e-commerce
Realizar o login de usuário em uma aplicação bancária: a sua agência bancária e conta
permanecem inalteradas durante a sessão
E muito outros exemplos...
A plataforma Java possui fornece um ambiente de execução para aplicações web
dinâmica
Este ambiente é chamado Web contêiner
Configurações adicionais:
spring.redis.password= #password
server.servlet.session.timeout= # Session timeout.
spring.session.redis.flush-mode=on-save # Sessions flush mode.
spring.session.redis.namespace=spring:session # Namespace for keys used to store sessions.