Workshop Microservices
Construindo APIs RESTful com
Spring Boot
Objetivos
• Ao final desta unidade você irá:
• Implementar a primeira aplicação utilizando Spring Boot
• Compreender as funcionalidades adicionais do Spring Boot
• Compreender como implementar serviços REST utilizando
Spring MVC
• Implementar persistência de dados utilizando Spring Data
• Expor os repositórios como serviços utilizando Spring Data
REST
• Implementar segurança utilizando Spring Security
• Explorar os demais projetos do ecossistema Spring
Agenda
• Spring Boot
• Spring MVC
• Spring REST
• Spring Data
• Spring Data REST
• Spring Security
• Demais projetos
• Batch, Cache, Messaging, Integration, WebSockets, …
Spring Ecosystem
Spring Boot
• Micro-framework para criação aplicações standalone
• Boot com embedded Java container
• Indicado para criação de micro-serviços
• Fornece várias funcionalidades por padrão
• Utiliza o conceito de configuração por “defaults”
• Ótima integração com toda plataforma Spring
• Spring MVC, Spring Data, Spring Security, …
• Suporta empacotamento JAR ou WAR
Spring Boot
• O que NÃO é:
• Plugins para IDE
• Você pode utilizar Spring Boot com qualquer IDE
• Ferramenta para geração de código
• Um novo container Java EE
• Arquitetura “ready” para Microservices
Spring Boot
Spring Boot (configuração inicial)
<project>
<!-- Inherit defaults from Spring Boot -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.3.RELEASE</version>
</parent>
<!-- Add typical dependencies for a web application -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<!-- Package as an executable jar -->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Spring Boot
• Como rodar a aplicação?
• IDE (Spring Tool Suite)
• Import… -> Existing Maven Projects
• Relaunch / Run
• Maven plugin
• mvn spring-boot:run
• export MAVEN_OPTS=-Xmx1024m -XX:MaxPermSize=128M
• Standalone “fat JAR”
• java -jar target/myproject-0.0.1-SNAPSHOT.jar
• java -Xdebug -
Xrunjdwp:server=y,transport=dt_socket,address=8000,suspend=n
-jar target/myproject-0.0.1-SNAPSHOT.jar
Spring Boot (deployment)
• Pode ser realizado via standalone “fat JAR”, ou por meio de
um WAR web package
• Suporta deployment em Java EE containers
• Tomcat, Jetty, Wildfly, TomEE, Glassfish, Weblogic
• Permite a configuração de “executable JARs”
• Podem ser configurados como serviços UNIX / Linux /
Windows
• UNIX/Linux services via init.d ou systemd
• Windows services via winsw
• Compatível com diferentes PaaS Cloud providers
• Cloud Foundry, Heroku, OpenShift, AWS, Boxfuse, Google App
Engine
Spring Boot (deployment)
• Configuração para deployment via WAR em um container
@SpringBootApplication
public class Application extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
} <project>
<!-- ... -->
<packaging>war</packaging>
<!-- ... -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<!-- ... -->
</dependencies>
</project>
Spring Boot (deployment)
• Configurando JAR executável no ambiente UNIX
• Fedora / CentOS
• sudo ln -s /var/myapp/myapp.jar /etc/init.d/myapp
• service myapp start
• Debian
• update-rc.d myapp defaults <priority>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<executable>true</executable>
</configuration>
</plugin>
Spring Boot (containers)
Container Servlet Version Java Version
Tomcat 8 3.1 Java 7+
Tomcat 7 3.0 Java 6+
Jetty 9.3 3.1 Java 8+
Jetty 9.2 3.1 Java 7+
Jetty 8 3.0 Java 6+
Undertow 1.3 3.1 Java 7+
Spring Boot (containers)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
<!-- OR -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
Laboratório 1 (boot-lab01)
• Criando uma primeira aplicação com Spring Boot
Spring Boot (starters)
• spring-boot-starter-web
• spring-boot-starter-data-jpa
• spring-boot-starter-data-rest
• spring-boot-starter-jdbc
• spring-boot-starter-websocket
• spring-boot-starter-cache
• spring-boot-starter-batch
• spring-boot-starter-hateoas
• spring-boot-starter-test
• spring-boot-starter-integration
• spring-boot-starter-validation
• spring-boot-starter-mobile…
Spring Boot (auto-configuration)
• AopAutoConfiguration
• JpaRepositoriesAutoConfiguration
• HibernateJpaAutoConfiguration
• DataSourceAutoConfiguration
• JmsTemplateAutoConfiguration
• MongoAutoConfiguration
• RedisAutoConfiguration
• WebMvcAutoConfiguration
• SecurityAutoConfiguration
• …
Spring Boot (configuration)
• Permite que você externalize as configurações da aplicação em arquivos
properties, YAML, variáveis de ambiente, argumentos de linha de comando
• Oferece uma lista bastante extensa de possíveis configurações
• https://docs.spring.io/spring-boot/docs/current/reference/html/common-application-
properties.html
• Propriedades podem ser injetadas utilizando @Value ou acessadas via
Spring Environment
• Pode ser configurado também via @ConfigurationProperties
• Podem ser ativadas e alternadas utilizando profiles de aplicação
• application-{profile}.properties
• Suporta o uso de expressões e oferece recursos como
• Valores randômicos: ${random.long}
• Referências internas: ${anotherproperty.value}
• Variáveis de ambiente: ${VARIABLE}
Spring Boot (configuration)
• YAML file
• Properties file
spring:
application:
name: cruncher
datasource:
driverClassName: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost/test
server:
port: 9000
my:
servers:
- dev.bar.com
- foo.bar.com
spring.application.name=cruncher
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost/test
server.port=9000
my.servers[0]=dev.bar.com
my.servers[1]=foo.bar.com
Spring Boot (configuration)
email=test@email.com
thread-pool=12
@Component
public class GlobalProperties {
@Value("${thread-pool}")
private int threadPool;
@Value("${email}")
private String email;
@Autowired
private Environment env;
public String getEmail() {
return env.getProperty("email");
}
public int getThreadPool() {
return env.getProperty("thread-pool");
}
//getters and setters
}
• Exemplo utilizando @Value e Spring Environment
application.properties
Spring Boot (configuration)
@ConfigurationProperties(
locations = "classpath:mail.properties",
prefix = "mail")
public class MailProperties {
public static class Smtp {
private boolean auth;
private boolean starttlsEnable;
// ... getters and setters
}
@NotBlank
private String host;
private int port;
private String from;
private String username;
private String password;
@NotNull
private Smtp smtp;
// ... getters and setters
}
mail.host=localhost
mail.port=25
mail.smtp.auth=false
mail.smtp.starttls-enable=false
mail.from=me@localhost
mail.username=
mail.password=
• Exemplo utilizando @ConfigurationProperties
mail.properties
Spring Boot (profiles)
• Fornece uma maneira de segmentar a configuração da
aplicação por diferentes ambientes de execução
• Qualquer @Component, @Configuration por ser anotado
com @Profile
• Para sinalizar um profile, basta utilizar:
• Propriedade: spring.profiles.active=dev
• CLI: --spring.profiles.active=dev
• JVM: -Dspring.profiles.active=dev
• Java: SpringApplication.setAdditionalProfiles(…)
• Podem ser sobrescritos e/ou combinados utilizando uma regra
de maior prioridade
• spring.profiles.active=default,dev
Spring Boot (profiles)
@Configuration
@Profile("production")
public class ProductionConfiguration {
// ...
}
server:
port: 9000
---
spring:
profiles: development
server:
port: 9001
---
spring:
profiles: production
server:
port: 0
@Configuration
@Profile(“!production")
public class NonProductionConfiguration {
// ...
}
• Exemplo de utilização @Profile
application.yml
Spring Boot (logging)
• Implementação interna via Commons Logging
• Por padrão utiliza Logback, mas suporta outros providers,
como Java Util Logging e Log4J
• Pode habilitar o level por execução
• java -jar myapp.jar --debug
• Formato padrão do log utilizado
• Date and Time, Log Level, Process ID, Thread Name, Logger Name, Log Message
2014-03-05 10:57:51.112 INFO 45469 --- [ main]
org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/7.0.52
2014-03-05 10:57:51.253 INFO 45469 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].
[localhost].[/] : Initializing Spring embedded WebApplicationContext
2014-03-05 10:57:51.253 INFO 45469 --- [ost-startStop-1] o.s.web.context.ContextLoader
: Root WebApplicationContext: initialization completed in 1358 ms
2014-03-05 10:57:51.698 INFO 45469 --- [ost-startStop-1]
o.s.b.c.e.ServletRegistrationBean : Mapping servlet: 'dispatcherServlet' to [/]
2014-03-05 10:57:51.702 INFO 45469 --- [ost-startStop-1]
o.s.b.c.embedded.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to:
[/*]
Spring Boot (logging)
• Configuração customizada de níveis de log
logging.level.root=WARN
logging.level.org.springframework.web=DEBUG
logging.level.org.hibernate=ERROR
application.properties
@Component
public class Service {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
public void doSomething(String param) {
try {
logger.debug("Trying to do something using param {}", param);
// process something
} catch (Exception ex) {
logger.error("Error to do something", ex);
}
}
// other methods
}
Spring Boot (actuator)
• Ajuda gerenciar e monitorar as aplicações em produção
• Acessível via HTTP, JMX ou remote shell
• Fornece uma lista de endpoints para gerenciar Spring
Boot app
• Publica as propriedades e Spring Beans em formato
JSON view
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
Spring Boot (actuator)
• /info
• Informação da aplicação
• /health
• Status da aplicação (UP/DOWN)
• /beans
• Lista de Spring Beans na aplicação
• /env
• Propriedades externas configuradas
• /dump
• Realiza um thread dump
• /metrics
• Métricas da aplicação corrente (número de requests, consumo memória, etc)
• /mappings
• Lista de todos os @RequestMapping’s da aplicação
• /trace
• Demonstra o trace dos últimos 100 requests
• /autoconfig
• Relatório de auto-configuração da aplicação
• /shutdown
• Realiza o shutdown da aplicação (não ativado por padrão)
Spring Boot (actuator)
• Customizando health indicator
@Component
public class MyHealthIndicator implements HealthIndicator {
@Override
public Health health() {
int errorCode = check();
// perform some specific health check
if (errorCode != 0) {
return Health.down().withDetail(
"Error Code", errorCode).build();
}
return Health.up().build();
}
}
Spring Boot (dev tools)
• Conjunto de ferramentas para facilitar o processo de
desenvolvimento e deployment das apps
• Principais funcionalidades
• Property defaults
• Automatic restart
• Live reload
• Global settings
• Remote applications
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
Laboratório 2 (boot-lab02)
• Explorando os recursos do Spring Boot
Spring Boot (testing)
• Fornece diversos utilitários e implementações para
implementação de testes unitários
• Habilitado via spring-boot-starter-test
• Módulos spring-boot-test (core), spring-boot-test-
autoconfigure (auto-configuração)
• Dependências
• JUnit - Biblioteca de unit testing em Java
• Spring Test - Utilitários para testes integração com Spring Boot
• AssertJ - Biblioteca para fluent assertion
• Hamcrest - Biblioteca para matcher objects (constraints / predicates)
• Mockito - Mock objects framework
• JSONassert - Biblioteca para JSON assertion
• JsonPath - Biblioteca para XPath para JOSN
Spring Boot (testing)
• Habilitado utilizando a anotação @SpringBootTest e via
JUnit SpringRunner
• Simula um webEnvironment que pode configurado como:
• MOCK, RANDON_PORT, DEFINED_PORT, NONE
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@Import(MyTestsConfiguration.class)
public class MyTests {
@Test
public void exampleTest() {
...
}
}
Spring Boot (testing)
• Suporta a utilização de Mock objects via Mockito
• Basta injetar objetos com uso da anotação @MockBean
@RunWith(SpringRunner.class)
@SpringBootTest
public class MyTests {
@MockBean
private RemoteService remoteService;
@Autowired
private Reverser reverser;
@Test
public void exampleTest() {
// RemoteService has been injected into the reverser bean
given(this.remoteService.someCall()).willReturn("mock");
String reverse = reverser.reverseSomeCall();
assertThat(reverse).isEqualTo("kcom");
}
}
Spring Boot (testing)
• Oferece uma boa alternativa para testar conteúdo JSON
por meio da anotação @JsonTest
• Utiliza por padrão Jackson como parser, mas pode ser
configurado para suportar Gson
@RunWith(SpringRunner.class)
@JsonTest
public class MyJsonTests {
@Autowired
private JacksonTester<VehicleDetails> json;
@Test
public void testSerialize() throws Exception {
VehicleDetails details = new VehicleDetails("Honda", "Civic");
// Assert against a `.json` file in the same package as the test
assertThat(this.json.write(details)).isEqualToJson("expected.json");
// Or use JSON path based assertions
assertThat(this.json.write(details)).hasJsonPathStringValue("@.make");
assertThat(this.json.write(details)).extractingJsonPathStringValue("@.make")
.isEqualTo("Honda");
}
}
Laboratório 3 (boot-lab03)
• Testando uma aplicação Spring Boot
Spring MVC
• Web MVC action framework suportado pelo Spring Boot
• Utilizado para implementação de aplicações Web content
e também para REST APIs
Spring MVC
• DispatcherServlet
• Implementação do design
pattern FrontController
• Recebe todas as requisições
e delega para os controllers
respectivos
• Utiliza ViewResolver para
resolver qual a tela deverá
ser retornada
Spring MVC (controller)
• @Controller é o componente principal do Spring MVC
• Define os server endpoints da aplicação Web
• Aplicações REST pode ser utilizado @RestController
@Controller
public class GreetingController {
@RequestMapping("/greeting")
public String greeting(
@RequestParam(required=false) String name, Model model) {
model.addAttribute("name", name);
return "greeting";
}
}
Spring MVC (annotations)
• @RequestMapping
• Define os server endpoints à serem processados pela aplicação
@Controller
@RequestMapping("/appointments")
public class AppointmentsController {
@Autowired AppointmentBook appointmentBook;
@RequestMapping(method = RequestMethod.GET)
public Map<String, Appointment> get() {
return appointmentBook.getAppointmentsForToday();
}
@RequestMapping(method = RequestMethod.POST)
public String add(@Valid AppointmentForm appointment, BindingResult result) {
if (result.hasErrors()) {
return "appointments/new";
}
appointmentBook.addAppointment(appointment);
return "redirect:/appointments";
}
}
Spring MVC (annotations)
• RequestMapping possui variações para melhor suportar
as operações HTTP
• @GetMapping, @PostMapping, @PutMapping
@DeleteMapping, @PatchMapping
@Controller
@RequestMapping("/appointments")
public class AppointmentsController {
@Autowired AppointmentBook appointmentBook;
@GetMapping
public Map<String, Appointment> get() {
return appointmentBook.getAppointmentsForToday();
}
@PostMapping
public String add(@Valid AppointmentForm appointment, BindingResult result) {
if (result.hasErrors()) {
return "appointments/new";
}
appointmentBook.addAppointment(appointment);
return "redirect:/appointments";
}
}
Spring MVC (annotations)
• @RequestParam
• Recuperação de um parâmetro da requisição
• @RequestBody
• Define o acesso para o conteúdo do corpo da requisição (ex: JSON, XML, etc)
• @ResponseBody
• Define o retorno do conteúdo como corpo da resposta (ex; JSON, XML, etc)
• @PathVariable
• Recuperação de um atributo como parte do path da requisição
• @ModelAttribute
• Recuperação de um grupo de atributos submetidos na requisição
• @SessionAttribute
• Referência e/ou recuperação de um atributo da sessão (HttpSession)
• @RequestAttribute
• Referência e/ou recuperação de um atributo da requisição
• @CookieValue
• Recuperação de um cookie na requisição
• @RequestHeader
• Recuperação de um cabeçalho da requisição
Spring MVC (annotations)
@Controller
public class PetController {
@PostMapping(path = "/pets", consumes=“application/json”, produces="application/json")
@ResponseBody
public Pet addPet(@RequestBody Pet pet, Model model) {...}
@GetMapping(path = "/pets/setup")
public String setupForm(@RequestParam("petId") int petId, ModelMap model) {}
@PostMapping(path = "/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(@ModelAttribute("pet") Pet pet, BindingResult result) {...}
@GetMapping(path = "/display/cookie")
public void displayCookie(@CookieValue("JSESSIONID") String cookie) {...}
@GetMapping(path = "/display/header")
public void displayHeader(@RequestHeader("Accept-Encoding") String encoding,
@RequestHeader("Keep-Alive") long keepAlive) {...}
@GetMapping(path = "/user")
public String handleUser(@SessionAttribute User user) {...}
}
• Exemplos de utilização das anotações
Spring MVC (error handling)
• Spring Boot oferece /error endpoint como página global
de erros, para tratar erros de maneira geral
• Oferece implementação de tratadores de execução
customizados via @ExceptionHandler
• Pode ser utilizado como método do @Controller ou por via
@ControllerAdvice
@Controller
public class SimpleController {
// @RequestMapping methods omitted ...
@ExceptionHandler(IOException.class)
@ResponseBody
public ResponseEntity<String> handleIOException(IOException ex) {
// prepare responseEntity
return responseEntity;
}
}
Spring MVC (error handling)
• Páginas de erros podem ser customizadas de maneira
estática ou utilizando templates
src/
+- main/
+- java/
| + <source code>
+- resources/
+- public/
+- error/
| +- 404.html
+- <other public assets>
src/
+- main/
+- java/
| + <source code>
+- resources/
+- templates/
+- error/
| +- 5xx.ftl
+- <other templates>
Spring MVC (static content)
• Por padrão Spring Boot irá buscar conteúdo estático nos
seguintes diretórios
• /static, /public, /resources ou /META-INF/resources
• A partir do diretório /src/main/resources (Maven)
• Não utilize o diretório /src/main/webapp
• Funciona apenas para empacotamento WAR
• Fornece LiveReload para browser refresh automático
• Apenas quando DevTools está habilitado no Spring Boot
• Suporta a utilização de WebJars
• http://www.webjars.org/
Spring MVC (view templates)
• Suporta uma variedade de ferramentas de view templates
para processamento conteúdo Web dinâmico
• FreeMaker
• Groovy
• Thymeleaf
• Mustache
• JSP
• Os templates serão buscados a partir do diretório template
na aplicação Spring Boot
• /src/main/resources/templates
Spring MVC (CORS)
• Pode ser customizado via configuração customizada
@Configuration
public class MyConfiguration {
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("http://domain2.com")
.allowedMethods("PUT", "DELETE")
.allowedHeaders("header1", "header2")
.exposedHeaders("header1", "header2")
.allowCredentials(false).maxAge(3600);
}
};
}
}
Spring MVC (CORS)
• Fornece a anotação @CrossOrigin para ser utilizada
diretamente nos controllers
@Controller
@RequestMapping("/account")
public class AccountController {
@CrossOrigin
@RequestMapping("/{id}")
public Account retrieve(@PathVariable Long id) {
// ...
}
@RequestMapping(method = RequestMethod.DELETE, path = "/{id}")
public void remove(@PathVariable Long id) {
// ...
}
}
@CrossOrigin(origins = "http://domain2.com", maxAge = 3600)
@Controller
@RequestMapping("/account")
public class AccountController {...}
Spring MVC (testing)
• Oferece uma customização especial para testes utilizando a
anotação @WebMvcTest
• Possui integração com frameworks de teste funcional (HtmlUnit,
Selenium)
@RunWith(SpringRunner.class)
@WebMvcTest(UserVehicleController.class)
public class MyControllerTests {
@Autowired MockMvc mvc;
@MockBean UserVehicleService userVehicleService;
@Test
public void testExample() throws Exception {
given(this.userVehicleService.getVehicleDetails("sboot"))
.willReturn(new VehicleDetails("Honda", “Civic"));
this.mvc.perform(get("/sboot/vehicle")
.accept(MediaType.TEXT_PLAIN))
.andExpect(status().isOk())
.andExpect(content().string("Honda Civic"));
}
}
Laboratório 4 (boot-lab04)
• Desenvolvimento Web com Spring MVC
Web Services APIs
Arquitetura REST
Arquitetura REST
• ︎Protocolo cliente/servidor sem estado (HTTP)
• ︎Operações bem definidas
• GET
• POST
• PUT
• DELETE, etc
• ︎Sintaxe universal para identificação de recursos
(URL)
• ︎Transferência de informações em formato padrão
(XML, HTML, JSON)
Richardson Maturity Model
RESTful Services
Spring REST
• @RestController
• Define uma anotação específica para controllers REST
@RestController
@RequestMapping(value="/users")
public class MyRestController {
@RequestMapping(value="/{user}", method=RequestMethod.GET)
public User getUser(@PathVariable Long user) {
// ...
}
@RequestMapping(value="/{user}/customers", method=RequestMethod.GET)
List<Customer> getUserCustomers(@PathVariable Long user) {
// ...
}
@RequestMapping(value="/{user}", method=RequestMethod.DELETE)
public User deleteUser(@PathVariable Long user) {
// ...
}
}
Spring REST
• Fornece flexibilidade para configuração na negociação de conteúdo
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.favorPathExtension(false).
favorParameter(true).
parameterName("mediaType").
ignoreAcceptHeader(true).
useJaf(false).
defaultContentType(MediaType.APPLICATION_JSON).
mediaType("xml", MediaType.APPLICATION_XML).
mediaType("json", MediaType.APPLICATION_JSON);
}
}
curl http://localhost:8080/spring-mvc-java/employee/10?mediaType=[json/xml]
<employee>
<contactNumber>999-999-9999</contactNumber>
<id>10</id>
<name>Test Employee</name>
</employee>
{
"id": 10,
"name": "Test Employee",
"contactNumber": "999-999-9999"
}
Spring REST
• Unit testing é implementado utilizando @WebMvcTest
@RunWith(SpringRunner.class)
@WebMvcTest(GreentingController.class)
public class GreetingControllerTests {
@Autowired
private MockMvc mvc;
@Test
public void givenGreetURIWithQueryParameter() {
this.mockMvc.perform(get("/greetWithQueryVariable")
.param("name", "John Doe")).andDo(print()).andExpect(status().isOk())
.andExpect(content().contentType("application/json;charset=UTF-8"))
.andExpect(jsonPath("$.message").value("Hello World John Doe!!!"));
}
@Test
public void givenGreetURIWithPost() {
this.mockMvc.perform(post("/greetWithPost")).andDo(print())
.andExpect(status().isOk()).andExpect(content()
.contentType("application/json;charset=UTF-8"))
.andExpect(jsonPath("$.message").value("Hello World!!!"));
}
}
Spring REST
• É possível utilizar especificação JAX-RS na implementação dos
REST endpoints
• Basta incluir a dependência spring-boot-starter-jersey
• Implementado via Jersey 2.x
• Para cada REST endpoint é necessário defini-los como um bean
gerenciado pelo Spring
• Configurado com a anotação @Component
@Component
public class JerseyConfig extends ResourceConfig {
public JerseyConfig() {
register(Endpoint.class);
}
}
@Component
@Path("/hello")
public class Endpoint {
@GET
public String message() {
return "Hello";
}
}
HATEOAS
• Hypermedia As The Engine of Application State
• Descrevem o estado atual da aplicação e como navegar para
o próximo estado
Hypermedia
Spring HATEOAS
• Adiciona suporte HATEOAS para REST endpoints
• Basta incluir a dependência spring-boot-starter-hateoas
• Definida pelos componentes Links e Resources
Link link = new Link("http://localhost:8080/something");
assertThat(link.getHref(), is("http://localhost:8080/something"));
assertThat(link.getRel(), is(Link.SELF));
class PersonResource extends ResourceSupport {
String firstname;
String lastname;
}
PersonResource resource = new PersonResource();
resource.firstname = "Dave";
resource.lastname = "Matthews";
resource.add(new Link("http://myhost/people"));
{ firstname : "Dave",
lastname : "Matthews",
links : [
{ rel : "self",
href : "http://myhost/people" } ] }
Spring HATEOAS
public class Greeting {
String name;
// getters and setters
}
public class GreetingResource
extends Resource<Greeting> {
public GreetingResource(Greeting greeting,
Link... links) {
super(greeting, links);
}
}
public class GreetingResourceAssembler
extends ResourceAssemblerSupport<Greeting, GreetingResource> {
public GreetingResourceAssembler() {
super(Greeting.class, GreetingResource.class);
}
@Override
public GreetingResource toResource(Aluno aluno) {
return new GreetingResource(aluno,
linkTo(methodOn(GreetingController.class).get(greeting.getName())).withSelfRel());
}
@Override
protected GreetingResource instantiateResource(Greeting aluno) {
return new GreetingResource(greeting);
}
}
Spring HATEOAS
@RestController
public class GreetingController {
GreetingResourceAssembler assembler = new GreetingResourceAssembler();
@RequestMapping("/greeting")
public ResponseEntity<GreetingResource> greeting(
@RequestParam(value = "name", required = false) String name) {
Greeting greeting = new Greeting("Hello, " + name);
return new ResponseEntity<>(assembler.toResource(greeting), HttpStatus.OK);
}
}
{
"content":"Hello, User!",
"_links":{
"self":{
"href":"http://localhost:8080/greeting?name=User"
}
}
}
curl http://localhost:8080/greeting?name=User
Swagger
• Alternativa para documentação da REST API
• Possui ótima integração com Spring Boot
• SpringFox - https://springfox.github.io/springfox/
• Oferece uma ferramenta para navegação Web
• Swagger UI - http://swagger.io/swagger-ui/
• Possui também uma ferramenta para modelagem da API
• Swagger Editor - http://swagger.io/swagger-editor/
Swagger (spring boot)
• Basta adicionar as dependências Maven
• springfox-swagger-ui e springfox-swagger2
• Habilitar suporte Swagger na aplicação via @EnableSwagger2
• Documentar os REST controllers utilizando anotações
• @ApiOperation
• Documentação de um REST endpoint
• @ApiParam, @ApiImplicitParam
• Documentação dos parâmetros do REST endpoint
• @ApiResponse
• Documentação da resposta do REST endpoint
• @ApiModel, @ApiModelProperty
• Documentação do modelo de dados de resposta do REST endpoint
• @Authorization
• Documentação do modelo de autorização do REST endpoint
• @ResponseHeader
• Documentação dos headers de resposta do REST endpoint
Swagger (spring boot)
@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
.build();
}
}
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.6.1</version>
</dependency>
• Exemplo de integração Swagger com Spring Boot
Swagger (spring boot)
@RestController
public class GreetingController {
@ApiOperation(value = "getGreeting", nickname = "getGreeting")
@RequestMapping(method = RequestMethod.GET, path="/greeting",
produces = "application/json")
@ApiImplicitParams({
@ApiImplicitParam(name = "name", value = "User's name", required = false,
dataType = "string", paramType = "query")
})
@ApiResponses(value = {
@ApiResponse(code = 200, message = "Success", response = Greeting.class),
@ApiResponse(code = 401, message = "Unauthorized"),
@ApiResponse(code = 403, message = "Forbidden"),
@ApiResponse(code = 404, message = "Not Found"),
@ApiResponse(code = 500, message = "Failure")})
public Greeting greeting(@RequestParam(value="name") String name) {
return new Greeting(new AtomicLong().incrementAndGet(),
String.format("Hello, %s!", name));
}
}
• Exemplo de documentação utilizando as anotações Swagger
Swagger UI
Laboratório 5 (boot-lab05)
• Implementando RESTful com Spring Boot
Spring Data
• Abstração para implementação de repositórios de
persistência de dados integrada ao Spring Boot
• Suporta diferentes modelos de persistência
• JDBC, JPA, MongoDB, LDAP, Redis, Gemfire, Cassandra
• DynamoDB, Couchbase, Solr, Elasticsearch, Neo4j,…
• Implementa ações de CRUD em repositórios abstratos
• Fornece queries dinâmicas criadas a partir nomes de
métodos dos repositórios
• Oferece flexibilidade para customização de repositórios
• Suporta configurações de auditoria
Spring Data
Spring Data
Spring Data
public interface CrudRepository<T, ID extends Serializable>
extends Repository<T, ID> {
<S extends T> S save(S entity);
T findOne(ID primaryKey);
Iterable<T> findAll();
Long count();
void delete(T entity);
boolean exists(ID primaryKey);
}
• Definição dos repositórios abstratos
public interface PagingAndSortingRepository<T, ID extends Serializable>
extends CrudRepository<T, ID> {
Iterable<T> findAll(Sort sort);
Page<T> findAll(Pageable pageable);
}
interface Repository<T, ID> extends Serializable> {}
Spring Data
public interface UserRepository extends PagingAndSortingRepository<User, Long> {
// other methods
}
• Utilização dos repositórios abstratos
@Component
public class SomeClient {
@Autowired
private UserRepository repository;
public void doSomething() {
PagingAndSortingRepository<User, Long> repository = // … get access to a bean
Page<User> users = repository.findAll(new PageRequest(1, 20));
}
}
Spring Data
interface UserRepositoryCustom {
public void someCustomMethod(User user);
}
interface UserRepository extends CrudJpaRepository<User, Long>, UserRepositoryCustom {
// Declare query methods here
}
• Implementação de repositórios “customizados"
class UserRepositoryImpl implements UserRepositoryCustom {
public void someCustomMethod(User user) {
// Your custom implementation
}
}
Spring Data
• Mecanismo de geração de
consultas dinâmicas
• Definição por DSL
• Via nome dos métodos
• Suporta diferentes variações
• ByProperty
• ByPropertyAsc
• ByPropertyDesc
• ByProp1AndProp2
• ByProp1OrProp2
• ByPropertyContaining
• …
Spring Data (queries)
• Definição das consultas dinâmicas
public interface PersonRepository extends Repository<User, Long> {
List<Person> findByEmailAddressAndLastname(EmailAddress emailAddress, String lastname);
// Enables the distinct flag for the query
List<Person> findDistinctPeopleByLastnameOrFirstname(String lastname, String firstname);
List<Person> findPeopleDistinctByLastnameOrFirstname(String lastname, String firstname);
// Enabling ignoring case for an individual property
List<Person> findByLastnameIgnoreCase(String lastname);
// Enabling ignoring case for all suitable properties
List<Person> findByLastnameAndFirstnameAllIgnoreCase(String lastname, String firstname);
// Enabling static ORDER BY for a query
List<Person> findByLastnameOrderByFirstnameAsc(String lastname);
List<Person> findByLastnameOrderByFirstnameDesc(String lastname);
}
Spring Data (queries)
Logical keyword Keyword expressions
AND And
OR Or
AFTER After, IsAfter
BEFORE Before, IsBefore
CONTAINING Containing, IsContaining, Contains
BETWEEN Between, IsBetween
ENDING_WITH EndingWith, IsEndingWith, EndsWith
EXISTS Exists
FALSE False, IsFalse
GREATER_THAN GreaterThan, IsGreaterThan
GREATER_THAN_EQUALS GreaterThanEqual, IsGreaterThanEqual
IN In, IsIn
IS Is, Equals, (or no keyword)
IS_NOT_NULL NotNull, IsNotNull
Spring Data (queries)
Logical keyword Keyword expressions
IS_NULL Null, IsNull
LESS_THAN LessThan, IsLessThan
LESS_THAN_EQUAL LessThanEqual, IsLessThanEqual
LIKE Like, IsLike
NEAR Near, IsNear
NOT Not, IsNot
NOT_IN NotIn, IsNotIn
NOT_LIKE NotLike, IsNotLike
REGEX Regex, MatchesRegex, Matches
STARTING_WITH StartingWith, IsStartingWith, StartsWith
TRUE True, IsTrue
WITHIN Within, IsWithin
Spring Data (queries)
• Limitação nos resultados de consulta
public interface PersonRepository extends Repository<User, Long> {
User findFirstByOrderByLastnameAsc();
User findTopByOrderByAgeDesc();
Page<User> queryFirst10ByLastname(String lastname, Pageable pageable);
Slice<User> findTop3ByLastname(String lastname, Pageable pageable);
List<User> findFirst10ByLastname(String lastname, Sort sort);
List<User> findTop10ByLastname(String lastname, Pageable pageable);
}
Spring Data JPA
• Oferece suporte à JPA
• Basta adicionar a dependência
• spring-boot-starter-data-jpa
• Habilitar por padrão Hibernate
como JPA provider
• Oferece integração QueryDSL
• Suporte à paginação, execução
dinâmica de consultas,
integração com repositórios
customizados, etc
Spring Data JPA
Spring Data JPA
public interface JpaRepository<T, ID> extends
PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {
List<T> findAll();
List<T> findAll(Sort sort);
List<T> findAllById(Iterable<ID> ids);
<S extends T> List<S> saveAll(Iterable<S> entities);
void flush();
<S extends T> S saveAndFlush(S entity);
void deleteInBatch(Iterable<T> entities);
void deleteAllInBatch();
T getOne(ID id);
}
• Definição do repositório JPA abstrato
Spring Data JPA
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(name = "username")
private String name;
private String password;
@OneToOne
private Person person;
// getters and setters
}
public interface UserRepository extends JpaRepository<User, Long> {
User findByName(String name);
List<User> findByNameContaining(String name);
}
• JPA Entity e repositório Spring Data JPA
Spring Data JPA
Keyword Sample JPQL snippet
And findByLastnameAndFirstnam
e
… where x.lastname = ?1 and
x.firstname = ?2
Or findByLastnameOrFirstname … where x.lastname = ?1 or
x.firstname = ?2
Is,Equals findByFirstname … where x.firstname = ?1
Between findByStartDateBetween … where x.startDate between
?1 and ?2
LessThan findByAgeLessThan … where x.age < ?1
LessThanEqual findByAgeLessThanEqual … where x.age <= ?1
GreaterThan findByAgeGreaterThan … where x.age > ?1
GreaterThanEqual findByAgeGreaterThanEqual … where x.age >= ?1
After findByStartDateAfter … where x.startDate > ?1
Spring Data JPA
@Entity
@NamedQuery(name = "User.findByEmailAddress",
query = "select u from User u where u.emailAddress = ?1")
public class User {
// Implementation
}
public interface UserRepository extends JpaRepository<User, Long> {
List<User> findByLastname(String lastname);
User findByEmailAddress(String emailAddress);
}
• Utilizando @NamedQuery's
Spring Data JPA
public interface UserRepository extends JpaRepository<User, Long> {
// JP-QL sample
@Query("select u from User u where u.emailAddress = ?1")
User findByEmailAddress(String emailAddress);
// JP-QL with named parameters
@Query("select u from User u where u.firstname = :firstname or u.lastname = :lastname")
User findByLastnameOrFirstname(@Param("lastname") String lastname,
@Param("firstname") String firstname);
// Native SQL query
@Query(value = "SELECT * FROM USERS WHERE EMAIL_ADDRESS = ?1", nativeQuery = true)
User findByEmailAddress(String emailAddress)
// Native SQL query for paging
@Query(value = "SELECT * FROM USERS WHERE LASTNAME = ?1",
countQuery = "SELECT count(*) FROM USERS WHERE LASTNAME = ?1",
nativeQuery = true)
Page<User> findByLastname(String lastname, Pageable pageable);
}
• Utilizando @Query’s customizadas
Spring Data JPA
public interface UserRepository extends JpaRepository<User, Long> {
// JP-QL sample with ordering
@Query("select u from User u where u.lastname like ?1%")
List<User> findByAndSort(String lastname, Sort sort);
// Delete query sample
@Modifying
@Query("delete from User u where user.role.id = ?1")
void deleteInBulkByRoleId(long roleId);
// Update query sample
@Modifying
@Query("update User u set u.firstname = ?1 where u.lastname = ?2")
int setFixedFirstnameFor(String firstname, String lastname);
// Using query hints
@QueryHints(value = { @QueryHint(name = "name", value = "value")},
forCounting = false)
Page<User> findByLastname(String lastname, Pageable pageable);
}
• Utilizando @Query’s customizadas
Spring Data JPA
• Executando Stored Procedures
/;
DROP procedure IF EXISTS plus1inout
/;
CREATE procedure plus1inout (IN arg int, OUT res int)
BEGIN ATOMIC
set res = arg + 1;
END
/;
@Entity
@NamedStoredProcedureQuery(name = "User.plus1", procedureName = "plus1inout", parameters = {
@StoredProcedureParameter(mode = ParameterMode.IN, name = "arg", type = Integer.class),
@StoredProcedureParameter(mode = ParameterMode.OUT, name = "res", type = Integer.class) })
public class User {}
public interface UserRepository extends JpaRepository<User, Long> {
@Procedure("plus1inout")
Integer explicitlyNamedPlus1inout(Integer arg);
@Procedure(name = "User.plus1IO")
Integer entityAnnotatedCustomNamedProcedurePlus1IO(@Param("arg") Integer arg);
}
Spring Data JPA (specification)
public class CustomerSpecs {
public static Specification<Customer> isLongTermCustomer() {
return new Specification<Customer>() {
public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> query,
CriteriaBuilder builder) {
LocalDate date = new LocalDate().minusYears(2);
return builder.lessThan(root.get(_Customer.createdAt), date);
}
};
}
}
public interface CustomerRepository extends JpaRepository<Customer, Long>,
JpaSpecificationExecutor<Customer> {...}
public interface Specification<T> {
Predicate toPredicate(Root<T> root, CriteriaQuery<?> query,
CriteriaBuilder builder);
}
List<Customer> customers = customerRepository.findAll(isLongTermCustomer());
Spring Data JPA (query by example)
public interface QueryByExampleExecutor<T> {
<S extends T> S findOne(Example<S> example);
<S extends T> Iterable<S> findAll(Example<S> example);
// … more functionality omitted.
}
public class PersonService {
@Autowired PersonRepository personRepository;
public List<Person> findPeople(Person probe) {
return personRepository.findAll(Example.of(probe));
}
}
public interface PersonRepository extends JpaRepository<Person, String> { … }
Person person = new Person();
person.setFirstname("Dave");
ExampleMatcher matcher = ExampleMatcher.matching()
.withIgnorePaths("lastname")
.withIncludeNullValues()
.withStringMatcherEnding();
Example<Person> example = Example.of(person, matcher);
Spring Data JPA (transactional)
public interface UserRepository extends JpaRepository<User, Long> {
// Transaction support
@Transactional(timeout = 10)
public List<User> findAll();
}
@Service
class UserManagementImpl implements UserManagement {
@Autowired UserRepository userRepository;
@Autowired RoleRepository roleRepository;
@Transactional
public void addRoleToAllUsers(String roleName) {
// Step 1
Role role = roleRepository.findByName(roleName);
// Step 2
for (User user : userRepository.findAll()) {
user.addRole(role);
userRepository.save(user);
}
}
• Suporte transacional
Spring Data JPA (auditing)
class Customer {
@CreatedBy
private User user;
@CreatedDate
private DateTime createdDate;
// … further properties omitted
}
• Controle de auditoria
class SpringSecurityAuditorAware implements AuditorAware<User> {
public User getCurrentAuditor() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null || !authentication.isAuthenticated()) {
return null;
}
return ((MyUserDetails) authentication.getPrincipal()).getUser();
}
}
@Configuration
@EnableJpaAuditing
class Config {
@Bean
public AuditorAware<AuditableUser> auditorProvider() {
return new AuditorAwareImpl();
}
}
Spring Data JPA (testing)
@RunWith(SpringRunner.class)
@DataJpaTest
public class UserRepositoryTests {
@Autowired TestEntityManager entityManager;
@Autowired UserRepository repository;
@Test
public void findByUsernameShouldReturnUser() {
this.entityManager.persist(new User("sboot", "123"));
User user = this.repository.findByUsername("sboot");
assertThat(user.getUsername()).isEqualTo("sboot");
assertThat(user.getVin()).isEqualTo("123");
}
}
• Unit testing com @DataJpaTest e TestEntityManager
Project Lombok
• Oferece anotações para substituir “boilerplate code” nos
beans da aplicação
• Fornece geração automática à diversas implementações
• Getters/setters, Constructors, Equals/hashcode
• ToString, Builder’s, Immutable classes, Synchronized,…
• Implementação por meio de anotações
• @Getter, @Setter, @EqualsAndHashCode, @ToString
• @NoArgsConstructor, @RequiredArgsConstructor
• @AllArgsContructor, @Data, @Builder, @Log
• @Synchronized, @Value, @NonNull, @Cleanup
Project Lombok
• Basta adicionar a dependência no projeto
• Implementar os beans utilizando as anotações
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.16</version>
</dependency>
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode
@ToString
public class User implements Serializable {
Long id;
String name;
String password;
}
Spring Boot (datasources)
• Oferece suporte à diferentes RDBMS
• MySQL, PostgreSQL, Oracle, SQLServer, H2, …
• É necessário configurá-los via spring.datasource.*
• Suporta diferentes tipos de definição para data sources
• Hikari, Tomcat, C3P0, DBCP2, JNDI
spring.datasource.url=jdbc:mysql://localhost/test
spring.datasource.username=dbuser
spring.datasource.password=dbpass
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.hikari.maximum-pool-size=5
spring.datasource.hikari.connection-timeout=10
Spring Boot (H2)
• Embedded in-memory RDBMS
• Rápido, opensource e suporta 100% JDBC API
• Small footprint (cerca 1.5 MB de tamanho)
• Pode ser instalado como server, e persistência em arquivo
• Ideal para utilização em testes de integração
• Oferece uma aplicação Web para administração
• Para habilitá-lo, basta adicionar a dependência
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<scope>runtime</scope>
</dependency>
Spring Boot (H2)
• Para habilitar no Spring Boot, basta adicionar a
dependência e habilitar interface Web, se desejado
• spring.h2.console.enabled = true
• http://boot/h2-console
Laboratório 6 (boot-lab06)
• Persistindo dados com Spring Data JPA
MongoDB
• NoSQL database orientado à documentos
• Persistência de dados no formato JSON
• Armazenamento em formato BSON (binary JSON)
• Suporte à full indexação, auto sharding, map reduce,
replicação e tolerância à falhas
db.createCollection('contato')
db.contato.insert({
name: 'Rodrigo',
email: 'rodrigo@email.com',
mensagem: 'Inserindo dados no MongoDB'
})
db.contato.find()
db.contato.update({name: 'Rodrigo'}, {$set: {email: 'rodrigo@new-email.com'}})
db.contato.remove({name: 'Rodrigo'})
db.contato.drop()
db.dropDatabase()
Spring Data MongoDB
• Suporte à persistência dados no MongoDB via Spring
• Basta adicionar a dependência no Spring Boot
• spring-boot-starter-data-mongodb
• Oferece helper classes para integração com MongoDB
• MongoTemplate, MongoOperations
• Anotações para mapeamento de entidades
• @Id, @Document, @DBRef, @Indexed,
• @CompoundIndex, @GeoSpatialIndexed, @Language
• @TextIndexed, @Transient, @Value, @Field
spring.data.mongodb.uri=mongodb://user:secret@mongo1.example.com:12345/test
spring.data.mongodb.host=mongoserver
spring.data.mongodb.port=27017
Spring Data MongoDB
• Definição de repositório abstrato MongoRepository
public interface MongoRepository<T, ID extends Serializable>
extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {
@Override
<S extends T> List<S> save(Iterable<S> entites);
@Override
List<T> findAll();
@Override
List<T> findAll(Sort sort);
<S extends T> S insert(S entity);
<S extends T> List<S> insert(Iterable<S> entities);
@Override
<S extends T> List<S> findAll(Example<S> example);
@Override
<S extends T> List<S> findAll(Example<S> example, Sort sort);
}
Spring Data MongoDB
@Document
public class Person {
@Id
private String id;
@Indexed
private Integer ssn;
private String firstName;
@Indexed
private String lastName;
// getters and setters
}
public interface PersonRepository extends MongoRepository<Person, String> {
List<Person> findByLastname(String lastname);
Page<Person> findByFirstname(String firstname, Pageable pageable);
Person findByShippingAddresses(Address address);
Stream<Person> findAllBy();
}
@Service
public class PersonService {
@Autowired PersonRepository repository;
public void doSomething() {
Page<Person> persons = repository.findAll(
new PageRequest(1, 20));
// do something
}
}
Spring Data MongoDB
Keyword Sample Logical result
After findByBirthdateAfter(Date date) {"birthdate" : {"$gt" : date}}
GreaterThan findByAgeGreaterThan(int age) {"age" : {"$gt" : age}}
GreaterThanEqual findByAgeGreaterThanEqual(int age) {"age" : {"$gte" : age}}
Before findByBirthdateBefore(Date date) {"birthdate" : {"$lt" : date}}
LessThan findByAgeLessThan(int age) {"age" : {"$lt" : age}}
LessThanEqual findByAgeLessThanEqual(int age) {"age" : {"$lte" : age}}
Between findByAgeBetween(int from, int to) {"age" : {"$gt" : from, "$lt" :
In findByAgeIn(Collection ages) {"age" : {"$in" : [ages… ]}}
NotIn findByAgeNotIn(Collection ages) {"age" : {"$nin" : [ages… ]}}
IsNotNull, findByFirstnameNotNull() {"firstname" : {"$ne" : null}}
IsNull, Null findByFirstnameNull() {"firstname" : null}
Spring Data MongoDB
• Suporte à JSON based @Query’s
public interface PersonRepository extends MongoRepository<Person, String>
@Query("{ 'firstname' : ?0 }")
List<Person> findByThePersonsFirstname(String firstname);
@Query(value="{ 'firstname': ?0 }", fields="{ 'firstname' : 1, 'lastname' : 1}")
List<Person> findByThePersonsFirstname(String firstname);
@Query("{ 'lastname': ?#{[0]} }")
List<Person> findByQueryWithExpression(String param0);
@Query("{'id': ?#{ [0] ? {$exists :true} : [1] }}")
List<Person> findByQueryWithExpressionAndNestedObject(boolean param0, String param1);
}
Spring Data MongoDB
• Exemplo utilizando MongoTemplate object
public class DomainRepositoryImpl implements DomainRepositoryCustom {
@Autowired
MongoTemplate mongoTemplate;
@Override
public int updateDomain(String domain, boolean displayAds) {
Query query = new Query(Criteria.where("domain").is(domain));
Update update = new Update();
update.set("displayAds", displayAds);
WriteResult result = mongoTemplate.updateFirst(query, update, Domain.class);
if(result!=null)
return result.getN();
else
return 0;
}
}
Laboratório 7 (boot-lab07)
• Persistindo NoSQL com Spring Data MongoDB
Spring Data REST
• Publica Spring Data Repo como RESTful API’s
• Expõe operações CRUD, consultas dinâmicas, paginação,
relacionamentos,…
• Incrementa o suporte HATEOAS
• HAL, ALPS, JSON Schema, URI templates, etc
• Permite
• Suporta
• JPA, MongoDB, GemFire, Neo4j, Solr, Cassandra
• Demais estão por vir
Spring Data REST
Spring Data REST
$ curl “http://localhost:8080/persons/1”
Spring Data REST
@CrossOrigin(origins = "http://domain2.com",
methods = { RequestMethod.GET, RequestMethod.POST, RequestMethod.DELETE },
maxAge = 3600)
@RepositoryRestResource(path = "people")
interface PersonRepository extends CrudRepository<Person, Long> {
@RestResource(path = "names")
List<Person> findByName(String name);
@RestResource(exported = false)
Person findByEmail(String email);
@Override
@RestResource(exported = false)
void delete(Person entity);
}
• Exemplo de customização dos REST endpoints
HAL
"Convenção para definição de REST hypermedia"
HAL Browser
• Utilitário para navegar nos REST endpoints gerados
Laboratório 8 (boot-lab08)
• Expondo os repositórios com Spring Data REST
Spring Security
• Solução de segurança para as aplicações Spring e/ou
Java EE-based
• Implementa os procedimentos autenticação e autorização
• Suporta autenticação em diferentes tecnologias
• HTTP BASIC, Digest, X.509, LDAP, Form-based, OpenID
• CAS, HttpInvoker, JAAS, Kerberos…
• Ótimo suporte aos protocolos OAuth2 e JWT
• Configuração facilitada por meio de anotações
• Oferece suporte à diferentes funcionalidades
• Remember-me, Run-as, CSRF, CORS, Crypto, ACL
Spring Security
• Basta adicionar a seguinte dependência no projeto
• Por padrão será habilitado a segurança HTTP BASIC
• Para acesso deve ser utilizando usuário user e a senha
gerada dinamicamente
• Caso queira customizar o usuário e senha, pode ser
definido via properties
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
Using default security password: 12aa6b86-08a7-4894-b899-3b2ebb1de248
security.user.name=root
security.user.password=t0ps3cr3t
Spring Security
• É possível implementar uma tela de login customizada
• src/main/resources/templates/login.html
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated()
.and().formLogin().loginPage("/login").permitAll()
.and().logout().permitAll();
}
}
<form th:action="@{/login}" method="post">
<div><label> User Name : <input type="text" name="username"/> </label></div>
<div><label> Password: <input type="password" name="password"/> </label></div>
<div><input type="submit" value="Sign In"/></div>
</form>
Spring Security
• Autenticação pode ser configurada globalmente (In Memory)
• Ou pode ser configurada via JDBC datasource
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("barry").password("t0ps3cr3t").roles("USER");
}
}
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired DataSource dataSource;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication().dataSource(dataSource)
.withDefaultSchema()
.withUser("barry").password("t0ps3cr3t").roles("USER");
}
}
Spring Security
• Autorização pode ser configurada globalmente
• Ou pode ser customizada via anotações @Secured,
@PreAuthorize
@Configuration
public class ApplicationConfigurerAdapter extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/foo/**")
.authorizeRequests()
.antMatchers("/foo/bar").hasRole("BAR")
.antMatchers("/foo/spam").hasRole("SPAM")
.anyRequest().isAuthenticated();
}
}
@SpringBootApplication
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class Application {...}
Spring Security
• Exemplos de uso das anotações @Secured, @PreAuthorize
public interface BankService {
@Secured("IS_AUTHENTICATED_ANONYMOUSLY")
public Account readAccount(Long id);
@Secured("ROLE_TELLER")
public Account post(Account account, double amount);
@PreAuthorize("isAnonymous()")
public Account readAccount(Long id);
@PreAuthorize("hasAuthority('ROLE_TELLER')")
public Account post(Account account, double amount);
@PreAuthorize("hasRole('ADMIN') AND hasRole('ROLE_TELLER')")
public void deleteAccount(Long id);
}
Laboratório 9 (boot-lab09)
• Habilitando segurança com Spring Boot
Spring Batch
• Lightweight Batch framework para desenvolvimento de
processos robustos com grande quantidade de dados
• Não é um scheduler, mas pode ser integrado
• Quartz, Spring Scheduler, Tivoli, CRON, Control-M
• Oferece diversas funcionalidades
• Logging/tracing, gerenciamento de transação, estatísticas, job
restart, skip, particionamento, gestão de concorrência,
gerenciamento de recursos (memória, cpu)
• Forte integração com demais projetos Spring
• Utilizado geralmente em use cases particulares
• ETL, exportação/importação de dados, cálculos,…
Spring Batch
• Basta adicionar a seguinte dependência no projeto
• Para habilitar processamento batch na aplicação Spring
Boot deve-ser utilizar @EnableBatchProcessing
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-batch</artifactId>
</dependency>
@SpringBootApplication
@EnableBatchProcessing
public class SpringBatchApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBatchApplication.class, args);
}
}
Spring Batch
• Chunk vs. Tasklet
• Implementam step dentro do job
• Chunk
• Encapsula padrão ETL
• Single Reader, Processor e Writer
• Executado por pedaços de dados (chunk)
• Chunk output é escrito unitariamente
• Tasklet
• Promove a execução de um único e simples processo
• Executado até o fim produzindo um código de retorno
Spring Batch
Chunk Tasklet
Spring Batch
• ItemReader
• ItemWriter
• ItemProcessor
public interface ItemReader<T> {
T read() throws Exception, UnexpectedInputException, ParseException;
}
public interface ItemWriter<T> {
void write(List<? extends T> items) throws Exception;
}
public interface ItemProcessor<I, O> {
O process(I item) throws Exception;
}
Spring Batch
• Exemplo de configuração do job na aplicação
@Configuration
@EnableBatchProcessing
public class BatchConfig {
@Autowired JobBuilderFactory jobBuilderFactory;
@Autowired StepBuilderFactory stepBuilderFactory;
@Bean
public Job job() {
return jobBuilderFactory.get("job")
.incrementer(new RunIdIncrementer())
.flow(step1()).end().build();
}
@Bean
public Step step1() {
return stepBuilderFactory.get("step1").chunk(1)
.reader(new Reader())
.processor(new Processor())
.writer(new Writer()).build();
}
}
Spring Batch
• Exemplo de execução job na aplicação
@RestController
public class JobLauncherController {
@Autowired JobLauncher jobLauncher;
@Autowired Job job;
@RequestMapping("/launchjob")
public String handle() throws Exception {
Logger logger = LoggerFactory.getLogger(this.getClass());
try {
JobParameters jobParameters = new JobParametersBuilder()
.addLong("time", System.currentTimeMillis())
.toJobParameters();
jobLauncher.run(job, jobParameters);
} catch (Exception e) {
logger.info(e.getMessage());
}
return "Done";
}
}
Spring Cache
• Oferece uma abstração para implementação de cache de
dados nas aplicações Spring
• Suporta diferente cache providers
• Generic, JCache, EhCache, Hazelcast, Infinitspan, Couchbase,
Redis, Caffeine, Guava, Simple
• Possui integração com Spring Data e JPA
• Ativação simples e fácil nas aplicações Spring Boot
• Basta adicionar a dependência spring-boot-starter-cache
• Ativar o sistema de cache com a anotação @EnableCaching
• Utilizar os objetos CacheManager e Cache
• Utilizar a anotação @Cachable
Spring Cache
• Exemplo de implementação de cache na aplicação
@SpringBootApplication
@EnableCaching
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@Component
public class SimpleBookRepository implements BookRepository {
@Override
@Cacheable("books")
public Book getByIsbn(String isbn) {
simulateSlowService();
return new Book(isbn, "Some book");
}
}
Spring Messaging
• Processamento mensagens assíncronas na aplicação Spring Boot
• Suporta diferentes tipos de protocolos mensagens
• JMS, AMQP, STOMP
• Suporte também diferentes providers de mensagens
• ActiveMQ, Artemis, RabbitMQ, Apache Kafka, …
• Oferece anotações e propriedades customizadas para trabalhar
com provedores de mensagens
• @JmsListener, @RabbitListener, @KafkaListener
• Basta adicionar a dependência desejada
• spring-boot-starter-activemq
• spring-boot-starter-amqp
• spring-boot-starter-kafka
Spring Messaging
@SpringBootApplication
@EnableRabbit
public class MessagingApplication {
@Bean
public Queue fooQueue() {
return new Queue("foo");
}
}
@Service
public class CustomService {
@RabbitListener(queues = "foo")
public void process(@Payload String foo) {
System.out.println(new Date() + ": " + foo);
}
}
public class Sender {
@Autowired RabbitTemplate rabbitTemplate;
public void send() {
this.rabbitTemplate.convertAndSend("foo", "hello");
}
}
• Exemplo de consumo e envio de mensagens RabbitMQ
Spring Integration
• Implementação de design patterns de integração (EIP)
• Endpoint, Channel, Aggregator, Filter, Transformer, Bus,…
• http://www.enterpriseintegrationpatterns.com/
• Oferece integração com diversos protocolos e sistemas
• FTP, sFTP, Twitter, Web Services (SOAP/REST), MQTT
• Feed, JMS, AMQP, Email, TCP/UDP, XMPP, WebSocket,…
• Expões objetos via JMX para monitoramento
• Para configurar, basta adicionar a dependência
• spring-boot-starter-integration
• Oferece anotações para facilitar a implementação
• @MessagingGateway, @Gateway, @ServiceActivator,
@MessageEndpoint, @InboundChannelAdapter,
@OutboundChannelAdapter
Spring Integration
@SpringBootApplication
public class Application {
@Bean
@InboundChannelAdapter(value = "feedChannel",
poller = @Poller(maxMessagesPerPoll = "100", fixedRate = "10000"))
public MessageSource<SyndEntry> feedAdapter() throws MalformedURLException {
return new FeedEntryMessageSource(
new URL("http://feeds.abcnews.com/abcnews/topstories"), "feedAdapter");
}
@MessageEndpoint
public static class Endpoint {
@ServiceActivator(inputChannel = "feedChannel")
public void log(Message<SyndEntry> message) {
SyndEntry payload = message.getPayload();
logger.info(payload.getPublishedDate() + " - " + payload.getTitle());
}
}
@Bean
public MessageChannel feedChannel() {
return new QueueChannel(500);
}
}
• Exemplo de consumo de dados via feed RSS
Spring WebSockets
• Fornece suporte ao protocolo WebSockets aos web
containers auto-contidos
• Tomcat, Jetty, Undertow
• Suportado pelos protocolos STOMP e SockJS
• http://stomp.github.io/stomp-specification-1.2.html
• https://github.com/sockjs/sockjs-protocol
• Integrado aos controllers Spring MVC
• Para configurar na aplicação
• Adicionar a configuração spring-boot-starter-websocket
• Habilitar @EnableWebSocketMessageBroker
Spring WebSockets
• Exemplo de configuração endpoint via WebSocket
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/app");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/gs-guide-websocket").withSockJS();
}
}
@Controller
public class GreetingController {
@MessageMapping("/hello")
@SendTo("/topic/greetings")
public Greeting greeting(HelloMessage message) throws Exception {
Thread.sleep(1000); // simulated delay
return new Greeting("Hello, " + message.getName() + "!");
}
}
Spring WebSockets
• Exemplo de cliente WebSocket em Javascript
function connect() {
var socket = new SockJS('/gs-guide-websocket');
stompClient = Stomp.over(socket);
stompClient.connect({}, function (frame) {
setConnected(true);
console.log('Connected: ' + frame);
stompClient.subscribe('/topic/greetings', function (greeting) {
showGreeting(JSON.parse(greeting.body).content);
});
});
}
function disconnect() {
if (stompClient != null) {
stompClient.disconnect();
}
setConnected(false);
console.log("Disconnected");
}
function sendName() {
stompClient.send("/app/hello", {}, JSON.stringify({'name': $("#name").val()}));
}
Laboratório 10 (boot-lab10)
• Explorando recursos adicionais no Spring Boot
Conclusões
• Spring Boot fornece diversos utilitários e facilitadores
para implementação com Microservices
• Spring Data e Data REST são projetos que aceleram a
implementação e exposição na camada de persistência
como serviços REST
• Spring Security tem um ótima infra-estrutura para lidar
com requisitos de segurança em aplicações Web
• Existem diversos outros projetos que podem ser
incorporados no boot da aplicação Spring, como Batch,
Cache, Messaging, Integration, WebSockets, etc
• Enjoy it ;)
Revisão
Nessa unidade você teve a oportunidade de compreender
como:
• Implementar a primeira aplicação utilizando Spring Boot
• Compreender as funcionalidades adicionais do Spring Boot
• Compreender como implementar serviços REST utilizando
Spring MVC
• Implementar persistência de dados utilizando Spring Data
• Expor os repositórios como serviços utilizando Spring Data
REST
• Implementar segurança utilizando Spring Security
• Explorar os demais projetos do ecossistema Spring
Referências
• https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/
• https://github.com/eugenp/tutorials/tree/master/spring-mvc-java
• http://www.restapitutorial.com/httpstatuscodes.html
• https://spring.io/guides/tutorials/bookmarks/
• http://docs.spring.io/spring-hateoas/docs/current/reference/html/
• http://docs.spring.io/spring-data/jpa/docs/current/reference/html/
• https://docs.spring.io/spring-data/rest/docs/current/reference/html/
• https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/
• https://spring.io/guides/gs/securing-web/
• https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-messaging.html
• https://spring.io/guides/gs/messaging-rabbitmq/
• http://docs.spring.io/spring-integration/reference/html/index.html
• https://spring.io/guides/gs/integration/
• http://docs.spring.io/spring-batch/reference/html/index.html
• https://spring.io/guides/gs/batch-processing/
• https://docs.spring.io/spring/docs/current/spring-framework-reference/html/cache.html
• https://spring.io/guides/gs/caching/
• https://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html
• https://spring.io/guides/gs/messaging-stomp-websocket/

Workshop Microservices - Construindo APIs RESTful com Spring Boot

  • 1.
  • 2.
    Objetivos • Ao finaldesta unidade você irá: • Implementar a primeira aplicação utilizando Spring Boot • Compreender as funcionalidades adicionais do Spring Boot • Compreender como implementar serviços REST utilizando Spring MVC • Implementar persistência de dados utilizando Spring Data • Expor os repositórios como serviços utilizando Spring Data REST • Implementar segurança utilizando Spring Security • Explorar os demais projetos do ecossistema Spring
  • 3.
    Agenda • Spring Boot •Spring MVC • Spring REST • Spring Data • Spring Data REST • Spring Security • Demais projetos • Batch, Cache, Messaging, Integration, WebSockets, …
  • 4.
  • 6.
    Spring Boot • Micro-frameworkpara criação aplicações standalone • Boot com embedded Java container • Indicado para criação de micro-serviços • Fornece várias funcionalidades por padrão • Utiliza o conceito de configuração por “defaults” • Ótima integração com toda plataforma Spring • Spring MVC, Spring Data, Spring Security, … • Suporta empacotamento JAR ou WAR
  • 7.
    Spring Boot • Oque NÃO é: • Plugins para IDE • Você pode utilizar Spring Boot com qualquer IDE • Ferramenta para geração de código • Um novo container Java EE • Arquitetura “ready” para Microservices
  • 8.
  • 9.
    Spring Boot (configuraçãoinicial) <project> <!-- Inherit defaults from Spring Boot --> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.3.RELEASE</version> </parent> <!-- Add typical dependencies for a web application --> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> <!-- Package as an executable jar --> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
  • 10.
    Spring Boot • Comorodar a aplicação? • IDE (Spring Tool Suite) • Import… -> Existing Maven Projects • Relaunch / Run • Maven plugin • mvn spring-boot:run • export MAVEN_OPTS=-Xmx1024m -XX:MaxPermSize=128M • Standalone “fat JAR” • java -jar target/myproject-0.0.1-SNAPSHOT.jar • java -Xdebug - Xrunjdwp:server=y,transport=dt_socket,address=8000,suspend=n -jar target/myproject-0.0.1-SNAPSHOT.jar
  • 11.
    Spring Boot (deployment) •Pode ser realizado via standalone “fat JAR”, ou por meio de um WAR web package • Suporta deployment em Java EE containers • Tomcat, Jetty, Wildfly, TomEE, Glassfish, Weblogic • Permite a configuração de “executable JARs” • Podem ser configurados como serviços UNIX / Linux / Windows • UNIX/Linux services via init.d ou systemd • Windows services via winsw • Compatível com diferentes PaaS Cloud providers • Cloud Foundry, Heroku, OpenShift, AWS, Boxfuse, Google App Engine
  • 12.
    Spring Boot (deployment) •Configuração para deployment via WAR em um container @SpringBootApplication public class Application extends SpringBootServletInitializer { @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { return application.sources(Application.class); } public static void main(String[] args) throws Exception { SpringApplication.run(Application.class, args); } } <project> <!-- ... --> <packaging>war</packaging> <!-- ... --> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <scope>provided</scope> </dependency> <!-- ... --> </dependencies> </project>
  • 13.
    Spring Boot (deployment) •Configurando JAR executável no ambiente UNIX • Fedora / CentOS • sudo ln -s /var/myapp/myapp.jar /etc/init.d/myapp • service myapp start • Debian • update-rc.d myapp defaults <priority> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <executable>true</executable> </configuration> </plugin>
  • 14.
    Spring Boot (containers) ContainerServlet Version Java Version Tomcat 8 3.1 Java 7+ Tomcat 7 3.0 Java 6+ Jetty 9.3 3.1 Java 8+ Jetty 9.2 3.1 Java 7+ Jetty 8 3.0 Java 6+ Undertow 1.3 3.1 Java 7+
  • 15.
  • 16.
    Laboratório 1 (boot-lab01) •Criando uma primeira aplicação com Spring Boot
  • 17.
    Spring Boot (starters) •spring-boot-starter-web • spring-boot-starter-data-jpa • spring-boot-starter-data-rest • spring-boot-starter-jdbc • spring-boot-starter-websocket • spring-boot-starter-cache • spring-boot-starter-batch • spring-boot-starter-hateoas • spring-boot-starter-test • spring-boot-starter-integration • spring-boot-starter-validation • spring-boot-starter-mobile…
  • 18.
    Spring Boot (auto-configuration) •AopAutoConfiguration • JpaRepositoriesAutoConfiguration • HibernateJpaAutoConfiguration • DataSourceAutoConfiguration • JmsTemplateAutoConfiguration • MongoAutoConfiguration • RedisAutoConfiguration • WebMvcAutoConfiguration • SecurityAutoConfiguration • …
  • 19.
    Spring Boot (configuration) •Permite que você externalize as configurações da aplicação em arquivos properties, YAML, variáveis de ambiente, argumentos de linha de comando • Oferece uma lista bastante extensa de possíveis configurações • https://docs.spring.io/spring-boot/docs/current/reference/html/common-application- properties.html • Propriedades podem ser injetadas utilizando @Value ou acessadas via Spring Environment • Pode ser configurado também via @ConfigurationProperties • Podem ser ativadas e alternadas utilizando profiles de aplicação • application-{profile}.properties • Suporta o uso de expressões e oferece recursos como • Valores randômicos: ${random.long} • Referências internas: ${anotherproperty.value} • Variáveis de ambiente: ${VARIABLE}
  • 20.
    Spring Boot (configuration) •YAML file • Properties file spring: application: name: cruncher datasource: driverClassName: com.mysql.jdbc.Driver url: jdbc:mysql://localhost/test server: port: 9000 my: servers: - dev.bar.com - foo.bar.com spring.application.name=cruncher spring.datasource.driverClassName=com.mysql.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost/test server.port=9000 my.servers[0]=dev.bar.com my.servers[1]=foo.bar.com
  • 21.
    Spring Boot (configuration) email=test@email.com thread-pool=12 @Component publicclass GlobalProperties { @Value("${thread-pool}") private int threadPool; @Value("${email}") private String email; @Autowired private Environment env; public String getEmail() { return env.getProperty("email"); } public int getThreadPool() { return env.getProperty("thread-pool"); } //getters and setters } • Exemplo utilizando @Value e Spring Environment application.properties
  • 22.
    Spring Boot (configuration) @ConfigurationProperties( locations= "classpath:mail.properties", prefix = "mail") public class MailProperties { public static class Smtp { private boolean auth; private boolean starttlsEnable; // ... getters and setters } @NotBlank private String host; private int port; private String from; private String username; private String password; @NotNull private Smtp smtp; // ... getters and setters } mail.host=localhost mail.port=25 mail.smtp.auth=false mail.smtp.starttls-enable=false mail.from=me@localhost mail.username= mail.password= • Exemplo utilizando @ConfigurationProperties mail.properties
  • 23.
    Spring Boot (profiles) •Fornece uma maneira de segmentar a configuração da aplicação por diferentes ambientes de execução • Qualquer @Component, @Configuration por ser anotado com @Profile • Para sinalizar um profile, basta utilizar: • Propriedade: spring.profiles.active=dev • CLI: --spring.profiles.active=dev • JVM: -Dspring.profiles.active=dev • Java: SpringApplication.setAdditionalProfiles(…) • Podem ser sobrescritos e/ou combinados utilizando uma regra de maior prioridade • spring.profiles.active=default,dev
  • 24.
    Spring Boot (profiles) @Configuration @Profile("production") publicclass ProductionConfiguration { // ... } server: port: 9000 --- spring: profiles: development server: port: 9001 --- spring: profiles: production server: port: 0 @Configuration @Profile(“!production") public class NonProductionConfiguration { // ... } • Exemplo de utilização @Profile application.yml
  • 25.
    Spring Boot (logging) •Implementação interna via Commons Logging • Por padrão utiliza Logback, mas suporta outros providers, como Java Util Logging e Log4J • Pode habilitar o level por execução • java -jar myapp.jar --debug • Formato padrão do log utilizado • Date and Time, Log Level, Process ID, Thread Name, Logger Name, Log Message 2014-03-05 10:57:51.112 INFO 45469 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/7.0.52 2014-03-05 10:57:51.253 INFO 45469 --- [ost-startStop-1] o.a.c.c.C.[Tomcat]. [localhost].[/] : Initializing Spring embedded WebApplicationContext 2014-03-05 10:57:51.253 INFO 45469 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1358 ms 2014-03-05 10:57:51.698 INFO 45469 --- [ost-startStop-1] o.s.b.c.e.ServletRegistrationBean : Mapping servlet: 'dispatcherServlet' to [/] 2014-03-05 10:57:51.702 INFO 45469 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
  • 26.
    Spring Boot (logging) •Configuração customizada de níveis de log logging.level.root=WARN logging.level.org.springframework.web=DEBUG logging.level.org.hibernate=ERROR application.properties @Component public class Service { private final Logger logger = LoggerFactory.getLogger(this.getClass()); public void doSomething(String param) { try { logger.debug("Trying to do something using param {}", param); // process something } catch (Exception ex) { logger.error("Error to do something", ex); } } // other methods }
  • 27.
    Spring Boot (actuator) •Ajuda gerenciar e monitorar as aplicações em produção • Acessível via HTTP, JMX ou remote shell • Fornece uma lista de endpoints para gerenciar Spring Boot app • Publica as propriedades e Spring Beans em formato JSON view <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> </dependencies>
  • 28.
    Spring Boot (actuator) •/info • Informação da aplicação • /health • Status da aplicação (UP/DOWN) • /beans • Lista de Spring Beans na aplicação • /env • Propriedades externas configuradas • /dump • Realiza um thread dump • /metrics • Métricas da aplicação corrente (número de requests, consumo memória, etc) • /mappings • Lista de todos os @RequestMapping’s da aplicação • /trace • Demonstra o trace dos últimos 100 requests • /autoconfig • Relatório de auto-configuração da aplicação • /shutdown • Realiza o shutdown da aplicação (não ativado por padrão)
  • 29.
    Spring Boot (actuator) •Customizando health indicator @Component public class MyHealthIndicator implements HealthIndicator { @Override public Health health() { int errorCode = check(); // perform some specific health check if (errorCode != 0) { return Health.down().withDetail( "Error Code", errorCode).build(); } return Health.up().build(); } }
  • 30.
    Spring Boot (devtools) • Conjunto de ferramentas para facilitar o processo de desenvolvimento e deployment das apps • Principais funcionalidades • Property defaults • Automatic restart • Live reload • Global settings • Remote applications <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> </dependency> </dependencies>
  • 31.
    Laboratório 2 (boot-lab02) •Explorando os recursos do Spring Boot
  • 32.
    Spring Boot (testing) •Fornece diversos utilitários e implementações para implementação de testes unitários • Habilitado via spring-boot-starter-test • Módulos spring-boot-test (core), spring-boot-test- autoconfigure (auto-configuração) • Dependências • JUnit - Biblioteca de unit testing em Java • Spring Test - Utilitários para testes integração com Spring Boot • AssertJ - Biblioteca para fluent assertion • Hamcrest - Biblioteca para matcher objects (constraints / predicates) • Mockito - Mock objects framework • JSONassert - Biblioteca para JSON assertion • JsonPath - Biblioteca para XPath para JOSN
  • 33.
    Spring Boot (testing) •Habilitado utilizando a anotação @SpringBootTest e via JUnit SpringRunner • Simula um webEnvironment que pode configurado como: • MOCK, RANDON_PORT, DEFINED_PORT, NONE @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) @Import(MyTestsConfiguration.class) public class MyTests { @Test public void exampleTest() { ... } }
  • 34.
    Spring Boot (testing) •Suporta a utilização de Mock objects via Mockito • Basta injetar objetos com uso da anotação @MockBean @RunWith(SpringRunner.class) @SpringBootTest public class MyTests { @MockBean private RemoteService remoteService; @Autowired private Reverser reverser; @Test public void exampleTest() { // RemoteService has been injected into the reverser bean given(this.remoteService.someCall()).willReturn("mock"); String reverse = reverser.reverseSomeCall(); assertThat(reverse).isEqualTo("kcom"); } }
  • 35.
    Spring Boot (testing) •Oferece uma boa alternativa para testar conteúdo JSON por meio da anotação @JsonTest • Utiliza por padrão Jackson como parser, mas pode ser configurado para suportar Gson @RunWith(SpringRunner.class) @JsonTest public class MyJsonTests { @Autowired private JacksonTester<VehicleDetails> json; @Test public void testSerialize() throws Exception { VehicleDetails details = new VehicleDetails("Honda", "Civic"); // Assert against a `.json` file in the same package as the test assertThat(this.json.write(details)).isEqualToJson("expected.json"); // Or use JSON path based assertions assertThat(this.json.write(details)).hasJsonPathStringValue("@.make"); assertThat(this.json.write(details)).extractingJsonPathStringValue("@.make") .isEqualTo("Honda"); } }
  • 36.
    Laboratório 3 (boot-lab03) •Testando uma aplicação Spring Boot
  • 37.
    Spring MVC • WebMVC action framework suportado pelo Spring Boot • Utilizado para implementação de aplicações Web content e também para REST APIs
  • 38.
    Spring MVC • DispatcherServlet •Implementação do design pattern FrontController • Recebe todas as requisições e delega para os controllers respectivos • Utiliza ViewResolver para resolver qual a tela deverá ser retornada
  • 39.
    Spring MVC (controller) •@Controller é o componente principal do Spring MVC • Define os server endpoints da aplicação Web • Aplicações REST pode ser utilizado @RestController @Controller public class GreetingController { @RequestMapping("/greeting") public String greeting( @RequestParam(required=false) String name, Model model) { model.addAttribute("name", name); return "greeting"; } }
  • 40.
    Spring MVC (annotations) •@RequestMapping • Define os server endpoints à serem processados pela aplicação @Controller @RequestMapping("/appointments") public class AppointmentsController { @Autowired AppointmentBook appointmentBook; @RequestMapping(method = RequestMethod.GET) public Map<String, Appointment> get() { return appointmentBook.getAppointmentsForToday(); } @RequestMapping(method = RequestMethod.POST) public String add(@Valid AppointmentForm appointment, BindingResult result) { if (result.hasErrors()) { return "appointments/new"; } appointmentBook.addAppointment(appointment); return "redirect:/appointments"; } }
  • 41.
    Spring MVC (annotations) •RequestMapping possui variações para melhor suportar as operações HTTP • @GetMapping, @PostMapping, @PutMapping @DeleteMapping, @PatchMapping @Controller @RequestMapping("/appointments") public class AppointmentsController { @Autowired AppointmentBook appointmentBook; @GetMapping public Map<String, Appointment> get() { return appointmentBook.getAppointmentsForToday(); } @PostMapping public String add(@Valid AppointmentForm appointment, BindingResult result) { if (result.hasErrors()) { return "appointments/new"; } appointmentBook.addAppointment(appointment); return "redirect:/appointments"; } }
  • 42.
    Spring MVC (annotations) •@RequestParam • Recuperação de um parâmetro da requisição • @RequestBody • Define o acesso para o conteúdo do corpo da requisição (ex: JSON, XML, etc) • @ResponseBody • Define o retorno do conteúdo como corpo da resposta (ex; JSON, XML, etc) • @PathVariable • Recuperação de um atributo como parte do path da requisição • @ModelAttribute • Recuperação de um grupo de atributos submetidos na requisição • @SessionAttribute • Referência e/ou recuperação de um atributo da sessão (HttpSession) • @RequestAttribute • Referência e/ou recuperação de um atributo da requisição • @CookieValue • Recuperação de um cookie na requisição • @RequestHeader • Recuperação de um cabeçalho da requisição
  • 43.
    Spring MVC (annotations) @Controller publicclass PetController { @PostMapping(path = "/pets", consumes=“application/json”, produces="application/json") @ResponseBody public Pet addPet(@RequestBody Pet pet, Model model) {...} @GetMapping(path = "/pets/setup") public String setupForm(@RequestParam("petId") int petId, ModelMap model) {} @PostMapping(path = "/owners/{ownerId}/pets/{petId}/edit") public String processSubmit(@ModelAttribute("pet") Pet pet, BindingResult result) {...} @GetMapping(path = "/display/cookie") public void displayCookie(@CookieValue("JSESSIONID") String cookie) {...} @GetMapping(path = "/display/header") public void displayHeader(@RequestHeader("Accept-Encoding") String encoding, @RequestHeader("Keep-Alive") long keepAlive) {...} @GetMapping(path = "/user") public String handleUser(@SessionAttribute User user) {...} } • Exemplos de utilização das anotações
  • 44.
    Spring MVC (errorhandling) • Spring Boot oferece /error endpoint como página global de erros, para tratar erros de maneira geral • Oferece implementação de tratadores de execução customizados via @ExceptionHandler • Pode ser utilizado como método do @Controller ou por via @ControllerAdvice @Controller public class SimpleController { // @RequestMapping methods omitted ... @ExceptionHandler(IOException.class) @ResponseBody public ResponseEntity<String> handleIOException(IOException ex) { // prepare responseEntity return responseEntity; } }
  • 45.
    Spring MVC (errorhandling) • Páginas de erros podem ser customizadas de maneira estática ou utilizando templates src/ +- main/ +- java/ | + <source code> +- resources/ +- public/ +- error/ | +- 404.html +- <other public assets> src/ +- main/ +- java/ | + <source code> +- resources/ +- templates/ +- error/ | +- 5xx.ftl +- <other templates>
  • 46.
    Spring MVC (staticcontent) • Por padrão Spring Boot irá buscar conteúdo estático nos seguintes diretórios • /static, /public, /resources ou /META-INF/resources • A partir do diretório /src/main/resources (Maven) • Não utilize o diretório /src/main/webapp • Funciona apenas para empacotamento WAR • Fornece LiveReload para browser refresh automático • Apenas quando DevTools está habilitado no Spring Boot • Suporta a utilização de WebJars • http://www.webjars.org/
  • 47.
    Spring MVC (viewtemplates) • Suporta uma variedade de ferramentas de view templates para processamento conteúdo Web dinâmico • FreeMaker • Groovy • Thymeleaf • Mustache • JSP • Os templates serão buscados a partir do diretório template na aplicação Spring Boot • /src/main/resources/templates
  • 48.
    Spring MVC (CORS) •Pode ser customizado via configuração customizada @Configuration public class MyConfiguration { @Bean public WebMvcConfigurer corsConfigurer() { return new WebMvcConfigurerAdapter() { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/api/**") .allowedOrigins("http://domain2.com") .allowedMethods("PUT", "DELETE") .allowedHeaders("header1", "header2") .exposedHeaders("header1", "header2") .allowCredentials(false).maxAge(3600); } }; } }
  • 49.
    Spring MVC (CORS) •Fornece a anotação @CrossOrigin para ser utilizada diretamente nos controllers @Controller @RequestMapping("/account") public class AccountController { @CrossOrigin @RequestMapping("/{id}") public Account retrieve(@PathVariable Long id) { // ... } @RequestMapping(method = RequestMethod.DELETE, path = "/{id}") public void remove(@PathVariable Long id) { // ... } } @CrossOrigin(origins = "http://domain2.com", maxAge = 3600) @Controller @RequestMapping("/account") public class AccountController {...}
  • 50.
    Spring MVC (testing) •Oferece uma customização especial para testes utilizando a anotação @WebMvcTest • Possui integração com frameworks de teste funcional (HtmlUnit, Selenium) @RunWith(SpringRunner.class) @WebMvcTest(UserVehicleController.class) public class MyControllerTests { @Autowired MockMvc mvc; @MockBean UserVehicleService userVehicleService; @Test public void testExample() throws Exception { given(this.userVehicleService.getVehicleDetails("sboot")) .willReturn(new VehicleDetails("Honda", “Civic")); this.mvc.perform(get("/sboot/vehicle") .accept(MediaType.TEXT_PLAIN)) .andExpect(status().isOk()) .andExpect(content().string("Honda Civic")); } }
  • 51.
    Laboratório 4 (boot-lab04) •Desenvolvimento Web com Spring MVC
  • 52.
  • 53.
  • 54.
    Arquitetura REST • ︎Protocolocliente/servidor sem estado (HTTP) • ︎Operações bem definidas • GET • POST • PUT • DELETE, etc • ︎Sintaxe universal para identificação de recursos (URL) • ︎Transferência de informações em formato padrão (XML, HTML, JSON)
  • 55.
  • 56.
  • 57.
    Spring REST • @RestController •Define uma anotação específica para controllers REST @RestController @RequestMapping(value="/users") public class MyRestController { @RequestMapping(value="/{user}", method=RequestMethod.GET) public User getUser(@PathVariable Long user) { // ... } @RequestMapping(value="/{user}/customers", method=RequestMethod.GET) List<Customer> getUserCustomers(@PathVariable Long user) { // ... } @RequestMapping(value="/{user}", method=RequestMethod.DELETE) public User deleteUser(@PathVariable Long user) { // ... } }
  • 58.
    Spring REST • Forneceflexibilidade para configuração na negociação de conteúdo @Configuration public class WebConfig extends WebMvcConfigurerAdapter { @Override public void configureContentNegotiation(ContentNegotiationConfigurer configurer) { configurer.favorPathExtension(false). favorParameter(true). parameterName("mediaType"). ignoreAcceptHeader(true). useJaf(false). defaultContentType(MediaType.APPLICATION_JSON). mediaType("xml", MediaType.APPLICATION_XML). mediaType("json", MediaType.APPLICATION_JSON); } } curl http://localhost:8080/spring-mvc-java/employee/10?mediaType=[json/xml] <employee> <contactNumber>999-999-9999</contactNumber> <id>10</id> <name>Test Employee</name> </employee> { "id": 10, "name": "Test Employee", "contactNumber": "999-999-9999" }
  • 59.
    Spring REST • Unittesting é implementado utilizando @WebMvcTest @RunWith(SpringRunner.class) @WebMvcTest(GreentingController.class) public class GreetingControllerTests { @Autowired private MockMvc mvc; @Test public void givenGreetURIWithQueryParameter() { this.mockMvc.perform(get("/greetWithQueryVariable") .param("name", "John Doe")).andDo(print()).andExpect(status().isOk()) .andExpect(content().contentType("application/json;charset=UTF-8")) .andExpect(jsonPath("$.message").value("Hello World John Doe!!!")); } @Test public void givenGreetURIWithPost() { this.mockMvc.perform(post("/greetWithPost")).andDo(print()) .andExpect(status().isOk()).andExpect(content() .contentType("application/json;charset=UTF-8")) .andExpect(jsonPath("$.message").value("Hello World!!!")); } }
  • 60.
    Spring REST • Épossível utilizar especificação JAX-RS na implementação dos REST endpoints • Basta incluir a dependência spring-boot-starter-jersey • Implementado via Jersey 2.x • Para cada REST endpoint é necessário defini-los como um bean gerenciado pelo Spring • Configurado com a anotação @Component @Component public class JerseyConfig extends ResourceConfig { public JerseyConfig() { register(Endpoint.class); } } @Component @Path("/hello") public class Endpoint { @GET public String message() { return "Hello"; } }
  • 61.
    HATEOAS • Hypermedia AsThe Engine of Application State • Descrevem o estado atual da aplicação e como navegar para o próximo estado
  • 62.
  • 63.
    Spring HATEOAS • Adicionasuporte HATEOAS para REST endpoints • Basta incluir a dependência spring-boot-starter-hateoas • Definida pelos componentes Links e Resources Link link = new Link("http://localhost:8080/something"); assertThat(link.getHref(), is("http://localhost:8080/something")); assertThat(link.getRel(), is(Link.SELF)); class PersonResource extends ResourceSupport { String firstname; String lastname; } PersonResource resource = new PersonResource(); resource.firstname = "Dave"; resource.lastname = "Matthews"; resource.add(new Link("http://myhost/people")); { firstname : "Dave", lastname : "Matthews", links : [ { rel : "self", href : "http://myhost/people" } ] }
  • 64.
    Spring HATEOAS public classGreeting { String name; // getters and setters } public class GreetingResource extends Resource<Greeting> { public GreetingResource(Greeting greeting, Link... links) { super(greeting, links); } } public class GreetingResourceAssembler extends ResourceAssemblerSupport<Greeting, GreetingResource> { public GreetingResourceAssembler() { super(Greeting.class, GreetingResource.class); } @Override public GreetingResource toResource(Aluno aluno) { return new GreetingResource(aluno, linkTo(methodOn(GreetingController.class).get(greeting.getName())).withSelfRel()); } @Override protected GreetingResource instantiateResource(Greeting aluno) { return new GreetingResource(greeting); } }
  • 65.
    Spring HATEOAS @RestController public classGreetingController { GreetingResourceAssembler assembler = new GreetingResourceAssembler(); @RequestMapping("/greeting") public ResponseEntity<GreetingResource> greeting( @RequestParam(value = "name", required = false) String name) { Greeting greeting = new Greeting("Hello, " + name); return new ResponseEntity<>(assembler.toResource(greeting), HttpStatus.OK); } } { "content":"Hello, User!", "_links":{ "self":{ "href":"http://localhost:8080/greeting?name=User" } } } curl http://localhost:8080/greeting?name=User
  • 66.
    Swagger • Alternativa paradocumentação da REST API • Possui ótima integração com Spring Boot • SpringFox - https://springfox.github.io/springfox/ • Oferece uma ferramenta para navegação Web • Swagger UI - http://swagger.io/swagger-ui/ • Possui também uma ferramenta para modelagem da API • Swagger Editor - http://swagger.io/swagger-editor/
  • 67.
    Swagger (spring boot) •Basta adicionar as dependências Maven • springfox-swagger-ui e springfox-swagger2 • Habilitar suporte Swagger na aplicação via @EnableSwagger2 • Documentar os REST controllers utilizando anotações • @ApiOperation • Documentação de um REST endpoint • @ApiParam, @ApiImplicitParam • Documentação dos parâmetros do REST endpoint • @ApiResponse • Documentação da resposta do REST endpoint • @ApiModel, @ApiModelProperty • Documentação do modelo de dados de resposta do REST endpoint • @Authorization • Documentação do modelo de autorização do REST endpoint • @ResponseHeader • Documentação dos headers de resposta do REST endpoint
  • 68.
    Swagger (spring boot) @Configuration @EnableSwagger2 publicclass SwaggerConfig { @Bean public Docket api() { return new Docket(DocumentationType.SWAGGER_2) .select() .apis(RequestHandlerSelectors.any()) .paths(PathSelectors.any()) .build(); } } <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.6.1</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.6.1</version> </dependency> • Exemplo de integração Swagger com Spring Boot
  • 69.
    Swagger (spring boot) @RestController publicclass GreetingController { @ApiOperation(value = "getGreeting", nickname = "getGreeting") @RequestMapping(method = RequestMethod.GET, path="/greeting", produces = "application/json") @ApiImplicitParams({ @ApiImplicitParam(name = "name", value = "User's name", required = false, dataType = "string", paramType = "query") }) @ApiResponses(value = { @ApiResponse(code = 200, message = "Success", response = Greeting.class), @ApiResponse(code = 401, message = "Unauthorized"), @ApiResponse(code = 403, message = "Forbidden"), @ApiResponse(code = 404, message = "Not Found"), @ApiResponse(code = 500, message = "Failure")}) public Greeting greeting(@RequestParam(value="name") String name) { return new Greeting(new AtomicLong().incrementAndGet(), String.format("Hello, %s!", name)); } } • Exemplo de documentação utilizando as anotações Swagger
  • 70.
  • 71.
    Laboratório 5 (boot-lab05) •Implementando RESTful com Spring Boot
  • 72.
    Spring Data • Abstraçãopara implementação de repositórios de persistência de dados integrada ao Spring Boot • Suporta diferentes modelos de persistência • JDBC, JPA, MongoDB, LDAP, Redis, Gemfire, Cassandra • DynamoDB, Couchbase, Solr, Elasticsearch, Neo4j,… • Implementa ações de CRUD em repositórios abstratos • Fornece queries dinâmicas criadas a partir nomes de métodos dos repositórios • Oferece flexibilidade para customização de repositórios • Suporta configurações de auditoria
  • 73.
  • 74.
  • 75.
    Spring Data public interfaceCrudRepository<T, ID extends Serializable> extends Repository<T, ID> { <S extends T> S save(S entity); T findOne(ID primaryKey); Iterable<T> findAll(); Long count(); void delete(T entity); boolean exists(ID primaryKey); } • Definição dos repositórios abstratos public interface PagingAndSortingRepository<T, ID extends Serializable> extends CrudRepository<T, ID> { Iterable<T> findAll(Sort sort); Page<T> findAll(Pageable pageable); } interface Repository<T, ID> extends Serializable> {}
  • 76.
    Spring Data public interfaceUserRepository extends PagingAndSortingRepository<User, Long> { // other methods } • Utilização dos repositórios abstratos @Component public class SomeClient { @Autowired private UserRepository repository; public void doSomething() { PagingAndSortingRepository<User, Long> repository = // … get access to a bean Page<User> users = repository.findAll(new PageRequest(1, 20)); } }
  • 77.
    Spring Data interface UserRepositoryCustom{ public void someCustomMethod(User user); } interface UserRepository extends CrudJpaRepository<User, Long>, UserRepositoryCustom { // Declare query methods here } • Implementação de repositórios “customizados" class UserRepositoryImpl implements UserRepositoryCustom { public void someCustomMethod(User user) { // Your custom implementation } }
  • 78.
    Spring Data • Mecanismode geração de consultas dinâmicas • Definição por DSL • Via nome dos métodos • Suporta diferentes variações • ByProperty • ByPropertyAsc • ByPropertyDesc • ByProp1AndProp2 • ByProp1OrProp2 • ByPropertyContaining • …
  • 79.
    Spring Data (queries) •Definição das consultas dinâmicas public interface PersonRepository extends Repository<User, Long> { List<Person> findByEmailAddressAndLastname(EmailAddress emailAddress, String lastname); // Enables the distinct flag for the query List<Person> findDistinctPeopleByLastnameOrFirstname(String lastname, String firstname); List<Person> findPeopleDistinctByLastnameOrFirstname(String lastname, String firstname); // Enabling ignoring case for an individual property List<Person> findByLastnameIgnoreCase(String lastname); // Enabling ignoring case for all suitable properties List<Person> findByLastnameAndFirstnameAllIgnoreCase(String lastname, String firstname); // Enabling static ORDER BY for a query List<Person> findByLastnameOrderByFirstnameAsc(String lastname); List<Person> findByLastnameOrderByFirstnameDesc(String lastname); }
  • 80.
    Spring Data (queries) Logicalkeyword Keyword expressions AND And OR Or AFTER After, IsAfter BEFORE Before, IsBefore CONTAINING Containing, IsContaining, Contains BETWEEN Between, IsBetween ENDING_WITH EndingWith, IsEndingWith, EndsWith EXISTS Exists FALSE False, IsFalse GREATER_THAN GreaterThan, IsGreaterThan GREATER_THAN_EQUALS GreaterThanEqual, IsGreaterThanEqual IN In, IsIn IS Is, Equals, (or no keyword) IS_NOT_NULL NotNull, IsNotNull
  • 81.
    Spring Data (queries) Logicalkeyword Keyword expressions IS_NULL Null, IsNull LESS_THAN LessThan, IsLessThan LESS_THAN_EQUAL LessThanEqual, IsLessThanEqual LIKE Like, IsLike NEAR Near, IsNear NOT Not, IsNot NOT_IN NotIn, IsNotIn NOT_LIKE NotLike, IsNotLike REGEX Regex, MatchesRegex, Matches STARTING_WITH StartingWith, IsStartingWith, StartsWith TRUE True, IsTrue WITHIN Within, IsWithin
  • 82.
    Spring Data (queries) •Limitação nos resultados de consulta public interface PersonRepository extends Repository<User, Long> { User findFirstByOrderByLastnameAsc(); User findTopByOrderByAgeDesc(); Page<User> queryFirst10ByLastname(String lastname, Pageable pageable); Slice<User> findTop3ByLastname(String lastname, Pageable pageable); List<User> findFirst10ByLastname(String lastname, Sort sort); List<User> findTop10ByLastname(String lastname, Pageable pageable); }
  • 83.
    Spring Data JPA •Oferece suporte à JPA • Basta adicionar a dependência • spring-boot-starter-data-jpa • Habilitar por padrão Hibernate como JPA provider • Oferece integração QueryDSL • Suporte à paginação, execução dinâmica de consultas, integração com repositórios customizados, etc
  • 84.
  • 85.
    Spring Data JPA publicinterface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> { List<T> findAll(); List<T> findAll(Sort sort); List<T> findAllById(Iterable<ID> ids); <S extends T> List<S> saveAll(Iterable<S> entities); void flush(); <S extends T> S saveAndFlush(S entity); void deleteInBatch(Iterable<T> entities); void deleteAllInBatch(); T getOne(ID id); } • Definição do repositório JPA abstrato
  • 86.
    Spring Data JPA @Entity publicclass User { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; @Column(name = "username") private String name; private String password; @OneToOne private Person person; // getters and setters } public interface UserRepository extends JpaRepository<User, Long> { User findByName(String name); List<User> findByNameContaining(String name); } • JPA Entity e repositório Spring Data JPA
  • 87.
    Spring Data JPA KeywordSample JPQL snippet And findByLastnameAndFirstnam e … where x.lastname = ?1 and x.firstname = ?2 Or findByLastnameOrFirstname … where x.lastname = ?1 or x.firstname = ?2 Is,Equals findByFirstname … where x.firstname = ?1 Between findByStartDateBetween … where x.startDate between ?1 and ?2 LessThan findByAgeLessThan … where x.age < ?1 LessThanEqual findByAgeLessThanEqual … where x.age <= ?1 GreaterThan findByAgeGreaterThan … where x.age > ?1 GreaterThanEqual findByAgeGreaterThanEqual … where x.age >= ?1 After findByStartDateAfter … where x.startDate > ?1
  • 88.
    Spring Data JPA @Entity @NamedQuery(name= "User.findByEmailAddress", query = "select u from User u where u.emailAddress = ?1") public class User { // Implementation } public interface UserRepository extends JpaRepository<User, Long> { List<User> findByLastname(String lastname); User findByEmailAddress(String emailAddress); } • Utilizando @NamedQuery's
  • 89.
    Spring Data JPA publicinterface UserRepository extends JpaRepository<User, Long> { // JP-QL sample @Query("select u from User u where u.emailAddress = ?1") User findByEmailAddress(String emailAddress); // JP-QL with named parameters @Query("select u from User u where u.firstname = :firstname or u.lastname = :lastname") User findByLastnameOrFirstname(@Param("lastname") String lastname, @Param("firstname") String firstname); // Native SQL query @Query(value = "SELECT * FROM USERS WHERE EMAIL_ADDRESS = ?1", nativeQuery = true) User findByEmailAddress(String emailAddress) // Native SQL query for paging @Query(value = "SELECT * FROM USERS WHERE LASTNAME = ?1", countQuery = "SELECT count(*) FROM USERS WHERE LASTNAME = ?1", nativeQuery = true) Page<User> findByLastname(String lastname, Pageable pageable); } • Utilizando @Query’s customizadas
  • 90.
    Spring Data JPA publicinterface UserRepository extends JpaRepository<User, Long> { // JP-QL sample with ordering @Query("select u from User u where u.lastname like ?1%") List<User> findByAndSort(String lastname, Sort sort); // Delete query sample @Modifying @Query("delete from User u where user.role.id = ?1") void deleteInBulkByRoleId(long roleId); // Update query sample @Modifying @Query("update User u set u.firstname = ?1 where u.lastname = ?2") int setFixedFirstnameFor(String firstname, String lastname); // Using query hints @QueryHints(value = { @QueryHint(name = "name", value = "value")}, forCounting = false) Page<User> findByLastname(String lastname, Pageable pageable); } • Utilizando @Query’s customizadas
  • 91.
    Spring Data JPA •Executando Stored Procedures /; DROP procedure IF EXISTS plus1inout /; CREATE procedure plus1inout (IN arg int, OUT res int) BEGIN ATOMIC set res = arg + 1; END /; @Entity @NamedStoredProcedureQuery(name = "User.plus1", procedureName = "plus1inout", parameters = { @StoredProcedureParameter(mode = ParameterMode.IN, name = "arg", type = Integer.class), @StoredProcedureParameter(mode = ParameterMode.OUT, name = "res", type = Integer.class) }) public class User {} public interface UserRepository extends JpaRepository<User, Long> { @Procedure("plus1inout") Integer explicitlyNamedPlus1inout(Integer arg); @Procedure(name = "User.plus1IO") Integer entityAnnotatedCustomNamedProcedurePlus1IO(@Param("arg") Integer arg); }
  • 92.
    Spring Data JPA(specification) public class CustomerSpecs { public static Specification<Customer> isLongTermCustomer() { return new Specification<Customer>() { public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder builder) { LocalDate date = new LocalDate().minusYears(2); return builder.lessThan(root.get(_Customer.createdAt), date); } }; } } public interface CustomerRepository extends JpaRepository<Customer, Long>, JpaSpecificationExecutor<Customer> {...} public interface Specification<T> { Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder builder); } List<Customer> customers = customerRepository.findAll(isLongTermCustomer());
  • 93.
    Spring Data JPA(query by example) public interface QueryByExampleExecutor<T> { <S extends T> S findOne(Example<S> example); <S extends T> Iterable<S> findAll(Example<S> example); // … more functionality omitted. } public class PersonService { @Autowired PersonRepository personRepository; public List<Person> findPeople(Person probe) { return personRepository.findAll(Example.of(probe)); } } public interface PersonRepository extends JpaRepository<Person, String> { … } Person person = new Person(); person.setFirstname("Dave"); ExampleMatcher matcher = ExampleMatcher.matching() .withIgnorePaths("lastname") .withIncludeNullValues() .withStringMatcherEnding(); Example<Person> example = Example.of(person, matcher);
  • 94.
    Spring Data JPA(transactional) public interface UserRepository extends JpaRepository<User, Long> { // Transaction support @Transactional(timeout = 10) public List<User> findAll(); } @Service class UserManagementImpl implements UserManagement { @Autowired UserRepository userRepository; @Autowired RoleRepository roleRepository; @Transactional public void addRoleToAllUsers(String roleName) { // Step 1 Role role = roleRepository.findByName(roleName); // Step 2 for (User user : userRepository.findAll()) { user.addRole(role); userRepository.save(user); } } • Suporte transacional
  • 95.
    Spring Data JPA(auditing) class Customer { @CreatedBy private User user; @CreatedDate private DateTime createdDate; // … further properties omitted } • Controle de auditoria class SpringSecurityAuditorAware implements AuditorAware<User> { public User getCurrentAuditor() { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if (authentication == null || !authentication.isAuthenticated()) { return null; } return ((MyUserDetails) authentication.getPrincipal()).getUser(); } } @Configuration @EnableJpaAuditing class Config { @Bean public AuditorAware<AuditableUser> auditorProvider() { return new AuditorAwareImpl(); } }
  • 96.
    Spring Data JPA(testing) @RunWith(SpringRunner.class) @DataJpaTest public class UserRepositoryTests { @Autowired TestEntityManager entityManager; @Autowired UserRepository repository; @Test public void findByUsernameShouldReturnUser() { this.entityManager.persist(new User("sboot", "123")); User user = this.repository.findByUsername("sboot"); assertThat(user.getUsername()).isEqualTo("sboot"); assertThat(user.getVin()).isEqualTo("123"); } } • Unit testing com @DataJpaTest e TestEntityManager
  • 97.
    Project Lombok • Ofereceanotações para substituir “boilerplate code” nos beans da aplicação • Fornece geração automática à diversas implementações • Getters/setters, Constructors, Equals/hashcode • ToString, Builder’s, Immutable classes, Synchronized,… • Implementação por meio de anotações • @Getter, @Setter, @EqualsAndHashCode, @ToString • @NoArgsConstructor, @RequiredArgsConstructor • @AllArgsContructor, @Data, @Builder, @Log • @Synchronized, @Value, @NonNull, @Cleanup
  • 98.
    Project Lombok • Bastaadicionar a dependência no projeto • Implementar os beans utilizando as anotações <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.16</version> </dependency> @Data @Builder @NoArgsConstructor @AllArgsConstructor @EqualsAndHashCode @ToString public class User implements Serializable { Long id; String name; String password; }
  • 99.
    Spring Boot (datasources) •Oferece suporte à diferentes RDBMS • MySQL, PostgreSQL, Oracle, SQLServer, H2, … • É necessário configurá-los via spring.datasource.* • Suporta diferentes tipos de definição para data sources • Hikari, Tomcat, C3P0, DBCP2, JNDI spring.datasource.url=jdbc:mysql://localhost/test spring.datasource.username=dbuser spring.datasource.password=dbpass spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.datasource.hikari.maximum-pool-size=5 spring.datasource.hikari.connection-timeout=10
  • 100.
    Spring Boot (H2) •Embedded in-memory RDBMS • Rápido, opensource e suporta 100% JDBC API • Small footprint (cerca 1.5 MB de tamanho) • Pode ser instalado como server, e persistência em arquivo • Ideal para utilização em testes de integração • Oferece uma aplicação Web para administração • Para habilitá-lo, basta adicionar a dependência <dependency> <groupId>org.hsqldb</groupId> <artifactId>hsqldb</artifactId> <scope>runtime</scope> </dependency>
  • 101.
    Spring Boot (H2) •Para habilitar no Spring Boot, basta adicionar a dependência e habilitar interface Web, se desejado • spring.h2.console.enabled = true • http://boot/h2-console
  • 102.
    Laboratório 6 (boot-lab06) •Persistindo dados com Spring Data JPA
  • 103.
    MongoDB • NoSQL databaseorientado à documentos • Persistência de dados no formato JSON • Armazenamento em formato BSON (binary JSON) • Suporte à full indexação, auto sharding, map reduce, replicação e tolerância à falhas db.createCollection('contato') db.contato.insert({ name: 'Rodrigo', email: 'rodrigo@email.com', mensagem: 'Inserindo dados no MongoDB' }) db.contato.find() db.contato.update({name: 'Rodrigo'}, {$set: {email: 'rodrigo@new-email.com'}}) db.contato.remove({name: 'Rodrigo'}) db.contato.drop() db.dropDatabase()
  • 104.
    Spring Data MongoDB •Suporte à persistência dados no MongoDB via Spring • Basta adicionar a dependência no Spring Boot • spring-boot-starter-data-mongodb • Oferece helper classes para integração com MongoDB • MongoTemplate, MongoOperations • Anotações para mapeamento de entidades • @Id, @Document, @DBRef, @Indexed, • @CompoundIndex, @GeoSpatialIndexed, @Language • @TextIndexed, @Transient, @Value, @Field spring.data.mongodb.uri=mongodb://user:secret@mongo1.example.com:12345/test spring.data.mongodb.host=mongoserver spring.data.mongodb.port=27017
  • 105.
    Spring Data MongoDB •Definição de repositório abstrato MongoRepository public interface MongoRepository<T, ID extends Serializable> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> { @Override <S extends T> List<S> save(Iterable<S> entites); @Override List<T> findAll(); @Override List<T> findAll(Sort sort); <S extends T> S insert(S entity); <S extends T> List<S> insert(Iterable<S> entities); @Override <S extends T> List<S> findAll(Example<S> example); @Override <S extends T> List<S> findAll(Example<S> example, Sort sort); }
  • 106.
    Spring Data MongoDB @Document publicclass Person { @Id private String id; @Indexed private Integer ssn; private String firstName; @Indexed private String lastName; // getters and setters } public interface PersonRepository extends MongoRepository<Person, String> { List<Person> findByLastname(String lastname); Page<Person> findByFirstname(String firstname, Pageable pageable); Person findByShippingAddresses(Address address); Stream<Person> findAllBy(); } @Service public class PersonService { @Autowired PersonRepository repository; public void doSomething() { Page<Person> persons = repository.findAll( new PageRequest(1, 20)); // do something } }
  • 107.
    Spring Data MongoDB KeywordSample Logical result After findByBirthdateAfter(Date date) {"birthdate" : {"$gt" : date}} GreaterThan findByAgeGreaterThan(int age) {"age" : {"$gt" : age}} GreaterThanEqual findByAgeGreaterThanEqual(int age) {"age" : {"$gte" : age}} Before findByBirthdateBefore(Date date) {"birthdate" : {"$lt" : date}} LessThan findByAgeLessThan(int age) {"age" : {"$lt" : age}} LessThanEqual findByAgeLessThanEqual(int age) {"age" : {"$lte" : age}} Between findByAgeBetween(int from, int to) {"age" : {"$gt" : from, "$lt" : In findByAgeIn(Collection ages) {"age" : {"$in" : [ages… ]}} NotIn findByAgeNotIn(Collection ages) {"age" : {"$nin" : [ages… ]}} IsNotNull, findByFirstnameNotNull() {"firstname" : {"$ne" : null}} IsNull, Null findByFirstnameNull() {"firstname" : null}
  • 108.
    Spring Data MongoDB •Suporte à JSON based @Query’s public interface PersonRepository extends MongoRepository<Person, String> @Query("{ 'firstname' : ?0 }") List<Person> findByThePersonsFirstname(String firstname); @Query(value="{ 'firstname': ?0 }", fields="{ 'firstname' : 1, 'lastname' : 1}") List<Person> findByThePersonsFirstname(String firstname); @Query("{ 'lastname': ?#{[0]} }") List<Person> findByQueryWithExpression(String param0); @Query("{'id': ?#{ [0] ? {$exists :true} : [1] }}") List<Person> findByQueryWithExpressionAndNestedObject(boolean param0, String param1); }
  • 109.
    Spring Data MongoDB •Exemplo utilizando MongoTemplate object public class DomainRepositoryImpl implements DomainRepositoryCustom { @Autowired MongoTemplate mongoTemplate; @Override public int updateDomain(String domain, boolean displayAds) { Query query = new Query(Criteria.where("domain").is(domain)); Update update = new Update(); update.set("displayAds", displayAds); WriteResult result = mongoTemplate.updateFirst(query, update, Domain.class); if(result!=null) return result.getN(); else return 0; } }
  • 110.
    Laboratório 7 (boot-lab07) •Persistindo NoSQL com Spring Data MongoDB
  • 111.
    Spring Data REST •Publica Spring Data Repo como RESTful API’s • Expõe operações CRUD, consultas dinâmicas, paginação, relacionamentos,… • Incrementa o suporte HATEOAS • HAL, ALPS, JSON Schema, URI templates, etc • Permite • Suporta • JPA, MongoDB, GemFire, Neo4j, Solr, Cassandra • Demais estão por vir
  • 112.
  • 113.
    Spring Data REST $curl “http://localhost:8080/persons/1”
  • 114.
    Spring Data REST @CrossOrigin(origins= "http://domain2.com", methods = { RequestMethod.GET, RequestMethod.POST, RequestMethod.DELETE }, maxAge = 3600) @RepositoryRestResource(path = "people") interface PersonRepository extends CrudRepository<Person, Long> { @RestResource(path = "names") List<Person> findByName(String name); @RestResource(exported = false) Person findByEmail(String email); @Override @RestResource(exported = false) void delete(Person entity); } • Exemplo de customização dos REST endpoints
  • 115.
  • 116.
    HAL Browser • Utilitáriopara navegar nos REST endpoints gerados
  • 117.
    Laboratório 8 (boot-lab08) •Expondo os repositórios com Spring Data REST
  • 118.
    Spring Security • Soluçãode segurança para as aplicações Spring e/ou Java EE-based • Implementa os procedimentos autenticação e autorização • Suporta autenticação em diferentes tecnologias • HTTP BASIC, Digest, X.509, LDAP, Form-based, OpenID • CAS, HttpInvoker, JAAS, Kerberos… • Ótimo suporte aos protocolos OAuth2 e JWT • Configuração facilitada por meio de anotações • Oferece suporte à diferentes funcionalidades • Remember-me, Run-as, CSRF, CORS, Crypto, ACL
  • 119.
    Spring Security • Bastaadicionar a seguinte dependência no projeto • Por padrão será habilitado a segurança HTTP BASIC • Para acesso deve ser utilizando usuário user e a senha gerada dinamicamente • Caso queira customizar o usuário e senha, pode ser definido via properties <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> Using default security password: 12aa6b86-08a7-4894-b899-3b2ebb1de248 security.user.name=root security.user.password=t0ps3cr3t
  • 120.
    Spring Security • Épossível implementar uma tela de login customizada • src/main/resources/templates/login.html @Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests().anyRequest().authenticated() .and().formLogin().loginPage("/login").permitAll() .and().logout().permitAll(); } } <form th:action="@{/login}" method="post"> <div><label> User Name : <input type="text" name="username"/> </label></div> <div><label> Password: <input type="password" name="password"/> </label></div> <div><input type="submit" value="Sign In"/></div> </form>
  • 121.
    Spring Security • Autenticaçãopode ser configurada globalmente (In Memory) • Ou pode ser configurada via JDBC datasource @Configuration public class SecurityConfiguration extends WebSecurityConfigurerAdapter { @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() .withUser("barry").password("t0ps3cr3t").roles("USER"); } } @Configuration public class SecurityConfiguration extends WebSecurityConfigurerAdapter { @Autowired DataSource dataSource; @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth.jdbcAuthentication().dataSource(dataSource) .withDefaultSchema() .withUser("barry").password("t0ps3cr3t").roles("USER"); } }
  • 122.
    Spring Security • Autorizaçãopode ser configurada globalmente • Ou pode ser customizada via anotações @Secured, @PreAuthorize @Configuration public class ApplicationConfigurerAdapter extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.antMatcher("/foo/**") .authorizeRequests() .antMatchers("/foo/bar").hasRole("BAR") .antMatchers("/foo/spam").hasRole("SPAM") .anyRequest().isAuthenticated(); } } @SpringBootApplication @EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true) public class Application {...}
  • 123.
    Spring Security • Exemplosde uso das anotações @Secured, @PreAuthorize public interface BankService { @Secured("IS_AUTHENTICATED_ANONYMOUSLY") public Account readAccount(Long id); @Secured("ROLE_TELLER") public Account post(Account account, double amount); @PreAuthorize("isAnonymous()") public Account readAccount(Long id); @PreAuthorize("hasAuthority('ROLE_TELLER')") public Account post(Account account, double amount); @PreAuthorize("hasRole('ADMIN') AND hasRole('ROLE_TELLER')") public void deleteAccount(Long id); }
  • 124.
    Laboratório 9 (boot-lab09) •Habilitando segurança com Spring Boot
  • 125.
    Spring Batch • LightweightBatch framework para desenvolvimento de processos robustos com grande quantidade de dados • Não é um scheduler, mas pode ser integrado • Quartz, Spring Scheduler, Tivoli, CRON, Control-M • Oferece diversas funcionalidades • Logging/tracing, gerenciamento de transação, estatísticas, job restart, skip, particionamento, gestão de concorrência, gerenciamento de recursos (memória, cpu) • Forte integração com demais projetos Spring • Utilizado geralmente em use cases particulares • ETL, exportação/importação de dados, cálculos,…
  • 126.
    Spring Batch • Bastaadicionar a seguinte dependência no projeto • Para habilitar processamento batch na aplicação Spring Boot deve-ser utilizar @EnableBatchProcessing <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-batch</artifactId> </dependency> @SpringBootApplication @EnableBatchProcessing public class SpringBatchApplication { public static void main(String[] args) { SpringApplication.run(SpringBatchApplication.class, args); } }
  • 127.
    Spring Batch • Chunkvs. Tasklet • Implementam step dentro do job • Chunk • Encapsula padrão ETL • Single Reader, Processor e Writer • Executado por pedaços de dados (chunk) • Chunk output é escrito unitariamente • Tasklet • Promove a execução de um único e simples processo • Executado até o fim produzindo um código de retorno
  • 128.
  • 129.
    Spring Batch • ItemReader •ItemWriter • ItemProcessor public interface ItemReader<T> { T read() throws Exception, UnexpectedInputException, ParseException; } public interface ItemWriter<T> { void write(List<? extends T> items) throws Exception; } public interface ItemProcessor<I, O> { O process(I item) throws Exception; }
  • 130.
    Spring Batch • Exemplode configuração do job na aplicação @Configuration @EnableBatchProcessing public class BatchConfig { @Autowired JobBuilderFactory jobBuilderFactory; @Autowired StepBuilderFactory stepBuilderFactory; @Bean public Job job() { return jobBuilderFactory.get("job") .incrementer(new RunIdIncrementer()) .flow(step1()).end().build(); } @Bean public Step step1() { return stepBuilderFactory.get("step1").chunk(1) .reader(new Reader()) .processor(new Processor()) .writer(new Writer()).build(); } }
  • 131.
    Spring Batch • Exemplode execução job na aplicação @RestController public class JobLauncherController { @Autowired JobLauncher jobLauncher; @Autowired Job job; @RequestMapping("/launchjob") public String handle() throws Exception { Logger logger = LoggerFactory.getLogger(this.getClass()); try { JobParameters jobParameters = new JobParametersBuilder() .addLong("time", System.currentTimeMillis()) .toJobParameters(); jobLauncher.run(job, jobParameters); } catch (Exception e) { logger.info(e.getMessage()); } return "Done"; } }
  • 132.
    Spring Cache • Ofereceuma abstração para implementação de cache de dados nas aplicações Spring • Suporta diferente cache providers • Generic, JCache, EhCache, Hazelcast, Infinitspan, Couchbase, Redis, Caffeine, Guava, Simple • Possui integração com Spring Data e JPA • Ativação simples e fácil nas aplicações Spring Boot • Basta adicionar a dependência spring-boot-starter-cache • Ativar o sistema de cache com a anotação @EnableCaching • Utilizar os objetos CacheManager e Cache • Utilizar a anotação @Cachable
  • 133.
    Spring Cache • Exemplode implementação de cache na aplicação @SpringBootApplication @EnableCaching public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } @Component public class SimpleBookRepository implements BookRepository { @Override @Cacheable("books") public Book getByIsbn(String isbn) { simulateSlowService(); return new Book(isbn, "Some book"); } }
  • 134.
    Spring Messaging • Processamentomensagens assíncronas na aplicação Spring Boot • Suporta diferentes tipos de protocolos mensagens • JMS, AMQP, STOMP • Suporte também diferentes providers de mensagens • ActiveMQ, Artemis, RabbitMQ, Apache Kafka, … • Oferece anotações e propriedades customizadas para trabalhar com provedores de mensagens • @JmsListener, @RabbitListener, @KafkaListener • Basta adicionar a dependência desejada • spring-boot-starter-activemq • spring-boot-starter-amqp • spring-boot-starter-kafka
  • 135.
    Spring Messaging @SpringBootApplication @EnableRabbit public classMessagingApplication { @Bean public Queue fooQueue() { return new Queue("foo"); } } @Service public class CustomService { @RabbitListener(queues = "foo") public void process(@Payload String foo) { System.out.println(new Date() + ": " + foo); } } public class Sender { @Autowired RabbitTemplate rabbitTemplate; public void send() { this.rabbitTemplate.convertAndSend("foo", "hello"); } } • Exemplo de consumo e envio de mensagens RabbitMQ
  • 136.
    Spring Integration • Implementaçãode design patterns de integração (EIP) • Endpoint, Channel, Aggregator, Filter, Transformer, Bus,… • http://www.enterpriseintegrationpatterns.com/ • Oferece integração com diversos protocolos e sistemas • FTP, sFTP, Twitter, Web Services (SOAP/REST), MQTT • Feed, JMS, AMQP, Email, TCP/UDP, XMPP, WebSocket,… • Expões objetos via JMX para monitoramento • Para configurar, basta adicionar a dependência • spring-boot-starter-integration • Oferece anotações para facilitar a implementação • @MessagingGateway, @Gateway, @ServiceActivator, @MessageEndpoint, @InboundChannelAdapter, @OutboundChannelAdapter
  • 137.
    Spring Integration @SpringBootApplication public classApplication { @Bean @InboundChannelAdapter(value = "feedChannel", poller = @Poller(maxMessagesPerPoll = "100", fixedRate = "10000")) public MessageSource<SyndEntry> feedAdapter() throws MalformedURLException { return new FeedEntryMessageSource( new URL("http://feeds.abcnews.com/abcnews/topstories"), "feedAdapter"); } @MessageEndpoint public static class Endpoint { @ServiceActivator(inputChannel = "feedChannel") public void log(Message<SyndEntry> message) { SyndEntry payload = message.getPayload(); logger.info(payload.getPublishedDate() + " - " + payload.getTitle()); } } @Bean public MessageChannel feedChannel() { return new QueueChannel(500); } } • Exemplo de consumo de dados via feed RSS
  • 138.
    Spring WebSockets • Fornecesuporte ao protocolo WebSockets aos web containers auto-contidos • Tomcat, Jetty, Undertow • Suportado pelos protocolos STOMP e SockJS • http://stomp.github.io/stomp-specification-1.2.html • https://github.com/sockjs/sockjs-protocol • Integrado aos controllers Spring MVC • Para configurar na aplicação • Adicionar a configuração spring-boot-starter-websocket • Habilitar @EnableWebSocketMessageBroker
  • 139.
    Spring WebSockets • Exemplode configuração endpoint via WebSocket @Configuration @EnableWebSocketMessageBroker public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer { @Override public void configureMessageBroker(MessageBrokerRegistry config) { config.enableSimpleBroker("/topic"); config.setApplicationDestinationPrefixes("/app"); } @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/gs-guide-websocket").withSockJS(); } } @Controller public class GreetingController { @MessageMapping("/hello") @SendTo("/topic/greetings") public Greeting greeting(HelloMessage message) throws Exception { Thread.sleep(1000); // simulated delay return new Greeting("Hello, " + message.getName() + "!"); } }
  • 140.
    Spring WebSockets • Exemplode cliente WebSocket em Javascript function connect() { var socket = new SockJS('/gs-guide-websocket'); stompClient = Stomp.over(socket); stompClient.connect({}, function (frame) { setConnected(true); console.log('Connected: ' + frame); stompClient.subscribe('/topic/greetings', function (greeting) { showGreeting(JSON.parse(greeting.body).content); }); }); } function disconnect() { if (stompClient != null) { stompClient.disconnect(); } setConnected(false); console.log("Disconnected"); } function sendName() { stompClient.send("/app/hello", {}, JSON.stringify({'name': $("#name").val()})); }
  • 141.
    Laboratório 10 (boot-lab10) •Explorando recursos adicionais no Spring Boot
  • 142.
    Conclusões • Spring Bootfornece diversos utilitários e facilitadores para implementação com Microservices • Spring Data e Data REST são projetos que aceleram a implementação e exposição na camada de persistência como serviços REST • Spring Security tem um ótima infra-estrutura para lidar com requisitos de segurança em aplicações Web • Existem diversos outros projetos que podem ser incorporados no boot da aplicação Spring, como Batch, Cache, Messaging, Integration, WebSockets, etc • Enjoy it ;)
  • 143.
    Revisão Nessa unidade vocêteve a oportunidade de compreender como: • Implementar a primeira aplicação utilizando Spring Boot • Compreender as funcionalidades adicionais do Spring Boot • Compreender como implementar serviços REST utilizando Spring MVC • Implementar persistência de dados utilizando Spring Data • Expor os repositórios como serviços utilizando Spring Data REST • Implementar segurança utilizando Spring Security • Explorar os demais projetos do ecossistema Spring
  • 144.
    Referências • https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/ • https://github.com/eugenp/tutorials/tree/master/spring-mvc-java •http://www.restapitutorial.com/httpstatuscodes.html • https://spring.io/guides/tutorials/bookmarks/ • http://docs.spring.io/spring-hateoas/docs/current/reference/html/ • http://docs.spring.io/spring-data/jpa/docs/current/reference/html/ • https://docs.spring.io/spring-data/rest/docs/current/reference/html/ • https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/ • https://spring.io/guides/gs/securing-web/ • https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-messaging.html • https://spring.io/guides/gs/messaging-rabbitmq/ • http://docs.spring.io/spring-integration/reference/html/index.html • https://spring.io/guides/gs/integration/ • http://docs.spring.io/spring-batch/reference/html/index.html • https://spring.io/guides/gs/batch-processing/ • https://docs.spring.io/spring/docs/current/spring-framework-reference/html/cache.html • https://spring.io/guides/gs/caching/ • https://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html • https://spring.io/guides/gs/messaging-stomp-websocket/