spring cloud实现websocket

1、java源代码

(1)、WebSocketServer类

import java.lang.management.ManagementFactory;
import java.util.ArrayList;
import java.util.List;

import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import com.portal.config.ApplicationContextRegister;
import com.portal.model.MessageVO;

@Component
@ServerEndpoint(value = "/socket/{token}/{bsCode}")
public class WebSocketServer {
	// 解决socket无法注入问题方案1
	// private static ApplicationContext applicationContext;
	// public static void setApplicationContext(ApplicationContext
	// applicationContext) {
	// WebSocketServer.applicationContext = applicationContext;
	// }
	// 解决socket无法注入问题方案2
	ApplicationContext act = ApplicationContextRegister.getApplicationContext();
	public common _common = act.getBean(common.class);

	private final static Logger logger = LoggerFactory.getLogger(WebSocketServer.class);
	public static final String NO = "NO";

	/*
	 * socket连接方法
	 */
	@OnOpen
	public void onOpen(@PathParam(value = "token") String token, @PathParam(value = "bsCode") String bsCode,
			Session session) {
		try {
			SaveUserSession(token, bsCode, session);
		} catch (Exception e) {
			logger.error("onOpen(),msg:" + e.getMessage() + ",---" + e.getStackTrace() + ",---" + e.getCause());
		}
	}

	/**
	 * 连接关闭调用的方法
	 */
	@OnClose
	public void onClose(@PathParam(value = "token") String token, @PathParam(value = "bsCode") String type,
			Session session) {
		try {
			String key = getUserKey(token, type);

			// 心跳检查是否在遍历对象
			if (!common.IsHeartbeatCheck) {
				if (!key.equals(NO)) {
					System.out.println("用户关闭,key:" + key);
					common.sl.remove(key);
					//common.curOnlineCount--;
				}
				//logger.info("移除连接,key:" + key);

				// 方法2
//				if (!key.equals(NO)) {
//					System.out.println("用户关闭,token:" + token);
//					List<Session> curUserList = new ArrayList<>();
//					if (common.sl.containsKey(key)) {
//						curUserList = (List<Session>) common.sl.get(key);
//						if (curUserList != null && curUserList.size() > 0) {
//							curUserList.remove(session);
//						}
//						common.sl.remove(key);
//						common.sl.put(key, curUserList);
//					}
//				}
			}
		} catch (Exception e) {
			logger.error("onClose(),msg:" + e.getMessage() + "," + e.getStackTrace());
		}
	}

	/**
	 * 收到客户端消息后调用的方法
	 *
	 * @param message
	 *            客户端发送过来的消息
	 */
	@OnMessage
	public void onMessage(String message, Session session) {
		MessageVO vo = new MessageVO();
		try {
			logger.info("message:" + message + ",msgType:");
			vo.setData("服务器接收消息成功");
			_common.sendMessage(vo, session);
		} catch (Exception e) {
			System.out.println("onMessage(),msg:" + e.getMessage() + "," + e.getStackTrace());
		}

	}

	// 拼接用户key
	public String getUserKey(String token, String bsCode) {
		String key = "";
		String userLoginName = _common.getUserLoginNameByToken(token);
		if (userLoginName.length() > 0) {
			key = userLoginName + "|" + bsCode; // 账号加业务类型作为key
		} else {
			key = NO;
		}
		return key;
	}

	/*
	 * desc:保存用户连接对象
	 */
	public void SaveUserSession(String token, String bsCode, Session session) {
		String key = getUserKey(token, bsCode);
		MessageVO vo = new MessageVO();
		List<Session> sArray = new ArrayList<>();
		if (!key.equals(NO)) {
			 logger.info("用户:token:" + token + ",连接成功");
			 //logger.info("用户key:" + key);
			 //若存在此连接对象,则移除再添加
			 if(common.sl.containsKey(key)) {
			 common.sl.remove(key);
			 }
			 common.sl.put(key, session);
			 //common.curOnlineCount++;
			 //logger.info("当前已连接总数:"+common.curOnlineCount);
			 //logger.info("进程ID:"+ManagementFactory.getRuntimeMXBean().getName());
			 //logger.info("线程ID:"+Thread.currentThread().getId()+",name:"+Thread.currentThread().getName());
			
			 // 方案2
//			if (common.sl.containsKey(key)) {
//				sArray = (List<Session>) common.sl.get(key);
//				sArray.add(session);
//				common.sl.remove(key);
//			} else {
//				sArray.add(session);
//			}
//			common.sl.put(key, sArray);
			 
			vo.setStatus(1);
			vo.setData("连接成功,您好:" + key);
		} else {
			vo.setStatus(1);
			vo.setData("无效用户,您好:" + key);
		}
		_common.sendMessage(vo, session);
	}
}

(2)、common类

import java.text.MessageFormat;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.websocket.Session;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import com.alibaba.fastjson.JSON;
import com.google.inject.spi.Message;
import com.portal.model.MessageVO;


@RestController
public class common {
	private final static Logger logger = LoggerFactory.getLogger(common.class);

	//public static Map<String,Session>  sessionlist=new HashMap<>();
	
	//保存建立连接用户的连接对象
	public static Map<String,Object>  sl=new HashMap<>();
	
	//当前连接数
	//public static int curOnlineCount;
	
	//判断是否在执行心跳检查服务
	public static boolean IsHeartbeatCheck=false;
	@Autowired
	public RestTemplate _RestTemplate;
	
	
	private String getLoginNameAddress="***";
	/*
	  * 回复客户端消息
	  * */
	 public void sendMessage(MessageVO vo,Session session)  {
		try {
			 String jsonObjStr=JSON.toJSONString(vo);
			 session.getBasicRemote().sendText(jsonObjStr);
		} catch (Exception e) {
			logger.error("回复客户端异常:"+e.getMessage()+","+e.getStackTrace());
		}
	        
	 }

	 
	 /*
	  * desc: http get请求方法
	  * params:url 请求地址
	  * **/
	 public String doGet(String resquestUrl) {
		String result="";
		try {
			  result =_RestTemplate.getForObject(resquestUrl,String.class);
			  //logger.info("请求结果:"+result);
		} catch (Exception e) {
			logger.error("doGet请求异常:"+e.getMessage()+","+e.getStackTrace());
		}
		return result;	
	 }
	 /*
	  * desc:获取用户token获取用户登录名
	  * params:token
	  * */
	 public  String getUserLoginNameByToken(String token) {
		 String result="";
		 result = doGet(MessageFormat.format(getLoginNameAddress, token)).replaceAll("\"","") ;
		 return result;
	 }
	 
	 
}

以下是配置类文件
(3)、CorsConfigurer(设置全局跨域)

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

@Configuration
public class CorsConfigurer extends WebMvcConfigurerAdapter{
	
	public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*") 
                .allowedMethods("GET", "HEAD", "POST","PUT", "DELETE", "OPTIONS")
                .allowCredentials(false).maxAge(3600);
    }

}

2、前端实现代码

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title></title>
</head>
<body>
    <input id="text" type="text" />
    <button onclick="send()">Send</button>
    <button onclick="closeWebSocket()">Close</button>
    <br />
    <div id="message">
    </div>
    <script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
    <script>

        var token = "220627AF-52DD-4D6C-99E8-C6CD7B50E2DD";
        if (getQueryString("token") != null && getQueryString("token").length > 0) {
            token = getQueryString("token");
        }
        var bsCode = "TASK1";
        if (getQueryString("bsCode") != null && getQueryString("bsCode").length > 0) {
            bsCode = getQueryString("bsCode");
        }
        var websocket = null;
        $(function () {
            connectWebSocket();
        })
        //建立WebSocket连接
        function connectWebSocket() {
            console.log("开始...");
            //建立webSocket连接
            websocket = new WebSocket("ws://localhost:3005/socket/" + token + "/" + bsCode);
            //打开webSokcet连接时,回调该函数
            websocket.onopen = function () {
                console.log("用户:" + token);
                console.log("onpen");
            }
            //关闭webSocket连接时,回调该函数
            websocket.onclose = function () {
                //关闭连接
                console.log("onclose");
            }
            //接收信息
            websocket.onmessage = function (msg) {
                //console.log(msg.data);
                var obj = JSON.parse(msg.data);
                console.log(obj);
                console.log("消息正文:");
                //console.log(JSON.parse(obj.data));
                $("#message").append("<div><span style='color:red;'>推送消息正文:</span><br>" + msg.data + "<div>");
            }
        }
        //发送消息
        function send() {
            var postValue = {};
            postValue.id = token;
            postValue.message = $("#text").val();
            postValue.msgType = "测试发送其它字段添加字段";
            websocket.send(JSON.stringify(postValue));
        }
        //关闭连接
        function closeWebSocket() {
            if (websocket != null) {
                websocket.close();
            }
        }
        function getQueryString(name) {
            var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
            var r = window.location.search.substr(1).match(reg);
            if (r != null) return unescape(r[2]); return null;
        }
        //window.open('http://www.imooc.com','_blank')//')
    </script>
