Spring Events
Este recurso vem como padrão no Spring framework, e é fornecido pela ApplicationContext.
Eventos são mensagens publicadas por alguma rotina (publisher), onde avisa que alguma operação do negócio foi executada, onde classes (listeners), irão executar alguma função do sistema.
Ex: Quando cair um pedido no sistema, dispara um evento para o listener de estoque, para decrementar o estoque.
A classe de Evento deve estender ApplicationEvent
O publisher deve injetar um objeto ApplicationEventPublisher
O listener deve implementar a interface ApplicationListener.
Agora mão na massa, assim podemos entender melhor o funcionamento dos eventos.
Temos o seguinte problema para resolver, clientes estão publicando produtos com sua descrição em inglês, e isso prejudica quem não conhece o o idioma, na hora da compra. Então queremos quando recebermos um texto em outro idioma, traduzir para o português.
Para isso vamos utilizar dos Eventos do Spring e da Api do google translation.
Criando Eventos Síncrono:
Precisamos criar um projeto Spring.
Agora vamos criar uma classe de evento, onde vai conter o idioma de origem do texto, e texto a ser traduzido, não se esqueça que as classes de eventos precisam estender a classe ApplicationEvent.
package com.springboot.events;
import org.springframework.context.ApplicationEvent;
public class MessageEvents extends ApplicationEvent {
private String code;
private String text;
public MessageEvents(Object source, String code, String text) {
super(source);
this.code = code;
this.text = text;
}
/*Getters and Setters*/
}
Agora vamos criar um editor, nossa classe responsável por disparar o evento. está classe precisa injetar a classe ApplicationEventPublisher, o método publishEvent é quem dispara o evento, recebendo como parâmetro o evento.
package com.springboot.publisher;
import com.springboot.events.MessageEvents;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;
@Component
public class MessageEventPublisher {
@Autowired
private ApplicationEventPublisher eventPublisher;
public void doStuffAndPublishAnEvent(final String code, final String text){
MessageEvents events = new MessageEvents(this, code, text);
eventPublisher.publishEvent(events);
}
}
Agora vamos criar a classe responsável em ouvir quando o evento for disparado, nossa listener. não esqueça de implementar a interface ApplicationListener.
package com.springboot.listener;
import com.springboot.events.MessageEvents;
import com.springboot.translate.TranslateMessageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
@Component
public class MessageEventsListener implements ApplicationListener<MessageEvents> {
@Autowired
private TranslateMessageService translate;
@Override
public void onApplicationEvent(MessageEvents messageEvents) {
System.out.println(translate.translate(messageEvents.getCode(), messageEvents.getText()));
}
}
Tudo certo, agora vamos criar nosso controller e testar, se nosso evento está funcionando, coloque um System.out.println, para verificar se chegou até nosso listener.
package com.springboot.controller;
import com.springboot.domain.MessageEventsDTO;
import com.springboot.events.MessageEvents;
import com.springboot.publisher.MessageEventPublisher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import static java.util.Objects.nonNull;
@RestController
public class MessageEventsAPI {
@Autowired
private MessageEventPublisher publisher;
@PostMapping(value = "/message")
public void sendMessage(@RequestBody MessageEventsDTO events){
if(nonNull(events.getCode()) && nonNull(events.getText())){
this.publisher.doStuffAndPublishAnEvent(events.getCode(), events.getText());
}
}
}
Tudo funcionando?
Mais travar nossa api até processar, não é algo muito bom. Então vamos configurar nossos evento para serem assíncronos.
Você pode ativar isso na configuração criando um bean ApplicationEventMulticaster com um executor. as implementações dos eventos se mantêm as mesma, apenas o listener agora executar de forma assíncrona.
Agora vamos implementar a tradução dos nossos texto, utilizando api do google, para isso precisa criar uma conta na cloud, e baixar o json com a chave de segurança.
vou disponibilizar alguns links para ajuda-los, eu estou colocando lendo meu arquivo direto em código, mais você também pode configurar nas suas variáveis de ambiente do windows.
coloque as seguintes dependências no seu pom:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.springboot.events</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
<version>2.0.3.RELEASE</version>
</dependency>
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>google-cloud-translate</artifactId>
<version>1.39.0</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>21.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Feito isso, sua integração está feita agora vamos criar um serviço que recebe essa mensagem e devolve o texto traduzido.
package com.springboot.translate;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.cloud.translate.Translate;
import com.google.cloud.translate.TranslateOptions;
import com.google.cloud.translate.Translation;
import com.google.common.collect.Lists;
import org.springframework.stereotype.Service;
import java.io.FileInputStream;
import java.io.IOException;
@Service
public class TranslateMessageService {
private static final String PT = "pt";
public String translate(String code, String text) {
Translate translate = TranslateOptions.newBuilder().setCredentials(credentials()).build().getService();
Translation translation =
translate.translate(
text,
Translate.TranslateOption.sourceLanguage(code),
Translate.TranslateOption.targetLanguage(PT));
return translation.getTranslatedText();
}
private GoogleCredentials credentials() {
GoogleCredentials credentials = null;
try {
credentials = GoogleCredentials.fromStream(new FileInputStream("PATH"))
.createScoped(Lists.newArrayList("https://www.googleapis.com/auth/cloud-platform"));
} catch (IOException e) {
e.printStackTrace();
}
return credentials;
}
}
Links de Referência:
https://www.baeldung.com/spring-context-events
https://www.baeldung.com/spring-events