springboot+vue实现长轮询
长轮询和短轮询应用场景
通常需要实时刷新数据时,需要用到轮询,字面意思就是不断重复请求。短轮询实现
实时刷新最简单的实现就是短轮询,实现方式就是隔一段时间发送一次请求,进行数据刷新,实现很简单,代码如下(这里不沾代码了,相信看到这个博文的对定时器,ajax请求很熟悉了)

以上就是短轮询代码,后台无需处理
长轮询代码
长轮询需要后台配合,后台代码如下:
@GetMapping("/getMapChange")
public List getMapChange(HttpServletRequest request) {UserOutPut user = (UserOutPut) request.getSession().getAttribute(LoginInterceptor.USER_KEY);try {mapManager.register(user);return mapManager.pollAll(user);}catch (Exception e){throw new IllegalStateException();}finally {mapManager.remove(user);}
}
截图解释:

下面看看 我这里消息管理类 MapManager中的代码,register pollAll 方法都做了什么
public class MapManager {
//保留消息的map key是请求时注册的,value是注册的请求要收到的消息private static final Map<UserOutPut, Queue<MapResult>> MESSAGE_MAP = new ConcurrentHashMap<>();private static final Map<UserOutPut, Integer> RETYR_TIME = new ConcurrentHashMap<>();//注册方法,只有注册了请求才会接收到消息public void register(UserOutPut token) {MESSAGE_MAP.computeIfAbsent(token,k-> new ConcurrentLinkedQueue());RETYR_TIME.computeIfAbsent(token,k -> 0);}//无论异常,还是空消息,最终都要将注册的请求销毁,防止驻留在map内存中。public void remove(UserOutPut token){MESSAGE_MAP.remove(token);RETYR_TIME.remove(token);}//将消息添加到所有请求的value中,这里参数只是我用到的消息结构public void push(Node node, NodeInfo nodeInfo) {MESSAGE_MAP.keySet().forEach(k -> {synchronized (k) {MapResult manChange = new MapResult(node,nodeInfo);MESSAGE_MAP.get(k).add(manChange);k.notifyAll();//唤醒该请求对应的pollAll方法中的睡眠}});}//根据请求弹出消息返回给前台的请求public List<MapResult> pollAll(UserOutPut token) {List<MapResult> result = new ArrayList<>(); //最终的返回结果Queue<MapResult> hashMaps = MESSAGE_MAP.get(token);//根据请求的key值,得到消息队列if (hashMaps != null) {while (true) {MapResult poll = hashMaps.poll();//弹出消息,并添加到结果集中if (poll == null) {//消息为空时,表示队列中无消息了,退出循环即可break;}result.add(poll);}}else {register(token);}if (result.isEmpty() && RETYR_TIME.get(token) < 3) {//如果结果集为空,就将请求挂起先不响应前台的请求,//这也是长轮询的核心,目的就是不响应前台,等有消息再向应,这里的第二个条件只是为了等待消息超时直接返回空响应给前台,这个超时可根据自己情况定try {Integer time = RETYR_TIME.get(token);RETYR_TIME.put(token,time+1);synchronized (token) { //没有消息该线程进入等待,释放资源占用//此处token用于被唤醒,唤醒位置在该类的push方法中token.wait(10000);}return pollAll(token);} catch (InterruptedException e) {Thread.currentThread().interrupt();}}return result;}/***这里是我的返回结果类,可根据情况自定义*/@Data@NoArgsConstructorpublic class MapResult{private Node node;private NodeInfo nodeInfo;public MapResult(Node node,NodeInfo nodeInfo) {this.node = node;this.nodeInfo = nodeInfo;}}
}
这里在附上我的push消息位置,用到了个aop,代码如下(这里直接截图,不附代码了,因为什么时候添加消息看个人应用场景):

后台代码就以上这些,最后就是前台请求代码了:
前台操作目的就是等请求返回了,再次发起,减少请求次数,熟悉vue的,这个方法只要在vue的create函数中调用一次即可,无需计时器。
小结:
应用场景:
因为我这里要实时刷新一个三维数组地图,但是地图节点信息改变又没那么频繁,所以 采用长轮询是最好的选择,因为短轮询会造成很多请求浪费。为什么长轮询在处理返回结果中调用不会发生栈溢出(个人想的问题,可能有点幼稚了):
因为ajax是异步请求,实时上请求发出后,该请求方法已经结束,处理请求的方法是新的栈,所以不在同一方法内部调用,所以不会溢出。我这里aop的使用:
因为我的地图是三维数组,小的库也要近千个货位,三维数据的遍历是三层循环,如果每次都把地图全部刷新,浪费效率。所以我这里aop拦截更新方法,只刷新内容改变的节点。本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
