FCMSendPush
Firebase Cloud Messaging example
Structure
1 .
2 ├── build.sh
3 ├── pom.xml
4 ├── run.sh
5 ├── src
6 │ └── main
7 │ ├── java
8 │ │ └── hello
9 │ │ ├── Application.java
10 │ │ ├── Data.java
11 │ │ ├── Message.java
12 │ │ ├── Notification.java
13 │ │ ├── PushMessage.java
14 │ │ ├── PushResponse.java
15 │ │ └── SendPushController.java
16 │ └── resources
17 │ ├── application.properties
18 │ ├── logback-spring.xml
19 │ └── templates
20 │ ├── sendpushform.html
21 │ └── sendpush.html
1 build.sh
2 pom.xml
3 run.sh
4 src/main/java/hello/Application.java
5 src/main/java/hello/Data.java
6 src/main/java/hello/Message.java
7 src/main/java/hello/Notification.java
8 src/main/java/hello/PushMessage.java
9 src/main/java/hello/PushResponse.java
10 src/main/java/hello/SendPushController.java
11 src/main/resources/application.properties
12 src/main/resources/logback-spring.xml
13 src/main/resources/templates/sendpushform.html
14 src/main/resources/templates/sendpush.html
build.sh
run.sh
pom.xml
1 <?xml version="1.0" encoding="UTF-8"?>
2 <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">
3 <modelVersion>4.0.0</modelVersion>
4 <groupId>hello</groupId>
5 <artifactId>test-spring-boot-push</artifactId>
6 <version>0.1.0</version>
7 <parent>
8 <groupId>org.springframework.boot</groupId>
9 <artifactId>spring-boot-starter-parent</artifactId>
10 <version>2.1.6.RELEASE</version>
11 </parent>
12 <dependencies>
13 <dependency>
14 <groupId>org.springframework.boot</groupId>
15 <artifactId>spring-boot-starter-thymeleaf</artifactId>
16 </dependency>
17 <dependency>
18 <groupId>org.springframework.boot</groupId>
19 <artifactId>spring-boot-starter-web</artifactId>
20 </dependency>
21 <dependency>
22 <groupId>com.google.code.gson</groupId>
23 <artifactId>gson</artifactId>
24 <version>2.8.6</version>
25 <scope>compile</scope>
26 </dependency>
27 </dependencies>
28 <properties>
29 <start-class>hello.Application</start-class>
30 </properties>
31 <build>
32 <plugins>
33 <plugin>
34 <groupId>org.springframework.boot</groupId>
35 <artifactId>spring-boot-maven-plugin</artifactId>
36 </plugin>
37 </plugins>
38 </build>
39 <repositories>
40 <repository>
41 <id>spring-milestone</id>
42 <url>http://repo.spring.io/libs-release</url>
43 </repository>
44 </repositories>
45 <pluginRepositories>
46 <pluginRepository>
47 <id>spring-milestone</id>
48 <url>http://repo.spring.io/libs-release</url>
49 </pluginRepository>
50 </pluginRepositories>
51 </project>
src/main/java/hello/Application.java
1 package hello;
2
3 import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
4 import org.springframework.boot.SpringApplication;
5 import org.springframework.context.annotation.ComponentScan;
6 import org.slf4j.Logger;
7 import org.slf4j.LoggerFactory;
8
9 @ComponentScan //scans for @Component beans
10 @EnableAutoConfiguration
11 public class Application {
12 private static Logger logger;
13
14 public static void main(String[] args) {
15 logger = LoggerFactory.getLogger(Application.class);
16 logger.info("Starting application");
17 SpringApplication.run(Application.class, args);
18 }
19 }
src/main/java/hello/Message.java
src/main/java/hello/PushMessage.java
1 package hello;
2
3 public class PushMessage {
4 private String to;
5 private Data data;
6 private Notification notification;
7
8 public PushMessage() {
9 }
10
11 public Notification getNotification() {
12 return notification;
13 }
14
15 public void setNotification(Notification notification) {
16 this.notification = notification;
17 }
18
19 public Data getData() {
20 return data;
21 }
22
23 public void setData(Data data) {
24 this.data = data;
25 }
26
27 public String getTo() {
28 return to;
29 }
30
31 public void setTo(String to) {
32 this.to = to;
33 }
34 }
src/main/java/hello/SendPushController.java
1 package hello;
2
3 import org.springframework.core.env.Environment;
4 import org.springframework.http.HttpHeaders;
5 import org.springframework.http.HttpMethod;
6 import org.springframework.stereotype.Controller;
7 import org.springframework.web.bind.annotation.RequestMapping;
8 import org.springframework.web.bind.annotation.RequestMethod;
9 import org.springframework.web.bind.annotation.RequestParam;
10 import org.springframework.ui.Model;
11 import org.springframework.util.MimeTypeUtils;
12
13 import java.io.BufferedReader;
14 import java.io.InputStreamReader;
15 import java.io.OutputStream;
16 import java.net.HttpURLConnection;
17 import java.net.URL;
18 import com.google.gson.Gson;
19 import org.slf4j.Logger;
20 import org.slf4j.LoggerFactory;
21
22 @Controller
23 public class SendPushController {
24 private static final String UTF_8 = "utf-8";
25 private final Logger logger = LoggerFactory.getLogger(SendPushController.class);
26 private Environment env;
27 private String fcmKey;
28 private String fcmSendUrl;
29
30 public SendPushController(Environment env) {
31 logger.debug("SendPush controller created.");
32 this.env = env;
33 this.fcmKey = this.env.getProperty("fcm.key");
34 this.fcmSendUrl = this.env.getProperty("fcm.send.url");
35 }
36
37 @RequestMapping("/sendpush")
38 // http://localhost:8181/sendpush
39 public String sendpush(Model model) {
40 logger.info("Greeting sendpush called.");
41 model.addAttribute("title", "Send push");
42 return "sendpush";
43 }
44
45 @RequestMapping(value = "/sendpushform", method = RequestMethod.POST)
46 public String sendpushform(@RequestParam("dev_token") String devToken,
47 @RequestParam("message_title") String messageTitle, @RequestParam("message") String message, Model model) {
48 logger.info("Greeting sendpushform called.");
49 model.addAttribute("devToken", devToken);
50 model.addAttribute("message", message);
51 model.addAttribute("messageTitle", messageTitle);
52 model.addAttribute("title", "Send push result");
53
54 try {
55 URL url = new URL(this.fcmSendUrl);
56 HttpURLConnection connection = (HttpURLConnection) url.openConnection();
57 connection.setRequestMethod(HttpMethod.POST.name());
58
59 connection.setRequestProperty(HttpHeaders.CONTENT_TYPE,
60 MimeTypeUtils.APPLICATION_JSON_VALUE + "; " + UTF_8);
61 connection.setRequestProperty(HttpHeaders.ACCEPT, MimeTypeUtils.APPLICATION_JSON_VALUE);
62 connection.setRequestProperty(HttpHeaders.AUTHORIZATION, "key=" + this.fcmKey);
63 connection.setDoOutput(true);
64
65 PushMessage push = new PushMessage();
66 push.setTo(devToken);
67 Data data = new Data();
68 data.setBody(message);
69 data.setTitle(messageTitle);
70 push.setData(data);
71
72 Notification notification = new Notification();
73 notification.setBody(message);
74 notification.setTitle(messageTitle);
75 push.setNotification(notification);
76 Gson gson = new Gson();
77 String payload = gson.toJson(push);
78 try (OutputStream os = connection.getOutputStream()) {
79 byte[] input = payload.getBytes(UTF_8);
80 os.write(input, 0, input.length);
81 }
82
83 try (BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream(), UTF_8))) {
84 StringBuilder response = new StringBuilder();
85 String responseLine = null;
86 while ((responseLine = br.readLine()) != null) {
87 response.append(responseLine.trim());
88 }
89 PushResponse pr = gson.fromJson(response.toString(), PushResponse.class);
90 model.addAttribute("prSuccess", pr.getSuccess());
91 model.addAttribute("multicastId", pr.getMulticast_id());
92 }
93
94 } catch (Exception e) {
95 e.printStackTrace();
96 }
97
98 return "sendpushform";
99 }
src/main/java/hello/Data.java
1 package hello;
2
3 public class Data {
4 private String title;
5 private String body;
6
7 public Data() {
8 }
9
10 public String getBody() {
11 return body;
12 }
13
14 public void setBody(String body) {
15 this.body = body;
16 }
17
18 public String getTitle() {
19 return title;
20 }
21
22 public void setTitle(String title) {
23 this.title = title;
24 }
25 }
src/main/java/hello/Notification.java
1 package hello;
2
3 public class Notification {
4 private String title;
5 private String body;
6
7 public Notification() {
8 }
9
10 public String getBody() {
11 return body;
12 }
13
14 public void setBody(String body) {
15 this.body = body;
16 }
17
18 public String getTitle() {
19 return title;
20 }
21
22 public void setTitle(String title) {
23 this.title = title;
24 }
25 }
src/main/java/hello/PushResponse.java
1 package hello;
2
3 public class PushResponse {
4
5 private long multicast_id;
6 private long success;
7 private long failure;
8 private long canonical_ids;
9 private Message[] results;
10
11 public Message[] getResults() {
12 return results;
13 }
14
15 public long getCanonical_ids() {
16 return canonical_ids;
17 }
18
19 public void setCanonical_ids(long canonical_ids) {
20 this.canonical_ids = canonical_ids;
21 }
22
23 public long getFailure() {
24 return failure;
25 }
26
27 public void setFailure(long failure) {
28 this.failure = failure;
29 }
30
31 public long getSuccess() {
32 return success;
33 }
34
35 public void setSuccess(long success) {
36 this.success = success;
37 }
38
39 public long getMulticast_id() {
40 return multicast_id;
41 }
42
43 public void setMulticast_id(long multicast_id) {
44 this.multicast_id = multicast_id;
45 }
46
47 public void setResults(Message[] results) {
48 this.results = results;
49 }
50 }
src/main/resources/application.properties
src/main/resources/logback-spring.xml
1 <?xml version="1.0" encoding="UTF-8"?>
2 <configuration>
3 <!--
4 <include resource="org/springframework/boot/logging/logback/defaults.xml" />
5 <property name="LOG_FILE" value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}/}spring.log}"/>
6 <include resource="org/springframework/boot/logging/logback/file-appender.xml" />
7 -->
8 <!-- override spring logback default behaviour -->
9 <appender name="FILE" class="ch.qos.logback.core.FileAppender">
10 <file>${filelog}</file>
11 <encoder>
12 <pattern>%date{ISO8601} [%thread] %-5level %logger{35} - %msg%n</pattern>
13 </encoder>
14 </appender>
15 <appender name="GREETFILE" class="ch.qos.logback.core.FileAppender">
16 <file>/tmp/greet.log</file>
17 <encoder>
18 <pattern>%date{ISO8601} [%thread] %-5level %logger{35} - %msg%n</pattern>
19 </encoder>
20 </appender>
21 <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
22 <layout class="ch.qos.logback.classic.PatternLayout">
23 <Pattern>%yellow(%date{ISO8601}) %green([%thread]) %highlight(%-5level) %cyan(%logger{35}) - %white(%msg%n) </Pattern>
24 </layout>
25 </appender>
26 <root level="INFO">
27 <appender-ref ref="FILE" />
28 <appender-ref ref="CONSOLE"/>
29 </root>
30 <logger name="hello.GreetingController" level="debug" additivity="false">
31 <appender-ref ref="GREETFILE"/>
32 <appender-ref ref="CONSOLE" />
33 </logger>
34 </configuration>
src/main/resources/templates/sendpushform.html
1 <!DOCTYPE HTML>
2 <html>
3 <head>
4 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
5 <meta name="viewport" content="width=device-width, initial-scale=1" />
6 <title>Send push result</title>
7 <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
8 <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous" />
9 <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.bundle.min.js"
10 integrity="sha384-ygbV9kiqUc6oa4msXn9868pTtWMgiQaeYH7/t7LECLbyPA2x65Kgf80OJFdroafW"
11 crossorigin="anonymous"></script>
12 </head>
13 <body>
14 <div class="container">
15 <div class="row">
16 <div class="col-2"></div>
17 <div class="col-8">
18 <div class="card text-white bg-success">
19 <div class="card-header">
20 <h1 th:text="${title}"></h1>
21 </div>
22 <div class="card-body bg-white" style="color:black;">
23 <h1 class="card-title">Dev token</h1>
24 <p class="card-text" th:text="${devToken}"></p>
25 <h1 class="card-title">Message title</h1>
26 <p class="card-text" th:text="${messageTitle}"></p>
27 <h1 class="card-title">Message</h1>
28 <p class="card-text" th:text="${message}"></p>
29 <h1 class="card-title">Push success</h1>
30 <p class="card-text" th:text="${prSuccess}"></p>
31 <h1 class="card-title">Push multicast Id</h1>
32 <p class="card-text" th:text="${multicastId}"></p>
33 </div>
34 <a href="/sendpush" class="btn btn-lg btn-primary btn-block">Go back</a>
35 </div>
36 </div>
37 <div class="col-2"></div>
38 </div>
39 </div>
40 </body>
41 </html>
src/main/resources/templates/sendpush.html
1 <!DOCTYPE HTML>
2 <html xmlns:th="http://www.thymeleaf.org">
3 <head>
4 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
5 <meta name="viewport" content="width=device-width, initial-scale=1" />
6 <title>Send push</title>
7 <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
8 <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet"
9 integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous" />
10 <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.bundle.min.js"
11 integrity="sha384-ygbV9kiqUc6oa4msXn9868pTtWMgiQaeYH7/t7LECLbyPA2x65Kgf80OJFdroafW"
12 crossorigin="anonymous"></script>
13 </head>
14 <body>
15 <div class="container">
16 <div class="row">
17 <div class="col-2"></div>
18 <div class="col-8">
19 <div class="card text-white bg-primary">
20 <div class="card-header">
21 <h1 th:text="${title}"></h1>
22 </div>
23 <div class="card-body bg-white" style="color:black;">
24 <form action="sendpushform" method="POST">
25 <input type="text" name="dev_token" class="form-control" placeholder="dev token" />
26 <br />
27 <input type="text" name="message_title" class="form-control" placeholder="message title" />
28 <br />
29 <input type="text" name="message" class="form-control" placeholder="message" />
30 <br />
31 <input type="submit" value="Send push notification"
32 class="btn btn-lg btn-primary btn-block" />
33 </form>
34 </div>
35 </div>
36 </div>
37 <div class="col-2"></div>
38 </div>
39 </div>
40 </body>
41 </html>