Skip to content

Instantly share code, notes, and snippets.

@thetekst
Last active April 2, 2019 11:29
Show Gist options
  • Save thetekst/b32621aedf4e56e7eba29396ac406171 to your computer and use it in GitHub Desktop.
Save thetekst/b32621aedf4e56e7eba29396ac406171 to your computer and use it in GitHub Desktop.
Server Side Events (SSE). Spring Boot 2
package ru.tkachenko.app.rest.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
import reactor.util.function.Tuple2;
import ru.tkachenko.app.data.converter.TopicConverter;
import ru.tkachenko.app.data.model.db.Topic;
import ru.tkachenko.app.rest.model.TopicDto;
import ru.tkachenko.app.rest.model.TopicRequest;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.stream.Stream;
/**
* @author d.tkachenko
*/
@Slf4j
@RestController
@RequestMapping(ControllerConstant.V1 + "/topic/futures")
public class FuturesTopicController {
private final List<Topic> favorites = new ArrayList<>();
private final TopicConverter topicConverter;
public FuturesTopicController(final TopicConverter topicConverter) {
this.topicConverter = topicConverter;
final LocalDateTime now = LocalDateTime.now();
final List<Topic> topics = List.of(
new Topic()
.setId(1L)
.setName("Left")
.setCreated(now)
.setUpdated(now),
new Topic()
.setId(2L)
.setName("Right")
.setCreated(now)
.setUpdated(now),
new Topic()
.setId(3L)
.setName("Top")
.setCreated(now)
.setUpdated(now),
new Topic()
.setId(4L)
.setName("Bottom")
.setCreated(now)
.setUpdated(now));
favorites.addAll(topics);
}
@GetMapping(produces = MediaType.TEXT_EVENT_STREAM_VALUE)
@CrossOrigin
public Flux<TopicDto> get() {
Flux<Long> interval = Flux.interval(Duration.ofSeconds(5));
interval.subscribe((i) -> favorites.forEach(topic -> topic.setUpdated(LocalDateTime.now())));
Flux<TopicDto> stockTransactionFlux = Flux.fromStream(Stream.generate(() -> {
final Topic randomTopic = getRandomTopic();
return new TopicDto()
.setId(randomTopic.getId())
.setCreated(randomTopic.getCreated())
.setUpdated(randomTopic.getUpdated())
.setName(randomTopic.getName());
}));
return Flux.zip(interval, stockTransactionFlux).map(Tuple2::getT2);
}
@DeleteMapping("{id}")
public void delete(@PathVariable final Long id) {
log.info("size before: {}", favorites.size());
favorites.removeIf(topic -> topic.getId().equals(id));
log.info("size after: {}. topic id {} removed", favorites.size(), id);
}
@PostMapping
public List<Topic> add(@RequestBody final TopicRequest request) {
request.setCreated(LocalDateTime.now());
request.setUpdated(LocalDateTime.now());
log.info("size before: {}", favorites.size());
favorites.add(topicConverter.convertToEntity(request));
log.info("size after: {}. topic id {} added", favorites.size(), request.getId());
return favorites;
}
private Topic getRandomTopic() {
return favorites.get(new Random().nextInt(favorites.size()));
}
}
<!-- location: src/main/resources/static/index.html -->
<!-- url: http://localhost:8080/index.html -->
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<h1>Socket</h1>
<script>
var eventSource = new EventSource("http://localhost:8080/v1/api/topic/futures", {
withCredentials: true
});
// where withCredentials: true // CORS
eventSource.onmessage = function(e) {
console.log("received: " + e.data);
};
// or custom listener
// eventSource.addEventListener('join', function(e) {
// console.log( 'received ' + e.data );
// });
// if we use WebSocket:
// var socket = new WebSocket("ws://localhost:8080/v1/api/topic/futures");
// socket.addEventListener('message', function(event) {
// window.alert('message from server: ' + event.data);
// })
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment