I have a problem with the implementation of SSE in spring. To be honest, I don't know if I use it correctly for what I want but I give it a try anyway.
What I try to do is a game where a user chooses a nickname and a game code. If then the game code exists he will be redirected to a lobby page.
Code for that: Angular:
this.joinGameService.addUser(nickname).subscribe(userId => { more calls for inserting data in database});
// more code
this.router.navigate(['/lobby']);
Spring boot:
Controller:
@RequestMapping(value = ["/addUser"], method = [RequestMethod.PUT])
fun addUser(@RequestBody userName: String?): ResponseEntity<String?> {
if (userName != null) {
var user_id = usersService.addUser(userName)
return ResponseEntity(user_id, HttpStatus.OK)
}
return ResponseEntity("Username must not be null", HttpStatus.BAD_REQUEST)
}
Service and JPA:
override fun addUser(name: String): String? {
var user = Users(name)
usersRepository.save(user)
return user.id
}
This works fine.
The problem:
What I want to do next, is making a constant call in the lobby component on the client-side, for retrieving users. So in my spring controller, I call every 10 seconds a service for returning data from my users table.
The code for that: Angular: ( I don't know if I did this correctly.. )
ngOnInit(): void {
// this.lobbyService.getUsers(this.gameCode).subscribe(a => console.log(a));
this.connect();
}
connect(): void {
const source = new EventSource('http://localhost:8080/api/users/getUsers?' + 'table_id=' + this.gameCode);
source.addEventListener('message', message => {
let n: Notification;
n = JSON.parse(message.data);
console.log(message.data);
// in the future, data will be mapped and pushed to an interface of kind User, to bind it to html file.
});
}
I don't get any data written in console.log.
Spring boot:
Controller:
@RequestMapping(value = ["/getUsers"], method = [RequestMethod.GET])
fun getAllUsers(@RequestParam table_id: String,response: HttpServletResponse?): SseEmitter? {
var emitter: SseEmitter? = null
try {
emitter = SseEmitter()
while (true) {
try {
print(table_id)
val count = usersService.getAllUsers(table_id)
print("\n\ncontroller: " + count) // this print the list of all list of users, so it works
emitter.send(count)
Thread.sleep((10 * // minutes to sleep
1 * // seconds to a minute
1000).toLong()) // milliseconds to a second
} catch (cae: ClientAbortException) {
BytecodeLogger.LOGGER.info("ClientAbortException Breaking the notification stream")
break
}
}
//Closes the stream
emitter.complete()
} catch (e: java.lang.Exception) {
//Closes the stream
emitter!!.complete()
}
return emitter // this doesn't return nothing
}
Service and JPA:
override fun getAllUsers(table_id: String) : List<Users?> {
val users = usersRepository.getUsers(table_id)
return users
}
@Query("SELECT * FROM users x WHERE x.id_game_table = ?1", nativeQuery = true)
fun getUsers(tableId: String): List<Users?>
The big problem, is that I don't get any response from the controller on the client-side.
PS: I know a better implementation would be to call usersService.getAllUsers only when I call the controller function, addUser, but I don't know how to do that (if you know you are free to help me out). Now I call data from ten to ten seconds and this is not quite a good implementation. I want a real-time application (without using a socket).