通过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
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值