</body>
</html>

以下为个人功能添加代码,与websocket无关

(4) taskController(推送消息方法,非核心方法,个人使用)


import java.util.ArrayList;
import java.util.List;

import javax.websocket.Session;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.portal.model.MessageVO;
import com.portal.model.ReceiveDTO;

@RestController
@RequestMapping("socket")
public class taskController {
	private final static Logger logger = LoggerFactory.getLogger(taskController.class);
	
	@Autowired
	public common _common;
	@PostMapping(value = "/pushNotification")
	public MessageVO pushNotification(@RequestBody ReceiveDTO receiveDto ) {
		String key="";
		String userLoginName="";
		String bsCode="";
		String jsonData="";
		Session ses=null;
		MessageVO vo=new MessageVO();
		MessageVO res=new MessageVO();
		//List<Session> sArray=new ArrayList<>();
		try {
			if(receiveDto!=null) {
				res.setData("消息接收成功");
				res.setStatus(1);
				jsonData=receiveDto.getData();
				List<String> userList=receiveDto.getUserList();
				List<String> bsCodeList=receiveDto.getBsCodeList();
				if(userList!=null&&userList.size()>0&&bsCodeList!=null&bsCodeList.size()>0) {
					for (int i = 0,len=userList.size(); i < len; i++) {
						userLoginName=userList.get(i);
						for (int j = 0,len2=bsCodeList.size(); j <len2; j++) {
							bsCode=bsCodeList.get(j);
							key=userLoginName+"|"+bsCode;
							ses=(Session)common.sl.get(key);
							vo.setStatus(1);
							vo.setData(jsonData);
							if(ses!=null&&ses.isOpen()) {
								_common.sendMessage(vo, ses);
								//logger.info("用户key:"+key+",jsonData:"+jsonData+",消息推送成功");
								logger.info("用户key:"+key+",消息推送成功");
							}else {
								logger.info("消息推送失败,用户key:"+key+",已关闭连接");
								res.setData("消息推送失败,用户未连接");
								res.setStatus(-1);
							}
							//方案2
//							sArray=(List<Session>)common.sl.get(key);
//							if(sArray!=null&&sArray.size()>0) {
//								vo.setStatus(1);
//								vo.setData(jsonData);
//								sendUserMsg(sArray,vo,key,jsonData);
//							}
							
						}
					}
				}else {
					res.setData("userList或bsCodeList参数为空");
					res.setStatus(0);
				}
			}else {
				res.setData("参数为空");
				res.setStatus(0);
			}
		} catch (Exception e) {
			logger.error("pushNotification(),错误信息:"+e.getMessage()+",StackTrace:"+e.getStackTrace());
		}
		return res;
	} 
	
	
	//推送消息
	public  void sendUserMsgByObj(Session ses,MessageVO vo,String key,String jsonData) {
		if(ses!=null&&ses.isOpen()) {
			_common.sendMessage(vo, ses);
			logger.info("用户key:"+key+",jsonData:"+jsonData+",消息推送成功");
		}else {
			logger.info("用户key:"+key+",已关闭连接");
		}
	}
	//推送消息
	public  void sendUserMsgByArray(List<Session> sArray,MessageVO vo,String key,String jsonData) {
		Session ses=null;
		for (int i = 0,len=sArray.size(); i < len; i++) {
			ses=sArray.get(i);
			if(ses.isOpen()) {
				_common.sendMessage(vo, ses);
				logger.info("用户key:"+key+",jsonData:"+jsonData+",消息推送成功");
			}else {
				logger.info("用户key:"+key+",已关闭连接");
			}
			
		}
	}

(4)、ReceiveDTO(消息推送接收信息,个人使用)

import java.util.List;

public class ReceiveDTO {
	public List<String> userList;
	public List<String> bsCodeList;
	public String data;
	
	public List<String> getUserList() {
		return userList;
	}
	public void setUserList(List<String> userList) {
		this.userList = userList;
	}
	public List<String> getBsCodeList() {
		return bsCodeList;
	}
	public void setBsCodeList(List<String> bsCodeList) {
		this.bsCodeList = bsCodeList;
	}
	public String getData() {
		return data;
	}
	public void setData(String data) {
		this.data = data;
	}
	
}

3、特殊说明

spring cloud中使用@ServerEndpoint注解后,是无法使用@Autowired注解注入其它类的,可使用以下解决方法2注入其它公共类;
在这里插入图片描述
以上方法如有疑问,可在下方回复评论

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大海中一粒沙子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值