spring-boot整合websocket消息推送

引入spring websocket 和springboot 启动 pom.xml:

        <dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-aop</artifactId>
		</dependency>

		<dependency>
			<groupId>com.huasuhui</groupId>
			<artifactId>huasuhui-spring-boot-starter-dubbo</artifactId>
			<version>1.0.0</version>
		</dependency>
		
		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>
        
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>

加入websocket 配置文件:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

/**
 * WebScoket配置处理器
 */
@Configuration
public class WebSocketConfig {
	
	 /**
     * ServerEndpointExporter 作用
     * 这个Bean会自动注册使用@ServerEndpoint注解声明的websocket endpoint
     * @return
     */
	@Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }

}

编写websocket 服务 WebSocketServer :

package com.huash.websocket.service;

import java.io.IOException;
import java.util.Date;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

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 org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSON;
import com.huash.websocket.listener.Message;

@ServerEndpoint("/webSocket/{username}")
@Component
public class WebSocketServer {
	
	//静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
    private static AtomicInteger onlineNum = new AtomicInteger();

    //concurrent包的线程安全Set,用来存放每个客户端对应的WebSocketServer对象。
    private static ConcurrentHashMap<String, Session> sessionPools = new ConcurrentHashMap<>();

    //发送消息
    public void sendMessage(Session session, String message) throws IOException {
        if(session != null){
            synchronized (session) {
            	if (session.isOpen()) {
            	    //System.out.println("发送数据:" + message);
                    session.getBasicRemote().sendText(message);
				}
            }
        }
    }
    //给指定用户发送信息
    public void sendInfo(String userName, String message){
    	
    	if (sessionPools.size() > 0 && !StringUtils.isBlank(message)){
    		Session session = sessionPools.get(userName);
    		if (session != null && session.isOpen()){
    			try {
    		           sendMessage(session, message);
    		        }catch (Exception e){
    		        	e.printStackTrace();
    		        }
			}
		}
    }
    // 群发消息
    public void broadcast(String message){
    	if (sessionPools.size() > 0 && !StringUtils.isBlank(message)) {
    		for (Session session: sessionPools.values()) {
                try {
                	if (session != null && session.isOpen()){
                		sendMessage(session,message);
                		//session.getBasicRemote().sendText(message);
					}
                	else {
                		session.close();
					}
                } catch(Exception e){
                	e.printStackTrace();
                	System.out.println("发生错误....");
                    continue;
                }
            }
		}
    }

    //建立连接成功调用
    @OnOpen
    public void onOpen(Session session, @PathParam(value = "username") String userName){
    	// 将老的session关闭
		try {
			Session session2 = sessionPools.get(userName);
			if (session2 != null) {
				session2.close();
	    	}
		} catch (IOException e) {
		}
    	// 用户加入连接
        sessionPools.put(userName, session);
        addOnlineCount();
    }

    //关闭连接时调用
    @OnClose
    public void onClose(@PathParam(value = "username") String userName){
    	// 将老的seesion关闭
    	try {
    		Session session2 = sessionPools.get(userName);
			if (session2 != null) {
				session2.close();
	    	}
		} catch (Exception e) {
		}
    	// 去掉用户连接
        sessionPools.remove(userName);
        subOnlineCount();
    }
    
    //收到客户端信息后,根据接收人的username把消息推下去或者群发
    // to=-1群发消息
    @OnMessage
    public void onMessage(String message) throws IOException{
        //System.out.println("server get" + message);
        Message msg=JSON.parseObject(message, Message.class);
		msg.setDate(new Date());
		if (msg.getTo().equals("-1")) {
			broadcast(JSON.toJSONString(msg,true));
		} else {
			sendInfo(msg.getTo(), JSON.toJSONString(msg,true));
		}
    }

    //错误时调用
    @OnError
    public void onError(Session session, Throwable throwable){
        //System.out.println("发生错误");
        //throwable.printStackTrace();
    }

    public static void addOnlineCount(){
        onlineNum.incrementAndGet();
    }

    public static void subOnlineCount() {
        onlineNum.decrementAndGet();
    }
    
    public static AtomicInteger getOnlineNumber() {
        return onlineNum;
    }
    
    public static ConcurrentHashMap<String, Session> getSessionPools() {
        return sessionPools;
    }
}

编写一个context类 ,方便后面服务端主动向前端推送消息:

import java.util.HashMap;



import java.util.Map;

import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;



@Component
public class HuashContext implements ApplicationContextAware{
	//系统事件///
	public static final String USER_JOIN_EVENT = "userJoin" ;							// 用户加入事件
	
	public static final String TEST = "test" ;						
	
