前端代码
<script type="text/javascript">
var websocket = null;
var last_health = -1;
var health_timeout = 20000;
var health_message = "520";//心跳包
var isOpenWebsocket = false;//是否已经建立连接
openWebsocket();
var timer = setInterval(function () {
sendHealth()
}, 5000);
//打开websocket
function openWebsocket() {
if (websocket != null) {
closeWebSocket();
}
//判断当前浏览器是否支持WebSocket
if ('WebSocket' in window) {
var address = "ws://" + location.host + "/productWebSocket/";
var loginName = [[${user.loginName}]];
websocket = new WebSocket(address + loginName);
} else {
//不支持websocket
}
//连接发生错误的回调方法
websocket.onerror = function () {
};
//连接成功建立的回调方法
websocket.onopen = function (event) {
isOpenWebsocket = true;
var time = new Date();
last_health = time.getTime();
sendMessage(health_message);
}
//接收到消息的回调方法
websocket.onmessage = function (event) {
if (health_message == event.data) {
//收到心跳包,重置最后一次时间
var time = new Date();
last_health = time.getTime();
return;
}
var message = {
"code": -1,
"desc": "",
"data": {"userPhone": "", "address": "", "headNumber": "", "driverName": "", "type": -1}
};
message = JSON.parse(event.data);
if (message.code == 0) {
if (message.data.type == 1) {
//告诉服务器消息已经发送成功
message.data.type = 2;
// sendMessage(JSON.stringify(message.data));
var s = message.data.headNumber+"距离最近的工厂地址"+message.data.address+"已超出50km范围外,请及时处理"
openAlarmAlert(s);
}
}
}
//连接关闭的回调方法
websocket.onclose = function () {
isOpenWebsocket = false;
}
//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function () {
closeWebSocket();
cancelTask();
}
}
//检测心跳是否正常
function sendHealth() {
//判断是否正常
var time = new Date();
if (last_health != -1 && (time.getTime() - last_health > health_timeout)) {
//此时即可以认为连接断开,重新连接
openWebsocket();
} else {
sendMessage(health_message);
}
}
function cancelTask() {
if (timer != null) {
clearInterval(timer);
}
}
//关闭连接
function closeWebSocket() {
try {
websocket.close();
} catch (e) {
}
}
//发送消息
function sendMessage(string) {
try {
if (isOpenWebsocket) {
websocket.send(string);
}
} catch (e) {
}
}
//弹窗方法
function openAlarmAlert(string) {
alert(string);
}
</script>
配置文件
package com.yj.oa.project.websocket.config;
import com.yj.oa.common.utils.shiro.ShiroUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import javax.websocket.HandshakeResponse;
import javax.websocket.server.HandshakeRequest;
import javax.websocket.server.ServerEndpointConfig;
/**
* create by niejin on 2019/10/10
* MyEndpointConfigure配置就是为了解决websocket无法注入的问题,如果没有需要可以不用配置
*/
public class MyEndpointConfigure extends ServerEndpointConfig.Configurator implements ApplicationContextAware {
//这个有问题 用了websocket生成对象貌似永远只有一个
// private static volatile BeanFactory context;
//
// @Override
// public <T> T getEndpointInstance(Class<T> clazz) throws InstantiationException {
// return context.getBean(clazz);
// }
//
// @Override
// public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
// MyEndpointConfigure.context = applicationContext;
// }
@Override
public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
// 将用户信息存储到socket的配置里
sec.getUserProperties().put("user", ShiroUtils.getUser());
super.modifyHandshake(sec, request, response);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
}
}
package com.yj.oa.project.websocket.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
/**
* create by niejin on 2019/10/10
* Websocket配置
*/
@Configuration
public class WebSocketConfig {
@Bean
public MyEndpointConfigure newConfigure() {
return new MyEndpointConfigure();
}
/**
* springboot需要配置方法(不是好像得去掉)
* @return
*/
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
最后的具体代码
package com.yj.oa.project.websocket;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yj.oa.project.po.DriverMessage;
import com.yj.oa.project.po.ResponseEntity;
import com.yj.oa.project.po.User;
import com.yj.oa.project.websocket.config.MyEndpointConfigure;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.util.concurrent.CopyOnWriteArraySet;
/**
* create by niejin on 2019/10/10
* Websocket 用来给网页弹窗
*/
@ServerEndpoint(value = "/productWebSocket/{loginName}", configurator = MyEndpointConfigure.class)
@Component
public class ProductWebSocket {
ObjectMapper mapper = new ObjectMapper();
// 静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
private static int onlineCount = 0;
// concurrent包的线程安全Set,用来存放每个客户端对应的ProductWebSocket对象。
private static CopyOnWriteArraySet<ProductWebSocket> webSocketSet = new CopyOnWriteArraySet<ProductWebSocket>();
// 与某个客户端的连接会话,需要通过它来给客户端发送数据
private Session session;
/**
* 用户信息
*/
private User user;
/**
* 心跳包
*/
private static final String HEALTH_MESSAGE = "520";
/**
* 连接建立成功调用的方法
*/
@OnOpen
public void onOpen(@PathParam("loginName") String loginName, Session session) {
addOnlineCount(); // 在线数加1
this.user = (User) session.getUserProperties().get("user");
//如果用户名对应
if (user != null && loginName != null && loginName.equals(user.getLoginName())) {
// int processID = getProcessID();
// System.out.println("websocket进程id:"+processID);
this.session = session;
ProductWebSocket.webSocketSet.add(ProductWebSocket.this); // 加入set中
} else {
try {
session.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static final int getProcessID() {
RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
System.out.println(runtimeMXBean.getName());
return Integer.valueOf(runtimeMXBean.getName().split("@")[0])
.intValue();
}
/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose() {
ProductWebSocket.webSocketSet.remove(ProductWebSocket.this); // 从set中删除
subOnlineCount(); // 在线数减1
}
/**
* 收到客户端消息后调用的方法
*
* @param message 客户端发送过来的消息
*/
@OnMessage
public void onMessage(String message, Session session) {
//收到心跳包回发
if (HEALTH_MESSAGE.equals(message)) {
sendMessage(message);
return;
}
// try {
// DriverMessage driverMessage = mapper.readValue(message, DriverMessage.class);
// if (driverMessage == null) {
// return;
// }
// if (driverMessage.getType() == 2) {//2代表是客服端返回已读标志 1代表是服务器发送的
// //更新数据库消息id状态,或者不保存到数据库 反正计时器几分钟就会扫描 到时候就会触发,不管发不发送成功
//
// }
// } catch (Exception e) {
// //解析异常
// e.printStackTrace();
// }
}
/**
* 发生错误时调用
*/
@OnError
public void onError(Session session, Throwable error) {
error.printStackTrace();
}
private void sendMessage(String message) {
try {
this.session.getBasicRemote().sendText(message);
} catch (IOException e) {
e.printStackTrace();
}
}
public static synchronized int getOnlineCount() {
return onlineCount;
}
public static synchronized void addOnlineCount() {
ProductWebSocket.onlineCount++;
}
public static synchronized void subOnlineCount() {
ProductWebSocket.onlineCount--;
}
/**
* 给特定用户发送消息
*
*/
public static void sendMessage(DriverMessage driverMessage) {
try {
if (driverMessage == null || driverMessage.getUserPhone() == null) {
return;
}
//发送弹窗消息
ResponseEntity responseEntity = new ResponseEntity(0, "有新消息", driverMessage);
for (ProductWebSocket productWebSocket : ProductWebSocket.webSocketSet) {
if (driverMessage.getUserPhone().equals(productWebSocket.user.getLoginName())) {
String message = productWebSocket.mapper.writeValueAsString(responseEntity);
productWebSocket.sendMessage(message);
}
}
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
}