美文网首页
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