From ead1d79cfe64da6a2d8966d105477b64d0851e9e Mon Sep 17 00:00:00 2001
From: lucas <xie.yan@ipsos.com>
Date: Wed, 31 Mar 2021 14:23:06 +0800
Subject: [PATCH] =?UTF-8?q?=E5=8A=A0=E5=85=A5=E5=88=97=E5=87=BA=E6=89=80?=
 =?UTF-8?q?=E6=9C=89=E7=BC=93=E5=AD=98=EF=BC=8C=E5=B9=B6=E4=B8=94=E5=8F=AF?=
 =?UTF-8?q?=E4=BB=A5=E6=B8=85=E7=A9=BA=E7=BC=93=E5=AD=98=EF=BC=8C=E4=B9=9F?=
 =?UTF-8?q?=E5=8F=AF=E4=BB=A5=E5=8D=95=E4=B8=AA=E5=88=A0=E9=99=A4=E7=BC=93?=
 =?UTF-8?q?=E5=AD=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../controller/monitor/CacheController.java   |  17 +-
 ruoyi-ui/src/api/monitor/cache.js             |  34 +-
 ruoyi-ui/src/views/monitor/cache/index.vue    | 356 ++++++++++--------
 3 files changed, 242 insertions(+), 165 deletions(-)

diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/CacheController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/CacheController.java
index fa9c623f2..6e86877f2 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/CacheController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/CacheController.java
@@ -9,9 +9,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.redis.core.RedisCallback;
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
 import com.ruoyi.common.core.domain.AjaxResult;
 import com.ruoyi.common.utils.StringUtils;
 
@@ -48,6 +46,19 @@ public class CacheController
             pieList.add(data);
         });
         result.put("commandStats", pieList);
+        result.put("allKeys", redisTemplate.keys("*"));
         return AjaxResult.success(result);
     }
+
+    @PreAuthorize("@ss.hasPermi('monitor:cache:remove')")
+    @DeleteMapping("/{key}")
+    public AjaxResult delRedisCache(@PathVariable("key") String key)
+    {
+        try {
+            redisTemplate.delete(key);
+            return AjaxResult.success();
+        } catch (Exception exception) {
+            return AjaxResult.error("删除失败,请告知管理员,说明这个错误:" + exception.getMessage());
+        }
+    }
 }
