add spring-rabbitmq example
Signed-off-by: Mohammad Sadegh Sheikh Zahedi <sheikhoo.iran@gmail.com>
This commit is contained in:
parent
3746d65ad1
commit
b670c71c4a
29
spring-rabbitmq/.docker/docker-compose.yaml
Normal file
29
spring-rabbitmq/.docker/docker-compose.yaml
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
services:
|
||||||
|
backend:
|
||||||
|
build: backend
|
||||||
|
ports:
|
||||||
|
- 8080:8080
|
||||||
|
environment:
|
||||||
|
- RABBITMQ_HOST=rabbitmq
|
||||||
|
- RABBITMQ_QUEUE_NAME=springboot-queue
|
||||||
|
- RABBITMQ_FANOUT_EXCHANGE=springboot-exchange
|
||||||
|
networks:
|
||||||
|
- spring-rabbitmq
|
||||||
|
depends_on:
|
||||||
|
- rabbitmq
|
||||||
|
rabbitmq:
|
||||||
|
image: rabbitmq
|
||||||
|
restart: always
|
||||||
|
volumes:
|
||||||
|
- rabbitmq-data:/var/lib/rabbitmq
|
||||||
|
networks:
|
||||||
|
- spring-rabbitmq
|
||||||
|
environment:
|
||||||
|
- RABBITMQ_DEFAULT_USER=guest
|
||||||
|
- RABBITMQ_DEFAULT_PASS=guest
|
||||||
|
expose:
|
||||||
|
- 5672
|
||||||
|
volumes:
|
||||||
|
rabbitmq-data:
|
||||||
|
networks:
|
||||||
|
spring-rabbitmq:
|
60
spring-rabbitmq/README.md
Normal file
60
spring-rabbitmq/README.md
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
## Compose sample application
|
||||||
|
|
||||||
|
### Java application with Spring framework and Rabbitmq
|
||||||
|
|
||||||
|
Project structure:
|
||||||
|
```
|
||||||
|
.
|
||||||
|
├── backend
|
||||||
|
│ ├── Dockerfile
|
||||||
|
│ └── ...
|
||||||
|
├── compose.yaml
|
||||||
|
└── README.md
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
[_compose.yaml_](compose.yaml)
|
||||||
|
```
|
||||||
|
services:
|
||||||
|
backend:
|
||||||
|
build: backend
|
||||||
|
ports:
|
||||||
|
- 8080:8080
|
||||||
|
rabbitmq:
|
||||||
|
rabbitmq:3.9-management
|
||||||
|
...
|
||||||
|
```
|
||||||
|
The compose file defines an application with two services `backend` and `rabbitmq`.
|
||||||
|
When deploying the application, docker compose maps port 8080 of the backend service container to port 8080 of the host as specified in the file.
|
||||||
|
Make sure port 8080 on the host is not already being in use.
|
||||||
|
|
||||||
|
## Deploy with docker compose
|
||||||
|
|
||||||
|
```
|
||||||
|
$ docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
## Expected result
|
||||||
|
|
||||||
|
Listing containers must show two containers running and the port mapping as below:
|
||||||
|
```
|
||||||
|
$ docker ps
|
||||||
|
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||||
|
86f6bb2a1585 spring-rabbitmq-backend "java -cp app:app/li…" 6 minutes ago Up 6 minutes 0.0.0.0:8080->8080/tcp spring-rabbitmq-backend-1
|
||||||
|
0c4522d3f075 rabbitmq "docker-entrypoint.s…" 6 minutes ago Up 6 minutes 4369/tcp, 5671-5672/tcp, 15691-15692/tcp, 25672/tcp spring-rabbitmq-rabbitmq-1
|
||||||
|
```
|
||||||
|
|
||||||
|
After the application starts, you can send and receive data to rabbitmq with this api :
|
||||||
|
|
||||||
|
`POST`: http://localhost:8080/sendMessage
|
||||||
|
Body:
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"title":""Hello, rabbitmq",
|
||||||
|
"text":"This is my test messag",
|
||||||
|
"sender":"admin"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`GET`: http://localhost:8080/getMessage
|
||||||
|
|
39
spring-rabbitmq/backend/Dockerfile
Normal file
39
spring-rabbitmq/backend/Dockerfile
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
# syntax=docker/dockerfile:1.4
|
||||||
|
|
||||||
|
FROM --platform=$BUILDPLATFORM maven:3.8.5-eclipse-temurin-17 AS builder
|
||||||
|
WORKDIR /workdir/server
|
||||||
|
COPY pom.xml /workdir/server/pom.xml
|
||||||
|
RUN mvn dependency:go-offline
|
||||||
|
|
||||||
|
COPY src /workdir/server/src
|
||||||
|
RUN mvn install
|
||||||
|
|
||||||
|
FROM builder AS dev-envs
|
||||||
|
RUN <<EOF
|
||||||
|
apt-get update
|
||||||
|
apt-get install -y --no-install-recommends git
|
||||||
|
EOF
|
||||||
|
|
||||||
|
RUN <<EOF
|
||||||
|
useradd -s /bin/bash -m vscode
|
||||||
|
groupadd docker
|
||||||
|
usermod -aG docker vscode
|
||||||
|
EOF
|
||||||
|
# install Docker tools (cli, buildx, compose)
|
||||||
|
COPY --from=gloursdocker/docker / /
|
||||||
|
CMD ["mvn", "spring-boot:run"]
|
||||||
|
|
||||||
|
FROM builder as prepare-production
|
||||||
|
RUN mkdir -p target/dependency
|
||||||
|
WORKDIR /workdir/server/target/dependency
|
||||||
|
RUN jar -xf ../*.jar
|
||||||
|
|
||||||
|
FROM eclipse-temurin:17-jre-focal
|
||||||
|
|
||||||
|
EXPOSE 8080
|
||||||
|
VOLUME /tmp
|
||||||
|
ARG DEPENDENCY=/workdir/server/target/dependency
|
||||||
|
COPY --from=prepare-production ${DEPENDENCY}/BOOT-INF/lib /app/lib
|
||||||
|
COPY --from=prepare-production ${DEPENDENCY}/META-INF /app/META-INF
|
||||||
|
COPY --from=prepare-production ${DEPENDENCY}/BOOT-INF/classes /app
|
||||||
|
ENTRYPOINT ["java","-cp","app:app/lib/*","com.company.project.Application"]
|
50
spring-rabbitmq/backend/pom.xml
Normal file
50
spring-rabbitmq/backend/pom.xml
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<?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 https://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>3.0.1</version>
|
||||||
|
<relativePath/> <!-- lookup parent from repository -->
|
||||||
|
</parent>
|
||||||
|
<groupId>com.company</groupId>
|
||||||
|
<artifactId>spring-rabbitmq</artifactId>
|
||||||
|
<version>0.0.1</version>
|
||||||
|
<name>spring-rabbitmq</name>
|
||||||
|
<description>Demo project for Spring Boot and Rabbitmq</description>
|
||||||
|
<properties>
|
||||||
|
<java.version>17</java.version>
|
||||||
|
</properties>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-amqp</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<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.amqp</groupId>
|
||||||
|
<artifactId>spring-rabbit-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
@ -0,0 +1,12 @@
|
|||||||
|
package com.company.project;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
public class Application {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(Application.class, args);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
package com.company.project.config;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.company.project.model.Message;
|
||||||
|
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class QueueConsumer {
|
||||||
|
|
||||||
|
private final RabbitTemplate rabbitTemplate;
|
||||||
|
|
||||||
|
@Value("${queue.name}")
|
||||||
|
private String queueName;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public QueueConsumer(RabbitTemplate rabbitTemplate) {
|
||||||
|
this.rabbitTemplate = rabbitTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String receiveMessage() {
|
||||||
|
String message = (String) rabbitTemplate.receiveAndConvert(queueName);
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Message processMessage() throws JsonProcessingException {
|
||||||
|
String message = receiveMessage();
|
||||||
|
return new ObjectMapper().readValue(message, Message.class);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
package com.company.project.config;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.company.project.model.Message;
|
||||||
|
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class QueueProducer {
|
||||||
|
|
||||||
|
@Value("${fanout.exchange}")
|
||||||
|
private String fanoutExchange;
|
||||||
|
|
||||||
|
private final RabbitTemplate rabbitTemplate;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public QueueProducer(RabbitTemplate rabbitTemplate) {
|
||||||
|
this.rabbitTemplate = rabbitTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void produce(Message message) throws JsonProcessingException {
|
||||||
|
|
||||||
|
rabbitTemplate.setExchange(fanoutExchange);
|
||||||
|
rabbitTemplate.convertAndSend(new ObjectMapper().writeValueAsString(message));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
package com.company.project.config;
|
||||||
|
|
||||||
|
import org.springframework.amqp.core.Binding;
|
||||||
|
import org.springframework.amqp.core.BindingBuilder;
|
||||||
|
import org.springframework.amqp.core.FanoutExchange;
|
||||||
|
import org.springframework.amqp.core.Queue;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class RabbitConfiguration {
|
||||||
|
@Value("${fanout.exchange}")
|
||||||
|
private String fanoutExchange;
|
||||||
|
|
||||||
|
@Value("${queue.name}")
|
||||||
|
private String queueName;
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
Queue queue() {
|
||||||
|
return new Queue(queueName, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
FanoutExchange fanoutExchange() {
|
||||||
|
return new FanoutExchange(fanoutExchange);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
Binding binding(Queue queue, FanoutExchange fanoutExchange) {
|
||||||
|
return BindingBuilder.bind(queue).to(fanoutExchange);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
package com.company.project.controller;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.company.project.config.QueueConsumer;
|
||||||
|
import com.company.project.config.QueueProducer;
|
||||||
|
import com.company.project.model.Message;
|
||||||
|
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
@Controller
|
||||||
|
@RequestMapping("/")
|
||||||
|
public class MessageController {
|
||||||
|
|
||||||
|
private final QueueProducer queueProducer;
|
||||||
|
private final QueueConsumer queueConsumer;
|
||||||
|
|
||||||
|
public MessageController(QueueProducer queueProducer, QueueConsumer queueConsumer) {
|
||||||
|
this.queueProducer = queueProducer;
|
||||||
|
this.queueConsumer = queueConsumer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("getMessage")
|
||||||
|
public ResponseEntity<?> getMessage() throws JsonProcessingException {
|
||||||
|
Message message = queueConsumer.processMessage();
|
||||||
|
return new ResponseEntity<Message>(message, HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("sendMessage")
|
||||||
|
public ResponseEntity<?> sendMessage(@RequestBody Message message) throws JsonProcessingException {
|
||||||
|
queueProducer.produce(message);
|
||||||
|
return new ResponseEntity<Message>(HttpStatus.CREATED);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
package com.company.project.model;
|
||||||
|
|
||||||
|
public class Message {
|
||||||
|
|
||||||
|
private String title;
|
||||||
|
private String text;
|
||||||
|
private String sender;
|
||||||
|
|
||||||
|
public String getTitle() {
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTitle(String title) {
|
||||||
|
this.title = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getText() {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setText(String text) {
|
||||||
|
this.text = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSender() {
|
||||||
|
return sender;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSender(String sender) {
|
||||||
|
this.sender = sender;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
server.port= 8080
|
||||||
|
spring.main.banner-mode= off
|
||||||
|
spring.rabbitmq.host= ${RABBITMQ_HOST:localhost}
|
||||||
|
spring.rabbitmq.port= 5672
|
||||||
|
spring.rabbitmq.username= guest
|
||||||
|
spring.rabbitmq.password= guest
|
||||||
|
queue.name= ${RABBITMQ_QUEUE_NAME:springboot-queue}
|
||||||
|
fanout.exchange= ${RABBITMQ_FANOUT_EXCHANGE:springboot-exchange}
|
||||||
|
|
29
spring-rabbitmq/compose.yaml
Normal file
29
spring-rabbitmq/compose.yaml
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
services:
|
||||||
|
backend:
|
||||||
|
build: backend
|
||||||
|
ports:
|
||||||
|
- 8080:8080
|
||||||
|
environment:
|
||||||
|
- RABBITMQ_HOST=rabbitmq
|
||||||
|
- RABBITMQ_QUEUE_NAME=springboot-queue
|
||||||
|
- RABBITMQ_FANOUT_EXCHANGE=springboot-exchange
|
||||||
|
networks:
|
||||||
|
- spring-rabbitmq
|
||||||
|
depends_on:
|
||||||
|
- rabbitmq
|
||||||
|
rabbitmq:
|
||||||
|
image: rabbitmq
|
||||||
|
restart: always
|
||||||
|
volumes:
|
||||||
|
- rabbitmq-data:/var/lib/rabbitmq
|
||||||
|
networks:
|
||||||
|
- spring-rabbitmq
|
||||||
|
environment:
|
||||||
|
- RABBITMQ_DEFAULT_USER=guest
|
||||||
|
- RABBITMQ_DEFAULT_PASS=guest
|
||||||
|
expose:
|
||||||
|
- 5672
|
||||||
|
volumes:
|
||||||
|
rabbitmq-data:
|
||||||
|
networks:
|
||||||
|
spring-rabbitmq:
|
Loading…
Reference in New Issue
Block a user