项目中要求用户A发起终止申请请求后,对应的相关权限的用户B、用户C等即时收到终止的请求,针对这个需求在项目中加入了websoket功能,下面是具体的使用过程。
1.在maven中添加jar引用
12 org.springframework 3spring-websocket 45.0.9.RELEASE 5
2.在xml的配置,在websocket-context.xml的配置,在service-context.xml的引入
<import resource="websocket-context.xml"/>
3.在后台拦截器和处理类
会话拦截器
1 import java.util.List; 2 import java.util.Map; 3 4 import org.springframework.http.server.ServerHttpRequest; 5 import org.springframework.http.server.ServerHttpResponse; 6 import org.springframework.stereotype.Component; 7 import org.springframework.web.socket.WebSocketHandler; 8 import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor; 9 10 import com.gta.scm.websocket.intercept.ServiceHandshakeInterceptor;11 12 13 @Component14 public class HandshakeInterceptor extends HttpSessionHandshakeInterceptor{15 public static final String JSESSIONID = "JSESSIONID";16 private Listlist;17 /**18 * 当用户连接ServerSocket时执行19 * 通过request获取用户登陆的jsessionId的值,放入到集合attributes中20 */21 @Override 22 public boolean beforeHandshake(ServerHttpRequest request, 23 ServerHttpResponse response, WebSocketHandler wsHandler, 24 Map attributes) throws Exception { 25 26 if(list!=null){27 for (ServiceHandshakeInterceptor serviceHandshakeInterceptor : list) {28 serviceHandshakeInterceptor.beforeHandshake(request, response, wsHandler, attributes);29 }30 }31 return super.beforeHandshake(request, response, wsHandler, attributes); 32 } 33 34 35 36 /**37 * 当用户连接完ServerSocket时执行38 */39 @Override 40 public void afterHandshake(ServerHttpRequest request, 41 ServerHttpResponse response, WebSocketHandler wsHandler, 42 Exception ex) { 43 if(list!=null){44 for (ServiceHandshakeInterceptor serviceHandshakeInterceptor : list) {45 serviceHandshakeInterceptor.afterHandshake(request, response, wsHandler, ex); 46 }47 }48 super.afterHandshake(request, response, wsHandler, ex); 49 }50 51 52 53 public List getList() {54 return list;55 }56 57 58 59 public void setList(List list) {60 this.list = list;61 } 62 63 }
1 import java.util.Map; 2 3 import org.springframework.http.server.ServerHttpRequest; 4 import org.springframework.http.server.ServerHttpResponse; 5 import org.springframework.web.socket.WebSocketHandler; 6 7 public interface ServiceHandshakeInterceptor { 8 public void beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, 9 Mapattributes);10 11 public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,12 Exception ex);13 }
websokect处理器
1 import org.springframework.web.socket.CloseStatus; 2 import org.springframework.web.socket.TextMessage; 3 import org.springframework.web.socket.WebSocketSession; 4 5 public interface ServiceTextWebSocketHandler { 6 public void handleTextMessage(WebSocketSession session, TextMessage message) ; 7 public void afterConnectionEstablished(WebSocketSession session); 8 public void handleTransportError(WebSocketSession session, Throwable exception) ; 9 public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) ; 10 11 }
1 import java.util.List; 2 3 import org.springframework.stereotype.Component; 4 import org.springframework.web.socket.CloseStatus; 5 import org.springframework.web.socket.TextMessage; 6 import org.springframework.web.socket.WebSocketSession; 7 import org.springframework.web.socket.handler.TextWebSocketHandler; 8 9 import com.gta.scm.websocket.intercept.ServiceTextWebSocketHandler;10 @Component11 public class WebsocketEndPoint extends TextWebSocketHandler {12 // 所有连接用户的WebSocketSession,键是用户的jsessionID,值是连接的会话对象13 private Listlist;14 /**15 * 该方法在用户前端进行发送消息后进行业务处理的行为16 */17 @Override18 public void handleTextMessage(WebSocketSession session, TextMessage message) {19 20 if (list!=null) {21 for (ServiceTextWebSocketHandler serviceTextWebSocketHandler : list) {22 serviceTextWebSocketHandler.handleTextMessage(session, message);23 }24 }25 }26 27 /**28 * 该方法是连接生效后进行的处理业务行为,每个用户和服务端建立websocket链接时调用29 */30 @Override31 public void afterConnectionEstablished(WebSocketSession session) throws Exception {32 // 与客户端完成连接后调用33 if (list!=null) {34 for (ServiceTextWebSocketHandler serviceTextWebSocketHandler : list) {35 serviceTextWebSocketHandler.afterConnectionEstablished(session);36 }37 }38 }39 40 @Override41 public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {42 // 消息传输出错时调用43 if (list!=null) {44 for (ServiceTextWebSocketHandler serviceTextWebSocketHandler : list) {45 serviceTextWebSocketHandler.handleTransportError(session,exception);46 }47 }48 }49 50 @Override51 public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {52 if (list!=null) {53 for (ServiceTextWebSocketHandler serviceTextWebSocketHandler : list) {54 serviceTextWebSocketHandler.afterConnectionClosed(session,closeStatus);55 }56 }57 }58 59 @Override60 public boolean supportsPartialMessages() {61 return false;62 }63 64 public List getList() {65 return list;66 }67 68 public void setList(List list) {69 this.list = list;70 }71 72 73 74 75 }
1 import java.io.IOException; 2 import java.util.HashMap; 3 import java.util.Iterator; 4 import java.util.List; 5 import java.util.Map; 6 import java.util.Map.Entry; 7 import java.util.Set; 8 9 import javax.servlet.http.Cookie; 10 11 import org.apache.commons.lang.StringUtils; 12 import org.slf4j.Logger; 13 import org.slf4j.LoggerFactory; 14 import org.springframework.http.server.ServerHttpRequest; 15 import org.springframework.http.server.ServerHttpResponse; 16 import org.springframework.http.server.ServletServerHttpRequest; 17 import org.springframework.stereotype.Component; 18 import org.springframework.web.socket.CloseStatus; 19 import org.springframework.web.socket.TextMessage; 20 import org.springframework.web.socket.WebSocketHandler; 21 import org.springframework.web.socket.WebSocketSession; 22 import org.springframework.web.socket.handler.TextWebSocketHandler; 23 24 import com.gta.scm.common.constant.CommonConstant; 25 import com.gta.scm.common.login.UserLoginRsp; 26 import com.gta.scm.websocket.intercept.ServiceHandshakeInterceptor; 27 import com.gta.scm.websocket.intercept.ServiceTextWebSocketHandler; 28 29 @Component 30 public class UserWebsocket implements ServiceTextWebSocketHandler,ServiceHandshakeInterceptor{ 31 Logger logger = LoggerFactory.getLogger(UserWebsocket.class); 32 public static final String JSESSIONID = "JSESSIONID"; 33 private static final Mapusers = new HashMap (); 34 35 /** 36 * 该方法在用户前端进行发送消息后进行业务处理的行为 37 */ 38 @Override 39 public void handleTextMessage(WebSocketSession session, TextMessage message) { 40 logger.debug("handleTextMessage..."); 41 try { 42 sendMsgToUsers(message.getPayload(), session.getId()) ; 43 } catch (Exception e) { 44 e.printStackTrace(); 45 } 46 } 47 48 /** 49 * 该方法是连接生效后进行的处理业务行为,每个用户和服务端建立websocket链接时调用 50 */ 51 @Override 52 public void afterConnectionEstablished(WebSocketSession session) { 53 logger.debug("afterConnectionEstablished..."); 54 Map m = session.getAttributes(); 55 UserLoginRsp user = (UserLoginRsp) m.get(CommonConstant.LOGIN_USER); 56 users.put(user.getUserInfoId().toString(), session); 57 logger.debug("put "+user.getUserAccount()+" in sessions"); 58 } 59 60 private String getJsessionId(WebSocketSession session){ 61 Object jsessionIdObj = session.getAttributes().get(HandshakeInterceptor.JSESSIONID); 62 if (jsessionIdObj != null) { 63 return jsessionIdObj.toString(); 64 } 65 return null; 66 } 67 68 @Override 69 public void handleTransportError(WebSocketSession session, Throwable exception) { 70 logger.debug("handleTransportError..."); 71 if(session.isOpen()){ 72 try { 73 session.close(); 74 } catch (IOException e) { 75 logger.debug("handleTransportError...",e); 76 } 77 } 78 logger.debug("connection closed......"); 79 Map m = session.getAttributes(); 80 UserLoginRsp user = (UserLoginRsp) m.get(CommonConstant.LOGIN_USER); 81 if(user!=null && users.get(user.getUserInfoId().toString())!=null) { 82 users.remove(user.getUserInfoId().toString(), session); 83 } 84 logger.debug("remove user success......"); 85 } 86 // 一个客户端连接断开时关闭 87 @Override 88 public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) { 89 logger.debug("afterConnectionClosed..."); 90 Map m = session.getAttributes(); 91 UserLoginRsp user = (UserLoginRsp) m.get(CommonConstant.LOGIN_USER); 92 if(user!=null && users.get(user.getUserInfoId().toString())!=null) { 93 users.remove(user.getUserInfoId().toString(), session); 94 } 95 96 } 97 /**向所有用户发送 信息 98 * @param message 99 * @throws Exception100 */101 public void sendMsgToAllUsers(String message) throws Exception{102 logger.debug("sendMsgToAllUsers..."); 103 Entry entry = null;104 Iterator > entryIt = users.entrySet().iterator();105 while(entryIt.hasNext()) {106 entry = entryIt.next();107 entry.getValue().sendMessage(new TextMessage(message.getBytes()));108 }109 }110 111 /**向Set jsessionSet 中设置的用户发送信息112 * @param message113 * @param jsessionSet114 * @throws Exception115 */116 public void sendMsgToUsers(String message,Set jsessionSet) throws Exception{117 logger.debug("sendMsgToUsers..."); 118 for(String jessionId : jsessionSet) {119 if (users.containsKey(jessionId)) {120 users.get(jessionId).sendMessage(new TextMessage(message.getBytes()));121 122 // ShiroAuthorizationHelper.clearAuthenticationInfo(users.get(jessionId).getId());123 }124 }125 }126 public void sendMsgToUsers(String message,String jessionId) throws Exception{127 logger.debug("sendMsgToUsers..."); 128 if (users.containsKey(jessionId)) {129 users.get(jessionId).sendMessage(new TextMessage(message.getBytes()));130 }131 }132 /**133 * 当用户连接ServerSocket时执行134 * 通过request获取用户登陆的jsessionId的值,放入到集合attributes中135 */136 @Override// 137 public void beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,138 Map attributes) {139 logger.debug("beforeHandshake...");140 141 if (request instanceof ServletServerHttpRequest) { 142 ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request; 143 Cookie cookies[] = servletRequest.getServletRequest().getCookies();144 String jsessionId = this.getTicket(cookies);145 if (!StringUtils.isNotEmpty(jsessionId)) {146 attributes.put(JSESSIONID, this.getTicket(cookies));147 }148 } 149 150 151 }152 private String getTicket(Cookie cookies[]){153 String jsessionId = null;154 if(cookies != null){155 for(Cookie ck: cookies){156 if(ck.getName().trim().equals(JSESSIONID)){157 jsessionId = ck.getValue();158 break;159 }160 }161 }162 return jsessionId;163 }164 /**165 * 当用户连接完ServerSocket时执行166 */167 @Override168 public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,169 Exception ex) {170 171 logger.debug("afterHandshake...");172 }173 174 public void sendMsgToUsers(String message, List idList) throws Exception{175 logger.debug("sendMsgToUsers..."); 176 for(String jessionId : idList) {177 if (users.containsKey(jessionId)) {178 logger.debug("sendMsgToUsers..."+jessionId); 179 users.get(jessionId).sendMessage(new TextMessage(message.getBytes()));180 181 }182 }183 184 }185 }
4.在具体业务的地方调用
1 //向学生端发通知强制退出到首页2 ListuserList=sysMessageBaseService.getTrainingUser(usp.getTrainingId());3 String[] idStr = (String[])userList.toArray(new String[userList.size()]);4 Set set = new HashSet (Arrays.asList(idStr));5 userWebsocket.sendMsgToUsers("signOut", set);
1 String[] idStr = new String[userAccount.size()]; 2 String[] ownId = new String[userAccount.size()]; 3 for (int i = 0; i < userAccount.size(); i++) { 4 String str = GsonUtils.parseJson(userAccount.get(i)); 5 JSONObject object = JSONObject.fromObject(str); 6 if (object.getString("organizationCode").equals(partyCode))// 自己方人员 7 { 8 ownId[i] = object.getString("userId"); 9 } else {10 idStr[i] = object.getString("userId");11 }12 13 }14 String strMessage = "";15 String myMessage = "1";16 if (stateType == CommonEnum.TradingContractStatus.SEND_TERMINATION.getTypeCode()) // 发送终止17 {18 strMessage="apply;"+contractCode;19 //strMessage = "对方申请终止" + contractCode + "(合同号),请尽快处理!";20 } else if (stateType == CommonEnum.TradingContractStatus.CONFIRMED.getTypeCode())// 终止不同意21 {22 strMessage="disagree;"+contractCode;23 //strMessage = "对方不同意终止" + contractCode + "(合同号),请尽快处理!";24 } else if (stateType == CommonEnum.TradingContractStatus.TERMINATION.getTypeCode())// 终止不同意25 {26 strMessage="agree;"+contractCode;27 //strMessage = "对方同意终止" + contractCode + "(合同号),请尽快处理!";28 } else if (stateType == 5)// 终止取消29 {30 strMessage="cancel;"+contractCode;31 //strMessage = "对方取消终止" + contractCode + "(合同号),请尽快处理!";32 }33 infoAndOut(idStr, strMessage); // 对方操作34 infoAndOut(ownId, myMessage); // 我方刷新数据
5.websoket.js的引入与在具体页面的实现
1 /** 2 * 3 * @param $ 4 */ 5 (function($) { //每页开始直接复制 6 $.websocket = { //外部可以直接访问的对象, 要导入该文件 调用对象$.devfrw.base.demo 7 connect : function(urlPath,initOpt) { //外部可以直接访问的对象的方法, 要导入该文件 调用方法$.devfrw.base.demo.pub 8 setUrl(urlPath); 9 var opt={onopen:function(){},onmessage:function(event){},onclose:function(event){}};10 if(initOpt){11 opt= $.extend(opt, initOpt);12 };13 if (!url) { 14 alert('websocket url 未设置!'); 15 return; 16 } 17 ws =new WebSocket(url); 18 ws.onopen = function () { 19 // console.log('打开链接');20 opt.onopen();21 }; 22 ws.onmessage = function (event) { 23 // console.log('消息接收');24 opt.onmessage(event);25 }; 26 ws.onclose = function (event) { 27 // console.log('关闭链接');28 opt.onclose(event);29 }; 30 },31 setUrl:function(urlPath){32 setUrl(urlPath);33 },34 send:function(message){35 if (ws != null) { 36 ws.send(message); 37 } else { 38 alert('websocket链接不存在!'); 39 } 40 },41 disconnect:function(){42 if (ws != null) { 43 ws.close(); 44 ws = null; 45 } 46 }47 };48 var ws = null; 49 var url = null; 50 function setUrl(urlPath) { 51 if (window.location.protocol == 'http:') { 52 url = 'ws://' + window.location.host + urlPath; 53 } else { 54 url = 'wss://' + window.location.host + urlPath; 55 } 56 } 57 })(jQuery);//直接复制 一定要;号
1 $.websocket.connect('/portal/websocket.do', { 2 onmessage : function(event) { //接收数据 3 if(event.data!=""&&event.data!=null) 4 { 5 if (contains(event.data, "clear")) { 6 $(".pay").each(function() { 7 var id = $(this).parent().attr("id"); 8 var salescode = $(this).parent().attr("salescode"); 9 if (contains(event.data, id + ";")) { 10 $("#send" + id).removeClass("disabled");11 $("#send" + id).addClass("send");12 $("#pay" + id).removeClass("pay");13 $("#pay" + id).addClass("disabled");14 $("#delete" + id).removeClass("disabled");15 $("#delete" + id).attr("onclick","del("+salescode+")");16 }17 });18 }19 if (contains(event.data, "signOut")) {20 layer.msg("轮次结束请返回首页!", {21 time: 5000,22 shade: 0.6,23 success: function (layero, index) {24 var msg = layero.text();25 var i = 5;26 var timer = null;27 var fn = function () {28 layero.find(".layui-layer-content").text(msg + '(倒计时' + i + '秒)');29 if (!i) {30 layer.close(index);31 clearInterval(timer);32 }33 i--;34 };35 timer = setInterval(fn, 1000);36 fn();37 },38 }, function () {39 window.location.href="${basePath}student/main/index";40 });41 42 }43 }44 45 },46 onclose : function(event) { 47 $.websocket.disconnect();48 }49 });