创建项目后,我需要向客户发送消息。该项目将创建一个ApiRest。然后,我使用@ApplicationScope创建了WebSocket,并使用@Inject注入了serviceREST。问题是当webSocket初始化时,在我的serviceRest中,此webSocket的会话仍然为null。 如何在apirest中使用网络套接字?
@Path("citas")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class citaResource {
@Inject
com.softcase.citasmanager.websocket.ws websocket;
@GET
@Path("cita")
@Produces("application/json")
public Response cita() {
websocket.onMessage("Your Item was created");//Session of webSocket is null
return Response.ok("ItemCreated", MediaType.APPLICATION_JSON).build();
}
}
@ApplicationScope
@ServerEndpoint("/item")
public class ws{
private Session session;
@OnOpen
public void open(Session session) {
this.session = session;
}
@OnMessage
public void onMessage(String message) {
this.session.getBasicRemote().sendText(message);
}
答案 0 :(得分:0)
实例:每个客户端/服务器对都有一个唯一的Session实例,即为连接到WebSocket服务器端点的每个客户端创建一个Session实例。简而言之,唯一会话实例的数量等于已连接客户端的数量
有关更多详细信息:https://tyrus-project.github.io/documentation/1.13.1/index/lifecycle.html
建议使用像{p>这样的static
变量
// @ApplicationScope
@ServerEndpoint("/item")
public class ws{
// something like
private static final Set<javax.websocket.Session> ALL_SESSIONS = new HashSet<>();
// ...
}
可以找到一个示例here。这是一个选择,但我认为它不能解决您的注射问题。
另一个选择是利用javax.websocket.Session#getOpenedSessions()
之类的chat example方法。再次,它不能解决注入问题。
您同时使用了websocket和REST。据我了解,流程为:
citas/cita
提交请求并收到REST响应因此,正如您所写,一方面,您拥有
@Path("citas")
// ...
public class CitaResource{
// ...
}
和
// @ApplicationScope -> commented as irrelevant in your situation
@ServerEndpoint("/item")
public class ws{
// ...
}
在该示例中,当用户A发出请求时,存在一个CitaResource
实例,并且连接了ws
的三个实例A,B,C。但是,您对注入是正确的:您需要在CitaResource
中注入一些东西,但是需要一个始终可用的bean,并且您已经注意到,websocket实例不是一个好的选择,容器必须注入哪个会话?
解决方案是使用应用程序范围的Bean处理所有现有会话。我是从Oracle tutorial获得的。它是这样的:
// com.softcase.citasmanager.websocket.SessionHandler
@ApplicatedScoped
@Named // optional
public class MySessionHandler{
private final Set<Session> ALL_SESSIONS;
// or use a map if you need to identify the
// the session by a key. This example uses Set
// private final Map<String, Session> ALL_SESSIONS;
public MySessionHandler(){
ALL_SESSIONS = new HashSet<>();
}
// manage sessions
public void addSession(Session session){
this.ALL_SESSIONS.add(session);
}
public void removeSession(Session session){
this.ALL_SESSIONS.remove(session);
}
// send messages to all instances:
public void sendMessage(String message){
this.ALL_SESSIONS.stream()
// optional
.filter(s -> s.isOpen())
// or whatever method you want to send a message
.forEach( s -> s.getBasicRemote().sendText(message);
}
// or if you want to target a specific session
// hence my questions in comments
public void sendMessage(String message, String target){
this.ALL_SESSIONS..stream()
// identity the target session
.filter(s -> s.equals(target))
// optional
.filter(s -> s.isOpen())
.forEach( s -> s.getBasicRemote().sendText(message);
}
}
注意:
isOpen()
不是强制性的,但可以避免某些错误但是,您需要调整端点以提高会话处理程序的效率:
// com.softcase.citasmanager.websocket.WsCita
@ServerEndpoint
public class WsCita{
// there is no need to declare the session as attribute
// private Session session;
// ApplicatedScoped so always defined
@Inject
private MySessionHandler handler;
@OnOpen
public void open(Session session){
handler.addSession(session); // "Aye cap'tain, reporting from duty!"
// your stuff
}
@OnClose
public void close(Session session, CloseReason closeReason){
handler.removeSession(session); // "Cya cap'tain, that's all for today!"
// your stuff
}
// your OnMessage and other stuff here
}
现在我们已经设置了websocket架构,现在怎么办?
WsCita
实例。在任何时候,可能有零个,一个或多个实例。 MySessionHandler
知道此信息并且是@ApplicatedScoped
,因此可以安全地注入它REST端点然后更改为:
@Path("citas")
// ...
public class citaResource {
@Inject
com.softcase.citasmanager.websocket.SessionHandler handler;
@GET
// ...
public Response cita() {
// REST processing
// ...
// Websocket processing:
// - Handler is always here for you
// - Handler knows which websocket sessions to send the message to.
// The RestController is not aware of the recipients
handler.sendMessage("Your Item was created");
}
}
请注意,我将websocket处理置于REST处理之后,因为您可能并不总是发送消息(例如创建或任何异常)。
与您的问题无关,但我对您的代码有一些评论:
Ws
。在示例中,我将其重命名为WsCita