	private static int WebIMPort = 5001 ;
	private static boolean imServerRunning = false ;			// IM服务状态
	
	private static ApplicationContext applicationContext ;

	public static Map<String , Boolean> model = new HashMap<String,Boolean>();
	

	public static int getWebIMPort() {
		return WebIMPort;
	}

	public static void setWebIMPort(int webIMPort) {
		WebIMPort = webIMPort;
	}
	
	public void setApplicationContext(ApplicationContext context){
		applicationContext = context ;
	}

	public static ApplicationContext getContext(){
		return applicationContext ;
	}
	
	public static void setIMServerStatus(boolean running){
		imServerRunning = running ;
	}
	public static boolean getIMServerStatus(){
		return imServerRunning;
	}
}

编写 推送事件 SysEvent 类:

import org.springframework.context.ApplicationEvent;

/**
 *  @ClassName: SysEvent  					    		
 *  @Description: 事件 
 *  @author Administrator									
 *  @date Dec 10, 2020									
 *  @version V1.0
 */
public class SysEvent extends ApplicationEvent
{
	private static final long serialVersionUID = 1L;
	
	
	public SysEvent(Object source)
	{
		super(source);
	}
	
}

/**
 *  @ClassName: TestEvent  					    		
 *  @Description:测试   																				
 */
public class TestEvent extends SysEvent{

	    
	private static final long serialVersionUID = 1L;

	public TestEvent(Object source) {
		super(source);
	}

	private String text;

	public String getText() {
		return text;
	}

	public void setText(String text) {
		this.text = text;
	}
}

编写监听SystemEventListener 类:


import java.io.IOException;
import java.io.Serializable;

import javax.annotation.Resource;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSON;
import com.huash.order.websocket.context.HuashContext;
import com.huash.order.websocket.event.SysEvent;
import com.huash.order.websocket.event.TestEvent;
import com.huash.order.websocket.service.WebSocketServer;

/**
 *  @ClassName: SystemEventListener  					    		
 *  @Description: 监听事件,执行操作    								
 *  @version V1.0
 */
@Component
@SuppressWarnings("all")
public class SystemEventListener implements ApplicationListener<SysEvent>
{
	Logger logger = Logger.getLogger(SystemEventListener.class);
	
	@Autowired
	private WebSocketServer webSocketServer;
	
	@Override
	public void onApplicationEvent(SysEvent event)
	{
		logger.info(String.format("%s 监听到事件源:%s.", SystemEventListener.class.getName(), event.getSource()));
		
		String es = event.getSource().toString();				
		switch( es ){
			case HuashContext.TEST: test(event); break;			// 事件
		}
	}
	
	// test 可做详细内容....
	private void test(SysEvent event)
	{
		TestEvent e = (TestEvent)event;
		
		Message message = new Message();
		
		message.setText(e.getText());
		
		webSocketServer.broadcast(JSON.toJSONString(message));
	}
}

添加一个消息文本 Message 类:


/**
 *  @ClassName: Message  					    		
 *  @Description: 消息文本    								
 *  @version V1.0
 */
public class Message {

	//发送者name
	public String from;
	//接收者name
	public String to = "-1";
	//发送的文本
	public String text;
	//发送时间
	@JSONField(format="yyyy-MM-dd HH:mm:ss")
	public Date date;

	public String getFrom() {
		return from;
	}

	public void setFrom(String from) {
		this.from = from;
	}

	public String getTo() {
		return to;
	}

	public void setTo(String to) {
		this.to = to;
	}

	public String getText() {
		return text;
	}

	public void setText(String text) {
		this.text = text;
	}

	public Date getDate() {
		return date;
	}

	public void setDate(Date date) {
		this.date = date;
	}

}

封装返回数据类:

import java.io.Serializable;

import org.apache.commons.lang3.StringUtils;

public class ResultJson implements Serializable
{

    private static final long serialVersionUID = 7646800798370648252L;

    private Object data;

    private String mess;

    private String result = SUCCESS_DESC;

    private int code = SUCCESS_CODE;

    private Long timeStamp = System.currentTimeMillis();

    private static final int SUCCESS_CODE = 200;
    private static final String SUCCESS_DESC = "操作成功";

    private static final int FAILURE_CODE = 10001;
    private static final String FAILURE_DESC = "操作异常";

    private static final int PARAMETER_EXCEPTION_CODE = 10002;
    private static final String PARAMETER_EXCEPTION_DESC = "传参异常";

    private static final int STATUS_EXCEPTION_CODE = 10009;
    private static final String STATUS_EXCEPTION_DESC = "订单状态异常";

