Mostrando postagens com marcador Spring Boot. Mostrar todas as postagens
Mostrando postagens com marcador Spring Boot. Mostrar todas as postagens

domingo, 4 de agosto de 2024

Redis com Spring Boot

         O Redis é um banco de dados em memória para criar caches na aplicação, tornando o acesso a dado mais rápidos.

      Claro que não é simplesmente fazer cache de toda a aplicação, por isso é preciso entender como funciona o sistema. O cache é indicado para tabelas que tem bastante acesso e pouca alteração, diminuindo dessa forma o acesso desnecessário ao banco e ajudando na saúde da aplicação como um todo, pois desonerando o acesso ao banco com coisas que mudam pouco deixamos ele livre para responder a requisições mais importantes.

        Pra começarmos, precisamos adicionar a dependência no projeto:


<dependency>

<groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-data-redis</artifactId>

</dependency>

<dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-cache</artifactId>

</dependency>


    Uma vez adicionada a dependência, é preciso adicionar o endereço e a porta no arquivo application.properties:


spring.data.redis.host=127.0.0.1

spring.data.redis.port=6379


        É preciso também habilitar o Cache na aplicação, assim como é habilitado as requisições assíncronas, com o uso de anotação na classe principal:


@EnableCaching


        Agora o Redis está configurado para ser usado, o que falta é usar o Cache no projeto. Os métodos que desejamos que tenham seu resultado guardado no cache (geralmente estão nas classes de negócio - também chamadas de services - ou no DAO). Basta anotá-los com @Cacheable e dar um nome para esses dados na tabela de cache:


@Cacheable(value = "nome_da_tb_de_cache")


        E para atualizar os dados, fazendo o sistema ir buscar no banco? Podemos anotar os métodos de inserção, update e exclusão com @CacheEvict passando o nome da tabela de cache e se queremos limpar todos os registros:


@CacheEvict(value = "nome_da_tb_de_cache", allEntries = true)


     Isso vai limpar os dados. Também podemos definir um tempo de vida (TTL) para o cache no application.properties, o que dá a ele um tempo padrão de vida (o default é ficar pra sempre).


# TTL em milissegundos (10 minutos)

spring.cache.redis.time-to-live=600000  


        Existem outras formas que podem ser pesquisadas caso haja necessidade, como o tamanho do cache.









terça-feira, 30 de julho de 2024

Pool de conexões no Spring Boot

         Toda aplicação precisa de um pool de conexões para gerenciar o acesso ao banco de dados de forma eficiente. No Spring Boot é carregado um pool automaticamente, mas devemos configurar para o ambiente de produção de acordo com a necessidade.

        

        A configuração varia de acordo com cada aplicação, então é preciso testar e observar o comportamento da aplicação pra saber se mais conexões disponíveis são necessárias.


        Segue um exemplo de configurações de pool no Spring Boot:


spring.datasource.hikari.minimum-idle=25

spring.datasource.hikari.maximum-pool-size=50

spring.datasource.hikari.connectionTimeout=15000  

spring.datasource.hikari.idleTimeout=600000

spring.datasource.hikari.maxLifetime=1800000 



quinta-feira, 12 de agosto de 2021

Consumindo API Rest com Spring Boot usando a classe WebClient

           Nesse artigo vou mostrar como fazer um cliente para uma API Rest com Spring 5 usando a classe WebClient que é parte do novo WebFlux Framework. Esse cliente vai consumir uma API de Livros. Aproveitando o post, já vou criar esse cliente em uma classe de teste usando JUnit para mostrar o teste de APIs com ele. Mas a forma de uso aqui não se limita a testes.

         

Como o foco é a construção de um cliente para consumir uma API, vou omitir o código da API, trazendo só a construção do cliente. Então vamos ao código:

 

import java.util.List;

import org.junit.jupiter.api.Assertions

import org.junit.jupiter.api.BeforeAll;

import org.junit.jupiter.api.Test;

import org.springframework.core.ParameterizedTypeReference;

import org.springframework.http.HttpHeaders;

import org.springframework.http.HttpMethod;

import org.springframework.http.MediaType;

import org.springframework.web.reactive.function.client.WebClient;

import org.springframework.web.reactive.function.client.WebClient.Builder;

import org.springframework.web.reactive.function.client.WebClient.ResponseSpec;

 

import br.com.socialbooks.model.Livro;

import reactor.core.publisher.Mono;

 

class LivroControllerTest {

 

       @BeforeAll

       static void inserirLivro() {

             // configura uma requisição

             Builder builder = WebClient.builder();

             builder.baseUrl("http://localhost:8080");

 

             Livro livro = new Livro("Aprendendo Spring boot");

 

             // prepara o cliente

             WebClient client = builder.build();

             ResponseSpec response = client.method(HttpMethod.POST).uri("/livros").bodyValue(livro).retrieve();

 

             // recebendo o recurso salvo

             Mono<Livro> monoLivro = response.bodyToMono(Livro.class);

             livro = monoLivro.block();

       }

 

       @Test

       void testGetListaLivros() {

             // configura uma requisição

             Builder builder = WebClient.builder();

             builder.baseUrl("http://localhost:8080");

             builder.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);

 

