当前位置:网站首页>websocket
websocket
2022-04-23 14:00:00 【Kramer_149】
概念
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{
//message 是接受到的客户端发送来的消息;session
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);
}
//把字符串转成json格式的字符串
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 {
//用来存储每个用户客户端对象的ChatEndpoint对象
private static Map<String,ChatEndpoint> onlineUsers = new ConcurrentHashMap<>();
//声明session对象,通过对象可以发送消息给指定的用户
private Session session;
//声明HttpSession对象,我们之前在HttpSession对象中存储了用户名
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);
//将当前在线用户的用户名推送给所有的客户端
//1 获取消息
String message = MessageUtils.getMessage(true, null, getNames());
//2 调用方法进行系统消息的推送
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
//注入ServerEndpointExporter bean对象,自动注册使用注解@ServerEndpoint的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 = (HttpSession) request.getHttpSession();
sec.getUserProperties().put(HttpSession.class.getName(),httpSession);
}
}
版权声明
本文为[Kramer_149]所创,转载请带上原文链接,感谢
https://blog.csdn.net/m0_46199937/article/details/122624747
边栏推荐
- OSS cloud storage management practice (polite experience)
- UML Unified Modeling Language
- Express ② (routing)
- How does redis solve the problems of cache avalanche, cache breakdown and cache penetration
- Move blog to CSDN
- 读了一篇博客,重新理解闭包整理一下
- Dynamic subset division problem
- Choreographer full resolution
- JS brain burning interview question reward
- 联想产品经理林林:天津当地网络运营商网络故障 ZUI系统后台服务器暂时无法正常工作
猜你喜欢
自动化的艺术
SSM project deployed in Alibaba cloud
go 语言 数组,字符串,切片
Quartus prime hardware experimental development (de2-115 board) experiment 1 CPU instruction calculator design
美联储数字货币最新进展
Un modèle universel pour la construction d'un modèle d'apprentissage scikit
联想产品经理林林:天津当地网络运营商网络故障 ZUI系统后台服务器暂时无法正常工作
Express ② (routage)
零拷貝技術
Business case | how to promote the activity of sports and health app users? It is enough to do these points well
随机推荐
Express中间件③(自定义中间件)
趣谈网络协议
淘宝发布宝贝提示“您的消保保证金额度不足,已启动到期保障”
Express middleware ③ (custom Middleware)
Oracle RAC database instance startup exception analysis IPC send timeout
Introduction to spark basic operation
低频量化之明日涨停预测
Oracle alarm log alert Chinese trace and trace files
JS force deduction brush question 102 Sequence traversal of binary tree
商家案例 | 运动健康APP用户促活怎么做?做好这几点足矣
L2-024 tribe (25 points)
Kettle--控件解析
基于Ocelot的gRpc网关
Choreographer full resolution
Atcoder beginer contest 248c dice sum (generating function)
金蝶云星空API调用实践
Solution of discarding evaluate function in surprise Library
New关键字的学习和总结
Tensorflow & pytorch common error reporting
变长参数__VA_ARGS__ 和 写日志的宏定义