4
hao
2025-04-16 c5fb1fbcbb2bf4d511773d348f9ef625855c61fc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
package com.web.jhsop.websocket.util;
 
 
 
import com.web.jhsop.websocket.config.WebSocketConfig;
import com.web.jhsop.websocket.dao.SopDeviceDao;
import com.web.jhsop.websocket.dao.SopFileDao;
import com.web.jhsop.websocket.entity.SopDevice;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
 
import javax.websocket.*;
import javax.websocket.server.PathParam;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
 
@ConditionalOnClass(value = WebSocketConfig.class)
@Component
//开发时候注释,打包时放出来
//@ServerEndpoint("/websocket/{deviceId}")  // 接口路径 ws://localhost:9999/webSocket/deviceId;
public class WebSocketUtil {
 
    protected Logger logger = LoggerFactory.getLogger(this.getClass());
 
    private static SopDeviceDao sopDeviceDao;
 
    private static SopFileDao sopFileDao;
 
    @Autowired
    public void setSopDeviceDao(SopDeviceDao sopDeviceDao){
        WebSocketUtil.sopDeviceDao = sopDeviceDao;
    }
 
    @Autowired
    public void setSopFileDao(SopFileDao sopFileDao){
        WebSocketUtil.sopFileDao = sopFileDao;
    }
 
    //与某个客户端的连接会话,需要通过它来给客户端发送数据
    private Session session;
    /**
     * 设备ID
     */
    private String deviceId;
 
    //concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
    //虽然@Component默认是单例模式的,但springboot还是会为每个websocket连接初始化一个bean,所以可以用一个静态set保存起来。
    //  注:底下WebSocket是当前类名
    private static CopyOnWriteArraySet<WebSocketUtil> webSockets =new CopyOnWriteArraySet<>();
    // 用来存在线连接用户信息
    private static ConcurrentHashMap<String,Session> sessionPool = new ConcurrentHashMap<String,Session>();
 
    /**
     * 链接成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam(value="deviceId")String deviceId) {
        try {
            if(StringUtils.isEmpty(deviceId)||deviceId.equals("undefined")){
                return;
            }
            if(deviceId.length() <= 12){
                //12位组成 则为设备唯一码 否则则是翻页功能中发起的socket连接
                List<SopDevice>  list = sopDeviceDao.findByBsDevice(deviceId);
                if(CollectionUtils.isEmpty(list)){
                    SopDevice sopDevice = new SopDevice();
                    sopDevice.setBsDevice(deviceId);
                    sopDevice.setCreatedTime(new Date());
                    sopDeviceDao.save(sopDevice);
                }
            }
 
            this.session = session;
            this.deviceId = deviceId;
            webSockets.add(this);
            sessionPool.put(deviceId, session);
            logger.info("【websocket消息】有新的连接,总数为:"+webSockets.size());
        } catch (Exception e) {
        }
    }
 
    /**
     * 链接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        try {
            webSockets.remove(this);
            sessionPool.remove(this.deviceId);
            logger.info("【websocket消息】连接断开,总数为:"+webSockets.size());
        } catch (Exception e) {
        }
    }
    /**
     * 收到客户端消息后调用的方法
     *
     * @param message
     */
    @OnMessage
    public void onMessage(String message) {
        logger.info("【websocket消息】收到客户端消息:"+message);
    }
 
    /** 发送错误时的处理
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
 
        logger.error("用户错误,原因:"+error.getMessage());
        error.printStackTrace();
    }
 
 
 
    // 此为广播消息
    public void sendAllMessage(String message) {
        logger.info("【websocket消息】广播消息:"+message);
        for(WebSocketUtil webSocket : webSockets) {
            try {
                if(webSocket.session.isOpen()) {
                    webSocket.session.getAsyncRemote().sendText(message);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
 
 
    // 此为单点消息
    public void sendOneMessage(String deviceId, String message) {
        Session session = sessionPool.get(deviceId);
        if (session != null&&session.isOpen()) {
            try {
                logger.info("【websocket消息】 单点消息:"+message);
                session.getAsyncRemote().sendText(message);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
 
    // 此为单点消息
    public void sendOneObject(String deviceId, Object object) {
        Session session = sessionPool.get(deviceId);
        if (session != null&&session.isOpen()) {
            try {
                logger.info("【websocket消息】 单点消息(对象):"+object);
                session.getAsyncRemote().sendObject(object);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
 
    // 此为单点消息(多人)
    public void sendMoreMessage(String[] deviceIds, String message) {
        for(String deviceId:deviceIds) {
            Session session = sessionPool.get(deviceId);
            if (session != null&&session.isOpen()) {
                try {
                    logger.info("【websocket消息】 单点消息:"+message);
                    session.getAsyncRemote().sendText(message);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
 
    }
 
}