注:本项目用的是shiro,前后端调试通之后,需要将 websocket的url添加到shiro不需要权限拦截中去,否则会302。(使用spring security同理)
eg:将/websocket/** 添加为 anon
前端JS
// 判断浏览器是否支持websocket
if (WebSocket && typeof (WebSocket) != "undefined") {
console.log("恭喜:您的浏览器支持WebSocket");
me.socket = new WebSocket("ws://localhost:8881/websocket/" + CarDis.deptId);
me.socket.onopen = function (ev) {
me.socket.send("消息发送测试(From Client)");
};
me.socket.onmessage = function (ev) {
var allCarData = JSON.parse(ev.data).data;
};
//连接关闭事件
me.socket.onclose = function () {
console.log("Socket已关闭");
};
//发生了错误事件
me.socket.onerror = function () {
alert("Socket发生了错误");
};
//窗口关闭时,关闭连接
window.unload = function () {
me.socket.close();
};
} else {
alert("遗憾,您的浏览器不支持WebSocket");
}
后端配置
- maven依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>javax.websocket</groupId>
<artifactId>javax.websocket-api</artifactId>
<version>1.0-rc3</version>
</dependency>
<!--剔除springboot内置的tomcat容器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.1.1.RELEASE</version>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-servlet-api</artifactId>
<version>9.0.17</version>
<scope>provided</scope>
</dependency>
- ServerEncoder 配置
/**
* websocket 发送对象需要对对象进行格式化,重写encode方法
*/
public class ServerEncoder implements Encoder.Text<WebSocketResult> {
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public void init(EndpointConfig arg0) {
// TODO Auto-generated method stub
}
@Override
public String encode(WebSocketResult arg0) {
return new GsonBuilder().create().toJson(arg0);
}
}
- WebSocketResult 配置
public class WebSocketResult implements Serializable {
private Object data;
private boolean success;
public WebSocketResult() {
}
public WebSocketResult(Object data, boolean success) {
this.data = data;
this.success = success;
}
public static WebSocketResult success(Object data) {
return new WebSocketResult(data, true);
}
public static WebSocketResult fail(Object data) {
return new WebSocketResult(data, false);
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
}
4.WebsocketServer 配置
@Slf4j
@Component
@ServerEndpoint(value = "/websocket/{deptId}", encoders = {ServerEncoder.class}, configurator = WebSocketConfig.class)
@DependsOn("springContextHolder")
@MessageMapping
public class WebSocketServer {
// 静态变量,用来记录当前在线连续数,应该把它设计成线程安全的
private static AtomicInteger onlineCount = new AtomicInteger(0);
// concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
private static CopyOnWriteArraySet<WebSocketServer> webSocketServers = new CopyOnWriteArraySet<>();
// 与某个客户端的连接会话,需要通过它来给客户端发送数据
private Session session;
private Long deptId;
private AtomicBoolean isOpen = new AtomicBoolean(false);
private CarService carService = SpringContextHolder.getBean(CarService.class);
@OnOpen
public void onOpen(@PathParam("deptId") Long deptId, Session session) {
this.session = session;
webSocketServers.add(this);
addOnlineCount();
this.deptId = deptId;
log.info("有新窗口开始监听:{}, 当前在线人数为:{}", session.getId(), getOnlineCount());
isOpen.set(true);
}
@OnClose
public void onClose() {
webSocketServers.remove(this); //从set中删除
subOnlineCount(); //在线数减1
log.info("有一连接关闭!当前在线人数为" + getOnlineCount());
isOpen.set(false);
}
/**
* @author:txzhang
* @param session
* @param e
* @return:[session, e]
* @date:2019/11/6 11:55
* 说明:
*/
@OnError
public void onError(Session session, Throwable e) {
log.error("发生错误:{}, Session Id:{}", e.getMessage(), session.getId());
}
/**
* @author:txzhang
* @param message
* @param session
* @return:[message, session]
* @date:2019/11/6 11:59
* 说明:收到客户端消息后调用的方法
*/
@OnMessage
public synchronized void onMessage(String message,Session session) throws IOException, EncodeException {
// todo
}
private void sendMessage(String message) throws IOException {
this.session.getBasicRemote().sendText(message);
}
public static synchronized int getOnlineCount() {
return onlineCount.get();
}
public static synchronized int addOnlineCount() {
return onlineCount.addAndGet(1);
}
public static synchronized int subOnlineCount() {
return onlineCount.decrementAndGet();
}
}
- WebSocketConfig 配置
/**
* @ClassName:WebSocketConfig
* @Author:txzhang
* @Date:2019/11/6—11:22
* @Description: 开启websocket支持
* 因为WebSocket是类似客户端服务端的形式(采用ws协议),那么这里的WebSocketServer其实就相当于一个ws协议的Controller
* 直接@ServerEndpoint("/websocket")@Component启用即可,然后在里面实现@OnOpen,@onClose,@onMessage等方法
*
**/
@Configuration
public class WebSocketConfig extends ServerEndpointConfig.Configurator {
/**
* 如果是使用的springboot内置的tomcat时,需要注入此bean;
* 如果打的war包则需要注释掉该bean.
*/
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
@Override
public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
super.modifyHandshake(sec, request, response);
}
}