springboot环境配置websocket

第一种方法:

后台只需两个文件即可:

package com.xy.admin.websocket;

import com.google.gson.Gson;
import com.xy.admin.entity.SateliteState;
import com.xy.admin.entity.SateliteStateValue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * @ServerEndpoint 注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端,
 *                 注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端
 */
@ServerEndpoint("/websocket")
@Component
public class WebSocketTest {
    private static final Logger logger = LoggerFactory.getLogger(WebSocketTest.class);
	// 静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
	private static int onlineCount = 0;

	// concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通信的话,可以使用Map来存放,其中Key可以为用户标识
	private static CopyOnWriteArraySet<WebSocketTest> webSocketSet = new CopyOnWriteArraySet<WebSocketTest>();

	// 与某个客户端的连接会话,需要通过它来给客户端发送数据
	private Session session;

	/**
	 * 连接建立成功调用的方法
	 * 
	 * @param session
	 *            可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据
	 */
	@OnOpen
	public void onOpen(Session session) {
		this.session = session;
		webSocketSet.add(this); // 加入set中
		addOnlineCount(); // 在线数加1
		System.out.println("有新连接加入!当前在线人数为" + getOnlineCount());
	}

	/**
	 * 连接关闭调用的方法
	 */
	@OnClose
	public void onClose() {
		webSocketSet.remove(this); // 从set中删除
		subOnlineCount(); // 在线数减1
		System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount());
	}

	public static String getString(ByteBuffer buffer) {

		Charset charset = null;
		CharsetDecoder decoder = null;
		CharBuffer charBuffer = null;

		try {
			charset = Charset.forName("UTF-8");
			decoder = charset.newDecoder();
			// 用这个的话,只能输出来一次结果,第二次显示为空
			// charBuffer = decoder.decode(buffer);
			charBuffer = decoder.decode(buffer.asReadOnlyBuffer());
			return charBuffer.toString();
		} catch (Exception ex) {
			ex.printStackTrace();
			return "error";
		}
	}

    /**
     * 接收文本消息
     * @param message
     * @param session
     */
//    @OnMessage
//    public void onMessage(String message, Session session) {
//        System.out.println("来自客户端的消息:" + message);
//    }
        /**
         * 接收二进制消息
         * 收到客户端消息后调用的方法
         *
         * @param byteBuffer
         *            客户端发送过来的消息
         * @param session
         *            可选的参数
         */
	@OnMessage
	public void onMessage(Session session, ByteBuffer byteBuffer) {
        logger.info("接收到来自客户端的消息");
		String satelistOrStationState = getString(byteBuffer);
//		System.out.println("来自客户端的消息:" + satelistOrStationState);

		sendMes(“123456”);
	}

	public void sendMes(String message) {
		// 群发消息
		for (WebSocketTest item : webSocketSet) {
			try {
				item.sendMessage(message);
			} catch (IOException e) {
				e.printStackTrace();
				continue;
			}
		}
	}

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

	/**
	 * 这个方法与上面几个方法不一样。没有用注解,是根据自己需要添加的方法。
	 * 
	 * @param message
	 * @throws IOException
	 */
	public void sendMessage(String message) throws IOException {
		this.session.getBasicRemote().sendText(message);
		// this.session.getAsyncRemote().sendText(message);
	}

	public static synchronized int getOnlineCount() {
		return onlineCount;
	}

	public static synchronized void addOnlineCount() {
		WebSocketTest.onlineCount++;
	}

	public static synchronized void subOnlineCount() {
		WebSocketTest.onlineCount--;
	}


//    @Configuration
//    public class WebSocketConfig {
//        @Bean
//        public ServerEndpointExporter serverEndpointExporter(){
//            return new ServerEndpointExporter();
//        }
//    }
}

还需要一个config

package com.xy.admin.websocket;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

@Configuration
@EnableWebSocket
public class WebSocketConfig {
    @Bean
    public ServerEndpointExporter serverEndpointExporter(){
        return new ServerEndpointExporter();
    }
}

前台页面调用时:

