通过websocket实现强制下线功能,并使用vuex存储
·
POM文件
<!-- websocket -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
配置文件
public class MySpringConfigurator extends ServerEndpointConfig.Configurator implements ApplicationContextAware {
private static volatile BeanFactory context;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
MySpringConfigurator.context = applicationContext;
}
@Override
public <T> T getEndpointInstance(Class<T> clazz) throws InstantiationException {
return context.getBean(clazz);
}
}
- 解决websocket初始化连接报404错误
@Configuration
@ConditionalOnWebApplication
public class WebSocketConfig {
//使用boot内置tomcat时需要注入此bean
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
@Bean
public MySpringConfigurator mySpringConfigurator() {
return new MySpringConfigurator();
}
}
核心代码
@Slf4j
@Component
@ServerEndpoint(value = "/education/bes/v1/system/user/websocket/{userOnlineInfoId}")
public class WebSocket {
private static int onlineCount = 0;
private static Map<String, WebSocket> clients = new ConcurrentHashMap<String, WebSocket>();
private Session session;
private String userOnlineInfoId;
@OnOpen
public void onOpen(@PathParam("userOnlineInfoId") String userOnlineInfoId, Session session) throws IOException {
this.userOnlineInfoId = userOnlineInfoId;
this.session = session;
beforeOpen();
addOnlineCount();
clients.put(userOnlineInfoId, this);
log.info("{}: 上线,已连接: {}", userOnlineInfoId, getOnlineCount());
}
@OnClose
public void onClose() throws IOException {
beforeClose();
clients.remove(userOnlineInfoId);
subOnlineCount();
log.info("{}: 下线,已连接: {}", userOnlineInfoId, getOnlineCount());
}
@OnMessage
public void onMessage(String message) throws IOException {
// DataWrapper res = new DataWrapper();
// System.out.println("message:" + message);
// JSONObject req = JSONObject.parseObject(message);
// 发送数据给服务端
// sendMessageAll(JSON.toJSONString(res));
}
@OnError
public void onError(Session session, Throwable error) {
error.printStackTrace();
}
public void sendMessageTo(CommonResponse commonResponse, String To) throws IOException {
for (WebSocket item : clients.values()) {
if (item.userOnlineInfoId.equals(To)){
item.session.getAsyncRemote().sendText(JSON.toJSONString(commonResponse));
break;
}
}
}
public void sendMessageToList(CommonResponse commonResponse, List<String> ToList) throws IOException {
for (WebSocket item : clients.values()) {
if(ToList.contains(item.userOnlineInfoId)){
item.session.getAsyncRemote().sendText(JSON.toJSONString(commonResponse));
}
}
}
public void sendMessageAll(String message) throws IOException {
for (WebSocket item : clients.values()) {
item.session.getAsyncRemote().sendText(message);
}
}
/**
* 连接前的操作,判断该用户是否已连接,若已登录则挤退
* @throws IOException
*/
public void beforeOpen() throws IOException {
for (WebSocket item : clients.values()) {
if(item.userOnlineInfoId.equals(userOnlineInfoId)){
sendMessageTo(CommonResponse.Builder.fail(ErrorCodeConstant.USER_ONLINE_CROWDING_OUT, ErrorCodeConstant.USER_ONLINE_CROWDING_OUT_MSG), userOnlineInfoId);
onClose();
break;
}
}
}
/**
* 下线前的操作,调用退出登录请求
* websocket无法使用注解注入bean ,因为每一次websocket的握手连接就像是new了一个对象
* @throws IOException
*/
public void beforeClose() throws IOException {
UserOnlineInfoDto userOnlineInfoDto = new UserOnlineInfoDto();
userOnlineInfoDto.setUserOnlineInfoId(Long.parseLong(userOnlineInfoId));
// 方法1,获取spring上下文
ApplicationContext act = ApplicationContextRegister.getApplicationContext();
IUserOnlineService userOnlineService = act.getBean(IUserOnlineService.class);
// 方法2,获取ApplicationContext上下文,注意,getBean后只能使用接口,不能使用Impl
// IUserOnlineService userOnlineService = ContextLoader.getCurrentWebApplicationContext().getBean(IUserOnlineService.class);
userOnlineService.logout(userOnlineInfoDto);
}
public static synchronized int getOnlineCount() {
return onlineCount;
}
public static synchronized void addOnlineCount() {
WebSocket.onlineCount++;
}
public static synchronized void subOnlineCount() {
WebSocket.onlineCount--;
}
public static synchronized Map<String, WebSocket> getClients() {
return clients;
}
}
工具类
@Component
@Lazy(false)
public class ApplicationContextRegister implements ApplicationContextAware {
private static ApplicationContext APPLICATION_CONTEXT;
/**
* 设置spring上下文
* @param applicationContext spring上下文
* @throws BeansException
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
APPLICATION_CONTEXT = applicationContext;
}
public static ApplicationContext getApplicationContext() {
return APPLICATION_CONTEXT;
}
}
前端部分
- store——webSocket.js
import { MessageBox } from 'element-ui'
import store from '@/store'
const state = {
websocket: null,
websocketonmessage: null
}
const mutations = {
SET_WEBSOCKET: (state, websocket) => {
state.websocket = websocket
},
SET_WEBSOCKETONMESSAGE: (state, websocketonmessage) => {
// 根据接收的消息内容进行处理
state.websocketonmessage = websocketonmessage
if(websocketonmessage.head.code !== '0'){
// 退出API
store.dispatch('user/logout')
MessageBox.confirm(websocketonmessage.head.message, '提示', {
showClose: false,
closeOnClickModal: false,
closeOnPressEscape: false,
showCancelButton: false,
confirmButtonText: '确定',
type: 'warning'
}).then(() => {
// 返回登录页面
location.reload()
})
}
}
}
const actions = {
// 初始化websocket
initWebSocket({commit}, userOnlineInfoId){
return new Promise((resolve, reject) => {
// 对应后端ws路径
const wsuri = `ws://localhost:9700/education/bes/v1/system/user/websocket/${userOnlineInfoId}`
commit('SET_WEBSOCKET', new WebSocket(wsuri))
// 接收消息方法,因为我这边现在只需要接收消息所以只定义了这个,还有发送消息,连接失败处理等等...
state.websocket.onmessage = function(e){
// 因为发过来的是String类型,所以先转为json对象
let res = JSON.parse(e.data)
commit('SET_WEBSOCKETONMESSAGE', res)
}
resolve()
})
},
// 销毁websocket
destoryedWebSocket(){
return new Promise((resolve) => {
state.websocket.close()
resolve()
})
}
}
export default {
namespaced: true,
state,
mutations,
actions
}
- 登录调用
// 我在调用初始化websocket之前先进行了用户信息验证,获取了userOnlineInfoId放到localStorage中,根据自己的情况来改
await store.dispatch('webSocket/initWebSocket', localStorage.getItem('userOnlineInfoId'))
- 退出调用
await store.dispatch('webSocket/destoryedWebSocket')
更多推荐
所有评论(0)