配置路径,在项目加载的时候就开始运行:
import javax.annotation.Resource; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; import org.springframework.web.socket.WebSocketHandler; import org.springframework.web.socket.config.annotation.EnableWebSocket; import org.springframework.web.socket.config.annotation.WebSocketConfigurer; import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; import com.hncy.optima.websocket.handler.MessageHandshakeInterceptor; import com.hncy.optima.websocket.handler.MessageWebSocketHandler; @Configuration @EnableWebMvc @EnableWebSocket public class WebConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer{ @Resource private MessageWebSocketHandler messageWebSocketHandler; @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry.addHandler(messageWebSocketHandler,"/message.msg").addInterceptors(new MessageHandshakeInterceptor()); registry.addHandler(messageWebSocketHandler,"/sockjs/message.msg").addInterceptors(new MessageHandshakeInterceptor()) .withSockJS(); } @Bean public WebSocketHandler messageWebSocketHandler(){ return new MessageWebSocketHandler(); } }
***************************************************从前台开始************************************
//------------------------------------------websocket---------------------------------------------
var websocket; if ('WebSocket' in window) { //websocket = new WebSocket("ws://${socketPath}/message.msg"); websocket = new WebSocket("ws://127.0.0.1:6060/message.msg"); } else if ('MozWebSocket' in window) { //websocket = new MozWebSocket("ws://${socketPath}/message.msg"); websocket = new MozWebSocket("ws://127.0.0.1:6060/message.msg"); } else { //websocket = new SockJS("ws://${socketPath}/sockjs/message.msg"); websocket = new SockJS("ws://127.0.0.1:6060/sockjs/message.msg"); } websocket.onopen = function (evnt) { alert("onopen"); }; websocket.onmessage = function (evnt) { alert(evnt.data); }; websocket.onerror = function (evnt) { //alert("onerror:"+evnt); //for(var name in evnt){ // alert(name + " : " +evnt[name]); //} }; websocket.onclose = function (evnt) { };
jSP页面
建立连接时websocket.onopen响应,当后台向前台发送信息时,websocket.onmessage接受信息,evnt只能是String类型,但是我们可以用JSON来传递多个参数。
********************************************************获取用户**************************
package com.hncy.optima.websocket.handler; import java.util.Map; import javax.servlet.http.HttpSession; 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 org.springframework.web.socket.server.HandshakeInterceptor; import com.optima.bedrock.utils.LoginInstance; import com.optima.bedrock.utils.Tools; public class MessageHandshakeInterceptor implements HandshakeInterceptor{ @Override public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception { String loginName = LoginInstance.getUser().getLoginName(); if(Tools.transNull(loginName).equals("") == false){ attributes.put("loginName", loginName); }else{ return false; } //在这里如果不需要定向发送,可以设置loginName为一个定值,返回true return true; } /* (non-Javadoc) * @see org.springframework.web.socket.server.HandshakeInterceptor#afterHandshake(org.springframework.http.server.ServerHttpRequest, org.springframework.http.server.ServerHttpResponse, org.springframework.web.socket.WebSocketHandler, java.lang.Exception) */ @Override public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) { // TODO Auto-generated method stub } }
获取用户信息为后面发送消息通信做准备
******************************响应,发送消息的方法*****************************
package com.hncy.optima.websocket.handler; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.web.socket.CloseStatus; import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.WebSocketSession; import org.springframework.web.socket.handler.TextWebSocketHandler; import com.hncy.optima.websocket.service.MessageWebSocketService; @Component public class MessageWebSocketHandler extends TextWebSocketHandler{ protected final static Log log = LogFactory.getLog(MessageWebSocketHandler.class); private static final Map<String, WebSocketSession> userSocketSessions; @Autowired private MessageWebSocketService messageWebSocketService; static{ userSocketSessions = new HashMap<String, WebSocketSession>(); } public List<String> getOnlineUsers(){ return new ArrayList<String>(userSocketSessions.keySet()); } /** * 当用户的链接成功后,获取该用户的消息数,并推送给该用户 */ @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { super.afterConnectionEstablished(session); String loginName = (String)session.getAttributes().get("loginName"); if(userSocketSessions.get(loginName) == null){ userSocketSessions.put(loginName, session); } //获取用户的未读信息 int count = this.messageWebSocketService.getUnReadMessagesCount(loginName); session.sendMessage(new TextMessage("连接成功")); } /** * 当关闭链接后,将用户从用户池中移除 */ @Override public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception { // TODO Auto-generated method stub super.afterConnectionClosed(session, status); Iterator<Entry<String, WebSocketSession>> it = userSocketSessions.entrySet().iterator(); while(it.hasNext()){ Entry<String,WebSocketSession> entry = it.next(); if(entry.getValue().getId().equals(session.getId())){ userSocketSessions.remove(entry.getKey()); break; } } System.out.println("关闭连接"); } /** * 消息处理,在客户端通过WebSocket API发送的消息会进过这里,然后进行相应的处理 */ @Override protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { // TODO Auto-generated method stub super.handleTextMessage(session, message); //如果客户端发送的消息为空,那么直接返回 if(message.getPayloadLength() == 0) return; } public void sendMessageToUser(String loginName,TextMessage message) throws IOException{ WebSocketSession session = userSocketSessions.get(loginName); if(session != null && session.isOpen()){ session.sendMessage(message); } } /** * 消息传输错误处理 */ @Override public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception { if(session.isOpen()){ session.close(); } Iterator<Entry<String,WebSocketSession>> it = userSocketSessions.entrySet().iterator(); while(it.hasNext()){ Entry<String,WebSocketSession> entry = it.next(); if(entry.getValue().getId().equals(session.getId())){ userSocketSessions.remove(entry.getKey()); break; } } } /** * 向所有在线用户发送消息 * @param message * @throws IOException */ public void sendMessageToAllOnlinUsers(final TextMessage message) throws IOException{ Iterator<Entry<String,WebSocketSession>> it = userSocketSessions.entrySet().iterator(); while(it.hasNext()){ final Entry<String,WebSocketSession> entry = it.next(); //采用多线程的方式发送消息 if(entry.getValue().isOpen()){ new Thread(new Runnable() { @Override public void run() { try{ if(entry.getValue().isOpen()){ entry.getValue().sendMessage(message); } }catch(IOException e){ log.error("多线程发送消息给用户错误,用户:" + entry.getKey(), e); } } }).start(); } } System.out.println("发送成功"); } /** * 将消息发送给指定的用户集合 * @param loginNames * @param message * @throws IOException */ public void sendMessageToUsers(List<String> loginNames,final TextMessage message) throws IOException{ for(String loginName : loginNames){ final WebSocketSession session = userSocketSessions.get(loginName); if(session != null && session.isOpen()){ new Thread(new Runnable() { @Override public void run() { try{ if(session.isOpen()){ session.sendMessage(message); } }catch(IOException e){ log.error("多线程发送消息给用户错误,用户:" + session.getAttributes().get("loginName"), e); } } }).start(); } } } }
我们可以修改其中的内容
**********************************************
package com.hncy.optima.websocket.service; public interface MessageWebSocketService { int getUnReadMessagesCount(String loginName); } package com.hncy.optima.websocket.service.impl; import org.springframework.stereotype.Component; import com.hncy.optima.websocket.service.MessageWebSocketService; @Component public class MessageWebSocketManagerImpl implements MessageWebSocketService{ /* (non-Javadoc) * @see com.optima.websocket.service.MessageWebSocketService#getUnReadMessagesCount(java.lang.String) */ @Override public int getUnReadMessagesCount(String loginName) { return 0; } }
*********************************调用发送信息*******************************
try { messageWebSocketHandler.sendMessageToAllOnlinUsers(new TextMessage("hello")); } catch (IOException e) { e.printStackTrace(); }
*********************************注意事项****************************
之前我用的是spring4.12但是报错了,后来我全部换成了4.16后就不在报错,为了保险起见,建议使用全家福,web,webSocket是必须要的。
在前台jsp页面,我们可以用http://<%= request.getServerName() %>:<%=request.getServerPort()%>来获取到地址与端口号,我之上写的地址一定要和调用地址相同,不然是不能达成连接的,不过最好的方法就是使用http://<%= request.getServerName() %>:<%=request.getServerPort()%>,就不会再担心这些问题了。