var websocket = null;
    //判断当前浏览器是否支持WebSocket
    if ('WebSocket' in window) {
        websocket = new WebSocket("ws://172.16.100.14:8080/websocket");
    }
    else {
        alert('当前浏览器 Not support websocket')
    }

    //连接发生错误的回调方法
    websocket.onerror = function () {
        setMessageInnerHTML("WebSocket连接发生错误");
    };

    //连接成功建立的回调方法
    websocket.onopen = function () {
        setMessageInnerHTML("WebSocket连接成功");
    }

    //接收到消息的回调方法
    websocket.onmessage = function (event) {
        setMessageInnerHTML(event.data);
    }

    //连接关闭的回调方法
    websocket.onclose = function () {
        setMessageInnerHTML("WebSocket连接关闭");
    }

    //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
    window.onbeforeunload = function () {
        closeWebSocket();
    }

    //将消息显示在网页上
    function setMessageInnerHTML(innerHTML) {
        document.getElementById('message').innerHTML += innerHTML + '<br/>';
    }

    //关闭WebSocket连接
    function closeWebSocket() {
        websocket.close();
    }

    //发送消息
    function send() {
        var message = document.getElementById('text').value;
        websocket.send(message);
    }

第二种方法

config:

package com.xy.admin.websocket;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
    @Bean
    public ServerEndpointExporter serverEndpointExporter(){
        return new ServerEndpointExporter();
    }

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(chatMessageHandler(),"/websocket").addInterceptors(new ChatHandshakeInterceptor()).setAllowedOrigins("*");
        registry.addHandler(chatMessageHandler(), "/sockjs/webSocketServer").addInterceptors(new ChatHandshakeInterceptor()).withSockJS();
    }

    @Bean
    public TextWebSocketHandler chatMessageHandler(){
        return new ChatMessageHandler();
    }

}

handler:

package com.xy.admin.websocket;

import java.io.IOException;
import java.util.ArrayList;
import org.apache.log4j.Logger;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import javax.annotation.Resource;

public class ChatMessageHandler extends TextWebSocketHandler {

    private static final ArrayList<WebSocketSession> users;// 这个会出现性能问题,最好用Map来存储,key用userid
    private static Logger logger = Logger.getLogger(ChatMessageHandler.class);
    @Resource
    private SimpMessagingTemplate temPlate;

    static {
        users = new ArrayList<WebSocketSession>();
    }

    /**
     * 连接成功时候,会触发UI上onopen方法
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        System.out.println("connect to the websocket success......");
        users.add(session);
        // 这块会实现自己业务,比如,当用户登录后,会把离线消息推送给用户
        // TextMessage returnMessage = new TextMessage("你将收到的离线");
        // session.sendMessage(returnMessage);
    }

    /**
     * 在UI在用js调用websocket.send()时候,会调用该方法
     */
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        System.out.println(message.getPayload()+"123456789-----------------------");
//        sendMessageToUsers(message);
        this.temPlate.convertAndSend("/topic/satelliteStatus",message.getPayload());
        //super.handleTextMessage(session, message);
    }

    /**
     * 给某个用户发送消息
     *
     * @param userName
     * @param message
     */
    public void sendMessageToUser(String userName, TextMessage message) {
        for (WebSocketSession user : users) {
            if (user.getAttributes().get("userName").equals(userName)) {
                try {
                    if (user.isOpen()) {
                        user.sendMessage(message);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
                break;
            }
        }
    }

    /**
     * 给所有在线用户发送消息
     *
     * @param message
     */
    public void sendMessageToUsers(TextMessage message) {
        for (WebSocketSession user : users) {
            try {
                if (user.isOpen()) {
                    user.sendMessage(message);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        if (session.isOpen()) {
            session.close();
        }
        logger.debug("websocket connection closed......");
        users.remove(session);
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
        logger.debug("websocket connection closed......");
        users.remove(session);
    }

    @Override
    public boolean supportsPartialMessages() {
        return false;
    }

}

ChatHandshakeInterceptor:

package com.xy.admin.websocket;

import java.util.Map;
import org.apache.shiro.SecurityUtils;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;

public class ChatHandshakeInterceptor extends HttpSessionHandshakeInterceptor {

    @Override
    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
                                   Map<String, Object> attributes) throws Exception {
        System.out.println("Before Handshake");
        /*
         * if (request instanceof ServletServerHttpRequest) {
         * ServletServerHttpRequest servletRequest = (ServletServerHttpRequest)
         * request; HttpSession session =
         * servletRequest.getServletRequest().getSession(false); if (session !=
         * null) { //使用userName区分WebSocketHandler,以便定向发送消息 String userName =
         * (String) session.getAttribute(Constants.SESSION_USERNAME); if
         * (userName==null) { userName="default-system"; }
         * attributes.put(Constants.WEBSOCKET_USERNAME,userName);
         *
         * } }
         */

        //使用userName区分WebSocketHandler,以便定向发送消息(使用shiro获取session,或是使用上面的方式)
        String userName = (String) SecurityUtils.getSubject().getSession().getAttribute("userName");
        if (userName == null) {
            userName = "default-system";
        }
        attributes.put("userName", userName);

        return super.beforeHandshake(request, response, wsHandler, attributes);
    }

    @Override
    public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
                               Exception ex) {
        System.out.println("After Handshake");
        super.afterHandshake(request, response, wsHandler, ex);
    }

}

前台页面调用时和前面一样;

第三种方法

config:

package com.xy.admin.websocket;

import okhttp3.WebSocket;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.ChannelRegistration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;

import javax.websocket.OnMessage;
import java.io.IOException;

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketMessageBrokerConfigurer extends AbstractWebSocketMessageBrokerConfigurer{

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry){
        /*
        * 注册stomp的端点
        * addEndpoint:添加stomp协议的端点,这个http URL是供websocket或sockjs客户端访问的地址
        * withsockjs:指定端点使用sockjs协议
        * */
        registry.addEndpoint("/websocket-simple").setAllowedOrigins("*").withSockJS();//添加允许跨域访问
//        registry.addEndpoint("/websocket").setAllowedOrigins("*");//添加允许跨域访问
    }

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry){
        /*
        * 配置消息代理
        * 启动简单Broker,消息的发送的地址符合配置的前缀来的消息才发送到这个broker
        *topic代表发布广播,queue代表点对点,发送指定用户
        * */
        registry.enableSimpleBroker("/topic","queue");
    }

    @Override
    public void configureClientInboundChannel(ChannelRegistration registration){
        super.configureClientInboundChannel(registration );
    }


}

