Este projeto demonstra uma integração completa de um serviço SOAP, um cliente REST/ACL, um fluxo Apache Camel e um módulo final que grava os dados em Postgres.
O repositório contém quatro módulos/projetos:
.
├── soap # Serviço SOAP que fornece informações sobre despesas
├── acl # API REST que consome o SOAP e expõe JSON
├── camel # Apache Camel que consome a API REST periodicamente
└── atom # Novo módulo que consome mensagens RabbitMQ e grava no Postgres
Expor um serviço SOAP para consultar despesas de clientes por data.
Define:
-
Request:
getExpensesByDateRequest(com a data) -
Response:
getExpensesByDateResponse(lista de despesas) -
Tipo
Expense:id(String)client(String)description(String)date(String)amount(Decimal)status(PAID,PENDING,CANCELLED)
http://localhost:8080/ws/expenses- Teste via SOAP:
<ns2:getExpensesByDateRequest xmlns:ns2="http://borella.com/soap/expenses">
<ns2:date>2025-09-09</ns2:date>
</ns2:getExpensesByDateRequest>- WSDL:
http://localhost:8080/ws/expenses.wsdlConsumir o SOAP e expor os dados em JSON para clientes REST.
- URL para buscar despesas por data:
GET http://localhost:8081/expenses/{date}- Exemplo de resposta:
[
{
"id": "1",
"client": "Cliente A",
"description": "Compra de materiais",
"date": "2025-09-09",
"amount": 123.45,
"status": "PAID"
},
{
"id": "2",
"client": "Cliente B",
"description": "Serviços prestados",
"date": "2025-09-09",
"amount": 678.90,
"status": "PENDING"
}
]- Responsável por chamar o SOAP.
- Configuração do
WebServiceTemplatecomJaxb2Marshaller.
Consumir a API REST do ACL periodicamente e enviar as despesas para a fila RabbitMQ.
Exemplo de rota Camel:
from("timer://fetchExpenses?period=10000")
.setHeader(Exchange.HTTP_METHOD, constant("GET"))
.to("http://localhost:8081/expenses/2025-09-09")
.unmarshal().json(JsonLibrary.Jackson)
.to("rabbitmq://localhost:5672/expenses-exchange?queue=expenses-queue&routingKey=expenses");- Executa a cada 10 segundos.
- Converte JSON em
List<Map<String,Object>>. - Publica cada despesa na fila
expenses-queue.
Consumir mensagens da fila RabbitMQ e gravar as despesas na base Postgres.
@Entity
public class Expense {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String description;
private String client;
private String status;
private Double amount;
private LocalDate date;
}@Component
public class ExpenseListener {
private final ExpenseRepository repository;
private final ObjectMapper objectMapper;
public ExpenseListener(ExpenseRepository repository) {
this.repository = repository;
this.objectMapper = new ObjectMapper()
.registerModule(new JavaTimeModule()) // Suporte para LocalDate
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
}
@RabbitListener(queues = "expenses-queue")
public void receive(String message) throws Exception {
List<Expense> expenses = objectMapper.readValue(message, new TypeReference<List<Expense>>() {});
expenses.forEach(e -> {
e.setId(null); // força inserção
if (e.getDate() == null) e.setDate(LocalDate.now());
});
repository.saveAll(expenses);
System.out.println("✅ Mensagens salvas no Postgres");
}
}public interface ExpenseRepository extends JpaRepository<Expense, Long> {}+----------------+ SOAP +----------------+ REST +----------------+
| Cliente | <------------> | SOAP | <------------> | ACL |
| (ou Postman) | | Expenses | | JSON Output |
+----------------+ +----------------+ +----------------+
|
v
+----------------+
| Apache Camel |
| Envia para |
| RabbitMQ |
+----------------+
|
v
+----------------+
| Atom |
| Consome fila |
| e grava no |
| Postgres |
+----------------+
- O SOAP fornece os dados.
- O ACL transforma em JSON.
- O Camel envia para a fila RabbitMQ.
- O Atom consome a fila e grava no Postgres.
cd soap
mvn spring-boot:run- Porta padrão:
8080
cd acl
mvn spring-boot:run- Porta padrão:
8081
cd camel
mvn spring-boot:run- Porta padrão:
8082 - Consome automaticamente a URL do ACL e publica na fila RabbitMQ.
cd atom
mvn spring-boot:run- Porta padrão:
8083 - Consome mensagens de
expenses-queuee salva no Postgres.
Exemplo application.properties:
spring.datasource.url=jdbc:postgresql://localhost:5432/expensesdb
spring.datasource.username=postgres
spring.datasource.password=senha
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true- Cria automaticamente a tabela
expensese não existir. - Usa
LocalDatecorretamente comJackson.
-
O
Atomgarante que IDs duplicados não causem erro, sempre insere novos registros. -
O fluxo pode ser expandido para filtros, relatórios ou outras integrações.
-
Teste rápido do fluxo completo:
- SOAP:
http://localhost:8080/ws/expenses.wsdl - ACL:
http://localhost:8081/expenses/2025-09-09 - Camel: console mostra publicações na fila
- Atom: console mostra mensagens salvas no Postgres
- SOAP: