当前位置:网站首页>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
边栏推荐
- L2-024 tribe (25 points)
- MySQL index [data structure + index creation principle]
- Un modèle universel pour la construction d'un modèle d'apprentissage scikit
- Android interview theme collection
- Analysis of unused index columns caused by implicit conversion of timestamp
- Android 面试主题集合整理
- MySQL [SQL performance analysis + SQL tuning]
- 第一章 电商秒杀商品回顾
- elmo(BiLSTM-CRF+elmo)(Conll-2003 命名实体识别NER)
- New关键字的学习和总结
猜你喜欢
随机推荐
MySQL 修改主数据库
美联储数字货币最新进展
FDFS start
UML统一建模语言
Port occupied 1
Modify the Jupiter notebook style
Detailed explanation of redis (Basic + data type + transaction + persistence + publish and subscribe + master-slave replication + sentinel + cache penetration, breakdown and avalanche)
Program compilation and debugging learning record
The art of automation
函数只执行第一次的执行一次 once函数
Reading notes: fedgnn: Federated graph neural network for privacy preserving recommendation
村上春树 --《当我谈跑步时,我谈些什么》句子摘录
Oracle alarm log alert Chinese trace and trace files
Basic SQL query and learning
Introduction to spark basic operation
Get the attribute value difference between two different objects with reflection and annotation
Express middleware ③ (custom Middleware)
Crontab timing task output generates a large number of mail and runs out of file system inode problem processing
基础知识学习记录
leetcode--357. 统计各位数字都不同的数字个数









