Commit 2372c25e8d80dd3768c060dfe111905e3a0d756d

Authored by YunaiV
1 parent a0f7f0ff

完善 Redis 缓存的查询

yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/redis/RedisController.java
1 1 package cn.iocoder.yudao.module.infra.controller.admin.redis;
2 2  
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.util.StrUtil;
3 5 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 6 import cn.iocoder.yudao.framework.redis.core.RedisKeyDefine;
5 7 import cn.iocoder.yudao.framework.redis.core.RedisKeyRegistry;
6   -import cn.iocoder.yudao.module.infra.controller.admin.redis.vo.RedisKeyRespVO;
  8 +import cn.iocoder.yudao.module.infra.controller.admin.redis.vo.RedisKeyDefineRespVO;
7 9 import cn.iocoder.yudao.module.infra.controller.admin.redis.vo.RedisKeyValueRespVO;
8 10 import cn.iocoder.yudao.module.infra.controller.admin.redis.vo.RedisMonitorRespVO;
9 11 import cn.iocoder.yudao.module.infra.convert.redis.RedisConvert;
10 12 import io.swagger.annotations.Api;
  13 +import io.swagger.annotations.ApiImplicitParam;
11 14 import io.swagger.annotations.ApiOperation;
12 15 import org.springframework.data.redis.connection.RedisServerCommands;
13 16 import org.springframework.data.redis.core.Cursor;
... ... @@ -18,11 +21,7 @@ import org.springframework.security.access.prepost.PreAuthorize;
18 21 import org.springframework.web.bind.annotation.*;
19 22  
20 23 import javax.annotation.Resource;
21   -import java.nio.charset.StandardCharsets;
22   -import java.util.HashSet;
23   -import java.util.List;
24   -import java.util.Properties;
25   -import java.util.Set;
  24 +import java.util.*;
26 25  
27 26 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
28 27  
... ... @@ -48,69 +47,66 @@ public class RedisController {
48 47 return success(RedisConvert.INSTANCE.build(info, dbSize, commandStats));
49 48 }
50 49  
51   - @GetMapping("/get-key-list")
  50 + @GetMapping("/get-key-define-list")