             // prepara o client

             WebClient client = builder.build();

             ResponseSpec response = client.method(HttpMethod.GET).uri("/livros").retrieve();

 

             /*

              * recebe o Mono que executa de forma assíncrona. OBS: Para carregar uma lista

              * de objetos, é preciso usar o ParameterizedTypeReference.

              */

             Mono<List<Livro>> monoLivro = response.bodyToMono(new                  ParameterizedTypeReference<List<Livro>>() {

             });

 

             // como funciona de forma assincrona, usamos o block para forçar ele esperar a resposta.

             List<Livro> livros = monoLivro.block();

 

              Assert.assertTrue(livros.get(0).getTituloLivro().equals("Aprendendo Spring boot"));

 

       }

 

       @Test

       void testGetLivro() {

             // configura uma requisição

             Builder builder = WebClient.builder();

             builder.baseUrl("http://localhost:8080");

             builder.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);

 

             // prepara o client

             WebClient client = builder.build();

             ResponseSpec response =             client.method(HttpMethod.GET).uri("/livros/1").retrieve();


             // recebe o Mono que executa de forma assíncrona

             Mono<Livro> monoLivro = response.bodyToMono(Livro.class);

 

             // como funciona de forma assincrona, usamos o block para forçar ele esperar 

             // a resposta.

             Livro livro = monoLivro.block();

             Assert.assertTrue(livro.getTituloLivro().equals("Aprendendo Spring boot"));

       }

}

 

Pra esse artigo é só.


Esse artigo foi baseado estudos feitos em:

quinta-feira, 4 de junho de 2020

Configurando o Spring Security 5 com autenticação em memória

    Do Spring Security 4 para o 5 configurar um usuário e senha em memória não é mais tão simples, porém nesse link abaixo tem a configuração necessária para fazê-lo basicamente como antes:

https://spring.io/guides/gs/securing-web/

    Basicamente o que muda é a classe WebSecurityConfig que passa a retornar um Bean do tipo UserDetailsService ao invés de criarmos o método: 

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("danieloliveira").password("oliveira").roles("USER");
}

    Ficando assim:

import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

@Override
protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers("/h2-console/**").permitAll().anyRequest().authenticated().and()
            .httpBasic().and().csrf().disable();
}

@Bean
@Override
public UserDetailsService userDetailsService() {
     UserDetails user = User.withDefaultPasswordEncoder().username("seu_usuario").password("sua_senha")
        .roles("USER").build();

    return new InMemoryUserDetailsManager(user);
}

}

quinta-feira, 7 de abril de 2016

Garantindo o encoding UTF-8 em aplicações com o Spring Boot

       Uma das formas mais eficientes de tratar a questão de caracteres estranhos e setar o encoding UTF-8 é através de um Filtro que intercepta a requisição ao servidor e antes de qualquer coisa atribui o encoding na request, e faz o mesmo com o response. O Spring Boot tem um filter para isso e basta usarmos esse filter para garantir que a nossa aplicação irá tratar corretamente os dados.

       Ao criar um projeto usando o Spring Boot duas classes são criadas, uma o o nome ServletInitializer.java e outra com o nome-da-aplicaçãoApplication.java. Esta segunda classe, se o nome da minha aplicação fosse teste, seu nome seria então TesteApplication.java, que é o que vamos considerar para o exemplo.

        Esta classe é responsável por configurações do projeto antes feitas no arquivo web.xml, de forma que declarações de filtros, servlets e listeners são declarados nela.

         No momento da criação do projeto, ele é muito simples, veja o código:

@SpringBootApplication
public class CobrancaApplication {

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

O que precisa ser feito é adicionar o seguinte trecho de código:

@Bean
public Filter getCharacterEncodingFilter() {

    CharacterEncodingFilter encodingFilter = new encodingFilter();

    encodingFilter.setEncoding("UTF-8");
    encodingFilter.setForceEncoding(true);

    return encodingFilter;

}

Os pacotes relacionados a esse trecho de código são:

import javax.servlet.Filter;
import org.springframework.context.annotation.Bean;
import org.springframework.web.filter.CharacterEncodingFilter;


Pronto! Dessa forma  sua aplicação com o Spring Boot está livre dos caracteres estranhos...

quarta-feira, 6 de abril de 2016

Usando o Thymeleaf para mapear automaticamente recursos estáticos (Imagens, scripts, estilos CSS, etc...)

     O Thymeleaf é um substituto do JSP que tem total integração com o Spring, trabalhando com layouts e fazendo a integração das páginas XHTML, HTML5 e XML com o Java no lado servidor.

      Dito isto, para quem usa Spring MVC com Spring Boot precia adicionar as dependências no pom.xml  da seguinte forma:

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

         Quem não usa o Spring Boot deve colocar:

<dependency>
    <groupId>org.thymeleaf</groupId>
    <artifactId>thymeleaf</artifactId>
    <version>3.0.0.BETA02</version>
</dependency>
<dependency>
    <groupId>org.thymeleaf</groupId>
    <artifactId>thymeleaf-spring4</artifactId>
    <version>3.0.0.BETA02</version>
</dependency>

