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注入其它公共类;
以上方法如有疑问,可在下方回复评论