最近在springboot项目中用到了websocket实现待办事项的实时提醒,在集成websocket中踩了好几个坑,还好通过我的聪明才智解决了,特此记录一下。
1.引入依赖,在pom文件中加依赖。由于springboot提供了websocket的starter
所以在pom中直接加依赖
<!--websocket-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
2.配置websocket。因为在之后的服务器消息类中要用到用户信息,所有要提前加入用户信息。其中shiroKit是本项目中shrio的一个工具类,获取shiro用户信息的。看代码注释应该已经能够理解了吧。
/**
* (websocket配置)
* @author tlj
* @date 2018年9月15日 上午10:27:58
*/
@Configuration
public class SpringWebSocketConfig extends ServerEndpointConfig.Configurator{
/**
* 修改握手,就是在握手协议建立之前修改其中携带的内容
* @param sec
* @param request
* @param response
*/
@Override
public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
sec.getUserProperties().put("user", ShiroKit.getUser());
//sec.getUserProperties().put("name", "wb");
super.modifyHandshake(sec, request, response);
}
@Bean
public ServerEndpointExporter serverEndpointExporter() {
//这个对象说一下,貌似只有服务器是tomcat的时候才需要配置,具体我没有研究
return new ServerEndpointExporter();
}
}
3.服务器端消息处理类。
/**
* @Author: tanleijin
* @description ()
* @Date:2018/9/14 17:45
*/
@ServerEndpoint(value = "/userMessageSocket",configurator = SpringWebSocketConfig.class)
@Component
public class UserMessageSocket {
private static ApplicationContext applicationContext;
private static int onlineCount = 0;
private static CopyOnWriteArraySet<UserMessageSocket> webSocketSet = new CopyOnWriteArraySet<>();
private Session session;
private UserServiceImpl userService;
//todo 这里需要一个变量来接收shiro中登录的人信息
private ShiroUser shiroUser ;
@OnOpen
public void onOpen (Session session){
this.session = session;
//注入userService
this.userService = applicationContext.getBean(UserServiceImpl.class);
//设置用户
this.shiroUser = (ShiroUser) session.getUserProperties().get("user");
webSocketSet.add(this);
addOnlineCount();
System.out.println("有新链接加入!当前在线人数为" + getOnlineCount());
}
@OnClose
public void onClose (){
webSocketSet.remove(this);
subOnlineCount();
System.out.println("有一链接关闭!当前在线人数为" + getOnlineCount());
}
@OnMessage
public void onMessage (String message, Session session) throws IOException {
//todo 1.制造给自己的初始化消息
String msg = userService.createUserMessage(this.shiroUser);
//2.发送给自己
sendMessage (msg);
}
public void sendMessage (String message) throws IOException {
//String m = "1,2,3,4,5";
this.session.getBasicRemote().sendText(message);
}
/**
* 群发自定义消息
*/
public void sendInfo() throws IOException {
for (UserMessageSocket item : webSocketSet) {
try {
String msg = userService.createUserMessage(item.shiroUser);
//2.发送消息
item.sendMessage(msg);
} catch (IOException e) {
continue;
}
}
}
public static synchronized int getOnlineCount (){
return UserMessageSocket.onlineCount;
}
public static synchronized void addOnlineCount (){
UserMessageSocket.onlineCount++;
}
public static synchronized void subOnlineCount (){
UserMessageSocket.onlineCount--;
}
public static void setApplicationContext(ApplicationContext applicationContext) {
UserMessageSocket.applicationContext = applicationContext;
}
}
4.前段js
var websocket = null;
$(function(){
//获取当前网址,如: http://localhost:8083/myproj/view/my.jsp
var curWwwPath=window.document.location.href;
var sos=curWwwPath.indexOf("//");
//获取主机地址,如: localhost:8083
var localhostPaht=curWwwPath.substring(sos+2);
//判断当前浏览器是否支持WebSocket
if ('WebSocket' in window) {
websocket = new WebSocket("ws://"+localhostPaht+"userMessageSocket");
}
else {
alert('Not support websocket')
}
//连接发生错误的回调方法
websocket.onerror = function () {
setMessageInnerHTML("error");
};
//连接成功建立的回调方法
websocket.onopen = function (event) {
setMessageInnerHTML("open");
}
//接收到消息的回调方法
websocket.onmessage = function (event) {
onmessage(event);
}
//连接关闭的回调方法
websocket.onclose = function () {
setMessageInnerHTML("close");
}
//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function () {
websocket.close();
}
//发送消息
setTimeout("websocket.send('')",500);
});
//将消息显示在网页上
function setMessageInnerHTML(innerHTML) {
console.log(innerHTML);
}
//手动关闭连接
function closeWebSocket() {
websocket.close();
}
//接收消息的回调方法
function onmessage(event) {
//console.log(event.data);
var data=event.data.split(',');
$("#done").empty();
$("#done").text("你有"+data[0]+"条代办");
}
5.特别注意的是在服务器端消息处理类中直接注入会失败,所以需要通过ApplicationContext对象去获取你想用的类。需要在springboot的启动类中配置:
@SpringBootApplication
public class MisApplication {
private final static Logger logger = LoggerFactory.getLogger(MisApplication.class);
public static void main(String[] args) {
SpringApplication springApplication = new SpringApplication(MisApplication.class);
ConfigurableApplicationContext configurableApplicationContext = springApplication.run(args);
UserMessageSocket.setApplicationContext(configurableApplicationContext);//解决WebSocket不能注入的问题
logger.info("MisApplication is success!");
}
}
最后总结:
以上只是个人思路,应该还有很多解决的方法。说的再多,不如copy动手试一试,保准你一波成功,爽到爆。