2017-11-15
https://zq99299.github.io/essay-note/chapter/websocket/spring.html 该文章结束了,
https://github.com/zq99299/java-websocket-demo 这是本次练习的demo注意:
注意:
注意:
注意:如果你想入门学习spring websocket那么直接看最新的文章。不要看本文分享的聊天demo;聊天demo的文章写得比较乱,而且是用最原始的websocket实现的。只能作为你们的一个使用参考。
2017-11-07
https://zq99299.gitbooks.io/essay-note/content/chapter/websocket/spring.html
如今在后台系统中重新使用了websocket,使用了stomp作为高级协议,实现了监控功能,广播,点对点推送功能。也算是对websocket有了更深一层的理解了。这里继续更新博文。从h5的websocket开始讲起。直到过渡到使用stomp。好把。gitbook最近貌似不太稳定,不翻墙的话貌似不太好打开了
如果gitbook打不开的话,github总能打开了吧。我把书籍放到github-pages里面了:https://zq99299.github.io/essay-note/chapter/websocket/spring.html
2017-09-30
~~~ 内容已被最新的替换
2017-06-29
https://git.oschina.net/zhuqiang/webTM-parent.git 该项目是群聊demo,可以正常运行,最近有好多网友在询问我。正好抽空把里面数据库相关的都给注释掉了。亲自验证过了,下载项目,用tomcat7+运行就行。我自己用的开发工具是idea,导入项目配置好tomcat就可以运行;记得用eclipse的同学部署项目不要加项目名
2015-11-22:这篇文章是一个入门,后来自己想用spring webSocket做一个聊天的小项目的,无奈做到一半的时候发现很多问题,自己那个时候处理不了,就放弃了,还有就是页面和js要写很多,就搁浅下来了。现在把源码放出来,放上几张图片,有需要的可以去git看。项目里面有完整的思维导图,怎么实现这个小项目的。打算做的一些功能。的设计文档。等时间空出来了,上个人网站的时候,我还会把这个小项目加以改造,放到网站上面去。
https://git.oschina.net/zhuqiang/webTM-parent.git
http://www.mrcode.cn/ 示例。点进去玩玩吧【示例已经移除,已经放上了自己写的博客项目】
上面的小项目中,发现一个bug:在页面上用www.mrcode.cn/echo 与spring Socket建立链接的时候 有时候会出现 403的错误码,原因是:socket中有一个AllowedOrigins的设置项,而如果你用mrcode.cn访问的话就和www.mrcode.cn不匹配,导致链接不上了。
示例代码,添加拦截器的:
registry.addHandler(webSokcetHandler(), "/websocket").addInterceptors(new HandshakeInterceptor()).setAllowedOrigins("http://localhost");
说明
本demo运行的环境是:ssm框架 + tomcat8 + jdk7+,由于只是demo。很简陋。能运行调式通过就行,再在此基础上进行扩展研究。
在网上看了很多列子。对于没有接触过websocket的人来说。真的是看不懂。本文列子应该算是比较简单的。 该demo核心代码 只保证能运行。能对话。其他的功能需要自己实现
Spring WebSocket API的核心接口是WebSocketHandler。我把它叫做消息处理中心。
其他的详细解说可以参考别人的博客
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
mvc的url-pattern 配置成 / 应该是拦截所有的访问请求?如果controller中有对应的地址就处理,没有就放行? 这一块不是太明白
pom.xml,版本自行查找。spring4.0+以上,在部署项目的时候。记得把tomcat8加入到jar包库(在eclipse中就是那个build path 中的 libraries )
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-messaging</artifactId>
</dependency>
WebSocketConfig 配置
由于之前使用xml配置,和springmvc中的地址冲突(忘记了是什么情况下发生的了,有可能是我访问地址访问错了)。就使用了注解配置类的形式配置
import cn.zymx.webTM.web.controller.HandshakeInterceptor;
import cn.zymx.webTM.web.controller.WebSocketHander;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
/**
* Created by zhuqiang on 2015/6/23 0023.
*/
@Configuration
@EnableWebSocket//开启websocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(new WebSocketHander(),"/echo").addInterceptors(new HandshakeInterceptor()); //支持websocket 的访问链接
registry.addHandler(new WebSocketHander(),"/sockjs/echo").addInterceptors(new HandshakeInterceptor()).withSockJS(); //不支持websocket的访问链接
}
}
HandshakeInterceptor 拦截器(握手)
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 javax.servlet.http.HttpSession;
import java.util.Map;
/**
* Created by zhuqiang on 2015/6/22 0022.
*/
public class HandshakeInterceptor implements org.springframework.web.socket.server.HandshakeInterceptor {
//初次握手访问前
@Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse serverHttpResponse, WebSocketHandler webSocketHandler, Map<String, Object> map) throws Exception {
if (request instanceof ServletServerHttpRequest) {
HttpServletRequest servletRequest = ((ServletServerHttpRequest) request).getServletRequest();
String userName = "xq";
//使用userName区分WebSocketHandler,以便定向发送消息
// String userName = (String) session.getAttribute("WEBSOCKET_USERNAME");
map.put("WEBSOCKET_USERNAME",userName);//存入数据,方便在hander中获取,这里只是在方便在webSocket中存储了数据,并不是在正常的httpSession中存储哦,想要在平时使用的session中获得这里的数据,需要使用session 来存储一下
servletRequest.getSession().setAttribute("WEBSOCKET_USERNAME", userName);
}
return true;
}
//初次握手访问后
@Override
public void afterHandshake(ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse, WebSocketHandler webSocketHandler, Exception e) {
}
}
WebSocketHandler 消息处理中心
import org.apache.log4j.Logger;
import org.springframework.web.socket.*;
import java.io.IOException;
import java.util.ArrayList;
/**
* Created by zhuqiang on 2015/6/22 0022.
*/
public class WebSocketHander implements WebSocketHandler {
private static final Logger logger = Logger.getLogger(WebSocketHander.class);
private static final ArrayList<WebSocketSession> users = new ArrayList<>();
//初次链接成功执行
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
logger.debug("链接成功......");
users.add(session);
String userName = (String) session.getAttributes().get("WEBSOCKET_USERNAME");
if(userName!= null){
//查询未读消息
int count = 5;
session.sendMessage(new TextMessage(count + ""));
}
}
//接受消息处理消息
@Override
public void handleMessage(WebSocketSession webSocketSession, WebSocketMessage<?> webSocketMessage) throws Exception {
sendMessageToUsers(new TextMessage(webSocketMessage.getPayload() + ""));
}
@Override
public void handleTransportError(WebSocketSession webSocketSession, Throwable throwable) throws Exception {
if(webSocketSession.isOpen()){
webSocketSession.close();
}
logger.debug("链接出错,关闭链接......");
users.remove(webSocketSession);
}
@Override
public void afterConnectionClosed(WebSocketSession webSocketSession, CloseStatus closeStatus) throws Exception {
logger.debug("链接关闭......" + closeStatus.toString());
users.remove(webSocketSession);
}
@Override
public boolean supportsPartialMessages() {
return false;
}
/**
* 给所有在线用户发送消息
*
* @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;
}
}
}
}
页面
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<script src="http://cdn.sockjs.org/sockjs-0.3.min.js"></script>
<!-- 新 Bootstrap 核心 CSS 文件 -->
<link rel="stylesheet" href="//cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap.min.css">
<!-- 可选的Bootstrap主题文件(一般不用引入) -->
<link rel="stylesheet" href="//cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap-theme.min.css">
<!-- jQuery文件。务必在bootstrap.min.js 之前引入 -->
<script src="//cdn.bootcss.com/jquery/1.11.3/jquery.min.js"></script>
<!--<script type="text/javascript" src="js/jquery-1.7.2.js"></script>-->
<!-- 最新的 Bootstrap 核心 JavaScript 文件 -->
<script src="//cdn.bootcss.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<title>webSocket测试</title>
<script type="text/javascript">
$(function(){
var websocket;
if ('WebSocket' in window) {
alert("WebSocket");
websocket = new WebSocket("ws://127.0.0.1:8080/echo");
} else if ('MozWebSocket' in window) {
alert("MozWebSocket");
websocket = new MozWebSocket("ws://echo");
} else {
alert("SockJS");
websocket = new SockJS("http://127.0.0.1:8080/sockjs/echo");
}
websocket.onopen = function (evnt) {
$("#tou").html("链接服务器成功!")
};
websocket.onmessage = function (evnt) {
$("#msg").html($("#msg").html() + "<br/>" + evnt.data);
};
websocket.onerror = function (evnt) {
};
websocket.onclose = function (evnt) {
$("#tou").html("与服务器断开了链接!")
}
$('#send').bind('click', function() {
send();
});
function send(){
if (websocket != null) {
var message = document.getElementById('message').value;
websocket.send(message);
} else {
alert('未与服务器链接.');
}
}
});
</script>
</head>
<body>
<div class="page-header" id="tou">
webSocket及时聊天Demo程序
</div>
<div class="well" id="msg">
</div>
<div class="col-lg">
<div class="input-group">
<input type="text" class="form-control" placeholder="发送信息..." id="message">
<span class="input-group-btn">
<button class="btn btn-default" type="button" id="send" >发送</button>
</span>
</div><!-- /input-group -->
</div><!-- /.col-lg-6 -->
</div><!-- /.row -->
</body>
</html>