spirng项目中集成webSocket踩到的坑

 

 

花费了将近一周的时间终于将webSocket 集成到了原来的springmvc+spring +mybatis 项目中了,一路心酸一路的泪水啊,网上的技术文档都没有解决我的问题,(很多文章都是你抄我的我抄你的)。

先来说一下我的环境:

windows  10, myeclipse 2014,orcale11 ,jdk 1.7.0.79 ,spring 4.3.8   springmvc 4.2.4.RELEASE  

 

websocket jar

           <dependency>
			    <groupId>javax.websocket</groupId>
			    <artifactId>javax.websocket-api</artifactId>
			    <version>1.0</version>
			    <scope>provided</scope>
			</dependency>
	        <dependency>
	            <groupId>org.springframework</groupId>
	            <artifactId>spring-websocket</artifactId>
	            <version>4.2.4.RELEASE</version>
	        </dependency>
	        <dependency>
	            <groupId>org.springframework</groupId>
	            <artifactId>spring-messaging</artifactId>
	            <version>4.2.4.RELEASE</version>
	        </dependency>	

下面就记录一下自己遇到的问题,以及如何解决的问题

想贴上自己的代码

SpringWebSocketConfig.java  文件

/**
 * 
 * 
 * @Description: TODO <p>SpringWebSocketConfig.java</p>
 * @作者: 王彦宝
 * @时间: 2018年10月24日下午3:52:57
 * @version V1.0
 * @see java.lang.Class
 * @since JDK{jdk1.7}
 */
//@EnableWebMvc//测试这个注解可以不要
@Configuration
@EnableWebSocket
public class SpringWebSocketConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer{

	
	@Override
	public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(webSocketHandler(),"/webSocketIMServer.json").addInterceptors(myInterceptor()).setAllowedOrigins("*");
        registry.addHandler(webSocketHandler(), "/sockjs/webSocketIMServer.json").withSockJS();
	}
	
	@Bean
    public SpringWebSocketHandler webSocketHandler(){
        return new SpringWebSocketHandler();
    }

	 @Bean
    public SpringWebSocketHandlerInterceptor myInterceptor(){
        return new SpringWebSocketHandlerInterceptor();
    }
}

 SpringWebSocketHandler.java  文件

import java.io.IOException;
import java.util.ArrayList;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

/**
 * 
 * 
 * @Description: TODO <p>SpringWebSocketHandler.java</p>
 * @作者: 王彦宝
 * @时间: 2018年10月24日下午3:55:49
 * @version V1.0
 * @see java.lang.Class
 * @since JDK{jdk1.7}
 */
public class SpringWebSocketHandler extends TextWebSocketHandler{
	
	private static final Logger LOGGER = LoggerFactory.getLogger(SpringWebSocketHandler.class);
	
	private static final ArrayList<WebSocketSession> users;//这个会出现性能问题,最好用Map来存储,key用userid
	
	 static {
        users = new ArrayList<WebSocketSession>();
    }
	    
    public SpringWebSocketHandler() {
        // TODO Auto-generated constructor stub
    }
	
