springboot + vue + websocket + ECharts

springboot + vue + websocket + ECharts

  • 初衷
    • 缘由
    • 后端Springboot实现
    • 前端VUE的实现
    • Echart动态拿数据时不显示原因(加载顺序问题)
    • 结语

初衷

因为刚接触VUE的前端开发,自己也是做起来也是模模糊糊的。遇到的一些坑记录一下

缘由

在完成一个页面展示的折线图时,虽然每次刷新都是直接从后端直接拿最新的数据,但是会导致界面的整体刷新,就想做一个异步的刷新,让折线图能像股市看板一样的存在,线是能实时变化的。思考了一下有两种解决方案

  1. 在前端JS中设置一个定时器,每秒往后端请求一次(这种感觉太耗资源了,尤其有时候需要看日志,控制台打印出来的东西根本看不了,所以直接放弃了这种)
  2. 使用websocket通讯,保证一个长连接,后端主动像前端推送消息(从被动的被访问变成主动,当需要时才给前端数据)

后端Springboot实现

1.创建一个配置文件完成websocket的启动


import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;


/**
 * 
 * @author 解咚咚
 * @date 创建时间2019年6月25日上午10:04:54
 * @version 1.0
 */
@Configuration
public class myWebSocketConfig {
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }

}

2.之后可以完成和前端建立连接的一些功能了


import java.io.IOException;
import java.util.List;
import java.util.concurrent.CopyOnWriteArraySet;

import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

import org.fh.entity.PageData;
import org.java_websocket.server.WebSocketServer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.chaintWMS.mapper.HomePageMapper;
import com.chaintWMS.utils.Result;

/**
 * 
 * @author 解咚咚
 * @date 创建时间2019年6月25日上午10:26:59
 * @version 1.0
 */
@ServerEndpoint(value = "/websocket")  //这里是前端访问地址时需要带的。
@Component
public class MyWebsocket {

	private static HomePageMapper homePageMapper;    
	// 注入的时候,给类的 service 注入
    @Autowired
    public void setChatService(HomePageMapper homePageMapper) {
    	MyWebsocket.homePageMapper = homePageMapper;
    }
	//上面这么写的原因是因为直接用   @Autowired注入会导致 homePageMapper未null 注入不成功,所以需要这么去写。具体原因可去百度其他文档
	//其实这里还可以  写一个连接数的静态变量,当每次连接成功后 ++一次,断开连接时 -- 一次,可以实时观测连接数,根据具体需求去做就可以了
	//concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
	private static CopyOnWriteArraySet webSocketSet = new CopyOnWriteArraySet();
	 
    //private volatile static List sessions = Collections.synchronizedList(new ArrayList());
	private Session session;
    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session) {
        this.session = session;
        webSocketSet.add(this);      //将连接添加到安全的线池去
    	System.out.println("连接成功");
        
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        System.out.println("有一连接关闭");
    }

    /**
     * 给前台推消息
     * @param session
     * @param rs
     * @throws IOException
     */
    public void sendMessage(String rs) throws IOException {
    	if(this.session.isOpen()) {   //判断session是否是打开状态的,打开状态的才发。
    		this.session.getBasicRemote().sendText(rs);
    	}
    }
    //下面这个方法是对外提供的静态方法,当业务层需要给改变前端显示内容,或给前端推送内容时调用此方法(可根据具体业务逻辑更改此方法)
    public static void sendInfo(String message) throws IOException {
    	List hhlist = homePageMapper.gethhData();
    	String json = Result.of(200,"得到实时数据成功").put("hhlist", hhlist).json();
    	if(message.equals("1")) {
    		for (MyWebsocket item : webSocketSet) {   //这是默认给全部的连接发送消息   如果不需要给全部发,可以定义一个变量来区别每次链接的ID 给对应的ID发
        		item.sendMessage(json);
        	}
    	}
    }
    
    /**
     * 收到前端客户端消息后调用的方方法
     * @param message 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        System.out.println("来自客户端的消息:" + message);
    }

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


}

前端VUE的实现

1.在 methods里创建一个初始化websocket的函数

initWebSocket(){ //初始化weosocket
        const $vm = this
        let ws = new WebSocket('ws://10.113.5.246:8080/chaintWMS/websocket');  //这里new 一个WebSocket对象将连接地址传入(这个连接地址很重要,很多情况连接不上就是连接地址没用写对)
         ws.onopen = () => {
          // Web Socket 已连接上,使用 send() 方法发送数据
          console.log('发送数据中。。。')
          ws.send('你好')
          console.log('数据发送完成。')
        }
        ws.onmessage = evt => {    //后端发来的消息接收(注意数据放在evt的data中并且是个JSON字符串,需要parse成JSON对象去使用)
          let hhlist = JSON.parse(evt.data);

 //具体业务逻辑
 
		 $vm.$set($vm.panelData,"rsumhh",psu) //这里是 vue给一些已经改变了的图表数据后,显示内容没用变化时用的。(直接用=去赋值界面的显示是不会变的 Echarts 图表就是需要用 set去改变值的变化)
          console.log('数据已接收...')

        }
        ws.onclose = function () {
          // 关闭 websocket
          console.log('连接已关闭...')
        }
        // 路由跳转时结束websocket链接
        this.$router.afterEach(function () {
          ws.close()
        })
    }

2.然后在created()中添加方法的调用

 created() {
      //页面刚进入时开启长连接
      this.initWebSocket()
  },

Echart动态拿数据时不显示原因(加载顺序问题)

1.需要在后端拿数据时,进行异步时,需要在拿完数据之后 在调用 this.initChart() 初始化的方法(在去加载图表信息)

getWarehouseInventory() {
      const $vm = this
      getWarehouseInventory().then(res => {
        if (res.code === 200) {
          for (var i in res.warehouseinventory) {
            $vm.xvalue.push(res.warehouseinventory[i].WarehouseCode)
            // $vm.wnvalue.push(res.warehouseinventory[i].netweight)
            $vm.wavalue.push(res.warehouseinventory[i].Amount)
          }
          this.initChart()   //ECharts的具体实现方法
        }
      })
    }

结语

第一次写,感觉很多没用表达清楚,也就记录一下自己在开发中遇到的一些坑吧。这此的坑主要就是 VUE的赋值机制问题,直接使用 =等于去赋值并不会改变显示的值,需要用 set 去改变,还有当Echart加载时顺序的问题

你可能感兴趣的:(SpringBoot,vue,websocket,VUE,Springboot,ECharts)