diff --git a/ruoyi-ui/src/api/monitor/cache.js b/ruoyi-ui/src/api/monitor/cache.js
index 2ffaf7a3f..7a8089117 100644
--- a/ruoyi-ui/src/api/monitor/cache.js
+++ b/ruoyi-ui/src/api/monitor/cache.js
@@ -1,9 +1,25 @@
-import request from '@/utils/request'
-
-// 查询缓存详细
-export function getCache() {
-  return request({
-    url: '/monitor/cache',
-    method: 'get'
-  })
-}
+import request from '@/utils/request'
+
+// 查询缓存详细
+export function getCache() {
+  return request({
+    url: '/monitor/cache',
+    method: 'get'
+  })
+}
+
+// 删除缓存
+export function delRedisCache(key) {
+  return request({
+    url: '/monitor/cache/'+key,
+    method: 'delete'
+  })
+}
+
+// 清空缓存
+export function clearRedisCache() {
+  return request({
+    url: '/monitor/cache/clear',
+    method: 'delete'
+  })
+}
diff --git a/ruoyi-ui/src/views/monitor/cache/index.vue b/ruoyi-ui/src/views/monitor/cache/index.vue
index 98eed22ec..c656c6d51 100644
--- a/ruoyi-ui/src/views/monitor/cache/index.vue
+++ b/ruoyi-ui/src/views/monitor/cache/index.vue
@@ -1,153 +1,203 @@
-<template>
-  <div class="app-container">
-    <el-row>
-      <el-col :span="24" class="card-box">
-        <el-card>
-          <div slot="header"><span>基本信息</span></div>
-          <div class="el-table el-table--enable-row-hover el-table--medium">
-            <table cellspacing="0" style="width: 100%">
-              <tbody>
-                <tr>
-                  <td><div class="cell">Redis版本</div></td>
-                  <td><div class="cell" v-if="cache.info">{{ cache.info.redis_version }}</div></td>
-                  <td><div class="cell">运行模式</div></td>
-                  <td><div class="cell" v-if="cache.info">{{ cache.info.redis_mode == "standalone" ? "单机" : "集群" }}</div></td>
-                  <td><div class="cell">端口</div></td>
-                  <td><div class="cell" v-if="cache.info">{{ cache.info.tcp_port }}</div></td>
-                  <td><div class="cell">客户端数</div></td>
-                  <td><div class="cell" v-if="cache.info">{{ cache.info.connected_clients }}</div></td>
-                </tr>
-                <tr>
-                  <td><div class="cell">运行时间(天)</div></td>
-                  <td><div class="cell" v-if="cache.info">{{ cache.info.uptime_in_days }}</div></td>
-                  <td><div class="cell">使用内存</div></td>
-                  <td><div class="cell" v-if="cache.info">{{ cache.info.used_memory_human }}</div></td>
-                  <td><div class="cell">使用CPU</div></td>
-                  <td><div class="cell" v-if="cache.info">{{ parseFloat(cache.info.used_cpu_user_children).toFixed(2) }}</div></td>
-                  <td><div class="cell">内存配置</div></td>
-                  <td><div class="cell" v-if="cache.info">{{ cache.info.maxmemory_human }}</div></td>
-                </tr>
-                <tr>
-                  <td><div class="cell">AOF是否开启</div></td>
-                  <td><div class="cell" v-if="cache.info">{{ cache.info.aof_enabled == "0" ? "否" : "是" }}</div></td>
-                  <td><div class="cell">RDB是否成功</div></td>
-                  <td><div class="cell" v-if="cache.info">{{ cache.info.rdb_last_bgsave_status }}</div></td>
-                  <td><div class="cell">Key数量</div></td>
-                  <td><div class="cell" v-if="cache.dbSize">{{ cache.dbSize }} </div></td>
-                  <td><div class="cell">网络入口/出口</div></td>
-                  <td><div class="cell" v-if="cache.info">{{ cache.info.instantaneous_input_kbps }}kps/{{cache.info.instantaneous_output_kbps}}kps</div></td>
-                </tr>
-              </tbody>
-            </table>
-          </div>
-        </el-card>
-      </el-col>
-
-      <el-col :span="12" class="card-box">
-        <el-card>
-          <div slot="header"><span>命令统计</span></div>
-          <div class="el-table el-table--enable-row-hover el-table--medium">
-            <div ref="commandstats" style="height: 420px" />
-          </div>
-        </el-card>
-      </el-col>
-
-      <el-col :span="12" class="card-box">
-        <el-card>
-          <div slot="header">
-            <span>内存信息</span>
-          </div>
-          <div class="el-table el-table--enable-row-hover el-table--medium">
-            <div ref="usedmemory" style="height: 420px" />
-          </div>
-        </el-card>
-      </el-col>
-    </el-row>
-  </div>
-</template>
-
-<script>
-import { getCache } from "@/api/monitor/cache";
-import echarts from "echarts";
-
-export default {
-  name: "Server",
-  data() {
-    return {
-      // 加载层信息
-      loading: [],
-      // 统计命令信息
-      commandstats: null,
-      // 使用内存
-      usedmemory: null,
-      // cache信息
-      cache: [],
-    };
-  },
-  created() {
-    this.getList();
-    this.openLoading();
-  },
-  methods: {
-    /** 查缓存询信息 */
-    getList() {
-      getCache().then((response) => {
-        this.cache = response.data;
-        this.loading.close();
-
-        this.commandstats = echarts.init(this.$refs.commandstats, "macarons");
-        this.commandstats.setOption({
-          tooltip: {
-            trigger: "item",
-            formatter: "{a} <br/>{b} : {c} ({d}%)",
-          },
-          series: [
-            {
-              name: "命令",
-              type: "pie",
-              roseType: "radius",
-              radius: [15, 95],
-              center: ["50%", "38%"],
-              data: response.data.commandStats,
-              animationEasing: "cubicInOut",
-              animationDuration: 1000,
-            },
-          ],
-        });
-        this.usedmemory = echarts.init(this.$refs.usedmemory, "macarons");
-        this.usedmemory.setOption({
-          tooltip: {
-            formatter: "{b} <br/>{a} : " + this.cache.info.used_memory_human,
-          },
-          series: [
-            {
-              name: "峰值",
-              type: "gauge",
-              min: 0,
-              max: 1000,
-              detail: {
-                formatter: this.cache.info.used_memory_human,
-              },
-              data: [
-                {
-                  value: parseFloat(this.cache.info.used_memory_human),
-                  name: "内存消耗",
-                },
-              ],
-            },
-          ],
-        });
-      });
-    },
-    // 打开加载层
-    openLoading() {
-      this.loading = this.$loading({
-        lock: true,
-        text: "拼命读取中",
-        spinner: "el-icon-loading",
-        background: "rgba(0, 0, 0, 0.7)",
-      });
-    },
-  },
-};
-</script>
+<template>
+  <div class="app-container">
+    <el-row>
+      <el-col :span="24" class="card-box">
+        <el-card>
+          <div slot="header"><span>基本信息</span></div>
+          <div class="el-table el-table--enable-row-hover el-table--medium">
+            <table cellspacing="0" style="width: 100%">
+              <tbody>
+                <tr>
+                  <td><div class="cell">Redis版本</div></td>
+                  <td><div class="cell" v-if="cache.info">{{ cache.info.redis_version }}</div></td>
+                  <td><div class="cell">运行模式</div></td>
+                  <td><div class="cell" v-if="cache.info">{{ cache.info.redis_mode == "standalone" ? "单机" : "集群" }}</div></td>
+                  <td><div class="cell">端口</div></td>
+                  <td><div class="cell" v-if="cache.info">{{ cache.info.tcp_port }}</div></td>
+                  <td><div class="cell">客户端数</div></td>
+                  <td><div class="cell" v-if="cache.info">{{ cache.info.connected_clients }}</div></td>
+                </tr>
+                <tr>
+                  <td><div class="cell">运行时间(天)</div></td>
+                  <td><div class="cell" v-if="cache.info">{{ cache.info.uptime_in_days }}</div></td>
+                  <td><div class="cell">使用内存</div></td>
+                  <td><div class="cell" v-if="cache.info">{{ cache.info.used_memory_human }}</div></td>
+                  <td><div class="cell">使用CPU</div></td>
+                  <td><div class="cell" v-if="cache.info">{{ parseFloat(cache.info.used_cpu_user_children).toFixed(2) }}</div></td>
+                  <td><div class="cell">内存配置</div></td>
+                  <td><div class="cell" v-if="cache.info">{{ cache.info.maxmemory_human }}</div></td>
+                </tr>
+                <tr>
+                  <td><div class="cell">AOF是否开启</div></td>
+                  <td><div class="cell" v-if="cache.info">{{ cache.info.aof_enabled == "0" ? "否" : "是" }}</div></td>
+                  <td><div class="cell">RDB是否成功</div></td>
+                  <td><div class="cell" v-if="cache.info">{{ cache.info.rdb_last_bgsave_status }}</div></td>
+                  <td><div class="cell">Key数量</div></td>
+                  <td><div class="cell" v-if="cache.dbSize">{{ cache.dbSize }} </div></td>
+                  <td><div class="cell">网络入口/出口</div></td>
+                  <td><div class="cell" v-if="cache.info">{{ cache.info.instantaneous_input_kbps }}kps/{{cache.info.instantaneous_output_kbps}}kps</div></td>
+                </tr>
+              </tbody>
+            </table>
+          </div>
+        </el-card>
+      </el-col>
+
+      <el-col :span="12" class="card-box">
+        <el-card>
+          <div slot="header"><span>命令统计</span></div>
+          <div class="el-table el-table--enable-row-hover el-table--medium">
+            <div ref="commandstats" style="height: 420px" />
+          </div>
+        </el-card>
+      </el-col>
+
+      <el-col :span="12" class="card-box">
+        <el-card>
+          <div slot="header">
+            <span>内存信息</span>
+          </div>
+          <div class="el-table el-table--enable-row-hover el-table--medium">
+            <div ref="usedmemory" style="height: 420px" />
+          </div>
+        </el-card>
+      </el-col>
+    </el-row>
+    <el-row>
+      <el-col :xs="8" :sm="8" :md="8" :lg="6" :xl="3" v-for="key in cache.allKeys" :key="key" >
+        <div  class="grid-content bg-purple" style="width: 95%; display: flex; justify-content: space-between; margin-bottom: 10px; font-size: 16px;">
+          <div style="width: 10%; line-height: 36px; text-align: center;">
+            <i class="el-icon-cpu" />
+          </div>
+          <div :title="key" style="line-height: 36px; width: 80%; height: 36px; overflow: hidden; text-overflow:ellipsis; white-space:nowrap;">
+            <label>{{ key }}</label>
+          </div>
+          <div style="width: 10%; line-height: 36px; cursor: pointer;" @click="delCache(key)">
+            <i class="el-icon-delete-solid" />
+          </div>
+        </div>
+      </el-col>
+    </el-row>
+    <el-row>
+      <el-alert
+        title="点击清空缓存,是把当前系统所用的整个index缓存库,直接清空,该操作不可逆,请慎重操作!"
+        type="error">
+      </el-alert>
+    </el-row>
+    <el-row>
+      <el-button type="danger" icon="el-icon-delete" @click="clearCache" style="float: right" round>清空缓存</el-button>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { getCache } from "@/api/monitor/cache";
+import echarts from "echarts";
+
+export default {
+  name: "Server",
+  data() {
+    return {
+      // 加载层信息
+      loading: [],
+      // 统计命令信息
+      commandstats: null,
+      // 使用内存
+      usedmemory: null,
+      // cache信息
+      cache: [],
+    };
+  },
+  created() {
+    this.getList();
+    this.openLoading();
+  },
+  methods: {
+    /** 查缓存询信息 */
+    getList() {
+      getCache().then((response) => {
+        this.cache = response.data;
+        this.loading.close();
+
+        this.commandstats = echarts.init(this.$refs.commandstats, "macarons");
+        this.commandstats.setOption({
+          tooltip: {
+            trigger: "item",
+            formatter: "{a} <br/>{b} : {c} ({d}%)",
+          },
+          series: [
+            {
+              name: "命令",
+              type: "pie",
+              roseType: "radius",
+              radius: [15, 95],
+              center: ["50%", "38%"],
+              data: response.data.commandStats,
+              animationEasing: "cubicInOut",
+              animationDuration: 1000,
+            },
+          ],
+        });
+        this.usedmemory = echarts.init(this.$refs.usedmemory, "macarons");
+        this.usedmemory.setOption({
+          tooltip: {
+            formatter: "{b} <br/>{a} : " + this.cache.info.used_memory_human,
+          },
+          series: [
+            {
+              name: "峰值",
+              type: "gauge",
+              min: 0,
+              max: 1000,
+              detail: {
+                formatter: this.cache.info.used_memory_human,
+              },
+              data: [
+                {
+                  value: parseFloat(this.cache.info.used_memory_human),
+                  name: "内存消耗",
+                },
+              ],
+            },
+          ],
+        });
+      });
+    },
+    // 打开加载层
+    openLoading() {
+      this.loading = this.$loading({
+        lock: true,
+        text: "拼命读取中",
+        spinner: "el-icon-loading",
+        background: "rgba(0, 0, 0, 0.7)",
+      });
+    },
+    // 删除缓存
+    delCache(key) {
+      this.$confirm('是否确认删除缓存"' + key + '"的数据项?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(function() {
+        return delRedisCache(key);
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("删除成功");
+      })
+    },
+    // 删除缓存
+    clearCache() {
+      this.$confirm('是否确认清空缓存? 该操作不可逆,请慎重操作!', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(function() {
+        return clearRedisCache();
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("删除成功");
+      })
+    }
+  },
+};
+</script>