junit 5 Latest reactive spring boot sse thymeleaf webflux

Spring Boot WebFlux + Example of events sent by the server – Mkyong.com

Project Directory

In this article we’ll present methods to develop a reactive net software using events sent by the server

  • Spring Begin 2.1.2.RELEASE
  • Spring WebFlux 5.1.four.RELEASE
  • Thymeleaf 3.0. 11.RELEASE
  • JUnit 5.3.2
  • Maven 3

Returning to Spring JSON and Title MediaType.TEXT_EVENT_STREAM_VALUE

@RestController
public class CommentController

@GetMapping (path = "/ comment / stream",
produce = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux feed ()
// …

In Javascript, EventSource is used to send the request to the endpoint above.

perform downloadComments ()

this.source = null;

this.start = perform ()

this.supply = new EventSource ("/ comment / stream");

this.source.addEventListener ("message", action (occasion)

var comment = JSON.parse (occasion.knowledge);

// … replace somewhere

);

this.supply.onerror = perform ()
this.shut ();
;

;

this.stop = perform ()
this.source.close ();

remark = new load ();

window.onload = perform ()
comment.begin ();
;
window.onbeforeunload = perform ()
comment.stop ();

1. Venture Directory

2. Maven

pom.xml

four.zero.0

com.mkyong.spring.reactive
to webflux-thymeleaf
1.0

1.eight
5.three.2 [19659017] org. springframework.boot
spring-play-starter for dad or mum
2.1.2.RELEASE

org.springframework.boot
bow-play-starter-webflux

org.springframework.boot
spring -boot-starter-thymeleaf

org.springframework.boot
spring-play-starter check
check

trains
trains

org.junit.jupiter
trains – Jupiter motor
$ junit-jupiter.version
check

org.springframework.boot
spring-boot-DevTools
true

org.springframework.boot
Spring – boot-maven plugin

org.apache.maven.plugins
maven-surefire plugin
2.22.0

Show undertaking dependencies

$ mvn dependence: tree

[INFO] com.mkyong.spring.reactive: webflux-thymeleaf: jar: 1.zero
[INFO] + – org.springframework.boot: spring-boot-starter-webflux: jar: 2.1.2.RELEASE: compile
[INFO] | + – org.springframework.boot: spring-boot-starter: jar: 2.1.2.RELEASE: flip
[INFO] | | + – org.springframework.boot: spring-boot-starter-logging: jar: 2.1.2.RELEASE: compile
[INFO] | | | + – ch.qos.logback: logback-basic: jar: 1.2.3: translate
[INFO] | | | | – ch.qos.logback: logback-core: jar: 1.2.three: compile
[INFO] | | | + – org.apache.logging.log4j: log4j-to-slf4j: jar: 2.11.1: compile
[INFO] | | | | – org.apache.logging.log4j: log4j-api: jar: 2.11.1: compile
[INFO] | | | – org.slf4j: jul-to-slf4j: jar: 1.7.25: translate
[INFO] | | + – javax.annotation: javax.annotation-api: jar: 1.3.2: compile
[INFO] | | – org.yaml: snakeyaml: jar: 1.23: runtime
[INFO] | + – org.springframework.boot: spring-boot-starter-json: jar: 2.1.2.RELEASE: compile
[INFO] | | + – com.fasterxml.jackson.core: jackson-datasind: jar: 2.9.eight: compile
[INFO] | | | + – com.fasterxml.jackson.core: jackson: jar: 2.9.zero: compile
[INFO] | | | com.fasterxml.jackson.core: jackson-core: jar: 2.9.eight: compile
[INFO] | | + – com.fasterxml.jackson.datatype: jackson-datatype-jdk8: jar: 2.9.eight: compile
[INFO] | | + – com.fasterxml.jackson.datatype: jackson-datatype-jsr310: jar: 2.9.eight: compile
[INFO] | | com.fasterxml.jackson.module: jackson-module-parameter-names: jar: 2.9.eight: assemble
[INFO] | + – org.springframework.boot: spring-boot-starter reactor: jar: 2.1.2.RELEASE: compile
[INFO] | | – io.projectreactor.netty: reactor: jar: zero.8.4.RELEASE: compile
[INFO] | | + – io.netty: netty-codec-http: jar: 4.1.31.The terminal: flip
[INFO] | | | – io.netty: netty-codec: jar: four.1.31.The terminal: turn
[INFO] | | + – io.netty: netty-codec-http2: jar: four.1.31.The terminal: flip
[INFO] | | + – io.netty: netty-handler: jar: four.1.31.The terminal: turn
[INFO] | | | + – io.netty: netty buffer: jar: four.1.31. Terminal: assemble
[INFO] | | | – io.netty: netty-transport: jar: four.1.31.The terminal: turn
[INFO] | | | – io.netty: netty-resolver: jar: 4.1.31.The terminal: flip
[INFO] | | + – io.netty: netty-handler-proxy: jar: four.1.31.The terminal: turn
[INFO] | | | – io.netty: netty-codec-socks: jar: four.1.31.The terminal: flip
[INFO] | | – io.netty: netty-transport-native epoll: jar: linux-x86_64: 4.1.31.Ultimate: compile
[INFO] | | + – io.netty: netty-widespread: jar: 4.1.31.The terminal: turn
[INFO] | | – io.netty: netty-transport-native-unix-widespread: jar: four.1.31.Conclusion: compile
[INFO] | + – org.hibernate.validator: Hibernate-Validator: jar: 6.0.14.Conclusion: compile
[INFO] | | + – javax.validation: validation-api: jar: 2.zero.1. Conclusion: put together
[INFO] | | + – org.jboss.logging: jboss-logging: jar: 3.3.2 Conclusion: assemble
[INFO] | | – com.fasterxml: Classmate: jar: 1.4.0: Translate
[INFO] | + – org.springframework: spring-net: jar: 5.1.four.RELEASE: put collectively
[INFO] | | – org.springframework: spring-beans: jar: 5.1.4.RELEASE: put collectively
[INFO] | + – org.springframework: spring-webflux: jar: 5.1.4.RELEASE: put collectively
[INFO] | | – io.projectreactor: reactor core: jar: 3.2.5.RELEASE: assemble
[INFO] | | – org.reactivestreams: reactive currents: jar: 1.zero.2: assemble
[INFO] | org.synchronoss.cloud:nio-multipart-parser:jar:1.1.zero:compile
[INFO] | + – org.slf4j: slf4j-api: jar: 1.7.25: translate
[INFO] | org.synchronoss.cloud:nio-stream-storage:jar:1.1.3:compile
[INFO] + – org.springframework.boot: spring-boot-starter-thymeleaf: jar: 2.1.2.RELEASE: compile
[INFO] | + – org.thymeleaf: thymeleaf-spring5: jar: three.0.11.RELEASE: compile
[INFO] | | – org.thymeleaf: thymeleaf: jar: 3.0.11.RELEASE: compile
[INFO] | | + – org.attoparser: attoparser: jar: 2.zero.5.RELEASE: Translate
[INFO] | | – org.unbescape: unbescape: jar: 1.1.6.RELEASE: assemble
[INFO] | org.thymeleaf.extras: thymeleaf-extras-java8time: jar: 3.0.2.RELEASE: compile
[INFO] + – org.springframework.boot: suspension begin check: jar: 2.1.2.RELEASE: check
[INFO] | + – org.springframework.boot: spring-boot-check: jar: 2.1.2.RELEASE: check
[INFO] | + – org.springframework.boot: spring-boot-check-autoconfigure: jar: 2.1.2.RELEASE: check
[INFO] | + – com.jayway.jsonpath: json-path: jar: 2.4.0: check
[INFO] | | – internet.minidev: json-sensible: jar: 2.three: check
[INFO] | | – internet.minidev: accessors-sensible: jar: 1.2: check
[INFO] | | – org.ow2.asm: asm: jar: 5.zero.four: check
[INFO] | + – org.assertj: assertj-core: jar: three.11.1: check
[INFO] | + – org.mockito: mockito-core: jar: 2.23.4: check
[INFO] | | + – internet.bytebuddy: byte-buddy: jar: 1.9.7: check
[INFO] | | + – internet.bytebuddy: byte-man-agent: jar: 1.9.7: check
[INFO] | | – org.objenesis: objenesis: jar: 2.6: check
[INFO] | + – org.hamcrest: hamcrest-core: jar: 1.three: check
[INFO] | + – org.hamcrest: hamcrest-library: jar: 1.three: check
[INFO] | + – org.skyscreamer: jsonassert: jar: 1.5.0: check
[INFO] | | com.vaadin.external.google:android-json:jar:0.zero.20131108.vaadin1:check
[INFO] | + – org.springframework: spring-core: jar: 5.1.four.RELEASE: compile
[INFO] | | – org.springframework: spring-jcl: jar: 5.1.four.RELEASE: put collectively
[INFO] | + – org.springframework: spring check: jar: 5.1.four.RELEASE: check
[INFO] | – org.xmlunit: xmlunit-core: jar: 2.6.2: check
[INFO] | – javax.xml.bind: jaxb-api: jar: 2.three.1: check
[INFO] | – javax.activation: javax.activation-api: jar: 1.2.0: check
[INFO] + – org.junit.jupiter: trains-Jupiter engine: jar: 5.three.2: check
[INFO] | + – org.apiguardian: apiguardian-api: jar: 1.0.zero: check
[INFO] | + – org.junit.platform: trains-platform engine: jar: 1.3.2: check
[INFO] | | + – org.junit.platform: junit-platform-Commons: jar: 1.3.2: check
[INFO] | | – org.opentest4j: opentest4j: jar: 1.1.1: check
[INFO] | – org.junit.jupiter: junit-Jupiter-api: jar: 5.three.2: check
[INFO] org.springframework.boot: spring-boot-devtools: jar: 2.1.2.RELEASE: compile (non-compulsory)
[INFO] + – org.springframework.boot: spring-boot: jar: 2.1.2.RELEASE: compile
[INFO] | – org.springframework: spring-context: jar: 5.1.4.RELEASE: compile
[INFO] | + – org.springframework: spring-aop: jar: 5.1.4.RELEASE: compile
[INFO] | – org.springframework: spring-expression: jar: 5.1.4.RELEASE: compile
[INFO] org.springframework.boot: spring-boot-autoconfigure: jar: 2.1.2.RELEASE: assemble

3. Spring Boot + Spring WebFlux

three.1 Spring WebFlux Mark Based mostly Management. Permit knowledge streaming. write produce = MediaType.TEXT_EVENT_STREAM_VALUE

CommentController.java

package deal com.mkyong.reactive.controller;

import com.mkyong.reactive.model.Comment;
import com.mkyong.reactive.repository.CommentRepository;
import org.springframework.beans.manufacturing unit.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.net.bind.annotation.GetMapping;
import org.springframework.net.bind.annotation.RestController;
tuontireaktori.core.writer.Flux;

@RestController
public class CommentController

@Autowired
personal commentRepository commentRepository;

@GetMapping (path = "/ comment / stream",
produce = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux feed ()
restore this.commentRepository.findAll ();

MainController.java

package deal com.mkyong.reactive.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Mannequin;
import org.springframework.net.bind.annotation.GetMapping;

@Controller
generic MainController

@GetMapping ("/")
public string (remaining template)
return "index";

three.2 Restore the Flux object in the archive.

CommentRepository.java

package deal com.mkyong.reactive.repository;

import com.mkyong.reactive.mannequin.Remark;
tuontireaktori.core.publisher.Flux;

public interface CommentRepository

Flux findAll ();

ReactiveCommentRepository.java

package deal com.mkyong.reactive.repository;

import com.mkyong.reactive.model.Remark;
import com.mkyong.reactive.utils.CommentGenerator;
import org.springframework.stereotype.Repository;
tuontireaktori.core.writer.Flux;

import java.time.
import java.util.Arrays;
import java.util.Record;

@Repository
public class ReactiveCommentRepository executes command register

@Bypass
public Flux findAll ()

// simulates knowledge streaming each two seconds.
return flux.interval (period of second seconds (1))
.onBackpressureDrop ()
.map (this :: generateComment)
.flatMapIterable (x -> x);

personal record createComment (long term)

Comment obj = new remark (
CommentGenerator.randomAuthor (),
CommentGenerator.randomMessage (),
CommentGenerator.getCurrentTimeStamp ());
returns Arrays.asList (obj);

three.3 Class Class for Random Feedback

CommentGenerator.java

package deal com.mkyong.reactive.utils;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.Record;
import java.util.Random;

publicGlassGenerator

personal static remaining DateTimeFormatter dtf = DateTimeFormatter.ofPattern ("yyyy / MM / dd HH: mm: ss");
personal static last Random RANDOM = new Random (System.currentTimeMillis ());

personal static last record COMMENT_AUTHOR =
Arrays.asList (
"Mkyong", "Oliver", "Jack", "Harry", "Jacob",
"Isla", "Emily", "Poppy", "Ava", "Isabella");

personal static ultimate record COMMENT_MESSAGE =
Arrays.asList (
"I love this!",
"Me too!",
"Wow,"
"True!",
"Hello everyone here?"
"Good!");

public Static String randomAuthor ()
restore COMMENT_AUTHOR.get (RANDOM.nextInt (COMMENT_AUTHOR.measurement ());

public static String randomMessage ()
restore COMMENT_MESSAGE.get (RANDOM.nextInt (COMMENT_MESSAGE.measurement ()));

public static string getCurrentTimeStamp ()
return to dtf.format (LocalDateTime.now ());

3.4 Remark Templates

Film.java

package deal com.mkyong.reactive.mannequin;

public grade remark

personal string;
personal string;
personal string;

// getter, setter and builder

3.5 Spring Begin

CommentWebApplication.java

package deal com.mkyong.reactive;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class CommentWebApplication

public Static void essential (String [] args)
SpringApplication.run (CommentWebApplication.class, args);

four. Thymeleaf

The Thymeleaf mannequin has no special reactive character, just normal loop

assets / templates / index.html

Spring WebFlux + Server Sent Events

Writer Message ] [[$comment.author]] [[$comment.message]] [[$comment.timestamp]]

5. JavaScript EventSource

The secret is to use the Javascript EventSource class to send the request and take heed to the message occasion and reactively update the streaming knowledge to the table.

assets / static / js / primary.js

perform downloadComments ()

this.supply = null;

this.start = perform ()

var commentTable = document.getElementById ("comments");

this.supply = new EventSource ("/ comment / stream");

this.source.addEventListener ("message", action (occasion)

// These events are JSON, so parsing and DOM spreading are wanted
var comment = JSON.parse (occasion.knowledge);

var row = commentTable.getElementsByTagName ("tbody") [0] .insertRow (0);
var cell0 = row.insertCell (zero);
var cell1 = row.insertCell (1);
var cell2 = row.insertCell (2);

cell0.className = "author style";
cell0.innerHTML = remark.writer;

cell1.className = "text";
cell1.innerHTML = remark.message;

cell2.className = "date";
cell2.innerHTML = comment.timestamp;

);

this.source.onerror = perform ()
this.close ();
;

;

this.stop = perform ()
this.supply.shut ();

comment = new load ();

/ *
* Register callback requests to start out and stop the SSE driver.
* /
window.onload = perform ()
comment.start ();
;
window.onbeforeunload = perform ()
remark.cease ();

6. Unit Check

WebTestClient Unit exams streaming responses

TestCommentWebApplication.java

package deal com.mkyong.reactive;

import com.mkyong.reactive.model.Comment;
convey org.junit.jupiter.api.Check;
import org.springframework.beans.manufacturing unit.annotation.Autowired;
import org.springframework.boot.check.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.check.net.reactive.server.WebTestClient;

import java.util.Listing;

import static org.junit.jupiter.api.Assertions.assertEquals;

@SpringBootTest (webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public category TestCommentWebApplication

@Autowired
personal WebTestClient webClient;

@Check
public void testCommentStream ()

Listing comments = webClient
.get (). URI ("/ comment / stream")
.Affirm (MediaType.valueOf (MediaType.TEXT_EVENT_STREAM_VALUE))
.change()
.expectStatus (). isOk ()
.returnResult (Comment.class)
.getResponseBody ()
.take (three) // takes three remark objects
.collectList ()
.block();

feedback. All (x -> System.out.println (x));

assertEquals (3, comments.measurement ());

7.Demo

$ mvn spring-boot: run

2019-02-11 15: 41: 17.657 INFO 257192 — [ restartedMain] o.s.b.net.embedded.netty.NettyWebServer: Netty began at the gate: 8080

URL = http: // localhost: 8080
The knowledge is streaming and a random remark is displayed every 1 second.

Download Supply

References