ssm中spring websocket 实现服务器推送消息 以及 一对一聊天

上网看了很多方式,最后觉得这种方式比较简单易懂,这边主要有三个类(包括注解的配置文件)就可以实现后台内容

文末会展示结果实例,如果是你所需要的效果,直接拿去用吧~项目中复制直接用

本文根据网上整理并修改!!!

本文思路来自:链接

现在开始。开始前请确保pom已经引入需要的包

首先是配置文件类(注解)

/** 
 * Spring WebSocket的配置,这里采用的是注解的方式 
 */  
  
@Configuration  
@EnableWebMvc//这个标注可以不加,如果有加,要extends WebMvcConfigurerAdapter  
@EnableWebSocket  
public class WebSocketConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer {  
  
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {  
        //1.注册WebSocket  
        String websocket_url = "/websocket/socketServer";                        //设置websocket的地址  
        registry.addHandler(webSocketHandler(), websocket_url).                          //注册Handler  
                addInterceptors(new WebSocketHandshakeInterceptor());                   //注册Interceptor  
  
        //2.注册SockJS,提供SockJS支持(主要是兼容ie8)  
        String sockjs_url = "/sockjs/socketServer";                              //设置sockjs的地址  
        registry.addHandler(webSocketHandler(), sockjs_url).                            //注册Handler  
                addInterceptors(new WebSocketHandshakeInterceptor()).                   //注册Interceptor  
                withSockJS();                                                           //支持sockjs协议  
    }  
  
    @Bean
    public TextWebSocketHandler webSocketHandler() {  
        return new WebSocketHandler();  
    }  
}  

然后是连接拦截器类,主要是拦截连接并且设置用户session标识作用,这样在最后一个处理请求类可以分清是哪个已连接用户发出的请求~,

/** 
 * WebSocket握手拦截器 
 */  
public class WebSocketHandshakeInterceptor implements HandshakeInterceptor {  
 
    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse serverHttpResponse, WebSocketHandler webSocketHandler, Map<String, Object> attributes) throws Exception {  

    	if (request instanceof ServletServerHttpRequest) {
    		ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;  
            HttpSession session = servletRequest.getServletRequest().getSession(false);  
            if (session != null) {  
                String userName = (String) session.getAttribute("SESSION_USERNAME");  //这边获得登录时设置的唯一用户标识
                if (userName == null) {  
                    userName = "未知" + session.getId();  
                }  
                attributes.put("WEBSOCKET_USERNAME", userName);  //将用户标识放入参数列表后,下一步的websocket处理器可以读取这里面的数据
            }  
        }  
        return true;  
    }  
  
    public void afterHandshake(ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse, WebSocketHandler webSocketHandler, Exception e) {  
        System.out.println("After Handshake");  
    }
}  

我在参考博客的基础上修改成一对一识别的方式,识别用户的方式是根据‘@‘分隔符处理传来的字符串,格式是

“目标用户标识@文本信息”,这样可以知道是要发给哪个已连接用户的,如果没有找到这个用户标识,返回给用户对方不在线或者对方在线异常 信息。。。返回的信息可以是“状态码@文本信息(或者是提示信息)”前端根据状态码来显示是否是正常聊天内容还是异常信息。。。 在文末看实例就知道啦

处理器:

/**
 * Websocket处理器
 */

public class WebSocketHandler extends TextWebSocketHandler {

	// 已建立连接的用户
	private static final ArrayList<WebSocketSession> users = new ArrayList<WebSocketSession>();

	/**
	 * 处理前端发送的文本信息 js调用websocket.send时候,会调用该方法
	 * 
	 * @param session
	 * @param message
	 * @throws Exception
	 */
	@Override
	protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
		String username = (String) session.getAttributes().get("WEBSOCKET_USERNAME");

