为什么使用websocket推送任务
一般现在服务器端有数据变化,我们采用的是定时拉去的方式,这种方式在一般数据量的时候还是可以接受的,但是对于数据量很大就不太合适了,websocket就是采取一种推的方式把任务推送给浏览器,具体websocket详细,请查询相关文档。这里就不过多阐述了,我们还是一步步的来完成我们如何实现待办任务的实时推送功能吧。
- 1. 引入pom
<!-- 使用spring websocket依赖的jar包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-messaging</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.5.4</version>
</dependency>
- 2. 配置websocket
@Configuration
@EnableWebSocket
public class SpringWebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(webSocketHandler(), "/socket/task").setAllowedOrigins("*").addInterceptors(new SpringWebSocketHandlerInterceptor());
}
@Bean
public TaskWebSocketHandler webSocketHandler() {
return new TaskWebSocketHandler();
}
}
- 3. 编写handler
@Component
public class TaskWebSocketHandler extends TextWebSocketHandler {
@Autowired
private IWebSocketService webSocketService;
/**
* 当客户连接的时候触发
* @param session
* @throws Exception
*/
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
//获取当前的用户id
String userid = (String) session.getAttributes().get(SpringWebSocketHandlerInterceptor.WEBSOCKET_USERID);
//添加到自己的缓存中去
webSocketService.addSession(userid, session);
//发送当前用户的任务列表给客户端
webSocketService.sendMessage(userid);
}
/**
* 当连接断开的时候触发
* @param session
* @param closeStatus
* @throws Exception
*/
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
//获取当前的userId
String userid = (String) session.getAttributes().get(SpringWebSocketHandlerInterceptor.WEBSOCKET_USERID);
if(null != userid){
//移除session
webSocketService.removeSession(userid);
}
}
/**
* 当出错的时候触发
* @param session
* @param exception
* @throws Exception
*/
@Override
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
String userid = (String) session.getAttributes().get(SpringWebSocketHandlerInterceptor.WEBSOCKET_USERID);
if (session.isOpen()) {
//关闭通道
session.close();
}
//移除通道
webSocketService.removeSession(userid);
}
}
- 4. 编写HttpSessionHandshakeInterceptor
/**
* websocket拦截器
*/
public class SpringWebSocketHandlerInterceptor extends HttpSessionHandshakeInterceptor {
public static final String WEBSOCKET_USERID = "websocket_userid";
@Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
Map<String, Object> attributes) throws Exception {
if (request instanceof ServletServerHttpRequest) {
ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
//获取当前session
HttpSession session = servletRequest.getServletRequest().getSession(false);
if (session != null) {
//获取当前登录用户
User user = (User) session.getAttribute(UserUtil.USER);
if (user==null) {
return false;
}
//把用户的id放入websocket通道属性里
attributes.put(WEBSOCKET_USERID,user.getId());
}
}
return super.beforeHandshake(request, response, wsHandler, attributes);
}
@Override
public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
Exception ex) {
super.afterHandshake(request, response, wsHandler, ex);
}
}
- 5. 编写js
/**
* websocket 消息推送
* @type {{ws: null, init: sckt.init, closeSocket: sckt.closeSocket, showMsgBox: sckt.showMsgBox, genMsgHtml: sckt.genMsgHtml}}
*/
var sckt= {
ws:null,
init:function () {
var _this = this;
this.ws = $.websocket({
domain: window.location.hostname,
port: window.location.port,
protocol: ctx + "/socket/task;jsessionid="+jsessionid,
onOpen: function (e) {
// console.log("WebSocket连接成功");
},
onError: function (e) {
// console.log("WebSocket连接错误");
},
onMessage: function (res) {
if(res){
_this.msgObj = JSON.parse(res);
_this.showMsgBox();
}
},
onClose: function (e) {
// console.log("WebSocket连接关闭");
}
});
//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常.
window.onbeforeunload = function () {
_this.closeSocket();
};
},
// 关闭连接
closeSocket:function(){
if (this.ws.socket == null || this.ws.socket.readyState == 2 || this.ws.socket.readyState == 3) {
return true;
}
this.ws.close();
},
// 显示消息框
showMsgBox:function(){
var _this = this;
if(!_this.msgBox){
_this.msgBox = $("<div class=\"msg-box\" id=\"jsMsgBox\"></div>");
_this.msgBox.appendTo($('body'));
_this.msgBox.dialog({
dialogClass: "no-close",
title:'消息提醒<i class="msg-total" id="jsMsgTotal">0</i>',
position: { my: "right bottom", at: "right bottom",of: window ,collision: "fit"},
resizable: false,
draggable:false,
maxHeight:600,
open: function (event, ui) {
var that = this;
$(".ui-dialog-titlebar-close", $(this).parent()).html('<span class="ui-icon ui-icon ui-icon-carat-1-s"></span>');
$(".ui-dialog-titlebar-close", $(this).parent()).unbind('click').bind('click',function (e) {
$(".ui-dialog-content", $(that).parent()).toggleClass('dialog-content-hide');
$(".ui-icon", $(this).parent()).toggleClass('ui-icon-carat-1-s');
_this.msgBox.dialog({position: { my: "right bottom", at: "right bottom",of: window ,collision: "fit"}});
});
}
});
_this.msgBox.dialog('close');
}
if(_this.msgObj){
if(!_this.msgBox.dialog('isOpen')){
_this.msgBox.dialog('open');
}
_this.msgBox.dialog({'title': '消息提醒<i class="msg-total" id="jsMsgTotal">'+_this.msgObj.total+'</i>'});
_this.msgBox.html(_this.genMsgHtml());
}
},
/**
* 将返回的内容组装成html
* @returns {string}
*/
genMsgHtml:function(){
var _this = this, html = '<ul>';
if(_this.msgObj.datas){
var arr = _this.msgObj.datas;
for(var i = 0; i<arr.length; i++){
html+='<li id="taskId_"+'+arr[i].taskId+'>'+arr[i].taskName+'</li>';
}
}
html+='</ul>';
return html;
}
};
- 6. 编写jsp
<%@ include file="/common/global.jsp"%>
<%
String rootPath = request.getContextPath();
String jsessionid = request.getSession().getId();
%>
<script>
var notLogon = ${empty user};
if (notLogon) {
location.href = '${ctx}/login?timeout=true';
}
var rootPath = "<%=rootPath%>";
var jsessionid = "<%=jsessionid%>";
var WEB_SOCKET_DEBUG = false;
var WEB_SOCKET_SWF_LOCATION = rootPath + '/js/common/plugins/websocket/WebSocketMain.swf';
</script>
效果如下:
今天先写到这里,明天在写IWebSocketService的实现和配置全局监听