Firebase Cloud Messaging – Spring Server to Push Notification Example | Spring Boot

In the article Firebase Cloud Messaging – How to Subscribe TOPIC & Receive Messages | Android, we have created an Android App that can subscribe/unsubscribe specific TOPIC and receive Message Data, but we used Firebase Notification Console GUI to generate Notification. Today, we’re gonna look at way to create a Spring Boot Application Server that can make message and push notification to Android Client via Firebase.

Related Post: Firebase Cloud Messaging – XMPP Server example to receive Upstream Messages | Spring Integration

I. Project Overview

1. Architecture

spring-boot-fcm-push-notification-architecture

2. Topic HTTP POST

Send to a single topic JavaSampleApproach:

https://fcm.googleapis.com/fcm/send
Content-Type:application/json
Authorization:key=SERVER_KEY
{
   "to": "/topics/JavaSampleApproach",
   "notification": {
      "title": "TITLE",
      "body": "BODY"
   },
   "data": {
      "Key-1": "VALUE 1",
      "Key-2": "VALUE 2"
   },
}

Send to devices subscribed to topics ABC or XYZ:

https://fcm.googleapis.com/fcm/send
Content-Type:application/json
Authorization:key=SERVER_KEY
{
  "condition": "'ABC' in topics || 'XYZ' in topics",
  "data": {
      ...
   }
}

This is the response:

// Success:
{
  "message_id": "123456"
}

// failure example:
{
  "error": "TopicsMessageRateExceeded"
}
3. Technology

– Java 1.8
– Maven 3.3.9
– Spring Tool Suite – Version 3.8.4.RELEASE
– Spring Boot: 2.0.0.M2

4. Structure

spring-boot-fcm-push-notification-structure

AndroidPushNotificationsService is the service that provides send() method (with ClientHttpRequestInterceptor and RestTemplate POST request) to Firebase FCM.
WebController is a REST Controller that creates Message Data Entity and uses Service above to push Notification.

II. Practice

1. Get Server Key

Go to Settings of your Firebase Project in Firebase Console to get Server Key.
spring-boot-fcm-push-notification-server-key

2. Create Spring Boot project

– Using Spring Tool Suite/Eclipse to create Spring Boot project.
– Add Dependencies to pom.xml file:


	org.springframework.boot
	spring-boot-starter-web



	org.json
	json
	20160810

3. Create Push Notification Service
package com.javasampleapproach.fcm.pushnotif.service;

import java.io.IOException;

import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.client.support.HttpRequestWrapper;

public class HeaderRequestInterceptor implements ClientHttpRequestInterceptor {

	private final String headerName;
	private final String headerValue;

	public HeaderRequestInterceptor(String headerName, String headerValue) {
		this.headerName = headerName;
		this.headerValue = headerValue;
	}

	@Override
	public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)
			throws IOException {
		HttpRequest wrapper = new HttpRequestWrapper(request);
		wrapper.getHeaders().set(headerName, headerValue);
		return execution.execute(wrapper, body);
	}
}

Remember to copy your Server Key at the first step to FIREBASE_SERVER_KEY.

package com.javasampleapproach.fcm.pushnotif.service;

import java.util.ArrayList;
import java.util.concurrent.CompletableFuture;

import org.springframework.http.HttpEntity;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

@Service
public class AndroidPushNotificationsService {

	private static final String FIREBASE_SERVER_KEY = "Your Server Key here!";
	private static final String FIREBASE_API_URL = "https://fcm.googleapis.com/fcm/send";
	
