参考案例
概念
websocket是全双工通道,建立连接后可以双向发送消息。
Tomcat 7.0.5之后开始支持websocket,并实现了websocket规范。Java websocket应用由一系列WebSocketEndpoint组成。一个Endpoint是一个Java对象,代表WebSocket链接的一段端,对于服务端,可以视为处理WebSocket消息的接口,就像servlet处理http一样。(注:建立一个websocket链接就会新建一个Endpoint对象)
有两种方式定义Endpointt: 1、继承javax.websocket.Endpoint 类并实现其方法。 2、定义POJO 并添加@ServerEndpoint 注解
数据传输
服务端接受数据
通过Session(和http中的session不同)添加MessageHandler消息处理器来接受消息,当采用注解方式定义Endpoint时,通过@OnMessage注解指定接受消息的方法。
服务端推送数据
发送消息是由RemoteEndpoint完成,其实例由Session维护,根据使用情况,我们可以通过Session.getBasicRemote获取同步消息发送实例,然后调用sendXxx()方法可以发送消息,可以通过Session.getAsyncRemote获取异步消息发送实例。
后端实现
继承Endpoint 实现方式
onOpen方法:建立链接之后自动调用 onClose方法:链接关闭自动调用 onError方法:链接中出现问题自动调用
注解@ServerEndpoint 实现方式(主要)
@OnClose @OnOpen @OnError
示例代码
@ServerEndpoint("/robin")
public class ChatEndPoint{
private static Set<ChatEndPoint> webSocketSet = new HashSet<>();
private Session session;
@OnMessage
public void onMessage(String message,Session session)throws IOException{
System.out.println("get message"+message);
System.out.println(session);
for(ChatEndPoint chat:webSocketSet){
if(chat!=this){
chat.session.getBasicRemote().setText(message);
}
}
}
@OnOpen
public void onOpen(Session session){
this.session = session;
webSocketSet.add(this);
}
@OnClose
public void onClose(Session session){
}
@OnError
public void onError(Session session,Throwable error){
}
}
基于websocket实现聊天室(后端代码)
依赖
webSocket依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
公共资源
Message类,客户端to服务端
@Data
public class Message{
private String toName;
private String message;
}
ResultMessage,服务端to客户端
@Data
public class ResultMessage{
private boolean isSystem;
private String fromName;
private Object message;
}
MessageUtils,消息工具类
public class MessageUtils {
public static String getMessage(boolean isSystemMessage,String fromName,Object message){
try {
ResultMessage result = new ResultMessage();
result.setSystem(isSystemMessage);
result.setMessage(message);
if (fromName!=null){
result.setFromName(fromName);
}
ObjectMapper mapper = new ObjectMapper();
return mapper.writeValueAsString(result);
}catch (JsonProcessingException e){
e.printStackTrace();
}
return null;
}
}
用户登录
@RestController
public class LoginController {
@RequestMapping("/toLogin")
public Result tologin(@RequestParam("user") String user,@RequestParam("pwd") String pwd, HttpSession session){
Result result = new Result();
if (user.equals("张三")&&pwd.equals("123")){
result.setFlag(true);
session.setAttribute("user",user);
}else if (user.equals("李四")&&pwd.equals("123")){
result.setFlag(true);
session.setAttribute("user",user);
}else if (user.equals("123")&&pwd.equals("123")){
result.setFlag(true);
session.setAttribute("user",user);
}
else if (user.equals("王五")&&pwd.equals("123")){
result.setFlag(true);
session.setAttribute("user",user);
}else {
result.setFlag(false);
result.setMessage("登录失败");
}
return result;
}
@RequestMapping("/getUsername")
public String getUsername(HttpSession session){
String username = (String) session.getAttribute("user");
return username;
}
}
Endpoint
@ServerEndpoint(value = "/chat",configurator = GetHttpSessionConfigurator.class)
@Component
public class ChatEndpoint {
private static Map<String,ChatEndpoint> onlineUsers = new ConcurrentHashMap<>();
private Session session;
private HttpSession httpSession;
@OnOpen
public void onOpen(Session session, EndpointConfig config){
this.session = session;
HttpSession httpSession = (HttpSession) config.getUserProperties().get(HttpSession.class.getName());
this.httpSession = httpSession;
String username = (String)httpSession.getAttribute("user");
onlineUsers.put(username,this);
String message = MessageUtils.getMessage(true, null, getNames());
broadcastAllUsers(message);
}
private void broadcastAllUsers(String message){
try {
Set<String> names = onlineUsers.keySet();
for (String name : names) {
ChatEndpoint chatEndpoint = onlineUsers.get(name);
chatEndpoint.session.getBasicRemote().sendText(message);
}
}catch (Exception e){
e.printStackTrace();
}
}
private Set<String> getNames(){
return onlineUsers.keySet();
}
@OnMessage
public void onMessage(String message,Session session){
try {
ObjectMapper mapper =new ObjectMapper();
Message mess = mapper.readValue(message, Message.class);
String toName = mess.getToName();
String data = mess.getMessage();
String username = (String) httpSession.getAttribute("user");
String resultMessage = MessageUtils.getMessage(false, username, data);
onlineUsers.get(toName).session.getBasicRemote().sendText(resultMessage);
} catch (Exception e) {
e.printStackTrace();
}
}
@OnClose
public void onClose(Session session) {
String username = (String) httpSession.getAttribute("user");
onlineUsers.remove(username);
MessageUtils.getMessage(true,null,getNames());
}
}
配置类
需要加了配置类 Spring才会管理。
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter(){
return new ServerEndpointExporter();
}
}
其他
获取HttpSession的类
public class GetHttpSessionConfigurator extends ServerEndpointConfig.Configurator {
@Override
public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
HttpSession httpSession = (HttpSession) request.getHttpSession();
sec.getUserProperties().put(HttpSession.class.getName(),httpSession);
}
}
|