controller:

package com.xy.admin.controller.xy_task;


import com.alibaba.fastjson.JSONObject;
import com.xy.admin.annotation.SysLog;
import com.xy.admin.entity.TaskBusinessException;
import com.xy.admin.entity.VO.TaskSchemeVO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicInteger;
@Controller
public class WebSocketController {
    private static WebSocketController webSocketController;

    private static final Logger LOGGER = LoggerFactory.getLogger(WebSocketController.class);
    @Resource
    private   SimpMessagingTemplate temPlate;
    //收到消息计数
    private AtomicInteger count = new AtomicInteger(0);

    @PostConstruct
    public void init(){
        webSocketController = this;
        webSocketController.temPlate = this.temPlate;
    }
    @MessageMapping("/receiveTaskScheme")/*类似于@requestmapping*/
    @SendTo("/topic/getTaskScheme")/*topic在WebSocketMessageBrokerConfigurer配置,getresponse类似于队列名*/
    @ResponseBody
//    @SysLog("发送生成成功计划到页面")
    public TaskSchemeVO receiveTaskScheme(@RequestBody TaskSchemeVO taskSchemeVO){
        return taskSchemeVO;
    }

    @MessageMapping("/changeToUploadQueue")/*类似于@requestmapping*/
    @SendTo("/topic/getChangeToUploadQueue")/*topic在WebSocketMessageBrokerConfigurer配置,getresponse类似于队列名*/
    @ResponseBody
//    @SysLog("发送生成成功计划到页面")
    public String changeToUploadQueue(@RequestBody String change){
        return change;
    }


    @RequestMapping(value = "/broadcast/index")
    public String broadcastIndex(HttpServletRequest request){
        LOGGER.info(request.getRemoteHost());
        return "websocket/simple/ws-broadcast";
    }

//    @MessageMapping("/createException")/*类似于@requestmapping*/
//    @SendTo("/topic/getTaskBusinessException")/*topic在WebSocketMessageBrokerConfigurer配置,getresponse类似于队列名*/
//    @ResponseBody
    @SysLog("发送生成成功计划到页面")
//    public TaskBusinessException createException(@RequestBody TaskBusinessException taskBusinessException){
//        taskBusinessException.insert();
//        return taskBusinessException;
//    }

}

service及实现类:

package com.xy.admin.service;

import com.xy.admin.entity.Log;
import com.xy.admin.entity.TaskBusinessException;
import com.xy.admin.entity.TaskBusinessLog;
import com.xy.admin.entity.VO.TaskRequirementInjectVO;
import com.xy.admin.util.RestResponse;

import java.util.Map;


public interface WebSocketService {

     void  receiveToUploadQueue(RestResponse restResponse);
     void  receiveErrorMessage(Log sysLog);
     void  receiveModuleDetail();
     void  receiveWebLogMessage(Log sysLog);
     void  receiveTaskRequirementInjectVO(String taskRequirementInjectVOName);
     void  receiveTaskBusinessLog(TaskBusinessLog taskBusinessLog);
     void  receiveChangeToUploadQueue();
     void  receiveReloadRequirement();
     void  receiveTaskBusinessException(TaskBusinessException taskBusinessException);
}

