上网看了很多方式,最后觉得这种方式比较简单易懂,这边主要有三个类(包括注解的配置文件)就可以实现后台内容
文末会展示结果实例,如果是你所需要的效果,直接拿去用吧~项目中复制直接用
本文根据网上整理并修改!!!
本文思路来自:链接
现在开始。开始前请确保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>
最后看成果:
首先随便发送消息,查看会有什么反应:
最后是双方互相发送消息:
好了 大功告成!!