package com.zhxk.ruralbus.controller;
import java.io.IOException;
import java.util.Calendar;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import javax.websocket.CloseReason;
import javax.websocket.CloseReason.CloseCodes;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zhxk.ruralbus.entity.WebSocketEntity;
import com.zhxk.ruralbus.utils.DateUtils;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@Component
@ServerEndpoint("/wx/{idCard}")
@Slf4j
public class WebSocketController {
private static boolean isHeart=false;
private static final Set<WebSocketEntity> connections = new CopyOnWriteArraySet<>();
@OnOpen
public synchronized void onOpen(@PathParam("idCard") String idCard, Session session) {
addUser(idCard, session);
if(connections.size()==1 && !isHeart){
isHeart=true;
startHeart();
}
}
@OnMessage
public synchronized void onMessage(@PathParam("idCard") String idCard, String message) throws IOException {
ObjectMapper mapper = new ObjectMapper();
WebSocketEntity webSocketEntity = mapper.readValue(message, WebSocketEntity.class);
if(webSocketEntity.getMesType()==1){
log.info("收到{}的心跳:{}",idCard,message);
WebSocketEntity entity=getUserEntity(idCard);
if(null!=entity){
entity.setHeart(true);
}
}else{
sendMsg(message);
}
}
@OnError
public synchronized void onError(@PathParam("idCard") String idCard, Throwable error) {
log.info("{}:发生了错误:{}",idCard,error);
removeUser(idCard,new CloseReason(CloseCodes.NO_EXTENSION, "客户端异常"));
}
@OnClose
public synchronized void onClose(@PathParam("idCard") String idCard, CloseReason reason){
log.info(idCard+":退出了链接");
removeUser(idCard,reason);
}
private synchronized int getUserOnlineNum(){
return connections.size();
}
@SuppressWarnings("unused")
private synchronized Set<WebSocketEntity> getUserOnline(){
return connections;
}
private synchronized void addUser(String idCard, Session session){
WebSocketEntity entity=getUserEntity(idCard);
if(null==entity){
WebSocketEntity webSocket = new WebSocketEntity();
webSocket.setSession(session);
webSocket.setIdCard(idCard);
connections.add(webSocket);
}else{
log.info("用户"+idCard+"上线了,当前人数为:"+getUserOnlineNum());
}
}
private static WebSocketEntity getUserEntity(String idCard){
WebSocketEntity entity=null;
if(connections.size()==0)
return null;
for (WebSocketEntity webSocketEntity : connections) {
if(webSocketEntity.getIdCard().contentEquals(idCard)){
entity=webSocketEntity;
break;
}
}
return entity;
}
private void removeUser(String idCard, CloseReason reason) {
WebSocketEntity entity=getUserEntity(idCard);
if(null!=entity){
try {
if(entity.getSession().isOpen()){
entity.getSession().close(reason);
}
connections.remove(entity);
} catch (IOException e) {
log.error("用户下线异常:",e);
}
}
log.info("当前人数:"+connections.size());
}
public synchronized void sendPing(String message) throws IOException{
if(connections.size()<=0)
return;
for (WebSocketEntity webSocketEntity : connections) {
synchronized (webSocketEntity) {
webSocketEntity.setTimeStr(DateUtils.getTimeInMillis());
webSocketEntity.setHeart(false);
((Session) webSocketEntity.getSession()).getBasicRemote().sendText(message);
}
}
}
public synchronized void sendMsg(String message) throws IOException{
if(connections.size()<=0)
return;
for (WebSocketEntity entity : connections) {
synchronized (entity) {
((Session) entity.getSession()).getBasicRemote().sendText(message);
}
}
}
private synchronized void startHeart(){
ExamineHeartThread examineHeart =new ExamineHeartThread();
Thread examineThread=new Thread(examineHeart);
KeepHeartThread keepHeart=new KeepHeartThread();
Thread keepThread=new Thread(keepHeart);
keepThread.start();
examineThread.start();
}
private class KeepHeartThread implements Runnable {
@SneakyThrows
@Override
public void run() {
WebSocketEntity entity = new WebSocketEntity();
entity.setMesType(1);
entity.setTimeStr(DateUtils.getTimeInMillis());
ObjectMapper obj = new ObjectMapper();
String s = obj.writeValueAsString(entity);
while (true) {
try {
log.info("发送心跳包当前人数为:"+getUserOnlineNum());
sendPing(s);
Thread.sleep(10000);
} catch (Exception e) {
log.error("发送心跳包异常:",e);
}
}
}
}
private class ExamineHeartThread implements Runnable{
@Override
public void run() {
while (true) {
try {
long timeMillions=System.currentTimeMillis();
for (WebSocketEntity entity : connections) {
if(!entity.isHeart() && entity.getTimeStr()!=0 && timeMillions>entity.getTimeStr()){
onClose(entity.getIdCard(), new CloseReason(CloseCodes.NORMAL_CLOSURE, "没有收到心跳"));
}
}
Thread.sleep(1000);
} catch (InterruptedException e) {
log.error("检测心跳异常:",e);
}
}
}
}
}
package com.zhxk.ruralbus.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}