package com.xy.admin.service.impl;


import com.google.common.collect.Maps;
import com.xy.admin.annotation.SysLog;
import com.xy.admin.entity.Log;
import com.xy.admin.entity.TaskBusinessException;
import com.xy.admin.entity.TaskBusinessLog;
import com.xy.admin.entity.VO.ModuleDetailData;
import com.xy.admin.entity.VO.TaskRequirementInjectVO;
import com.xy.admin.entity.VO.TestObject;
import com.xy.admin.service.ModuleService;
import com.xy.admin.service.TaskRequirementInjectService;
import com.xy.admin.service.WebSocketService;
import com.xy.admin.util.RestResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 服务端发送websockt消息实现类
 */
@Service
public class WebSocketServiceImpl  implements WebSocketService {
    private static final Logger LOGGER = LoggerFactory.getLogger(WebSocketServiceImpl.class);

    @Resource
    private SimpMessagingTemplate temPlate;
    @Autowired
    private TaskRequirementInjectService taskRequirementInjectService;
    @Autowired
    protected ModuleService moduleService;
    @Override
    public  void  receiveToUploadQueue(RestResponse restResponse) {
        this.temPlate.convertAndSend("/topic/getToUploadQueue",restResponse);

    }

    @Override
//    @SysLog("websocket发送logError日志到websocket队列")
    public void receiveErrorMessage(Log sysLog) {
        sysLog.setCreateDate(new Date());
        this.temPlate.convertAndSend("/topic/getErrorMessage",sysLog);
    }

    @Override
//    @SysLog("模组有状态变更后发送模组详情到websocket队列")
    public void receiveModuleDetail() {
        List<ModuleDetailData> list = moduleService.selectModuleDetail();
        Integer moduleAll = 0;
        for (ModuleDetailData moduleDetail:list) {
            moduleAll+=moduleDetail.getY();
        }
        Map<String,Object> datamap = Maps.newHashMap();
        datamap.put("moduleAll",moduleAll);
        datamap.put("colorByPoint",true);
        datamap.put("data",list);
        this.temPlate.convertAndSend("/topic/getModuleDetail",datamap);
    }

    @Override
//    @SysLog("发送log日志到websocket队列")
    public void receiveWebLogMessage(Log sysLog) {
        sysLog.setCreateDate(new Date());
        this.temPlate.convertAndSend("/topic/getWebLogMessage",sysLog);
    }

    @Override
//    @SysLog("发送注入需求到websocket队列")
    public void receiveTaskRequirementInjectVO(String taskRequirementInjectVOName) {
        TaskRequirementInjectVO taskRequirementInjectVO = taskRequirementInjectService.selectInjectVOByName(taskRequirementInjectVOName);
        this.temPlate.convertAndSend("/topic/getZhddTRInject",taskRequirementInjectVO);
    }

    @Override
//    @SysLog("发送业务日志到websocket队列")
    public void receiveTaskBusinessLog(TaskBusinessLog taskBusinessLog) {
        this.temPlate.convertAndSend("/topic/getTaskBusinessLog",taskBusinessLog);
    }

    @Override
//    @SysLog("上注队列有更改时触发前台刷新")
    public void receiveChangeToUploadQueue() {
        this.temPlate.convertAndSend("/topic/getChangeToUploadQueue","");
    }

    @Override
//    @SysLog("用户需求有变动时触发前台刷新")
    public void receiveReloadRequirement() {
        this.temPlate.convertAndSend("/topic/getReloadRequirement","");
    }

    @Override
    //业务异常
    public void receiveTaskBusinessException(TaskBusinessException taskBusinessException) {
        TestObject testObject = new TestObject();
        testObject.setKind(1);
        testObject.setKindObject(taskBusinessException);
        this.temPlate.convertAndSend("/topic/getTaskBusinessException",testObject);
    }

}

前台页面调用时:

var stompClient = null;
var socket = new SockJS('/websocket-simple');
      stompClient = Stomp.over(socket);
        stompClient.connect({}, function(frame) {
        //接收消息
        stompClient.subscribe('/topic/satelliteStatus', function (data) {
                console.log(data+"-------------------------");
            });
                                });
        //发送消息
                                stompClient.send("/receiveTaskScheme", {}, JSON.stringify(item));
   if(stompClient != null){
                                stompClient.disconnect();
                            }
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值