Allinone51 Allinone51 - 7 months ago 562
Java Question

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.

Answer

I managed to make the SseEmitter work. I'll example how I did it, maybe it will help someone else.

The first thing I found out is that EventSource("url") actually just 'calls' that url (correct me if I'm wrong). So in the case of a Restcontroller it would just call that controller over and over. Now when you use SseEmitter.send, the onMessage() method of the EventSource get triggered. So what I did is add another controller method with mapping "/sse" and let my eventSource call that method. Now when my original controller method which returns a user is called, I just set a global variable to true, and if that variable is true, I send a message. Code will explain this better:

My method called within my android app follow by the controller method for SSE:

@RequestMapping(value = "/{imei}", method = RequestMethod.GET)
    public User getUser(@PathVariable String imei) { // @PathVariable for
                                                        // passing variables
                                                        // in uri.
                                                        // (<root-url>/service/greeting/myVariable)
        User myUser = null;
        try {
            myUser = DbConnector.getUserWithImei(imei);
        } catch (Exception e) {
            System.out.println("Couldn't get user from database");
            e.printStackTrace();
        }
        if (myUser != null) {
            if (myUser.getAccess() == 1) {
                calledImei = true;
            }
        }
        return myUser;
    }

    @RequestMapping(value = "/sse")
    public SseEmitter getSseEmitter() {
        SseEmitter sseEmitter = new SseEmitter();
        if(calledImei) {
            try {
                sseEmitter.send("Message 1");
                calledImei = false;
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        sseEmitter.complete();
        return sseEmitter;
    }
}

And now the HTML page with the EventSource:

<body>
    <script>
            var source = new EventSource("rest/user/sse");
            source.onmessage = function(event) {
                 //Do what you need to do when message received.
            }
    </script>
</body>

Hope this will help some other people.