         E adicionar o seguinte namespace no layout principal e das páginas:

xmlns:th="http://www.thymeleaf.org"

Desta forma, já possível usar as TAGS do Thymeleaf nos arquivos XHTML, HTML5 e XML. Porém o foco desse post é o uso do Thymeleaf para encapsular a chamada de recursos estáticos como imagens, arquivos Javascript e CSS, etc., fazendo com que o Thymeleaf mapeie de forma dinâmica o caminho absoluto desses recursos. Isso é muito útil, principalmente para quem usa o Spring Boot com o Tomcat embutido, no desenvolvimento, porém vai fazer o deploy em um servidor de aplicação mais robusto ou mesmo em um Tomcat externo, pois o context-path (caminho do contexto) muda e causa vários transtornos.

Vou apresentar a maneira com e sem o Thymeleaf para percebermos a diferença. Primeiro vamos à maneira comum, sem o uso do Thymeleaf, onde nós somos responsáveis por mapear o caminho dos recursos:

<a class="btn btn-link link-panel" href="/carros">Carros</a>
<form class="form-horizontal" method="POST" action="/carro">
<script src="/js/jquery-2.2.2.min.js"></script>
<link rel="stylesheet" type="text/css" th:href="/css/estyle.css"/>
<img  src="/images/logo.png" width="200dp" />

      E agora vamos ver como ficam esses recursos com o Thymeleaf:

<a class="btn btn-link link-panel" th:href="@{/titulos}">Carros</a>
<form class="form-horizontal" method="POST" th:action="@{/carro}">
<script th:src="@{/js/jquery-2.2.2.min.js}"></script>
<link rel="stylesheet" type="text/css" th:href="@{/css/estyle.css}"/>
<img  th:src="@{/images/logo.png}" width="200dp" />

Veja que praticamente todos os casos foram abordados: imagens, scripts, action de forms, e estilos CSS. Tudo o que apresenta um caminho, pode ser encapsulado com o Thymeleaf. O que tivemos que acrescentar foi o namespace  th: antes das propriedades que guardam o caminho dos recursos, e englobar os caminhos com @{}. Muito simples não é mesmo? Dessa forma, mudando o context-path, não é preciso me preocupar, pois os recursos serão trazidos da mesma maneira.


Espero ter ajudado. Abraços.

domingo, 3 de abril de 2016

Usando o Spring Boot no Wildfly 8.1.0

         Nesse post eu vou falar sobre rodar o Spring Boot no Wildfly. Bom, como o wildfly é um container de aplicações JavaEE completo, espera-se que não seja nenhum problema rodar o Spring Boot, certo? Pois é, mas algumas configurações são válidas para melhorar isso, que devem ser feitas no pom.xml.

         O Spring Boot carrega um Tomcat incorporado através da seguinte configuração no pom.xml:

<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-tomcat</artifactId>
      <scope>provided</scope>
</dependency>

         Esta dependência não é necessária pois o Wildfly tem um Toncat Servidor Web chamado Undertow rodando em suas entranhas (O Tomcat era usado nas versões antigas quando era chamado JBoss). Comente esta dependência e no lugar dela deve ficar:

<dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <scope>provided</scope>
</dependency>

      Pelo que pesquisei, para garantir que não irá ser carregado o Toncat, é bom alterar também a seguinte dependência:

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

         Deixando da seguinte forma:

<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>

Outra coisa importante é garantir que o Mavem vai exportar um arquivo do tipo war:

<packaging>war</packaging>

Basicamente, com essas configurações o projeto que usa Spring Boot vai rodar muito bem no Wildfly, porém deixará de funcionar no modo que usava o Tomcat embutido, e a aplicação terá que ser sempre iniciada através do Wildfly, por isso indiquei que comentasse a configuração antiga, assim pode revezar a configuração quando necessário, comentando as configurações referentes ao wildfly e retirando o comentário a respeito do Tomcat.

Outra dica importante é que a URI quando usamos o Tomcat embutido não necessita do nome da aplicação, bastando digitar apenas o endereço local, a porta e o caminho definido no controller através da annotetion @RequestMapping, por exemplo:

http://localhost:8080/carros/novo  //tomcat embutido

Já com a aplicação no wildfly será necessário acrescentar o nome da aplicação ficando:

http://localhost:8080/loccar/carros/novo  //wildfly


E acrescentar a seguinte configuração no arquivo application.properties:

server.context-path=/loccar   //loccar é o nome da minha aplicação, subtitua pelo nome dado ao pacote war da sua aplicação.

       Se você usava o Tomcat embutido, terá que fazer várias alterações nos links de páginas, imagens, arquivos CSS, arquivos JavaScript, etc... Para isso não ser uma grande dor de cabeça, recomenda-se o uso do Thymeleaf (http://www.thymeleaf.org/) nos projetos, pois ele oferece meios de mapear de forma automática estes recursos.

Veja o link de um post sobre o Thymeleaf usado para este fim AQUI!

       Espero ter ajudado, qualquer dúvida, deixa nos comentários que eu tento da uma força...


Links úteis: