Angular 9 + ActiveMQ Producer/Consumer + SpringBoot RestAPIs example

In the tutorial, we show how to Producer/Consumer data from ActiveMQ with Angular 9 & SpringBoot RestAPIs.

Related posts:
ActiveMQ Producer/Consumer + SpringBoot RestAPIs example
RabbitMq – How to create Spring RabbitMq Publish/Subcribe pattern with SpringBoot
How to use Spring Kafka JsonSerializer (JsonDeserializer) to produce/consume Java Object messages

Related Pages:

Technologies

  • Java 1.8
  • Maven 3.3.9
  • Spring Tool Suite – Version 3.9.4.RELEASE
  • Spring Boot: 2.0.3.RELEASE
  • ActiveMQ
  • Angular 9

Overview

We create a Spring JMS ActiveMQ with JMS Producer & JMS Consumer as below:

Angular-6-Spring-Boot-RestAPI-ActiveMQ-Producer-Consumer +springboot-project-structure

Angular-6-Spring-Boot-RestAPI-ActiveMQ-Producer-Consumer + activemq-producer-consumer

Then expose RestAPIs to POST/GET data to/from ActiveMQ:

  • @PostMapping(value="/api/task")
  • @GetMapping(value="/api/tasks")

Use Angular Client to submit/get data from ActiveMQ via above RestAPI:

Angular-6-Spring-Boot-RestAPI-ActiveMQ-Producer-Consumer +add-new-task

Angular-6-Spring-Boot-RestAPI-ActiveMQ-Producer-Consumer +processing-all-task

ActiveMQ state:

Angular-6-Spring-Boot-RestAPI-ActiveMQ-Producer-Consumer + activemq-state

Practice

SpringBoot Backend

Setup SpringBoot project

Use SpringToolSuite to create a SpringBoot project with below dependencies:

<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-jms</artifactId>
</dependency>
<dependency>
	<groupId>org.apache.activemq</groupId>
	<artifactId>activemq-broker</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>

ActiveMQ Connection Factory

ActiveMqConnectionFactoryConfig ->


package com.ozenero.activemq.config;

import javax.jms.ConnectionFactory;

import org.apache.activemq.ActiveMQConnectionFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.jms.DefaultJmsListenerContainerFactoryConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
import org.springframework.jms.config.JmsListenerContainerFactory;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.support.converter.MappingJackson2MessageConverter;
import org.springframework.jms.support.converter.MessageConverter;
import org.springframework.jms.support.converter.MessageType;

@Configuration
public class ActiveMqConnectionFactoryConfig {

	@Value("${gkz.activemq.broker.url}")
	String brokerUrl;
	
	@Value("${gkz.activemq.borker.username}")
	String userName;
	
	@Value("${gkz.activemq.borker.password}")
	String password;

	/*
	 * Initial ConnectionFactory
	 */
    @Bean
    public ConnectionFactory connectionFactory(){
        ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory();
        connectionFactory.setBrokerURL(brokerUrl);
        connectionFactory.setUserName(userName);
        connectionFactory.setPassword(password);
        return connectionFactory;
    }
    
	@Bean // Serialize message content to json using TextMessage
	public MessageConverter jacksonJmsMessageConverter() {
	    MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
	    converter.setTargetType(MessageType.TEXT);
	    converter.setTypeIdPropertyName("_type");
	    return converter;
	}
    
    /*
     * Used for Receiving Message
     */
    @Bean
    public JmsListenerContainerFactory jsaFactory(ConnectionFactory connectionFactory,
                                                    DefaultJmsListenerContainerFactoryConfigurer configurer) {
        DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
        factory.setMessageConverter(jacksonJmsMessageConverter());
        configurer.configure(factory, connectionFactory);
        return factory;
    }
 
    /*
     * Used for Sending Messages.
     */
    @Bean
    public JmsTemplate jmsTemplate(){
        JmsTemplate template = new JmsTemplate();
        template.setMessageConverter(jacksonJmsMessageConverter());
        template.setConnectionFactory(connectionFactory());
        return template;
    }
}

Add ActiveMQ configuration in application.properties ->


gkz.activemq.broker.url=tcp://localhost:61616
gkz.activemq.borker.username=admin
gkz.activemq.borker.password=admin
gkz.activemq.queue=gkz-queue

Data Model

– Create Task model ->


package com.ozenero.activemq.model;

public class Task {
	private Long id;
	private String name;
	
	public Task(){
	}
	
	public Task(Long id, String name){
		this.id = id;
		this.name = name;
	}
	
	public Long getId() {
		return id;
	}
	
	public void setId(Long id) {
		this.id = id;
	}
	
	public String getName() {
		return name;
	}
	
	public void setName(String name) {
		this.name = name;
	}
}

– Create MessageStorage to storage Task list ->


package com.ozenero.activemq.model;

import java.util.ArrayList;
import java.util.List;

public class MessageStorage {
	private List tasks = new ArrayList();
	
	public void add(Task task) {
		tasks.add(task);
	}
	
	public void clear() {
		tasks.clear();
	}
	
	public List getAll(){
		return tasks;
	}
}

Create a bean for MessageStorage ->


package com.ozenero.activemq.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.ozenero.activemq.model.MessageStorage;

@Configuration
public class BeanConfiguration {

  @Bean
  public MessageStorage customerStorage() {
    return new MessageStorage();
  }
}

JMS Producer

JmsProducer send messages to ActiveMQ ->


package com.ozenero.activemq.jms.producer;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.stereotype.Component;

import com.ozenero.activemq.model.Task;

@Component
public class JmsProducer {
	@Autowired
	JmsTemplate jmsTemplate;
	
	@Value("${gkz.activemq.queue}")
	String queue;
	
	public void send(Task task){
		jmsTemplate.convertAndSend(queue, task);
	}
}

JMS Consumer

JmsConsumer recieves messages from ActiveMQ ->


package com.ozenero.activemq.jms.consumer;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;

import com.ozenero.activemq.model.MessageStorage;
import com.ozenero.activemq.model.Task;

@Component
public class JmsConsumer {
	@Autowired
	private MessageStorage taskStorage;
	
	@JmsListener(destination = "${gkz.activemq.queue}", containerFactory="jsaFactory")
	public void receive(Task task){
		taskStorage.add(task);
	}
}

Rest APIs

RestAPI ->


package com.ozenero.activemq.controller;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import com.ozenero.activemq.jms.producer.JmsProducer;
import com.ozenero.activemq.model.MessageStorage;
import com.ozenero.activemq.model.Task;

@CrossOrigin(origins = "http://localhost:4200")
@RestController
public class RestAPIs {
	
	@Autowired
	JmsProducer jmsProducer;
	
	@Autowired
	private MessageStorage taskStorage;
	
	@PostMapping(value="/api/task")
	public Task postCustomer(@RequestBody Task task){
		jmsProducer.send(task);
		return task;
	}
	
	@GetMapping(value="/api/tasks")
	public List getAll(){
		List tasks = new ArrayList(taskStorage.getAll());
		taskStorage.clear();
		return tasks;
	}
}

Angular Frontend

Setup Angular Project

Setup guide:

  • Create Angular project with commandline: ng new angular6-client
  • Generate Task model with commandline ng generate class Task
  • Generate TaskService with commandline ng generate service Task
  • Generate TaskComponent with commandline ng generate component Task

Then install Bootstrap by commandline ->

>npm install bootstrap jquery --save

Configure installed Bootstrap & JQuery in angular.json file ->


...
 
"styles": [
  "src/styles.css",
  "node_modules/bootstrap/dist/css/bootstrap.min.css"
],
"scripts": [
  "node_modules/jquery/dist/jquery.min.js",
  "node_modules/bootstrap/dist/js/bootstrap.min.js"
]
 
...

Data Model

Task ->


export class Task {
    id: number;
    name: string;
}

Implement HttpClient Service

TaskService ->


import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable } from 'rxjs';
import { Task } from './task';
 
const httpOptions = {
  headers: new HttpHeaders({ 'Content-Type': 'application/json' })
};
 
@Injectable({
  providedIn: 'root'
})
export class   {
  constructor( 
    private http: HttpClient
  ) { }
 
  getTasks (): Observable {
    return this.http.get("http://localhost:8080/api/tasks")
  }
  
  addTask (task: Task): Observable {
    return this.http.post("http://localhost:8080/api/task", task, httpOptions);
  }
}

Implement ActiveMQ Component

activemq-task.component.html ->

<div [hidden]="submitted">
    <h3>Add Task</h3>
    <form #addTaskForm="ngForm">

      <div class="form-group">
        <label for="id">Id</label>
        <input type="number" class="form-control" id="id" 
        placeholder="Enter Id"
        required
        [(ngModel)]="task.id" name="id" #id="ngModel">
        <div [hidden]="id.valid || id.pristine"
              class="alert alert-danger">
            Id is required
        </div>
      </div>
 
      <div class="form-group">
        <label for="name">Name</label>
        <input type="text" class="form-control" id="name" placeholder="Enter Task Name" 
        required
        [(ngModel)]="task.name" name="name" #name="ngModel">
        <div [hidden]="name.valid || name.pristine"
             class="alert alert-danger">
            Name is required
        </div>
      </div>  
      <button class="btn btn-dark" (click)="addTask()" [disabled]="!addTaskForm.form.valid">Add Task</button>
    </form>
</div>
 
<div [hidden]="!submitted">
  <p>Submitted Successfully! -> <span class="badge badge-dark">Task's Info -> Id: {{task.id}}, Name: {{task.name}}</span></p>
	<div class="btn-group btn-group-sm">
    <button class="btn btn-secondary" (click)="newTask(); addTaskForm.reset();">New Task</button>
    <button class="btn btn-secondary" (click)="processTasks();">Process Tasks</button>
  </div>
  <div [hidden]="!processing">
      <br>
      <h5>Processing</h5>
      <ul>
        <li *ngFor="let task of tasks">
          Task id = {{task.id}}, name = {{task.name}}
        </li>
      </ul>
  </div>
</div>

activemq-task.component.ts ->


import { Component, OnInit } from '@angular/core';
import { Task } from '../task';
import { TaskService } from '../task.service';

@Component({
  selector: 'app-activemq-task',
  templateUrl: './activemq-task.component.html',
  styleUrls: ['./activemq-task.component.css']
})
export class ActivemqTaskComponent{

  task = new Task();
  tasks: Task[];
  submitted = false;
  processing = false;

  constructor(private taskService: TaskService) { }

  newTask(): void {
    this.submitted = false;
    this.processing = false;
    this.task = new Task();
  }
 
  addTask() {
    this.submitted = true;
    this.taskService.addTask(this.task)
    .subscribe();
  }

  processTasks(){
    this.processing = true;
    return this.taskService.getTasks()
                .subscribe(
                  tasks => {
                    console.log(tasks);
                    this.tasks = tasks;
                  }
                );
  }
}

– Create style file assets/forms.css ->


.ng-valid[required], .ng-valid.required  {
    border-left: 5px solid rgba(32, 77, 32, 0.623);
}
 
.ng-invalid:not(form)  {
    border-left: 5px solid rgb(148, 27, 27);
}

– Add above style file assets/forms.css to index.html file ->

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Angular6Client</title>
  <base href="/">

  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
  <link rel="stylesheet" href="assets/forms.css">
</head>
<body>
  <app-root></app-root>
</body>
</html>

– Add app-activemq-task selector to app.component.html file ->

<div class="container">
  <div class="row">
    <div class="col-sm-4"> 
      <app-activemq-task></app-activemq-task>
   </div>
  </div>
</div>

Run & Check Results

– Build & Run SpringBoot project with commandlines {mvn clean install, mvn spring-boot:run}.
– Run the Angular project as commandline: ng serve

Add Task ->

Angular-6-Spring-Boot-RestAPI-ActiveMQ-Producer-Consumer +add-new-task

Angular-6-Spring-Boot-RestAPI-ActiveMQ-Producer-Consumer +submit-successfully

Get Tasks ->

Angular-6-Spring-Boot-RestAPI-ActiveMQ-Producer-Consumer +processing-all-task

ActiveMQ state ->

Angular-6-Spring-Boot-RestAPI-ActiveMQ-Producer-Consumer + activemq-state

SourceCode

SpringBootRestAPIsActiveMQ
Angular6-Client

24 thoughts on “Angular 9 + ActiveMQ Producer/Consumer + SpringBoot RestAPIs example”

  1. 615463 792488This website is often a walk-through like the information you wanted in regards to this and didnt know who to question. Glimpse here, and you will undoubtedly discover it. 168031

  2. I have been exploring for a little bit for any high quality articles or blog posts in this sort of space . Exploring in Yahoo I eventually stumbled upon this web site. Studying this info So i am happy to express that I’ve an incredibly just right uncanny feeling I found out just what I needed. I such a lot for sure will make sure to do not fail to remember this site and provides it a look a relentless basis.

  3. Nice post. I understand something much harder on diverse blogs everyday. Most commonly it is stimulating to learn to read content off their writers and employ a little something from their site. I’d opt to use some while using content on my own weblog whether you do not mind. Natually I’ll provide link in your internet blog. Many thanks sharing.

  4. 677107 929269This web-site can be a walk-through rather than the info you wished about it and didnt know who ought to. Glimpse here, and youll definitely discover it. 606154

  5. Hello there! This post couldn’t be written any better! Reading this post
    reminds me of my old room mate! He always kept talking about this.
    I will forward this article to him. Fairly certain he will have a good read.

    Many thanks for sharing!

  6. We are a group of volunteers and opening a new scheme in our
    community. Your web site provided us with valuable information to work on. You have done
    an impressive job and our whole community will be thankful
    to you.

  7. My brother suggested I may like this blog.
    He was once totally right. This submit actually made my
    day. You can not imagine just how a lot time I had spent for this info!

    Thanks!

  8. My brother suggested I might like this website. He was totally right.
    This post actually made my day. You cann’t imagine just how much time I
    had spent for this information! Thanks!

  9. Thanks for your personal marvelous posting! I quite enjoyed reading it, you might be a great author.I will be sure to bookmark your blog
    and may come back in the future. I want to encourage you continue your great job, have a nice afternoon!

  10. A motivating discussion is definitely worth comment.
    I think that you ought to publish more about this topic,
    it might not be a taboo matter but generally people do
    not speak about these subjects. To the next!
    All the best!!

  11. I am not sure where you’re getting your information, but great
    topic. I needs to spend some time learning more
    or understanding more. Thanks for great info I was looking for this info for my mission.

  12. I’m extremely impressed together with your writing skills and also with
    the structure to your blog. Is that this
    a paid theme or did you modify it yourself? Anyway keep up the nice quality
    writing, it’s uncommon to see a great weblog like this
    one nowadays..

  13. Hey there! I’ve been reading your blog for a long time now
    and finally got the courage to go ahead and give you a shout
    out from Porter Texas! Just wanted to tell you keep up the excellent
    job!

Leave a Reply

Your email address will not be published. Required fields are marked *