本文共 7822 字,大约阅读时间需要 26 分钟。
org.springframework.boot spring-boot-starter-websocket org.springframework.boot spring-boot-starter-thymeleaf
package com.company.system.config;import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;import org.springframework.web.servlet.config.annotation.InterceptorRegistry;import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;import org.springframework.context.annotation.Configuration;@Configurationpublic class StaticResourceLoadingConfig implements WebMvcConfigurer{ @Override public void addResourceHandlers(ResourceHandlerRegistry registry){ registry.addResourceHandler("/**") .addResourceLocations("classpath:/resources/") .addResourceLocations("classpath:/static/") .addResourceLocations("classpath:/css"); } }
package com.company.system.config;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.web.socket.server.standard.ServerEndpointExporter;/** * 开启WebSocket支持 */@Configuration public class WebSocketConfig { @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); } }
package com.company.system.config;import java.io.IOException;import java.util.concurrent.ConcurrentHashMap;import javax.websocket.OnClose;import javax.websocket.OnError;import javax.websocket.OnMessage;import javax.websocket.OnOpen;import javax.websocket.Session;import javax.websocket.server.PathParam;import javax.websocket.server.ServerEndpoint;import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.JSONObject;import org.apache.commons.lang.StringUtils;import org.springframework.stereotype.Component;import org.slf4j.Logger;import org.slf4j.LoggerFactory;@ServerEndpoint("/imserver/{userId}")@Componentpublic class WebSocketServerConfig { static Logger log=LoggerFactory.getLogger(WebSocketServerConfig.class); //当前在线连接数 private static int onlineCount = 0; //concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象 private static ConcurrentHashMapwebSocketMap = new ConcurrentHashMap<>(); //与某个客户端的连接会话,需要通过它来给客户端发送数据 private Session session; //接收userId private String userId=""; /** * 连接建立成功调用的方法*/ @OnOpen public void onOpen(Session session,@PathParam("userId") String userId) { this.session = session; this.userId=userId; if(webSocketMap.containsKey(userId)){ webSocketMap.remove(userId); webSocketMap.put(userId,this); //加入set中 }else{ webSocketMap.put(userId,this); //加入set中 addOnlineCount(); //在线数加1 } log.info("用户连接:"+userId+",当前在线人数为:" + getOnlineCount()); try { sendMessage("我在线上"); } catch (IOException e) { log.error("用户:"+userId+",网络异常!!!!!!"); } } /** * 连接关闭调用的方法 */ @OnClose public void onClose() { if(webSocketMap.containsKey(userId)){ webSocketMap.remove(userId); //从set中删除 subOnlineCount(); } log.info("用户退出:"+userId+",当前在线人数为:" + getOnlineCount()); } /** * 收到客户端消息后调用的方法 * @param message 发送的信息 * @param session 会话 */ @OnMessage public void onMessage(String message, Session session) { log.info("用户消息:"+userId+",报文:"+message); //可以群发消息 //消息保存到数据库、redis if(StringUtils.isNotBlank(message)){ try { //解析发送的报文 JSONObject jsonObject = JSON.parseObject(message); //追加发送人(防止串改) jsonObject.put("fromUserId",this.userId); String toUserId=jsonObject.getString("toUserId"); //传送给对应toUserId用户的websocket if(StringUtils.isNotBlank(toUserId)&&webSocketMap.containsKey(toUserId)){ webSocketMap.get(toUserId).sendMessage(jsonObject.toJSONString()); }else{ log.error("请求的userId:"+toUserId+"不在该服务器上"); //否则不在这个服务器上,发送到mysql或者redis } }catch (Exception e){ e.printStackTrace(); } } } /** * 数据传输错误 * @param session 会话 * @param error 错误 */ @OnError public void onError(Session session, Throwable error) { log.error("用户错误:"+this.userId+",原因:"+error.getMessage()); error.printStackTrace(); } /** * 服务端向客户端推送消息 * @param message 推送的消息 * @throws IOException 抛出异常 */ public void sendMessage(String message) throws IOException { this.session.getBasicRemote().sendText(message); } /** * 自定义发送消息 * @param message 发送的消息 * @param userId 用户ID * @throws IOException 抛出异常 */ public static void sendInfo(String message,@PathParam("userId") String userId) throws IOException { log.info("发送消息到:"+userId+",报文:"+message); if(StringUtils.isNotBlank(userId)&&webSocketMap.containsKey(userId)){ webSocketMap.get(userId).sendMessage(message); }else{ log.error("用户"+userId+",不在线!"); } } public static synchronized int getOnlineCount() { return onlineCount; } public static synchronized void addOnlineCount() { WebSocketServerConfig.onlineCount++; } public static synchronized void subOnlineCount() { WebSocketServerConfig.onlineCount--; }}
package com.company.system.controller;import java.util.Map;import java.util.HashMap;import com.company.system.config.WebSocketServerConfig;import org.springframework.http.ResponseEntity;import org.springframework.web.bind.annotation.CrossOrigin;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.PathVariable;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.RequestBody;import org.springframework.web.bind.annotation.ResponseBody;import org.springframework.web.bind.annotation.RestController;import org.springframework.stereotype.Controller;import org.springframework.web.servlet.ModelAndView;import java.io.IOException;@CrossOrigin(origins="*", maxAge=3600)@RequestMapping("/websocket")@Controllerpublic class MsgController { /** * web消息发送测试 * @return */ @GetMapping("/instance/message") public String page(){ return "websocket/chatpage"; } /** * 回调接口,向客户端推送实时消息 * @param params 消息数据结构 * @param toUserId 发动到用户ID * @return * @throws IOException 异常 */ @RequestMapping(value="/push/{toUserId}", method=RequestMethod.POST) @ResponseBody public Map pushToWeb(@RequestBody Map params,@PathVariable String toUserId) throws IOException { String message = params.get("message").toString(); WebSocketServerConfig.sendInfo(message,toUserId); Map returnMap = new HashMap(); returnMap.put("code", 200); returnMap.put("msg", "成功发送消息"); return returnMap; }}
websocket即时消息 当前用户
好友
消息记录
操作
消息记录
浏览器打开两个页面,分别访问:http://localhost:10106/websocket/instance/message
通过接口给小红
发送消息,在用户小红
对话框历史中可以看到该条记录:测试消息
.
Error: Request path contains unescaped characters
, 将URL中的中文编码: 编码后的URL:http://localhost:10106/websocket/push/%E5%B0%8F%E8%8A%B1
【参考文献】
[1] [2] [3] [4] [5] [6] [7]转载地址:http://npht.baihongyu.com/