Search code examples
javaandroidspringrestserver-sent-events

Spring rest service with SseEmitter


I'm trying to notify a simple html page when I call a controller on my server. I have an android application who calls my controller and when this is done I would like to notify my webpage that the controller was called.

Here is some of my code:

    @RequestMapping("/user") 
public class UserController {

    /**
     * Returns user by id.
     * 
     * @param user IMEI
     * @return
     */
    @RequestMapping(value = "/{imei}", method = RequestMethod.GET)
    public User getUser(@PathVariable String imei) {

        User myUser = null;
        try {
            myUser = DbConnector.getUserWithImei(imei);
        } catch (Exception e) {
            System.out.println("Couldn't get user from database");
            e.printStackTrace();
        }
        SseEmitter emitter = new SseEmitter();
        try {
            emitter.send("Hallokes");
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        emitter.complete();
        return myUser;
    }
}

All tutorials I see, the controller returns SseEmitter but I have to return a User. Must I make another controller with another mapping and listen on that url? How would I call that controller method within my existing controller? To what URL must my EventSource listen?

Thanks in advance for your help!

Kind regards.


Solution

  • I think you are almost there, Allinone51.

    Your call to SseEmitter.send() should probably be in the getUser method. The general pattern is that when you create the SseEmitter you need to "store" it somewhere for other code to get hold of it. You correctly return the SseEmitter from the getSseEmitter method, you just forgot to store it for the other method to be able to call 'send' on it.

    Adjusting on your example above, it could be something like this:

    //...
    private SseEmitter emitter;
    
    @RequestMapping(value = "/{imei}", method = RequestMethod.GET)
    public User getUser(@PathVariable String imei) { 
        User myUser = null;
    
        // .. do resolving of myUser (e.g. database etc).
    
        // Send message to "connected" web page:
        if (emitter != null) {
            emitter.send(myUser.toString()); // Or format otherwise, e.g. JSON.
        }
    
        // This return value goes back as a response to your android device
        // i.e. the caller of the getUser rest service.
        return myUser;
    }
    
    @RequestMapping(value = "/sse")
    public SseEmitter getSseEmitter() {
        emitter = new SseEmitter();
        return emitter;
    }
    

    Of course, the code above caters for only one single connection/emitter. There are more intelligent ways of storing that emitter. For example, in my online game application I hook the emitter into each Player object. That way whenever the player object on my server has something to tell to the player device, it has access to the correct emitter inside itself.