Spring 使用 SseEmitter 休息服务
Spring rest service with SseEmitter
我试图在我调用服务器上的控制器时通知一个简单的 html 页面。我有一个 android 应用程序调用我的控制器,完成后我想通知我的网页控制器被调用。
这是我的一些代码:
@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;
}
}
我看到的所有教程,控制器 returns SseEmitter 但我必须 return 一个用户。我必须用另一个映射制作另一个控制器并监听那个 url 吗?我将如何在现有控制器中调用该控制器方法?
URL 我的 EventSource 必须监听什么?
在此先感谢您的帮助!
亲切的问候。
我设法使 SseEmitter 正常工作。我将解释我是如何做到的,也许它会对其他人有所帮助。
我发现的第一件事是 EventSource("url") 实际上只是 'calls' url(如果我错了请纠正我)。因此,在 Restcontroller 的情况下,它只会一遍又一遍地调用该控制器。现在,当您使用 SseEmitter.send 时,会触发 EventSource 的 onMessage() 方法。所以我所做的是添加另一个带有映射“/sse”的控制器方法,并让我的 eventSource 调用该方法。现在,当调用 returns 一个用户的原始控制器方法时,我只需将一个全局变量设置为 true,如果该变量为 true,我将发送一条消息。代码会更好地解释这一点:
我的方法在我的 android 应用程序中调用,然后是 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;
}
}
现在 HTML 带有事件源的页面:
<body>
<script>
var source = new EventSource("rest/user/sse");
source.onmessage = function(event) {
//Do what you need to do when message received.
}
</script>
</body>
希望这对其他人有所帮助。
Allinone51,我想你快到了。
您对 SseEmitter.send() 的调用可能应该在 getUser 方法中。
一般模式是,当您创建 SseEmitter 时,您需要将它 "store" 放在某个地方以便其他代码获取它。您正确地 return 来自 getSseEmitter 方法的 SseEmitter,您只是忘记存储它以便其他方法能够在其上调用 'send'。
调整你上面的例子,它可能是这样的:
//...
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;
}
当然,上面的代码只能满足一个人的需求connection/emitter。有更智能的方法来存储该发射器。例如,在我的在线游戏应用程序中,我将发射器挂接到每个玩家对象中。这样,每当我的服务器上的播放器对象有东西要告诉播放器设备时,它就可以访问其内部的正确发射器。
我试图在我调用服务器上的控制器时通知一个简单的 html 页面。我有一个 android 应用程序调用我的控制器,完成后我想通知我的网页控制器被调用。
这是我的一些代码:
@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;
}
}
我看到的所有教程,控制器 returns SseEmitter 但我必须 return 一个用户。我必须用另一个映射制作另一个控制器并监听那个 url 吗?我将如何在现有控制器中调用该控制器方法? URL 我的 EventSource 必须监听什么?
在此先感谢您的帮助!
亲切的问候。
我设法使 SseEmitter 正常工作。我将解释我是如何做到的,也许它会对其他人有所帮助。
我发现的第一件事是 EventSource("url") 实际上只是 'calls' url(如果我错了请纠正我)。因此,在 Restcontroller 的情况下,它只会一遍又一遍地调用该控制器。现在,当您使用 SseEmitter.send 时,会触发 EventSource 的 onMessage() 方法。所以我所做的是添加另一个带有映射“/sse”的控制器方法,并让我的 eventSource 调用该方法。现在,当调用 returns 一个用户的原始控制器方法时,我只需将一个全局变量设置为 true,如果该变量为 true,我将发送一条消息。代码会更好地解释这一点:
我的方法在我的 android 应用程序中调用,然后是 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;
}
}
现在 HTML 带有事件源的页面:
<body>
<script>
var source = new EventSource("rest/user/sse");
source.onmessage = function(event) {
//Do what you need to do when message received.
}
</script>
</body>
希望这对其他人有所帮助。
Allinone51,我想你快到了。
您对 SseEmitter.send() 的调用可能应该在 getUser 方法中。 一般模式是,当您创建 SseEmitter 时,您需要将它 "store" 放在某个地方以便其他代码获取它。您正确地 return 来自 getSseEmitter 方法的 SseEmitter,您只是忘记存储它以便其他方法能够在其上调用 'send'。
调整你上面的例子,它可能是这样的:
//...
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;
}
当然,上面的代码只能满足一个人的需求connection/emitter。有更智能的方法来存储该发射器。例如,在我的在线游戏应用程序中,我将发射器挂接到每个玩家对象中。这样,每当我的服务器上的播放器对象有东西要告诉播放器设备时,它就可以访问其内部的正确发射器。