页面实时数据监听

页面实时数据监听

数据更新页面数据自动同步-多端
需求
无需手动点击刷新页面数据实时同步更新

实现想法一 定时器setInterval+watch

setInterval(() => {
          let _that = this;
          setTimeout(
            function () {
              _that.getlist(); //加载数据函数 自己的方法
              console.log("刷新" + new Date());
            }, 0);

        }, 1000);
		
watch,它可以用来监测Vue实例上的数据变动

于是发现比较浪费性能并没有达到我想要的预期效果

实现想法二 ajax的长轮询

Ajax轮询:客户端是按照规定时间像服务端发送请求,前一次请求完成后,无论有无结果返回,规定时间之后下一次请求又会发出

Ajax长轮询:当服务端收到客户端发来的请求后,服务端不会直接进行响应,而是先将这个请求挂起,然后判断服务器端数据是否有更新。如果有更新,则进行响应,如果一直没有数据,则到达一定的时间限制(服务器端设置)才返回。 客户端JavaScript响应处理函数会在处理完服务器返回的信息后,再次发出请求,重新建立连接。既把循环放到了服务端

启动类上开启异步 @EnableAsync

@RequestMapping("/async")
@RestController
public class AsyncRequestDemo {

    @Autowired
    private AsyncRequestService asyncRequestService;

    @GetMapping("/value")
    public String getValue() {

        String msg =  null;
        Future<String> result = null;
        try{
            result = asyncRequestService.getValue();
            msg = result.get(10, TimeUnit.SECONDS);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if (result != null){
                result.cancel(true);
            }
        }

        return msg;
    }

    @PostMapping("/value")
    public void postValue(String msg) {
        asyncRequestService.postValue(msg);
    }
}

@Service
public class AsyncRequestService {

    private String msg = null;

    @Async
    public Future<String> getValue() throws InterruptedException {

        while (true){
            synchronized (this){
                if (msg != null){
                    String resultMsg = msg;
                    msg = null;
                    return new AsyncResult(resultMsg);
                }
            }
            Thread.sleep(100);
        }
    }

    public synchronized void postValue(String msg) {
        this.msg = msg;
    }
}

这里是根据 msg 是否变化判断是否响应返回

@EnableAsync 开启异步
@Sync 标记异步方法
Future 用于接收异步返回值
result.get(10, TimeUnit.SECONDS); 阻塞,超时获取结果
Future.cancel() 中断线程

于是发现在多端中判断服务器端数据是否有更新自己发现比较困难

实现想法三 websocket

收到客户端消息后既对数据请求响应,数据的实时同步性比较好,

<!-- websocket -->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
/**
 * 前后端交互的类实现消息的接收推送(自己发送给自己)
 *
 * @ServerEndpoint(value = "/ws/one") 前端通过此URI和后端交互,建立连接
 */
@Slf4j
@ServerEndpoint(value = "/ws/one/{userid}",encoders = { EncoderClassVo.class })
@Component
public class OneWebSocket {

    /**
     *  与某个客户端的连接对话,需要通过它来给客户端发送消息
     */
    private Session session;

    /**
     * 标识当前连接客户端的用户名
     */
    private String userid;

    /**
     *  用于存所有的连接服务的客户端,这个对象存储是安全的
     */
    private static ConcurrentHashMap<String,OneWebSocket> webSocketSet = new ConcurrentHashMap<>();

    // websocket 不能注入( @Autowired )
    private static VdataService vdataService;

    @Autowired
    public void setVdataService(VdataService vdataService) {
        OneWebSocket.vdataService = vdataService;
    }

    /**
     * 记录当前在线连接数
     */
//    private static AtomicInteger onlineCount = new AtomicInteger(0);


    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam(value = "userid")String userid) {
        this.session = session;
        this.userid = userid;
        // userid是用来表示唯一客户端,如果需要指定发送,需要指定发送通过userid来区分
        webSocketSet.put(userid,this);
//        onlineCount.incrementAndGet(); // 在线数加1
        log.info("有新连接加入:用户id,{},当前在线人数为:{}",this.userid, webSocketSet.size());

    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose(Session session) {
//        onlineCount.decrementAndGet(); // 在线数减1
        webSocketSet.remove(this.userid);
        log.info("有一连接关闭:{},用户id,{},当前在线人数为:{}", session.getId(),this.userid, webSocketSet.size());
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(String message) throws ExecutionException, InterruptedException {
		// 你的业务逻辑
        JSONObject obj = JSONUtil.parseObj(message);
        String userid = obj.get("userid").toString();
        String page = obj.get("page").toString();
        String size = obj.get("size").toString();
        String isend = obj.get("isend").toString();
        System.err.println(obj);
        Future<Object> vData = vdataService.getlistVData(Integer.parseInt(userid), page, size, Integer.parseInt(isend));
        log.info("服务端 收到  客户端 [{}]的消息:{}", userid, message);
		// 你的业务逻辑
        this.sendMessage(ResultDTO.success(vData.get()), userid);
    }

    @OnError
    public void onError(Throwable error) {
        webSocketSet.remove(this.userid);
        log.error("发生错误");
        error.printStackTrace();
    }

    /**
     * 服务端发送消息给客户端
     */
    private void sendMessage(ResultDTO message, String userid) {
        System.err.println("userid "+userid);
        try {
            log.info("服务端 给 客户端[{}]发送消息{}", userid, JSONUtil.parseObj(message));
            webSocketSet.get(userid).session.getBasicRemote().sendObject(message);
        } catch (Exception e) {
            log.error("服务端发送消息给客户端失败:{}", e);
        }
    }
}

发现服务端发送消息给客户端发送消息发送的object类型解析不了
需要配置解析类

public class EncoderClassVo implements Encoder.Text<ResultDTO>{

    @Override
    public void init(EndpointConfig config) {
        // TODO Auto-generated method stub

    }

    @Override
    public void destroy() {
        // TODO Auto-generated method stub

    }

    //如果你传递的是一个类,则使用如下写法
    @Override
    public String encode(ResultDTO resultDTO) throws EncodeException {
        return JSONUtil.toJsonStr(resultDTO);
    }
}

	destroyed() {
      this.websock.close() //离开路由之后断开websocket连接
    },
    created() {
      this.initWebSocket();
    },
	initWebSocket(){ //初始化weosocket
        console.log("初始化weosocket");
        const wsuri = "ws://127.0.0.1:80/ws/one/"+this.userid;
        this.websock = new WebSocket(wsuri);
        this.websock.onopen = this.websocketonopen;
        this.websock.onmessage = this.websocketonmessage;
        this.websock.onerror = this.websocketonerror;
        this.websock.onclose = this.websocketclose;
      },
      websocketonopen(){ //连接建立之后执行send方法发送数据
        console.log("websocket-连接成功")
        let data = {"hi":"发送数据"};
        this.websocketsend(JSON.stringify(data));
      },
      websocketonerror(){//连接建立失败重连
        this.initWebSocket();
      },
      websocketonmessage(e){ //数据接收
        const redata = JSON.parse(e.data);
        console.log("ws--数据接收")
        this.listData = redata.data.records;
        console.log(redata)
      },
      websocketsend(Data){//数据发送
        this.websock.send(Data);
      },
      websocketclose(e){  //关闭
        console.log('断开连接',e);
      },


在有数据操作的地方只需向服务端发送消息即可 new OneWebSocket().onMessage(msg);

于是实现了自己想要的功能,以此记录

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值