		// 获取提交过来的消息详情
		System.out.println("收到用户 " + username + " 的消息:" + message.toString());
		// 分割成id和信息内容
		String[] messageInfo = message.getPayload().split("@");
		if (messageInfo.length != 2) {
			sendMessageToUser(username, new TextMessage("500@服务器出错请稍后再发送吧"));
		} else {
			String target = messageInfo[0];
			String content = messageInfo[1];
			// 遍历所有已连接用户
			for (WebSocketSession user : users) {
				if (user.getAttributes().get("WEBSOCKET_USERNAME").equals(target)) {
					//遇到匹配用户 连接正常则发送消息
					if (user.isOpen()) {
						sendMessageToUser(target, new TextMessage("200@"+content));
					}else{//若异常则发送失败
						sendMessageToUser(username, new TextMessage("404@对方在线异常,发送失败"));
					}
					return;
				}
			}
			//未找到匹配用户 发送失败
			sendMessageToUser(username, new TextMessage("404@对方暂时不在线"));
		}
	}

	/**
	 * 当新连接建立的时候,被调用 连接成功时候,会触发页面上onOpen方法
	 * 
	 * @param session
	 * @throws Exception
	 */
	@Override
	public void afterConnectionEstablished(WebSocketSession session) throws Exception {
		users.add(session);
		String username = (String) session.getAttributes().get("WEBSOCKET_USERNAME");
		System.out.println("用户 " + username + " Connection Established");
		session.sendMessage(new TextMessage(username + " connect"));
	}

	/**
	 * 当连接关闭时被调用
	 * 
	 * @param session
	 * @param status
	 * @throws Exception
	 */
	@Override
	public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
		String username = (String) session.getAttributes().get("WEBSOCKET_USERNAME");
		System.out.println("用户 " + username + " Connection closed. Status: " + status);
		users.remove(session);
	}

	/**
	 * 传输错误时调用
	 * 
	 * @param session
	 * @param exception
	 * @throws Exception
	 */
	@Override
	public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
		String username = (String) session.getAttributes().get("WEBSOCKET_USERNAME");
		if (session.isOpen()) {
			session.close();
		}
		System.out.println("用户: " + username + " websocket connection closed......");
		users.remove(session);
	}

	/**
	 * 给所有在线用户发送消息
	 * 
	 * @param message
	 */
	public void sendMessageToUsers(TextMessage message) {
		for (WebSocketSession user : users) {
			try {
				if (user.isOpen()) {
					user.sendMessage(message);
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 给某个用户发送消息
	 * 
	 * @param userName
	 * @param message
	 */
	public void sendMessageToUser(String userName, TextMessage message) {
		for (WebSocketSession user : users) {
			if (user.getAttributes().get("WEBSOCKET_USERNAME").equals(userName)) {
				try {
					if (user.isOpen()) {
						user.sendMessage(message);
					}
				} catch (IOException e) {
					e.printStackTrace();
				}
				break;
			}
		}
	}
}

接下来是实例:

先创建一个登录控制器,这样能区分用户。

@Controller
public class WebSocketController {

	@Bean // 这个注解会从Spring容器拿出Bean
	public WebSocketHandler infoHandler() {
		return new WebSocketHandler();
	}

	@RequestMapping("/login")
	public String login(HttpServletRequest request, HttpServletResponse response) throws Exception {
		String username = request.getParameter("username");
		System.out.println(username + "登录");
		HttpSession session = request.getSession();
		session.setAttribute("SESSION_USERNAME", username);
		return "websocket";
	}
}

然后是登陆页面 index.jsp

<%@ page language="java" contentType="text/html; charset=utf-8"
	pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<body>
	<h2>Wellcome</h2>
	<form action="login">
		登录名:<input type="text" name="username" /> <input type="submit"
			value="登录" />
	</form>
</body>
</html>

聊天界面:websocket.jsp

<%@ page language="java" contentType="text/html; charset=utf-8"  
         pageEncoding="utf-8" %>  
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">  
<html>  
<head>  
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">  
    <title>Java API for WebSocket (JSR-356)</title>  
</head>  
<body>  
<script type="text/javascript" src="http://cdn.bootcss.com/jquery/3.1.0/jquery.min.js"></script>  
<script type="text/javascript" src="http://cdn.bootcss.com/sockjs-client/1.1.1/sockjs.js"></script>  
<script type="text/javascript">  
    var websocket = null;  
    if ('WebSocket' in window) {  
        //Websocket的连接  
        websocket = new WebSocket("ws://localhost:8080/Creator/websocket/socketServer");//WebSocket对应的地址  
    }  
    else if ('MozWebSocket' in window) {  
        //Websocket的连接  
        websocket = new MozWebSocket("ws://localhost:8080/Creator/websocket/socketServer");//SockJS对应的地址  
    }  
    else {  
        //SockJS的连接  
        websocket = new SockJS("http://localhost:8080/Creator/sockjs/socketServer");    //SockJS对应的地址  
    }  
    websocket.onopen = onOpen;  
    websocket.onmessage = onMessage;  
    websocket.onerror = onError;  
    websocket.onclose = onClose;  
  
    function onOpen(openEvt) {  
        //alert(openEvt.Data);   
    }  
  
    function onMessage(evt) {  
        $("#content").append(evt.data+"<br>"); // 接收后台发送的数据
    }  
    function onError() {  
    }  
    function onClose() {  
    }  
  
    function doSend() {  
        if (websocket.readyState == websocket.OPEN) {  
            websocket.send($("#targetName").val()+"@"+$("#inputMsg").val());//调用后台handleTextMessage方法  
            alert("发送成功!");  
        } else {  
        
            alert("连接失败!"+websocket.readyState);  
        }  
    }  
  
    window.close = function () {  
        websocket.onclose();  
    }  
</script>  
请输入目标名称:<input type="text" id = "targetName" />
请输入:<textarea rows="3" cols="100" id="inputMsg" name="inputMsg"></textarea>  
<button onclick="doSend();">发送</button>  
<div id="content"></div>
</body>  
</html>  

最后看成果:

首先随便发送消息,查看会有什么反应:


最后是双方互相发送消息:


好了 大功告成!!

猜你喜欢

转载自blog.csdn.net/qq_33683097/article/details/80692886