美文网首页
springmvc集成webSocket

springmvc集成webSocket

作者: nickbi | 来源:发表于2018-07-11 00:46 被阅读0次
    在我们的日出业务中,会遇到有实时刷新数据,实时监控系统某种状态或信息等情况。
    通常我们会想到通过ajax定时发起请求、轮询等方式实现这种功能,通过这几种方式都是由客户端发起的,时间间隔设置的很短,数据能实时刷新,但会占用系统的资源,如果请求基数很大,可能会导致系统内存溢出、资源耗尽等情况发生。如果我们将时间间隔设置的比较长,那么我们的实时性需求也就无法实现。
    
    在H5中,WebSockt成为了我们的一直选择方案,webSocket现在已被很多浏览器所支持,所以使用场景的兼容性也有了一定的保障
    
    • webSockt可以实现客户端、服务端的双向对话,webSockt是建立在tcp协议只上的,数据格式比较轻量,性能开销小,通信高效。可以发送文本,也可以发送二进制数据。没有同源限制,客户端可以与任意服务器通信。

    1.服务端实

    WebSocket 控制器类

    在springmvc中,我们可以通过@ServerEndPoint注解,指定socket的路径,配置、编码方式。webSocket接口的定义,我们可以类比为Controller的api的定义,通过ip:port/path去访问。

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.web.socket.server.standard.SpringConfigurator;
    
    import javax.websocket.*;
    import javax.websocket.server.ServerEndpoint;
    import java.io.IOException;
    import java.util.HashSet;
    import java.util.Set;
    
    /**
     * webSocket 控制器
     *
     * @author nickBi
     * create on 2018/7/4.
     */
    @ServerEndpoint(value = "/websocket", configurator = SpringConfigurator.class, encoders = NBWebSocketEncoder.class)
    public class NBWebSocket {
        //日志记录
        private Logger logger = LoggerFactory.getLogger(TPPWebSocket.class);
    
        //记录每个用户下多个终端的连接
        private static Set<TPPWebSocket> userSocket = new HashSet<>();
    
        //需要session来对用户发送数据, 获取连接特征userId
        private Session session;
    
        /**
         * @param @param  session websocket连接的session属性
         * @param @throws IOException
         * @Title: onOpen
         * @Description: websocekt连接建立时的操作
         */
        @OnOpen
        public void onOpen(Session session) throws IOException {
            this.session = session;
            userSocket.add(this);
            logger.debug("webSocket open");
        }
    
        /**
         * @Title: onClose
         * @Description: 连接关闭的操作
         */
        @OnClose
        public void onClose() {
            userSocket.remove(this);
            logger.debug("webSocket closed!");
        }
    
        /**
         * @param @param message 收到的消息
         * @param @param session 该连接的session属性
         * @Title: onMessage
         * @Description: 收到消息后的操作
         */
        @OnMessage
        public void onMessage(String message, Session session) {
            logger.debug("收到消息" + message);
            if (session == null) logger.debug("session null");
        }
    
        /**
         * @param @param session 该连接的session
         * @param @param error 发生的错误
         * @Title: onError
         * @Description: 连接发生错误时候的操作
         */
        @OnError
        public void onError(Session session, Throwable error) {
            logger.debug("连接发送错误");
            error.printStackTrace();
        }
    
        /**
         * @param @param  message 发送的消息
         * @param @return 发送成功返回true,反则返回false
         * @Title: sendMessage
         * @Description: 发送消息给用户下的所有终端
         */
        public Boolean sendMessage(String message) {
            userSocket.stream().forEach(ws -> {
                try {
                    ws.session.getBasicRemote().sendText(message);
    
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });
            return true;
        }
    
        public Boolean sendMessage(Object message) {
            userSocket.stream().forEach(ws -> {
                try {
                    ws.session.getBasicRemote().sendObject(message);
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (EncodeException e) {
                    e.printStackTrace();
                }
            });
            return true;
        }
    }
    

    NBWebSocket的自定义编码器

    如需传递Object类型,则需要定义自己的message编码器,如果传递的是string信息则无需编写,此处我们使用的jackson,将对象转化为jsonString再传递到前端(非必须)。

    import com.jeeplus.common.json.JsonUtils;
    import com.lingrit.tpp.core.result.JsonResult;
    
    import javax.websocket.Encoder;
    import javax.websocket.EndpointConfig;
    
    /**
     * webSocket 编码器
     *
     * @author nickBi
     * create on 2018/7/4.
     */
    public class NBWebSocketEncoder implements Encoder.Text<JsonResult> {
    
    
        @Override
        public String encode(JsonResult jsonResult) {
    
            return JsonUtils.writeValueAsString(jsonResult);
        }
    
        @Override
        public void init(EndpointConfig endpointConfig) {
    
        }
    
        @Override
        public void destroy() {
    
        }
    }
    

    WebSocketService

    在此,我们可以发送消息到前端

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Service;
    
    /**
     * @author nickBi
     * create on 2018/7/4.
     */
    @Service
    public class NBWebSocketService {
        private Logger logger = LoggerFactory.getLogger(NBWebSocketService.class);
        //声明websocket连接类
        private NBWebSocket nbWebSocket = new NBWebSocket();
    
        /**
         * @param @param  message 消息
         * @param @return 发送成功返回true,否则返回false
         * @Title: sendToAllTerminal
         * @Description: 调用websocket类给用户下的所有终端发送消息
         */
        public Boolean sendToAllTerminal(String message) {
            logger.debug(message);
            if (nbWebSocket.sendMessage(message)) {
                return true;
            } else {
                return false;
            }
        }
    
        public Boolean sendToAllTerminal(Object message) {
            logger.debug(message.toString());
            if (nbWebSocket.sendMessage(message)) {
                return true;
            } else {
                return false;
            }
        }
    
    }
    

    JsonUtils工具类

    import com.fasterxml.jackson.databind.ObjectMapper;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import java.text.SimpleDateFormat;
    import java.util.*;
    
    /**
     * json工具类 使用jackson
     *
     */
    public abstract class JsonUtils {
    
        private static Logger LOGGER = LoggerFactory.getLogger(JsonUtils.class);
        private static ObjectMapper objectMapper = new ObjectMapper();
    
        static {
            objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
            objectMapper.setTimeZone(TimeZone.getTimeZone("GMT+8"));
        }
    
        /**
         * 解析JSON对象
         */
        public static <T> T parseJsonObject(String json, Class<T> clazz) {
            try {
                return objectMapper.readValue(json, clazz);
            } catch (Exception e) {
                LOGGER.error("JSON对象解析失败", e);
                throw new RuntimeException("JSON对象解析失败");
            }
        }
    
        /**
         * 解析JSON集合
         */
        public static <T> List<T> parseJsonList(String json, Class<T> clazz) {
            try {
                return objectMapper.readValue(json, objectMapper.getTypeFactory().constructParametricType(ArrayList.class, clazz));
            } catch (Exception e) {
                LOGGER.error("JSON集合解析失败", e);
                throw new RuntimeException("JSON集合解析失败");
            }
        }
    
        /**
         * 解析JSON集合,class是集合类型
         * @param <T>
         * @param json
         * @param clazz
         * @return
         */
        public static <T> List<T> parseCollectionJsonList(String json, Class<T> clazz){
            try {
                return objectMapper.readValue(json, objectMapper.getTypeFactory().constructCollectionType(ArrayList.class, clazz));
            } catch (Exception e) {
                LOGGER.error("JSON集合解析失败", e);
                throw new RuntimeException("JSON集合解析失败");
            }
        }
    
    
    
    
        /**
         * 转化为json字符串
         */
        public static String writeValueAsString(Object object){
            try{
                return objectMapper.writeValueAsString(object);
            }catch (Exception e){
                LOGGER.error("转换为JSON字符串失败", e);
                throw new RuntimeException("JSON集合解析失败");
            }
        }
    
    
        public static void main(String[] args){
    
            int[] integerJson = new int[] {4, 5, 1, 2,8, 9, 10, 10, 1, 2, 3, 4, 5, 6 , 9, 11, 10, 11, 9, 10, 1, 2, 10};
    
    
    
            List<Map<String, Integer>> list = new ArrayList<Map<String, Integer>>();
            for(int i=0; i<integerJson.length; i++){
                Map<String, Integer> map = new HashMap<String, Integer>();
                map.put("nums", i);
                map.put("vl", integerJson[i]);
                list.add(map);
            }
    
    
    
            System.out.println(writeValueAsString(list));
    
        }
    

    JsonResult

    import com.alibaba.fastjson.JSON;
    
    /**
     * 统一API响应结果封装
     */
    public class JsonResult {
        private int code;
        private String message;
        private String debugMessage;
        private Object data;
        private boolean success;
    
        public JsonResult setCode(int resultCode) {
            this.code =resultCode;
            return this;
        }
    
        public int getCode() {
            return code;
        }
    
        public JsonResult setCode(int code) {
            this.code = code;
            return this;
        }
    
        public String getMessage() {
            return message;
        }
    
        public JsonResult setMessage(String message) {
            this.message = message;
            return this;
        }
    
        public Object getData() {
            return data;
        }
    
        public JsonResult setData(Object data) {
            this.data = data;
            return this;
        }
    
        public String getDebugMessage() {
            return debugMessage;
        }
    
        public JsonResult setDebugMessage(String debugMessage) {
            this.debugMessage = debugMessage;
            return this;
        }
    
        @Override
        public String toString() {
            return JSON.toJSONString(this);
        }
    
     
    
        public void setSuccess(boolean success) {
            this.success = success;
        }
    
    }
    

    客户端实现

    客户端以网页端为例说明,socket接口地址为前面我们定义的路径,并用WS最为WebSocket的标志:ws://localhost:8080/websocket

      <head lang="en">
        <meta charset="UTF-8">
        <script src="http://cdn.sockjs.org/sockjs-0.3.min.js"></script>
        <link rel="stylesheet" href="//cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap.min.css">
        <link rel="stylesheet" href="//cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap-theme.min.css">
        <script src="//cdn.bootcss.com/jquery/1.11.3/jquery.min.js"></script>
        <script src="//cdn.bootcss.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
        <title>webSocket-用户66</title>
        <script type="text/javascript">
            $(function () {
                var websocket;
                if ('WebSocket' in window) {
                    console.log("此浏览器支持websocket");
                    websocket = new WebSocket("ws://localhost:8080/websocket");
                } else if ('MozWebSocket' in window) {
                    alert("此浏览器只支持MozWebSocket");
                } else {
                    alert("此浏览器只支持SockJS");
                }
                websocket.onopen = function (evnt) {
                    $("#tou").html("链接服务器成功!")
                };
                websocket.onmessage = function (evnt) {
                    console.log(evnt);
                    $("#msg").html($("#msg").html() + "<br/>" + evnt.data + "batchNo:" + evnt.data[0].batchNo);
                };
                websocket.onerror = function (evnt) {
                };
                websocket.onclose = function (evnt) {
                    $("#tou").html("与服务器断开了链接!")
                }
                $('#send').bind('click', function () {
                    send();
                });
    
                function send() {
                    if (websocket != null) {
                        var message = document.getElementById('message').value;
                        websocket.send(message);
                    } else {
                        alert('未与服务器链接.');
                    }
                }
            });
        </script>
    </head>
    
    <body>
    <div class="page-header" id="tou">
        webSocket测试
    </div>
    <div class="well" id="msg"></div>
    <div class="col-lg">
        <div class="input-group">
            <input type="text" class="form-control" placeholder="发送信息..." id="message">
            <span class="input-group-btn">
                        <button class="btn btn-default" type="button" id="send">发送</button>
                    </span>
        </div>
    </div>
    </body>
    
    </html>
    

    相关文章

      网友评论

          本文标题:springmvc集成webSocket

          本文链接:https://www.haomeiwen.com/subject/wprcpftx.html