	@Async
	public CompletableFuture send(HttpEntity entity) {

		RestTemplate restTemplate = new RestTemplate();

		/**
		https://fcm.googleapis.com/fcm/send
		Content-Type:application/json
		Authorization:key=FIREBASE_SERVER_KEY*/

		ArrayList interceptors = new ArrayList<>();
		interceptors.add(new HeaderRequestInterceptor("Authorization", "key=" + FIREBASE_SERVER_KEY));
		interceptors.add(new HeaderRequestInterceptor("Content-Type", "application/json"));
		restTemplate.setInterceptors(interceptors);

		String firebaseResponse = restTemplate.postForObject(FIREBASE_API_URL, entity, String.class);

		return CompletableFuture.completedFuture(firebaseResponse);
	}
}
4. Create Controller
package com.javasampleapproach.fcm.pushnotif.controller;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.javasampleapproach.fcm.pushnotif.service.AndroidPushNotificationsService;

@RestController
public class WebController {

	private final String TOPIC = "JavaSampleApproach";
	
	@Autowired
	AndroidPushNotificationsService androidPushNotificationsService;

	@RequestMapping(value = "/send", method = RequestMethod.GET, produces = "application/json")
	public ResponseEntity send() throws JSONException {

		JSONObject body = new JSONObject();
		body.put("to", "/topics/" + TOPIC);
		body.put("priority", "high");

		JSONObject notification = new JSONObject();
		notification.put("title", "JSA Notification");
		notification.put("body", "Happy Message!");
		
		JSONObject data = new JSONObject();
		data.put("Key-1", "JSA Data 1");
		data.put("Key-2", "JSA Data 2");

		body.put("notification", notification);
		body.put("data", data);

/**
		{
		   "notification": {
		      "title": "JSA Notification",
		      "body": "Happy Message!"
		   },
		   "data": {
		      "Key-1": "JSA Data 1",
		      "Key-2": "JSA Data 2"
		   },
		   "to": "/topics/JavaSampleApproach",
		   "priority": "high"
		}
*/

		HttpEntity request = new HttpEntity<>(body.toString());

		CompletableFuture pushNotification = androidPushNotificationsService.send(request);
		CompletableFuture.allOf(pushNotification).join();

		try {
			String firebaseResponse = pushNotification.get();
			
			return new ResponseEntity<>(firebaseResponse, HttpStatus.OK);
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (ExecutionException e) {
			e.printStackTrace();
		}

		return new ResponseEntity<>("Push Notification ERROR!", HttpStatus.BAD_REQUEST);
	}
}
5. Run & Check Result

– Config maven build:
clean install
– Run project with mode Spring Boot App.
– Open Browser, enter URL:
http://localhost:8080/send
spring-boot-fcm-push-notification-result-web

Look back to the Android App Client that can subscribe/unsubscribe TOPIC and receive Message:
– Android App Client in background:
spring-boot-fcm-push-notification-result-android

– Android App Client in running foreground:
spring-boot-fcm-push-notification-result-logcat

III. Source Code

SpringBootFCMPushNotif

28 thoughts on “Firebase Cloud Messaging – Spring Server to Push Notification Example | Spring Boot”

    1. Hi jagadish,

      I haven’t tried yet, but I think it works with iOS devices because we just make HTTP POST request to Firebase Server, then it will send Notification to devices which have subscribed TOPIC.

      Regards,
      JSA.

  1. 저는 전자정부프레임웍을 사용하는데
    import org.springframework.http.HttpRequest;
    import org.springframework.http.client.ClientHttpRequestExecution;
    import org.springframework.http.client.ClientHttpRequestInterceptor;
    import org.springframework.http.client.ClientHttpResponse;
    import org.springframework.http.client.support.HttpRequestWrapper;
    모든게 다 임폴트가 되지 않습니다.

    1. The thing is firebase generates a unique device Id for your target device when the app is run for the first time,and is being used as the identity of the device,If the User uninstalls the app or clears the data of the app then In that case On re installing or reopening the app the device Id will differ which will not be identified by firebase to send the notification this will result in the error Not Registered

  2. Most of whatever you articulate is supprisingly precise and it makes me wonder why I had not looked at this with this light previously. This article truly did turn the light on for me as far as this subject goes. But there is actually one particular position I am not too cozy with so whilst I make an effort to reconcile that with the core theme of the point, let me observe what all the rest of the readers have to say.Nicely done.

Leave a Reply

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