spring websocket的使用记录

注:本文是在已有的spring boot框架 引用webSocket框架。

1 引用依赖

        <!-- websocket -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>

2 实现webSocket处理器


/**
 * 处理器
 *
 * @author terry
 */
@Component
@Slf4j
public class NetgateHandler extends TextWebSocketHandler {


    /**
     * 网关连接集合
     */
    public static ConcurrentHashMap<Integer, ConcurrentHashMap<String, WebSocketSession>> netgates = new ConcurrentHashMap<>();

    @Resource
    private SysOrgCsMsgService sysOrgCsMsgService;

    /**
     * 处理前端发送的文本信息
     * js调用websocket.send时候,会调用该方法
     */
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        if (!session.isOpen()) {
            log.info("连接已关闭,不再处理该连接的消息!");
            return;
        }

        String msg = message.getPayload();
        if (message == null || "".equals(msg)) {
            //收到空消息,不予处理
            return;
        } else if (msg.equals("Ping")) {
            //心跳消息过滤掉
            session.sendMessage(new TextMessage("Pong"));
            return;
        } else {
            System.out.println("收到消息======"+msg);
            SysOrgCsMsgDo sysOrgCsMsgDo = JSON.parseObject(msg, SysOrgCsMsgDo.class);
            sysOrgCsMsgDo.setIsRead(YesNoEnum.NO);

            if (!this.checkMsg(sysOrgCsMsgDo)) {
                session.sendMessage(new TextMessage("消息体异常"));
                return;
            }

            //发送消息
            Integer value = sysOrgCsMsgDo.getToUserType().getValue();
            String toUserId = sysOrgCsMsgDo.getToUserId();
            ConcurrentHashMap<String, WebSocketSession> netgate = netgates.get(value);
            if (netgate != null && netgate.containsKey(toUserId)) {
                WebSocketSession webSocketSession = netgate.get(toUserId);
                webSocketSession.sendMessage(new TextMessage(msg));
                sysOrgCsMsgDo.setIsRead(YesNoEnum.YES);
            }
            sysOrgCsMsgService.saveSysOrgCsMsg(sysOrgCsMsgDo, KelpConstants.adminId);
        }

    }

    /**
     * 消息检查
     *
     * @param sysOrgCsMsgDo 消息体
     * @return 结果
     */
    private Boolean checkMsg(SysOrgCsMsgDo sysOrgCsMsgDo) {
        if (StringUtil.isBlank(sysOrgCsMsgDo.getProviderId())) {
            return false;
        }
        if (StringUtil.isBlank(sysOrgCsMsgDo.getFromUserId())) {
            return false;
        }
        if (StringUtil.isBlank(sysOrgCsMsgDo.getToUserId())) {
            return false;
        }
        if (StringUtil.isBlank(sysOrgCsMsgDo.getMsgContent())) {
            return false;
        }
        if (sysOrgCsMsgDo.getFromUserType() == null) {
            return false;
        }
        if (sysOrgCsMsgDo.getToUserType() == null) {
            return false;
        }
        if (sysOrgCsMsgDo.getMsgContentType() == null) {
            return false;
        }
        return true;
    }


    /**
     * 当新连接建立的时候,被调用
     * 连接成功时候,会触发页面上onOpen方法
     *
     * @param session
     * @throws Exception
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        log.info("时间:{} ,正在初始化连接: {}",getSysDate(), session.getId());
        try {
            //初始化连接,把session存储起来
            this.initUsers(session);
        } catch (Exception e) {
            e.printStackTrace();
        }
        log.info("初始化连接完成:{},时间{}",session.getId(),getSysDate());
    }

    /**
     * 当连接关闭时被调用
     *
     * @param session
     * @param status
     * @throws Exception
     */
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        log.info("时间:{} ,正在关闭连接: {}",getSysDate(), session.getId());
        try {
            log.info("断开连接状态值{}" , status.getCode());
            this.removeSession(session);
        } catch (Exception e) {
            e.printStackTrace();
        }
        log.info("正在关闭完成{}:" , session.getId() );

    }

    /**
     * 传输错误时调用
     *
     * @param session
     * @param exception
     * @throws Exception
     */
    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        log.error("发生传输错误:{};exception:{} ; 时间{}" , session.getId(), exception.getMessage(),getSysDate());
        exception.printStackTrace();
        if (session.isOpen()) {
            //try { session.close(); } catch (Exception e) {e.printStackTrace();}
        } else {
            try {
                this.removeSession(session);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
     }


    /**
     * 连接接入的处理方法
     *
     * @param session session
     */
    private synchronized void initUsers(WebSocketSession session) {
        WebSocketParamDo webSocketParamDo = new WebSocketParamDo(session.getUri().toString());
        if (webSocketParamDo.getUserTypeEnum() != null && StringUtils.isNotEmpty(webSocketParamDo.getUserId())) {
            ConcurrentHashMap<String, WebSocketSession> netgate = netgates.get(webSocketParamDo.getUserTypeEnum().getValue());
            if (netgate == null) {
                netgate = new ConcurrentHashMap<>(KelpConstants.EIGHTEEN);
            }
            WebSocketSession session_exist = netgate.get(webSocketParamDo.getUserId());
            if (session_exist != null) {
                log.info("检测到相同SN重复连接,SN:{},连接ID:{},准备清理失效的连接。。。" , webSocketParamDo.getUserTypeEnum().getValue() ,session_exist.getId() );
                try {
                    session_exist.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            netgate.putIfAbsent(webSocketParamDo.getUserId(), session);
            netgates.put(webSocketParamDo.getUserTypeEnum().getValue(), netgate);
        }
    }

    /**
     * 连接被关闭时处理集合
     *
     * @param session
     */
    private synchronized void removeSession(WebSocketSession session) {
        String string = session.getUri().toString();
        WebSocketParamDo webSocketParamDo = new WebSocketParamDo(string);
        if (netgates.get(webSocketParamDo.getUserTypeEnum().getValue()).containsKey(webSocketParamDo.getUserId())) {
            WebSocketSession exist_session = netgates.get(webSocketParamDo.getUserTypeEnum().getValue()).get(webSocketParamDo.getUserId());
            //确保是同一个session 不是同一个session则不应该进行下一步的处理
            if (exist_session.getId() != null && exist_session.getId().equals(session.getId())) {
                netgates.get(webSocketParamDo.getUserTypeEnum().getValue()).remove(webSocketParamDo.getUserId());
                log.info("有一网关连接关闭!SN:{},当前在线数量为{}" , webSocketParamDo.getUserTypeEnum(), netgates.get(webSocketParamDo.getUserTypeEnum().getValue()).keySet().size());
            } else {
                log.error("检测到关闭session异常,程序中断处理,关闭sessionId:{},当前实际sessionId: {}" , session.getId() , exist_session.getId());
            }
        } else {
            log.error("检测到关闭session异常,程序中断处理,系统中未找到对应的session,Sn={} , openid= {}" , webSocketParamDo.getUserTypeEnum().getValue() ,webSocketParamDo.getUserId());
        }
    }

    private String getSysDate() {
        //设置日期格式
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return df.format(new Date());
    }
}

3 实现webSocket过滤器


/**
 * webSocket过滤器
 * @author terry
 */
public class WebSocketHandshakeInterceptor implements HandshakeInterceptor {


    /**
     * 鉴权逻辑
     * @param url 请求路径
     * @return
     */
    private boolean requestIsValid(String url){
        //在这里可以写上具体的鉴权逻辑
        return true;
    }



    @Override
    public boolean beforeHandshake(org.springframework.http.server.ServerHttpRequest serverHttpRequest, org.springframework.http.server.ServerHttpResponse serverHttpResponse, org.springframework.web.socket.WebSocketHandler webSocketHandler, Map<String, Object> map) throws Exception {
        if (serverHttpRequest instanceof ServletServerHttpRequest) {
            String path = serverHttpRequest.getURI().getPath();
            WebSocketParamDo webSocketParamDo = WebSocketParamDo.getWebSocketParamDo(path);
            if ( StringUtil.isBlank(webSocketParamDo.getUserId()) || webSocketParamDo.getUserTypeEnum() == null) {
                Magic.throwException("链接参数不合法");
                return false;
            }

            String[] tokens = ((ServletServerHttpRequest) serverHttpRequest).getServletRequest().getParameterValues("token");
            String token =tokens[0];
            if(requestIsValid(token)){
                ((ServletServerHttpRequest) serverHttpRequest).getServletRequest().setAttribute("token",token);
                ((ServletServerHttpRequest) serverHttpRequest).getServletRequest().setAttribute("userId",webSocketParamDo.getUserId());
                ((ServletServerHttpRequest) serverHttpRequest).getServletRequest().setAttribute("linkType",webSocketParamDo.getUserTypeEnum().getValue());
            }else {
                //鉴权失败 断开链接
                return false;
            }
        }
        System.out.println("================Before Handshake================");
        return true;
    }

    @Override
    public void afterHandshake(org.springframework.http.server.ServerHttpRequest serverHttpRequest, org.springframework.http.server.ServerHttpResponse serverHttpResponse, org.springframework.web.socket.WebSocketHandler webSocketHandler, Exception e) {
        System.out.println("================After Handshake================");
        if(e!=null) {
            e.printStackTrace();
        }
        System.out.println("================After Handshake================");
    }
}

4 配置类的实现

/**
 * 配置类
 * @author terry
 */
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {


    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry
                .addHandler(webSocketHandler(), "/WebSocket/clothing/{type}/{userId}")
                .addInterceptors(new WebSocketHandshakeInterceptor())
                //允许跨域,方便本地调试,生产建议去掉
                .setAllowedOrigins("*");
    }


    @Bean
    public TextWebSocketHandler webSocketHandler() {
        return new NetgateHandler();
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值