如何做一個zookeeper可視化項目

如何做一個zookeeper可視化項目

author: huifer

gir_repo: https://github.com/huifer/zk-view

技術選型

  • 後端技術
    • spring boot
    • curator-framework
  • 前端技術
    • vue
    • element-ui

選型說明:

  • spring boot 快速搭建 rest-api
  • curator-framework 與zookeeper 進行交互的jar
  • vue element-ui 前端展示

實現

  • curator-framework 的使用具體查看: CSDN
  • zookeeper 的數據存儲是樹結構存儲, 因此選擇 element-ui 的樹形控件比較合理. element-ui-tree

創建樹結構

  • 選好了數據格式接下來就是處理出這份數據了. 創建出這個樹結構
  • 定義樹結構的 java 對象
  @Data
  @AllArgsConstructor
  public static class Hc {

    private String path;
    private String showName;
    private List<Hc> child;

  }
  • 造樹的方法
   private static List<Hc> child(List<String> strings, String path) {
     List<Hc> hc = new ArrayList<>();
 
     for (String string : strings) {
       if (path.equals("/")) {
         hc.add(new Hc(path + string, string, null));
       } else {
 
         Hc hc1 = new Hc(path + "/" + string, string, null);
         hc.add(hc1);
       }
     }
     return hc;
   }
  public static void calcTree(CuratorFramework curatorFramework, String path, Hc c) throws Exception {
    List<String> strings = curatorFramework.getChildren().forPath(path);
    c.setPath(path);
    c.setChild(child(strings, path));

    for (Hc hc : c.getChild()) {
      calcTree(curatorFramework, hc.getPath(), hc);
    }

  }


  public Hc tree() throws Exception {

    CuratorFramework build = CuratorFrameworkFactory.builder().connectString(ZkConfig.getIP_PORT())
        .sessionTimeoutMs(30000)
        .retryPolicy(new ExponentialBackoffRetry(1000, 10)).build();
    build.start();
    Hc hc = new Hc(null, "/", null);
    calcTree(build, "/", hc);
    build.close();
    return hc;
  }
  • 通過這樣的方式我們就可以獲取這個樹結構了.
{"path":"/","showName":"/","child":[{"path":"/a","showName":"a","child":[{"path":"/a/a_1","showName":"a_1","child":[{"path":"/a/a_1/a_1_1","showName":"a_1_1","child":[]}]},{"path":"/a/a_2","showName":"a_2","child":[]}]},{"path":"/temp","showName":"temp","child":[]},{"path":"/zookeeper","showName":"zookeeper","child":[{"path":"/zookeeper/config","showName":"config","child":[]},{"path":"/zookeeper/quota","showName":"quota","child":[]}]},{"path":"/d","showName":"d","child":[]}]}

單個節點的信息

  • 節點信息再次作者定義三個信息
    1. stat: 狀態
    2. data: 數據
    3. type: 節點類型
      1. 持久化節點
      2. 臨時節點
@Data
@AllArgsConstructor
@NoArgsConstructor
public class NodeInfo {

  private Stat stat;
  private String data;

  /**
   * 持久化節點,臨時節點
   */
  private String type;

}
  • 獲取信息的方法
  public Object info(String path) throws Exception {
    CuratorFramework build = CuratorFrameworkFactory.builder().connectString(ZkConfig.getIP_PORT())
        .sessionTimeoutMs(30000)
        .retryPolicy(new ExponentialBackoffRetry(1000, 10)).build();
    build.start();
    // 數據
    Stat stat = new Stat();
    byte[] bytes = build.getData().storingStatIn(stat).forPath(path);

    String data;
    if (bytes != null && bytes.length > 0) {

      data = new String(bytes);
    } else {
      data = "";
    }
    build.close();
    return new NodeInfo(stat, data, nodeType(stat));
  }
  • controller 就不在此進行貼代碼了有興趣的可以查看zk-view

前端展示

  • 前端不是很熟練,就直接貼一貼代碼就過了. 後續各位如果需要做創建節點的操作可以自行開發.
<!doctype html>
<html lang="zh">
<head>
  <meta charset="UTF-8">
  <meta name="viewport"
        content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>zk-view</title>
  <script src="https://cdn.jsdelivr.net/npm/vue"></script>
  <!-- 引入樣式 -->
  <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
  <!-- 引入組件庫 -->
  <script src="https://unpkg.com/element-ui/lib/index.js"></script>
  <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="app">
  <el-col :span="12">
    <el-tree width="200px" :data="og" :props="defaultProps" @node-click="handleNodeClick"></el-tree>
  </el-col>

  <div>
    <el-col :span="12">
      <h3>狀態</h3>
      {{message}}
      
      <h3>數據</h3>

      <el-input
          type="textarea"
          :rows="2"
          placeholder=""
          v-model="node_info.data">
      </el-input>

      <span>節點類型: {{node_type}}</span>

    </el-col>


  </div>
</div>

</body>

<script>

  var app = new Vue({
    el: '#app',
    data: {
      radio: '1',
      message: "hello",
      node_type: "",

      og: [],
      defaultProps: {
        children: 'child',
        label: 'showName'
      },
      node_info: {},
    },
    methods: {
      handleNodeClick: function (data) {
        console.log("當前選中的節點是", data.path)
        axios.get("/node/get/info", {params: {path: data.path}}).then(response => {
          this.node_info = response.data.data
          this.message = response.data.data.stat;
          this.node_type = response.data.data.type
        }).catch(function (error) {
          console.log(error);
        });

      },
      tree: function () {
        axios.get('/node/tree').then(response => {
          console.log("ogog");
          console.log(this.og);
          this.og = [response.data.data];
          console.log(this.og);

        }).catch(function (error) {
          console.log(error);
        });

      }
    },
    created: function () {
      this.tree();
      this.node_info = {
        state: {
          czxid: 2,
          mzxid: 0,
          ctime: 0,
          mtime: 0,
          version: 0,
          cversion: 0,
          aversion: 0,
          ephemeralOwner: 0,
          dataLength: 0,
          numChildren: 0,
          pzxid: 0
        },
        data: "數據",
        type: "臨時節點"
      }

    }
  })


</script>
</html>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章