52 51 @ApiOperation("获得 Redis Key 模板列表")
53 52 @PreAuthorize("@ss.hasPermission('infra:redis:get-key-list')")
54   - public CommonResult<List<RedisKeyRespVO>> getKeyList() {
  53 + public CommonResult<List<RedisKeyDefineRespVO>> getKeyDefineList() {
55 54 List<RedisKeyDefine> keyDefines = RedisKeyRegistry.list();
56 55 return success(RedisConvert.INSTANCE.convertList(keyDefines));
57 56 }
58 57  
59   - @GetMapping("/get-key-Defines")
  58 + @GetMapping("/get-key-list")
60 59 @ApiOperation("获得 Redis keys 键名列表")
  60 + @ApiImplicitParam(name = "keyTemplate", value = "Redis Key 定义", example = "true", dataTypeClass = String.class)
61 61 @PreAuthorize("@ss.hasPermission('infra:redis:get-key-list')")
62   - public CommonResult<Set<String>> getKeyDefines(@RequestParam("keyDefine") String keyDefine) {
63   - Set<String> keys = new HashSet<>();
64   - stringRedisTemplate.execute((RedisCallback<Set<String>>) connection -> {
65   - try (Cursor<byte[]> cursor = connection.scan(ScanOptions.scanOptions()
66   - .match(keyDefine + "*")
67   - .count(Integer.MAX_VALUE).build())) {
68   - while (cursor.hasNext()) {
69   - keys.add(new String(cursor.next(), StandardCharsets.UTF_8));
70   - }
  62 + public CommonResult<Set<String>> getKeyDefineList(@RequestParam("keyTemplate") String keyTemplate) {
  63 + return success(getKeyDefineList0(keyTemplate));
  64 + }
  65 +
  66 + private Set<String> getKeyDefineList0(String keyTemplate) {
  67 + // key 格式化
  68 + String key = StrUtil.replace(keyTemplate, "%[s|c|b|d|x|o|f|a|e|g]", parameter -> "*");
  69 + // scan 扫描 key
  70 + Set<String> keys = new LinkedHashSet<>();
  71 + stringRedisTemplate.execute((RedisCallback<Set<String>>) connection -> {
  72 + try (Cursor<byte[]> cursor = connection.scan(ScanOptions.scanOptions().match(key).count(100).build())) {
  73 + cursor.forEachRemaining(value -> keys.add(StrUtil.utf8Str(value)));
71 74 } catch (Exception e) {
72 75 throw new RuntimeException(e);
73 76 }
74 77 return keys;
75 78 });
76   - return success(keys);
77   - }
78   -
79   - @DeleteMapping("/delete-key-defines")
80   - @ApiOperation("删除 Redis Key 根据模板")
81   - @PreAuthorize("@ss.hasPermission('infra:redis:get-key-list')")
82   - public CommonResult<Boolean> deleteKeyDefines(@RequestParam("keyDefine") String keyDefine) {
83   - Set<String> keys = stringRedisTemplate.keys(keyDefine + "*");
84   - if(keys != null && keys.isEmpty()){
85   - stringRedisTemplate.delete(keys);
86   - }
87   - return success(Boolean.TRUE);
  79 + return keys;
88 80 }
89 81  
90 82 @GetMapping("/get-key-value")
91 83 @ApiOperation("获得 Redis key 内容")
  84 + @ApiImplicitParam(name = "key", value = "Redis Key", example = "oauth2_access_token:233", dataTypeClass = String.class)
92 85 @PreAuthorize("@ss.hasPermission('infra:redis:get-key-list')")
93   - public CommonResult<RedisKeyValueRespVO> getKeyValue(@RequestParam("keyDefine") String keyDefine, @RequestParam("cacheKey") String cacheKey) {
94   - String cacheValue = stringRedisTemplate.opsForValue().get(cacheKey);
95   - return success(RedisKeyValueRespVO.of(keyDefine, cacheKey, cacheValue));
  86 + public CommonResult<RedisKeyValueRespVO> getKeyValue(@RequestParam("key") String key) {
  87 + String value = stringRedisTemplate.opsForValue().get(key);
  88 + return success(new RedisKeyValueRespVO(key, value));
96 89 }
97 90  
98   - @DeleteMapping("/delete-key-value")
99   - @ApiOperation("删除 Redis Key 根据key")
  91 + @DeleteMapping("/delete-key")
  92 + @ApiOperation("删除 Redis Key")
  93 + @ApiImplicitParam(name = "key", value = "Redis Key", example = "oauth2_access_token:233", dataTypeClass = String.class)
100 94 @PreAuthorize("@ss.hasPermission('infra:redis:get-key-list')")
101   - public CommonResult<Boolean> deleteKeyValue(@RequestParam("cacheKey") String cacheKey) {
102   - stringRedisTemplate.delete(cacheKey);
  95 + public CommonResult<Boolean> deleteKey(@RequestParam("key") String key) {
  96 + stringRedisTemplate.delete(key);
103 97 return success(Boolean.TRUE);
104 98 }
105 99  
106   - @DeleteMapping("/delete-cache-all")
107   - @ApiOperation(value="删除 所有缓存", notes="不使用该接口")
  100 + @DeleteMapping("/delete-keys")
  101 + @ApiOperation("删除 Redis Key 根据模板")
  102 + @ApiImplicitParam(name = "keyTemplate", value = "Redis Key 定义", example = "true", dataTypeClass = String.class)
108 103 @PreAuthorize("@ss.hasPermission('infra:redis:get-key-list')")
109   - public CommonResult<Boolean> deleteCacheAll() {
110   - return success(stringRedisTemplate.execute((RedisCallback<Boolean>) connection -> {
111   - connection.flushAll();
112   - return Boolean.TRUE;
113   - }));
  104 + public CommonResult<Boolean> deleteKeys(@RequestParam("keyTemplate") String keyTemplate) {
  105 + Set<String> keys = getKeyDefineList0(keyTemplate);
  106 + if (CollUtil.isNotEmpty(keys)) {
  107 + stringRedisTemplate.delete(keys);
  108 + }
  109 + return success(Boolean.TRUE);
114 110 }
115 111  
116 112 }
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/redis/vo/RedisKeyRespVO.java renamed to yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/redis/vo/RedisKeyDefineRespVO.java
... ... @@ -13,9 +13,9 @@ import java.time.Duration;
13 13 @Data
14 14 @Builder
15 15 @AllArgsConstructor
16   -public class RedisKeyRespVO {
  16 +public class RedisKeyDefineRespVO {
17 17  
18   - @ApiModelProperty(value = "login_user:%s", required = true, example = "String")
  18 + @ApiModelProperty(value = "Key 模板", required = true, example = "login_user:%s")
19 19 private String keyTemplate;
20 20  
21 21 @ApiModelProperty(value = "Key 类型的枚举", required = true, example = "String")
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/redis/vo/RedisKeyValueRespVO.java
... ... @@ -3,32 +3,17 @@ package cn.iocoder.yudao.module.infra.controller.admin.redis.vo;
3 3 import io.swagger.annotations.ApiModel;
4 4 import io.swagger.annotations.ApiModelProperty;
5 5 import lombok.AllArgsConstructor;
6   -import lombok.Builder;
7 6 import lombok.Data;
8   -import org.apache.commons.lang3.StringUtils;
9 7  
10   -@ApiModel("管理后台 - Redis Key Value onse VO")
  8 +@ApiModel("管理后台 - 单个 Redis Key Value Response VO")
11 9 @Data
12   -@Builder
13 10 @AllArgsConstructor
14 11 public class RedisKeyValueRespVO {
15 12  
16   - @ApiModelProperty(value = "oauth2_access_token:%s", required = true, example = "String")
17   - private String keyTemplate;
18   -
19 13 @ApiModelProperty(value = "c5f6990767804a928f4bb96ca249febf", required = true, example = "String")
20 14 private String key;
21 15  
22 16 @ApiModelProperty(required = true, example = "String")
23 17 private String value;
24 18  
25   - public static RedisKeyValueRespVO of(String keyTemplate, String key, String value){
26   - return RedisKeyValueRespVO.builder()
27   - .keyTemplate(StringUtils.replace(keyTemplate, ":", ""))
28   - .key(StringUtils.replace(key, keyTemplate, ""))
29   - .value(value)
30   - .build();
31   - }
32   -
33   -
34 19 }
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/redis/RedisConvert.java
... ... @@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.infra.convert.redis;
2 2  
3 3 import cn.hutool.core.util.StrUtil;
4 4 import cn.iocoder.yudao.framework.redis.core.RedisKeyDefine;
5   -import cn.iocoder.yudao.module.infra.controller.admin.redis.vo.RedisKeyRespVO;
  5 +import cn.iocoder.yudao.module.infra.controller.admin.redis.vo.RedisKeyDefineRespVO;
6 6 import cn.iocoder.yudao.module.infra.controller.admin.redis.vo.RedisMonitorRespVO;
7 7 import org.mapstruct.Mapper;
8 8 import org.mapstruct.factory.Mappers;
... ... @@ -29,6 +29,6 @@ public interface RedisConvert {
29 29 return respVO;
30 30 }
31 31  
32   - List<RedisKeyRespVO> convertList(List<RedisKeyDefine> list);
  32 + List<RedisKeyDefineRespVO> convertList(List<RedisKeyDefine> list);
33 33  
34 34 }
... ...
yudao-ui-admin/src/api/infra/redis.js
... ... @@ -9,34 +9,46 @@ export function getCache() {
9 9 }
10 10  
11 11 // 获取模块
12   -export function getKeyList() {
  12 +export function getKeyDefineList() {
13 13 return request({
14   - url: '/infra/redis/get-key-list',
  14 + url: '/infra/redis/get-key-define-list',
15 15 method: 'get'
16 16 })
17 17 }
18 18  
19 19 // 获取键名列表
20   -export function getKeyDefines(keyDefine) {
  20 +export function getKeyList(keyTemplate) {
21 21 return request({
22   - url: '/infra/redis/get-key-Defines?keyDefine=' + keyDefine,
23   - method: 'get'
  22 + url: '/infra/redis/get-key-list',
  23 + method: 'get',
  24 + params: {
  25 + keyTemplate
  26 + }
24 27 })
25 28 }
26 29  
27 30 // 获取缓存内容
28   -export function getKeyValue(keyDefine, key) {
  31 +export function getKeyValue(key) {
29 32 return request({
30   - url: '/infra/redis/get-key-value?keyDefine=' + keyDefine + "&cacheKey=" + key,
  33 + url: '/infra/redis/get-key-value?key=' + key,
31 34 method: 'get'
32 35 })
33 36 }
34 37  
35 38 // 根据键名删除缓存
36   -export function deleteKeyValue(key) {
  39 +export function deleteKey(key) {
37 40 return request({
38   - url: '/infra/redis/delete-key-value?cacheKey=' + key,
  41 + url: '/infra/redis/delete-key?key=' + key,
39 42 method: 'delete'
40 43 })
41 44 }
42 45  
  46 +export function deleteKeys(keyTemplate) {
  47 + return request({
  48 + url: '/infra/redis/delete-keys?',
  49 + method: 'delete',
  50 + params: {
  51 + keyTemplate
  52 + }
  53 + })
  54 +}
... ...
yudao-ui-admin/src/views/infra/redis/index.vue
... ... @@ -31,7 +31,7 @@
31 31 </tr>
32 32 <tr>
33 33 <td><div class="cell">AOF是否开启</div></td>
34   - <td><div class="cell" v-if="cache.info">{{ cache.info.aof_enabled == "0" ? "否" : "是" }}</div></td>
  34 + <td><div class="cell" v-if="cache.info">{{ cache.info.aof_enabled === "0" ? "否" : "是" }}</div></td>
35 35 <td><div class="cell">RDB是否成功</div></td>
36 36 <td><div class="cell" v-if="cache.info">{{ cache.info.rdb_last_bgsave_status }}</div></td>
37 37 <td><div class="cell">Key数量</div></td>
... ... @@ -66,12 +66,7 @@
66 66 </el-col>
67 67 </el-row>
68 68  
69   - <el-table
70   - v-loading="keyListLoad"
71   - :data="keyList"
72   - row-key="id"
73   - @row-click="openCacheInfo"
74   - >
  69 + <el-table v-loading="keyDefineListLoad" :data="keyDefineList" row-key="id" @row-click="openKeyTemplate">
75 70 <el-table-column prop="keyTemplate" label="Key 模板" width="200" />
76 71 <el-table-column prop="keyType" label="Key 类型" width="100" />
77 72 <el-table-column prop="valueType" label="Value 类型" />
... ... @@ -90,92 +85,44 @@
90 85 </el-table>
91 86  
92 87 <!-- 缓存模块信息框 -->
93   - <el-dialog
94   - :title="keyTemplate + '模块'"
95   - :visible.sync="open"
96   - width="60vw"
97   - append-to-body
98   - >
  88 + <el-dialog :title="keyTemplate + ' 模板'" :visible.sync="open" width="70vw" append-to-body>
99 89 <el-row :gutter="10">
100   - <el-col :span="10" class="card-box">
101   - <el-card style="height: 70vh">
  90 + <el-col :span="14" class="card-box">
  91 + <el-card style="height: 70vh; overflow: scroll">
102 92 <div slot="header">
103 93 <span>键名列表</span>
104   - <el-button
105   - style="float: right; padding: 3px 0"
106   - type="text"
107   - icon="el-icon-refresh-right"
108   - @click="refreshCacheKeys"
109   - ></el-button>
  94 + <el-button style="float: right; padding: 3px 0" type="text" icon="el-icon-refresh-right" @click="refreshKeys" />
110 95 </div>
111   - <el-table
112   - :data="cachekeys"
113   - style="width: 100%"
114   - @row-click="handleCacheValue"
115   - >
116   - <el-table-column
117   - label="序号"
118   - width="60"
119   - type="index"
120   - ></el-table-column>
121   - <el-table-column
122   - label="缓存键名"
123   - align="center"
124   - :show-overflow-tooltip="true"
125   - :formatter="keyFormatter"
126   - >
  96 + <el-table :data="cacheKeys" style="width: 100%" @row-click="handleKeyValue">
  97 + <el-table-column label="缓存键名" align="center" :show-overflow-tooltip="true">
  98 + <template slot-scope="scope">{{ scope.row }}</template>
127 99 </el-table-column>
128   - <el-table-column
129   - label="操作"
130   - width="60"
131   - align="center"
132   - class-name="small-padding fixed-width"
133   - >
  100 + <el-table-column label="操作" width="60" align="center" class-name="small-padding fixed-width">
134 101 <template slot-scope="scope">
135   - <el-button
136   - size="mini"
137   - type="text"
138   - icon="el-icon-delete"
139   - @click="handleClearCacheKey(scope.row)"
140   - ></el-button>
  102 + <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDeleteKey(scope.row)" />
141 103 </template>
142 104 </el-table-column>
143 105 </el-table>
144 106 </el-card>
145 107 </el-col>
146 108  
147   - <el-col :span="14">
  109 + <el-col :span="10">
148 110 <el-card :bordered="false" style="height: 70vh">
149 111 <div slot="header">
150 112 <span>缓存内容</span>
151   - <!-- <el-button
152   - style="float: right; padding: 3px 0"
153   - type="text"
154   - icon="el-icon-refresh-right"
155   - @click="handleClearCacheAll()"
156   - >清理全部</el-button>
157   - -->
  113 + <el-button style="float: right; padding: 3px 0" type="text" icon="el-icon-refresh-right"
  114 + @click="handleDeleteKeys(keyTemplate)">清理全部</el-button>
158 115 </div>
159 116 <el-form :model="cacheForm">
160 117 <el-row :gutter="32">
161 118 <el-col :offset="1" :span="22">
162   - <el-form-item label="缓存名称:" prop="keyTemplate">
163   - <el-input v-model="cacheForm.keyTemplate" :readOnly="true" />
164   - </el-form-item>
165   - </el-col>
166   - <el-col :offset="1" :span="22">
167 119 <el-form-item label="缓存键名:" prop="key">
168 120 <el-input v-model="cacheForm.key" :readOnly="true" />
169 121 </el-form-item>
170 122 </el-col>
171 123 <el-col :offset="1" :span="22">
172 124 <el-form-item label="缓存内容:" prop="value">
173   - <el-input
174   - v-model="cacheForm.value"
175   - type="textarea"
176   - :rows="12"
177   - :readOnly="true"
178   - />
  125 + <el-input v-model="cacheForm.value" type="textarea" :rows="12" :readOnly="true"/>
179 126 </el-form-item>
180 127 </el-col>
181 128 </el-row>
... ... @@ -188,7 +135,7 @@
188 135 </template>
189 136  
190 137 <script>
191   -import { getCache, getKeyList, getKeyDefines, getKeyValue, deleteKeyValue } from "@/api/infra/redis";
  138 +import {getCache, getKeyDefineList, getKeyList, getKeyValue, deleteKey, deleteKeys} from "@/api/infra/redis";
192 139 import echarts from "echarts";
193 140  
194 141 export default {
... ... @@ -202,12 +149,12 @@ export default {
202 149 // cache 信息
203 150 cache: [],
204 151 // key 列表
205   - keyListLoad: true,
206   - keyList: [],
  152 + keyDefineListLoad: true,
  153 + keyDefineList: [],
207 154 // 模块弹出框
208 155 open: false,
209 156 keyTemplate: "",
210   - cachekeys: [],
  157 + cacheKeys: [],
211 158 cacheForm: {}
212 159 };
213 160 },
... ... @@ -275,9 +222,9 @@ export default {
275 222 });
276 223  
277 224 // 查询 Redis Key 列表
278   - getKeyList().then(response => {
279   - this.keyList = response.data;
280   - this.keyListLoad = false;
  225 + getKeyDefineList().then(response => {
  226 + this.keyDefineList = response.data;
  227 + this.keyDefineListLoad = false;
281 228 });
282 229 },
283 230  
... ... @@ -287,46 +234,45 @@ export default {
287 234 },
288 235  
289 236 // 打开缓存弹窗
290   - openCacheInfo (e) {
  237 + openKeyTemplate (keyDefine) {
291 238 this.open = true;
292   - let keyDefine = e.keyTemplate.substring(0, e.keyTemplate.length - 2);
293   - this.keyTemplate = keyDefine;
294 239 // 加载键名列表
295   - this.handleCacheKeys(keyDefine);
296   - },
297   -
298   - /** 键名前缀去除 */
299   - keyFormatter (cacheKey) {
300   - return cacheKey.replace(this.keyTemplate, "");
  240 + this.keyTemplate = keyDefine.keyTemplate;
  241 + this.doGetKeyList(this.keyTemplate);
301 242 },
302 243  
303 244 // 获取键名列表
304   - handleCacheKeys (keyDefine){
305   - const cacheName = keyDefine !== undefined ? keyDefine : this.keyTemplate;
306   - getKeyDefines(cacheName).then(response => {
307   - this.cachekeys = response.data
  245 + doGetKeyList (keyTemplate) {
  246 + getKeyList(keyTemplate).then(response => {
  247 + this.cacheKeys = response.data
308 248 this.cacheForm = {}
309 249 })
310 250 },
311 251  
312 252 // 获取缓存值
313   - handleCacheValue (e){
314   - getKeyValue(this.keyTemplate, e).then(response => {
  253 + handleKeyValue (key) {
  254 + getKeyValue(key).then(response => {
315 255 this.cacheForm = response.data
316 256 })
317 257 },
318 258  
319 259 // 刷新键名列表
320   - refreshCacheKeys(){
  260 + refreshKeys() {
321 261 this.$modal.msgSuccess("刷新键名列表成功");
322   - this.handleCacheKeys();
  262 + this.doGetKeyList(this.keyTemplate);
323 263 },
324 264  
325 265 // 删除缓存
326   - handleClearCacheKey(key){
327   - deleteKeyValue(key).then(response =>{
  266 + handleDeleteKey(key){
  267 + deleteKey(key).then(response => {
328 268 this.$modal.msgSuccess("清理缓存键名[" + key + "]成功");
329   - this.handleCacheKeys();
  269 + this.doGetKeyList(this.keyTemplate);
  270 + })
  271 + },
  272 + handleDeleteKeys(keyTemplate){
  273 + deleteKeys(keyTemplate).then(response => {
  274 + this.$modal.msgSuccess("清空[" + keyTemplate + "]成功");
  275 + this.doGetKeyList(this.keyTemplate);
330 276 })
331 277 },
332 278 },
... ...