    public static ResultJson success(Object data, String mess, String result) {
        ResultJson resultJson = new ResultJson();
        resultJson.setData(data);
        resultJson.setMess(mess);
        resultJson.setResult(result);
        return resultJson;
    }

    public static ResultJson success() {
        return new ResultJson();
    }

    public static ResultJson success(Object data, String mess) {
        ResultJson responseJson = new ResultJson();
        responseJson.setData(data);
        responseJson.setMess(mess);
        responseJson.setCode(SUCCESS_CODE);
        return responseJson;
    }

    public static ResultJson success(Object data) {
        return success(data, SUCCESS_DESC);
    }

    public static ResultJson success(String mess)
    {
    	ResultJson responseJson = new ResultJson();
        responseJson.setMess(StringUtils.isEmpty(mess) ? SUCCESS_DESC : mess);
        responseJson.setCode(SUCCESS_CODE);
        return responseJson;
    }

    public static ResultJson failure(String mess) {
        return error(FAILURE_CODE, FAILURE_DESC, mess);
    }

    public static ResultJson statusFailure(String mess) {
        return error(STATUS_EXCEPTION_CODE, STATUS_EXCEPTION_DESC, mess);
    }

    public static ResultJson parameterException(String msg)
    {
    	return error(PARAMETER_EXCEPTION_CODE, PARAMETER_EXCEPTION_DESC, msg);
    }

    public static ResultJson error(Integer code, String result, String msg) {
        ResultJson responseJson = new ResultJson();
        responseJson.setMess(msg);
        responseJson.setResult(result);
        responseJson.setCode(code);
        return responseJson;
    }

    public ResultJson() {
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

    public String getMess() {
        return mess;
    }

    public void setMess(String mess) {
        this.mess = mess;
    }

    public String getResult() {
        return result;
    }

    public void setResult(String result) {
        this.result = result;
    }

    public Long getTimeStamp() {
        return timeStamp;
    }

    public void setTimeStamp(Long timeStamp) {
        this.timeStamp = timeStamp;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    @Override
    public String toString() {
        return "ResultJson{" +
                "data=" + data +
                ", mess='" + mess + '\'' +
                ", result='" + result + '\'' +
                ", code=" + code +
                ", timeStamp=" + timeStamp +
                '}';
    }
}

前端html 代码:

<!DOCTYPE HTML>
<html>
<head>
<base href="localhost://localhost:8080/">
<title>My WebSocket</title>
</head>
 
<body>
	Welcome
	<br />
	<input id="text" type="text" />
	<button onclick="send()">Send</button>
	<button onclick="closeWebSocket()">Close</button>
	<div id="message"></div>
</body>
 
<script type="text/javascript">
	var websocket = null;
 
 var user = '111';
	//判断当前浏览器是否支持WebSocket  
	if ('WebSocket' in window) {
		websocket = new WebSocket("ws://localhost:8080/webSocket/" + user);
	} else {
		alert('Not support websocket')
	}
 
	//连接发生错误的回调方法  
	websocket.onerror = function() {
		setMessageInnerHTML("error");
	};
 
	//连接成功建立的回调方法  
	websocket.onopen = function(event) {
		setMessageInnerHTML("open");
	}
 
	//接收到消息的回调方法  
	websocket.onmessage = function(event) {
		setMessageInnerHTML(event.data);
	}
 
	//连接关闭的回调方法  
	websocket.onclose = function() {
		setMessageInnerHTML("close");
	}
 
	//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。  
	window.onbeforeunload = function() {
		websocket.close();
	}
 
	//将消息显示在网页上  
	function setMessageInnerHTML(innerHTML) {
		document.getElementById('message').innerHTML += innerHTML + '<br/>';
	}
 
	//关闭连接  
	function closeWebSocket() {
		websocket.close();
	}
 
	//发送消息  
	function send() {
		var message = document.getElementById('text').value;
		
		var text = {"text":message,"to":"-1"};
		
		websocket.send(JSON.stringify(text));
	}
</script>
</html>

然后服务端推送测试demo:

@Controller
public class TestController {

	
	@RequestMapping(value ="test", method = RequestMethod.GET,
			produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
	@ResponseBody
	public ResultJson test() 
	{
		TestEvent testEvent = new TestEvent(HuashContext.TEST);
		
		testEvent.setText("测试");
		
		HuashContext.getContext().publishEvent(testEvent);
		
		return ResultJson.success("成功");
	}
	
	
}

用spring 事件去推送消息内容,每一个事件继承Event并编写事件消息内容,然后通过监听listener监听事件,编写对应方法然后执行。

前端页面接收:

前端发送,后端接收:

整体项目结构:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值