	/**
     * 连接成功时候,会触发页面上onopen方法
     */
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
    	LOGGER.info("connect to the websocket success......当前数量:"+users.size());
        users.add(session);
        //这块会实现自己业务,比如,当用户登录后,会把离线消息推送给用户,这里需要查询数据库把待发送的消息发送给医生
        TextMessage returnMessage = new TextMessage("你将收到的离线");
        session.sendMessage(returnMessage);
    }
    
   
   /**
    * 关闭连接时触发
    */
    public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
        String username= (String) session.getAttributes().get("WEBSOCKET_EDU_SESSION_USERID");
        LOGGER.info("用户"+username+"已退出!");
        users.remove(session);
        LOGGER.info("剩余在线用户"+users.size());
    }

    /**
     * 给某个用户发送消息
     * @param userAndHosId
     * @param message
     * @作者: 王彦宝
     * @时间: 2018年11月30日下午1:51:32
     * @返回 void
     */
    public void sendMessageToUser(String username, TextMessage message) {
    	LOGGER.info("发送消息:"+message);
        for (WebSocketSession user : users) {
            if (user.getAttributes().get("WEBSOCKET_SESSION_USERID").equals(username)) {
                try {
                    if (user.isOpen()) {
                    	LOGGER.info("发送消息:"+message);
                        user.sendMessage(message);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
                break;
            }
        }
    }
    
    /**
     * 群发所有在线用户消息
     *
     * @param userName
     * @param message
     */
    public void sendMessage(TextMessage message) {
    	LOGGER.info("发送消息:"+message);
        for (WebSocketSession user : users) {
            try {
                if (user.isOpen()) {
                	LOGGER.info("发送消息:"+message);
                    user.sendMessage(message);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
    /**
     * js调用websocket.send时候,会调用该方法
     */
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
 
        super.handleTextMessage(session, message);
 
        /**
         * 收到消息,自定义处理机制,实现业务
         */
        System.out.println("服务器收到消息:"+message);
 
        if(message.getPayload().startsWith("#anyone#")){ //单发某人
 
             sendMessageToUser((String)session.getAttributes().get("WEBSOCKET_SESSION_USERID"), new TextMessage("服务器单发:" +message.getPayload())) ;
 
        }else if(message.getPayload().startsWith("#everyone#")){
 
        	sendMessage(new TextMessage("服务器群发:" +message.getPayload()));
 
        }else{
 
        }
 
    }
}

SpringWebSocketHandlerInterceptor.java 文件

import java.util.Map;

import javax.servlet.http.HttpSession;

import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;

/**
 * 
 * WebSocket拦截器
 * @Description: TODO <p>SpringWebSocketHandlerInterceptor.java</p>
 * @作者: 王彦宝
 * @时间: 2018年10月24日下午3:58:34
 * @version V1.0
 * @see java.lang.Class
 * @since JDK{jdk1.7}
 */
public class SpringWebSocketHandlerInterceptor extends HttpSessionHandshakeInterceptor{

	
	@Override
    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
            Map<String, Object> attributes) throws Exception {
        // TODO Auto-generated method stub
        System.out.println("Before Handshake");
        if (request instanceof ServletServerHttpRequest) {
            ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
            HttpSession session = servletRequest.getServletRequest().getSession(false);
            if (session != null) {
                //使用userName区分WebSocketHandler,以便定向发送消息
                String username = (String) session.getAttribute("SESSION_USERID");
                if (username==null) {
                	username="default-system";
                }
                attributes.put("WEBSOCKET_SESSION_USERID",username);
            }
        }
        return super.beforeHandshake(request, response, wsHandler, attributes);
        
    }
    
    @Override
    public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
            Exception ex) {
        // TODO Auto-generated method stub
        super.afterHandshake(request, response, wsHandler, ex);
    }
}

这就是核心的代码了。在spring  的配置文件中加入  SpringWebSocketConfig  文件的扫描路径,然后启动项目在前端进行访问

ws://localhost:8081/XXXXX/webSocketIMServer.json");  这样访问就OK 了。

遇到的问题我总结一下:

1、404问题:

    在第一次访问的时候报出了404  的错误,找不到路径,最后发现问题在这里

        registry.addHandler(webSocketHandler(),"/webSocketIMServer.json").addInterceptors(myInterceptor()).setAllowedOrigins("*");
        registry.addHandler(webSocketHandler(), "/sockjs/webSocketIMServer.json").withSockJS();

前端访问的方法必须和后台写的这个方法名一致(包括后缀名,如果后台代码没有后缀,前端访问时候就不要加后缀,不然就是访问不到)"/webSocketIMServer.json"。

2、403问题:

    上面解决了404 的问题就又报出了403 的问题,然后我就在网上各种搜索,有各种各样的方案,都试过了,没有解决问题,然后搜到了这个

博客:https://blog.csdn.net/goxidono/article/details/53414897

和我的问题一模一样,说的挺详细,spring-webSocket.jar  里面自动实现了HandshakeInterceptor  接口 

public class OriginHandshakeInterceptor implements HandshakeInterceptor {

 

然后再执行到这个方法的时候,this.interceptors   就会又两个 interceptors,  第一个是我们自己实现的SpringWebSocketHandlerInterceptor  这个接口实现类,第二个就是   spring-webSocket  自动帮你实现的  OriginHandshakeInterceptor  这个接口实现类,

public boolean applyBeforeHandshake(ServerHttpRequest request, ServerHttpResponse response,
			Map<String, Object> attributes) throws Exception {

		for (int i = 0; i < this.interceptors.size(); i++) {
			HandshakeInterceptor interceptor = this.interceptors.get(i);
			if (!interceptor.beforeHandshake(request, response, this.wsHandler, attributes)) {
				if (logger.isDebugEnabled()) {
					logger.debug(interceptor + " returns false from beforeHandshake - precluding handshake");
				}
				applyAfterHandshake(request, response, null);
				return false;
			}
			this.interceptorIndex = i;
		}
		return true;
	}

就在这个方法中会被拦截,然后我就改变了写法,

下面是我刚开始的写法:

public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        //WebIM WebSocket通道
        registry.addHandler(webSocketHandler(),"/webSocketIMServer").addInterceptors(myInterceptor());
        registry.addHandler(webSocketHandler(), "/sockjs/webSocketIMServer").addInterceptors(myInterceptor()).withSockJS();
    }

改变后的写法:

public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
		//WebIM WebSocket通道
        registry.addHandler(webSocketHandler(),"/webSocketIMServer.json").addInterceptors(myInterceptor()).setAllowedOrigins("*");
        registry.addHandler(webSocketHandler(), "/sockjs/webSocketIMServer.json").withSockJS();
	}

然后继续测试,发现还是不行,原因在执行到  applyBeforeHandshake 方法时有两个拦截器,按照上面的写法我们自己实现的拦截器时通过了,但是spring-webSocket 实现的拦截器没有通过,然后又被拦截了报403 ,但是还是没有解决我的问题。文章里用的jdk 8 ,tomcat 8 ,和我的问题相似但是环境不同,用不了他的写法,测试到这里的时候我用的spirng 的版本  时4.2.4  ,然后我就想想换一个高点的spring  的版本试试看,之后就换了Spirng 4.3.8 的版本,启动测试,居然OK了。好吧原来时版本的问题  最后的的环境是:

    

windows  10, myeclipse 2014,orcale11 ,jdk 1.7.0.79 ,spring 4.3.8   springmvc 4.2.4.RELEASE  

 

websocket jar

           <dependency>
			    <groupId>javax.websocket</groupId>
			    <artifactId>javax.websocket-api</artifactId>
			    <version>1.0</version>
			    <scope>provided</scope>
			</dependency>
	        <dependency>
	            <groupId>org.springframework</groupId>
	            <artifactId>spring-websocket</artifactId>
	            <version>4.2.4.RELEASE</version>
	        </dependency>
	        <dependency>
	            <groupId>org.springframework</groupId>
	            <artifactId>spring-messaging</artifactId>
	            <version>4.2.4.RELEASE</version>
	        </dependency>	

这样就可以了。在此做一个记录。

 

 

转载于:https://my.oschina.net/u/3267498/blog/2980800

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值