当前位置:网站首页>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
边栏推荐
- Failure to connect due to improper parameter setting of Rac environment database node. Troubleshooting
- 33 million IOPs, 39 microsecond delay, carbon footprint certification, who is serious?
- Question bank and answer analysis of the 2022 simulated examination of the latest eight members of Jiangxi construction (quality control)
- Postman reference summary
- MySQL [acid + isolation level + redo log + undo log]
- [code analysis (5)] communication efficient learning of deep networks from decentralized data
- Crontab timing task output generates a large number of mail and runs out of file system inode problem processing
- STM32 learning record 0007 - new project (based on register version)
- 淘宝发布宝贝提示“您的消保保证金额度不足,已启动到期保障”
- Analysis of redo log generated by select command
猜你喜欢
随机推荐
FDFS start
项目中遇到的问题(五)操作Excel接口Poi的理解
How does redis solve the problems of cache avalanche, cache breakdown and cache penetration
Business case | how to promote the activity of sports and health app users? It is enough to do these points well
解决方案架构师的小锦囊 - 架构图的 5 种类型
[code analysis (1)] communication efficient learning of deep networks from decentralized data
Move blog to CSDN
The art of automation
VsCode-Go
redis如何解决缓存雪崩、缓存击穿和缓存穿透问题
【报名】TF54:工程师成长地图与卓越研发组织打造
Express ② (routing)
Quartus prime hardware experimental development (de2-115 board) experiment II function adjustable comprehensive timer design
Use future and countdownlatch to realize multithreading to execute multiple asynchronous tasks, and return results after all tasks are completed
大专的我,闭关苦学 56 天,含泪拿下阿里 offer,五轮面试,六个小时灵魂拷问
Express middleware ③ (custom Middleware)
JUC interview questions about synchronized, ThreadLocal, thread pool and atomic atomic classes
淘宝发布宝贝提示“您的消保保证金额度不足,已启动到期保障”
Detailed explanation of redis (Basic + data type + transaction + persistence + publish and subscribe + master-slave replication + sentinel + cache penetration, breakdown and avalanche)
[VMware] address of VMware Tools