1.修改对接过程中发现的系统管理相关功能接口问题

2.添加系统监控功能
This commit is contained in:
panbaolin 2025-10-10 10:09:56 +08:00
parent fcec555a44
commit 67cad8b525
42 changed files with 1037 additions and 904 deletions

View File

@ -333,17 +333,6 @@
<groupId>edu.ucar</groupId>
<artifactId>netcdfAll</artifactId>
<version>${netcdfAll.version}</version>
<!-- <exclusions>-->
<!-- <exclusion>-->
<!-- <groupId>edu.ucar</groupId>-->
<!-- <artifactId>jj2000</artifactId>-->
<!-- </exclusion>-->
<!-- </exclusions>-->
</dependency>
<!-- <dependency>-->
<!-- <groupId>edu.ucar</groupId>-->
<!-- <artifactId>jj2000</artifactId>-->
<!-- <version>${grib2.version}</version>-->
<!-- </dependency>-->
</dependencies>
</project>

View File

@ -0,0 +1,21 @@
package org.jeecg.common.properties;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Data
@Component
@ConfigurationProperties(prefix = "prometheus")
public class PrometheusServerProperties {
/**
* prometheus 服务地址
*/
private String serverUrl;
/**
* node-exporter实例地址
*/
private String instance;
}

View File

@ -45,14 +45,19 @@ public class JeecgPermissionService {
return false;
}
LoginUser loginUser = SecureUtil.currentUser();
// if(loginUser.getUsername().equals("admin")) {
// return true;
// }
if(loginUser.getUsername().startsWith("admin")) {
return true;
}
Object cache = redisUtil.get(buildKey("permission", loginUser.getId()));
List<String> permissionList;
if (Objects.nonNull(cache)) {
permissionList = (List<String>) cache;
} else {
List<String> permissionList = List.of();
boolean flag = false;
if (Objects.nonNull(cache) && cache instanceof List) {
if(!((List<?>) cache).isEmpty()){
flag = true;
permissionList = (List<String>) cache;
}
}
if(!flag){
permissionList = commonAPI.queryUserAuths(loginUser.getId());
redisUtil.set(buildKey("permission", loginUser.getId()), permissionList);
}

View File

@ -24,6 +24,10 @@
<groupId>org.jeecgframework.boot3</groupId>
<artifactId>hibernate-re</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -1,4 +1,4 @@
package org.jeecg.modules.monitor.actuator.undertow;
package org.jeecg.config.init;
import io.micrometer.core.instrument.MeterRegistry;
import io.undertow.server.HttpHandler;
@ -9,12 +9,6 @@ import org.springframework.stereotype.Component;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.LongAdder;
/**
* 自定义undertow监控指标工具类
* for [QQYUN-11902]tomcat 替换undertow 这里的功能还没修改
* @author chenrui
* @date 2025/4/8 19:06
*/
@Component("jeecgCustomUndertowMetricsHandler")
public class CustomUndertowMetricsHandler {
@ -87,4 +81,4 @@ public class CustomUndertowMetricsHandler {
next.handleRequest(exchange);
};
}
}
}

View File

@ -3,7 +3,6 @@ package org.jeecg.config.init;
import io.undertow.server.DefaultByteBufferPool;
import io.undertow.server.handlers.BlockingHandler;
import io.undertow.websockets.jsr.WebSocketDeploymentInfo;
import org.jeecg.modules.monitor.actuator.undertow.CustomUndertowMetricsHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;

View File

@ -1,38 +0,0 @@
package org.jeecg.modules.monitor.actuator;
import org.jeecg.modules.monitor.actuator.httptrace.CustomInMemoryHttpTraceRepository;
import org.springframework.boot.actuate.autoconfigure.web.exchanges.HttpExchangesAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.exchanges.HttpExchangesProperties;
import org.springframework.boot.actuate.web.exchanges.HttpExchangeRepository;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 自定义健康监控配置类
*
* @Author: chenrui
* @Date: 2024/5/13 17:20
*/
@Configuration
@EnableConfigurationProperties(HttpExchangesProperties.class)
@AutoConfigureBefore(HttpExchangesAutoConfiguration.class)
public class CustomActuatorConfig {
/**
* 请求追踪
* @return
* @author chenrui
* @date 2024/5/14 14:52
*/
@Bean
@ConditionalOnProperty(prefix = "management.trace.http", name = "enabled", matchIfMissing = true)
@ConditionalOnMissingBean(HttpExchangeRepository.class)
public CustomInMemoryHttpTraceRepository traceRepository() {
return new CustomInMemoryHttpTraceRepository();
}
}

View File

@ -1,44 +0,0 @@
package org.jeecg.modules.monitor.actuator.httptrace;
import lombok.Getter;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.actuate.endpoint.annotation.Selector;
import org.springframework.boot.actuate.web.exchanges.HttpExchange;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import java.util.List;
import static org.springframework.boot.actuate.endpoint.annotation.Selector.Match.ALL_REMAINING;
/**
* @Description: ENDPOINT: 请求追踪(),支持通过responseCode筛选
* @Author: chenrui
* @Date: 2024/5/13 17:02
*/
@Component
@Endpoint(id = "jeecghttptrace")
public class CustomHttpTraceEndpoint{
private final CustomInMemoryHttpTraceRepository repository;
public CustomHttpTraceEndpoint(CustomInMemoryHttpTraceRepository repository) {
Assert.notNull(repository, "Repository must not be null");
this.repository = repository;
}
@ReadOperation
public HttpTraceDescriptor traces(@Selector(match = ALL_REMAINING) String query) {
return new HttpTraceDescriptor(this.repository.findAll(query));
}
@Getter
public static final class HttpTraceDescriptor {
private final List<HttpExchange> traces;
private HttpTraceDescriptor(List<HttpExchange> traces) {
this.traces = traces;
}
}
}

View File

@ -1,94 +0,0 @@
package org.jeecg.modules.monitor.actuator.httptrace;
import org.springframework.boot.actuate.web.exchanges.HttpExchange;
import org.springframework.boot.actuate.web.exchanges.InMemoryHttpExchangeRepository;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* @Description: 自定义内存请求追踪存储
* @Author: chenrui
* @Date: 2024/5/13 17:02
*/
public class CustomInMemoryHttpTraceRepository extends InMemoryHttpExchangeRepository {
@Override
public List<HttpExchange> findAll() {
return super.findAll();
}
public List<HttpExchange> findAll(String query) {
List<HttpExchange> allTrace = super.findAll();
if (null != allTrace && !allTrace.isEmpty()) {
Stream<HttpExchange> stream = allTrace.stream();
String[] params = query.split(",");
stream = filter(params, stream);
stream = sort(params, stream);
allTrace = stream.collect(Collectors.toList());
}
return allTrace;
}
private Stream<HttpExchange> sort(String[] params, Stream<HttpExchange> stream) {
if (params.length < 2) {
return stream;
}
String sortBy = params[1];
String order;
if (params.length > 2) {
order = params[2];
} else {
order = "desc";
}
return stream.sorted((o1, o2) -> {
int i = 0;
if("timeTaken".equalsIgnoreCase(sortBy)) {
i = o1.getTimeTaken().compareTo(o2.getTimeTaken());
}else if("timestamp".equalsIgnoreCase(sortBy)){
i = o1.getTimestamp().compareTo(o2.getTimestamp());
}
if("desc".equalsIgnoreCase(order)){
i *=-1;
}
return i;
});
}
private static Stream<HttpExchange> filter(String[] params, Stream<HttpExchange> stream) {
if (params.length == 0) {
return stream;
}
String statusQuery = params[0];
if (null != statusQuery && !statusQuery.isEmpty()) {
statusQuery = statusQuery.toLowerCase().trim();
switch (statusQuery) {
case "error":
stream = stream.filter(httpTrace -> {
int status = httpTrace.getResponse().getStatus();
return status >= 404 && status < 501;
});
break;
case "warn":
stream = stream.filter(httpTrace -> {
int status = httpTrace.getResponse().getStatus();
return status >= 201 && status < 404;
});
break;
case "success":
stream = stream.filter(httpTrace -> {
int status = httpTrace.getResponse().getStatus();
return status == 200;
});
break;
case "all":
default:
break;
}
return stream;
}
return stream;
}
}

View File

@ -1,56 +0,0 @@
package org.jeecg.modules.monitor.controller;
import cn.hutool.core.util.NumberUtil;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.api.vo.Result;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.lang.management.ManagementFactory;
import java.lang.management.OperatingSystemMXBean;
import java.util.HashMap;
import java.util.Map;
/**
* @Description: 内存健康检查
* @author: chenrui
*/
@Slf4j
@RestController
@RequestMapping("/sys/actuator/memory")
public class ActuatorMemoryController {
/**
* 内存详情
* @return
*/
@GetMapping("/info")
public Result<?> getRedisInfo() {
Runtime runtime = Runtime.getRuntime();
Map<String,Number> result = new HashMap<>();
result.put("memory.runtime.total", runtime.totalMemory());
result.put("memory.runtime.used", runtime.freeMemory());
result.put("memory.runtime.max", runtime.totalMemory() - runtime.freeMemory());
result.put("memory.runtime.free", runtime.maxMemory() - runtime.totalMemory() + runtime.freeMemory());
result.put("memory.runtime.usage", NumberUtil.div(runtime.totalMemory() - runtime.freeMemory(), runtime.totalMemory()));
//update-begin---author:chenrui ---date:20240705 for[TV360X-1695]内存信息-立即更新 功能报错 #6635------------
OperatingSystemMXBean operatingSystemMXBean = ManagementFactory.getOperatingSystemMXBean();
if (operatingSystemMXBean instanceof com.sun.management.OperatingSystemMXBean) {
com.sun.management.OperatingSystemMXBean opBean = (com.sun.management.OperatingSystemMXBean) operatingSystemMXBean;
// JSONObject operatingSystemJson = JSONObject.parseObject(JSONObject.toJSONString(operatingSystemMXBean));
long totalPhysicalMemory = opBean.getTotalPhysicalMemorySize();
long freePhysicalMemory = opBean.getFreePhysicalMemorySize();
long usedPhysicalMemory = totalPhysicalMemory - freePhysicalMemory;
result.put("memory.physical.total", totalPhysicalMemory);
result.put("memory.physical.used", freePhysicalMemory);
result.put("memory.physical.free", usedPhysicalMemory);
result.put("memory.physical.usage", NumberUtil.div(usedPhysicalMemory, totalPhysicalMemory));
}
//update-end---author:chenrui ---date:20240705 for[TV360X-1695]内存信息-立即更新 功能报错 #6635------------
return Result.ok(result);
}
}

View File

@ -1,138 +0,0 @@
package org.jeecg.modules.monitor.controller;
import com.alibaba.fastjson.JSONArray;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.api.vo.Result;
import org.jeecg.modules.monitor.domain.RedisInfo;
import org.jeecg.modules.monitor.service.RedisService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import javax.swing.filechooser.FileSystemView;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @Description: ActuatorRedisController
* @author: jeecg-boot
*/
@Slf4j
@RestController
@RequestMapping("/sys/actuator/redis")
public class ActuatorRedisController {
@Autowired
private RedisService redisService;
/**
* Redis详细信息
* @return
* @throws Exception
*/
@GetMapping("/info")
public Result<?> getRedisInfo() throws Exception {
List<RedisInfo> infoList = this.redisService.getRedisInfo();
//log.info(infoList.toString());
return Result.ok(infoList);
}
//update-begin---author:chenrui ---date:20240514 for[QQYUN-9247]系统监控功能优化------------
/**
* Redis历史性能指标查询(过去一小时)
* @return
* @throws Exception
* @author chenrui
* @date 2024/5/14 14:56
*/
@GetMapping(value = "/metrics/history")
public Result<?> getMetricsHistory() throws Exception {
Map<String,List<Map<String,Object>>> metricsHistory = this.redisService.getMetricsHistory();
return Result.OK(metricsHistory);
}
//update-end---author:chenrui ---date:20240514 for[QQYUN-9247]系统监控功能优化------------
@GetMapping("/keysSize")
public Map<String, Object> getKeysSize() throws Exception {
return redisService.getKeysSize();
}
/**
* 获取redis key数量 for 报表
* @return
* @throws Exception
*/
@GetMapping("/keysSizeForReport")
public Map<String, JSONArray> getKeysSizeReport() throws Exception {
return redisService.getMapForReport("1");
}
/**
* 获取redis 内存 for 报表
*
* @return
* @throws Exception
*/
@GetMapping("/memoryForReport")
public Map<String, JSONArray> memoryForReport() throws Exception {
return redisService.getMapForReport("2");
}
/**
* 获取redis 全部信息 for 报表
* @return
* @throws Exception
*/
@GetMapping("/infoForReport")
public Map<String, JSONArray> infoForReport() throws Exception {
return redisService.getMapForReport("3");
}
@GetMapping("/memoryInfo")
public Map<String, Object> getMemoryInfo() throws Exception {
return redisService.getMemoryInfo();
}
//update-begin--Author:zhangweijian Date:20190425 for获取磁盘信息
/**
* @功能获取磁盘信息
* @param request
* @param response
* @return
*/
@GetMapping("/queryDiskInfo")
public Result<List<Map<String,Object>>> queryDiskInfo(HttpServletRequest request, HttpServletResponse response){
Result<List<Map<String,Object>>> res = new Result<>();
try {
// 当前文件系统类
FileSystemView fsv = FileSystemView.getFileSystemView();
// 列出所有windows 磁盘
File[] fs = File.listRoots();
log.info("查询磁盘信息:"+fs.length+"");
List<Map<String,Object>> list = new ArrayList<>();
for (int i = 0; i < fs.length; i++) {
if(fs[i].getTotalSpace()==0) {
continue;
}
Map<String,Object> map = new HashMap(5);
map.put("name", fsv.getSystemDisplayName(fs[i]));
map.put("max", fs[i].getTotalSpace());
map.put("rest", fs[i].getFreeSpace());
map.put("restPPT", (fs[i].getTotalSpace()-fs[i].getFreeSpace())*100/fs[i].getTotalSpace());
list.add(map);
log.info(map.toString());
}
res.setResult(list);
res.success("查询成功");
} catch (Exception e) {
res.error500("查询失败"+e.getMessage());
}
return res;
}
//update-end--Author:zhangweijian Date:20190425 for获取磁盘信息
}

View File

@ -0,0 +1,54 @@
//package org.jeecg.modules.monitor.controller;
//
//import lombok.RequiredArgsConstructor;
//import org.jeecg.common.api.vo.Result;
//import org.jeecg.common.aspect.annotation.AutoLog;
//import org.jeecg.modules.monitor.service.DatabaseMonitorService;
//import org.springframework.web.bind.annotation.GetMapping;
//import org.springframework.web.bind.annotation.RequestMapping;
//import org.springframework.web.bind.annotation.RestController;
//
//@RestController
//@RequestMapping("monitor")
//@RequiredArgsConstructor
//public class DatabaseMonitorController {
//
// private final DatabaseMonitorService databaseMonitorService;
//
// @AutoLog(value = "获取CPU信息")
// @GetMapping("getCpuInfo")
// public Result<?> getCpuInfo() {
// return Result.OK(databaseMonitorService.getCpuInfo());
// }
//
// @AutoLog(value = "获取内存监测数据")
// @GetMapping("getMemoryInfo")
// public Result<?> getMemoryInfo() {
// return Result.OK(databaseMonitorService.getMemoryInfo());
// }
//
// @AutoLog(value = "获取表空间信息")
// @GetMapping("getTableSpaceInfo")
// public Result<?> getNetworkInfo() {
// return Result.OK(databaseMonitorService.getTableSpaceInfo());
// }
//
// @AutoLog(value = "获取活跃连接数信息")
// @GetMapping("getActiveSessionInfo")
// public Result<?> getDiskInfo() {
// return Result.OK(databaseMonitorService.getActiveSessionInfo());
// }
//
// @AutoLog(value = "获取死锁信息")
// @GetMapping("getDeadlocksInfo")
// public Result<?> getDeadlocksInfo() {
// return Result.OK(databaseMonitorService.getDeadlocksInfo());
// }
//
// @AutoLog(value = "获取数据库占比信息")
// @GetMapping("getDatabaseProportionInfo")
// public Result<?> getDatabaseProportionInfo() {
// return Result.OK(databaseMonitorService.getDatabaseProportionInfo());
// }
//
//}

View File

@ -0,0 +1,47 @@
package org.jeecg.modules.monitor.controller;
import lombok.RequiredArgsConstructor;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.aspect.annotation.AutoLog;
import org.jeecg.modules.monitor.service.HostMonitorService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("monitor")
@RequiredArgsConstructor
public class ServiceMonitorController {
private final HostMonitorService hostMonitorService;
@AutoLog(value = "获取CPU信息")
@GetMapping("getCpuInfo")
public Result<?> getCpuInfo() {
return Result.OK(hostMonitorService.getCpuInfo());
}
@AutoLog(value = "获取CPU核心数")
@GetMapping("getCpuCoreInfo")
public Result<?> getCpuCoreInfo() {
return Result.OK(hostMonitorService.getCpuCoreInfo());
}
@AutoLog(value = "获取内存监测数据")
@GetMapping("getMemoryInfo")
public Result<?> getMemoryInfo() {
return Result.OK(hostMonitorService.getMemoryInfo());
}
@AutoLog(value = "获取网络带宽监测数据")
@GetMapping("getNetworkInfo")
public Result<?> getNetworkInfo() {
return Result.OK(hostMonitorService.getNetworkInfo());
}
@AutoLog(value = "获取磁盘使用率")
@GetMapping("getDiskInfo")
public Result<?> getDiskInfo() {
return Result.OK(hostMonitorService.getDiskInfo());
}
}

View File

@ -1,141 +0,0 @@
package org.jeecg.modules.monitor.domain;
import java.util.HashMap;
import java.util.Map;
/**
* @Description: redis信息
* @author: jeecg-boot
*/
public class RedisInfo {
private static Map<String, String> map = new HashMap(5);
static {
map.put("redis_version", "Redis 服务器版本");
map.put("redis_git_sha1", "Git SHA1");
map.put("redis_git_dirty", "Git dirty flag");
map.put("os", "Redis 服务器的宿主操作系统");
map.put("arch_bits", " 架构32 或 64 位)");
map.put("multiplexing_api", "Redis 所使用的事件处理机制");
map.put("gcc_version", "编译 Redis 时所使用的 GCC 版本");
map.put("process_id", "服务器进程的 PID");
map.put("run_id", "Redis 服务器的随机标识符(用于 Sentinel 和集群)");
map.put("tcp_port", "TCP/IP 监听端口");
map.put("uptime_in_seconds", "自 Redis 服务器启动以来,经过的秒数");
map.put("uptime_in_days", "自 Redis 服务器启动以来,经过的天数");
map.put("lru_clock", " 以分钟为单位进行自增的时钟,用于 LRU 管理");
map.put("connected_clients", "已连接客户端的数量(不包括通过从属服务器连接的客户端)");
map.put("client_longest_output_list", "当前连接的客户端当中,最长的输出列表");
map.put("client_longest_input_buf", "当前连接的客户端当中,最大输入缓存");
map.put("blocked_clients", "正在等待阻塞命令BLPOP、BRPOP、BRPOPLPUSH的客户端的数量");
map.put("used_memory", "由 Redis 分配器分配的内存总量以字节byte为单位");
map.put("used_memory_human", "以人类可读的格式返回 Redis 分配的内存总量");
map.put("used_memory_rss", "从操作系统的角度,返回 Redis 已分配的内存总量(俗称常驻集大小)。这个值和 top 、 ps 等命令的输出一致");
map.put("used_memory_peak", " Redis 的内存消耗峰值(以字节为单位)");
map.put("used_memory_peak_human", "以人类可读的格式返回 Redis 的内存消耗峰值");
map.put("used_memory_lua", "Lua 引擎所使用的内存大小(以字节为单位)");
map.put("mem_fragmentation_ratio", "sed_memory_rss 和 used_memory 之间的比率");
map.put("mem_allocator", "在编译时指定的, Redis 所使用的内存分配器。可以是 libc 、 jemalloc 或者 tcmalloc");
map.put("redis_build_id", "redis_build_id");
map.put("redis_mode", "运行模式单机standalone或者集群cluster");
map.put("atomicvar_api", "atomicvar_api");
map.put("hz", "redis内部调度进行关闭timeout的客户端删除过期key等等频率程序规定serverCron每秒运行10次。");
map.put("executable", "server脚本目录");
map.put("config_file", "配置文件目录");
map.put("client_biggest_input_buf", "当前连接的客户端当中最大输入缓存用client list命令观察qbuf和qbuf-free两个字段最大值");
map.put("used_memory_rss_human", "以人类可读的方式返回 Redis 已分配的内存总量");
map.put("used_memory_peak_perc", "内存使用率峰值");
map.put("total_system_memory", "系统总内存");
map.put("total_system_memory_human", "以人类可读的方式返回系统总内存");
map.put("used_memory_lua_human", "以人类可读的方式返回Lua 引擎所使用的内存大小");
map.put("maxmemory", "最大内存限制0表示无限制");
map.put("maxmemory_human", "以人类可读的方式返回最大限制内存");
map.put("maxmemory_policy", "超过内存限制后的处理策略");
map.put("loading", "服务器是否正在载入持久化文件");
map.put("rdb_changes_since_last_save", "离最近一次成功生成rdb文件写入命令的个数即有多少个写入命令没有持久化");
map.put("rdb_bgsave_in_progress", "服务器是否正在创建rdb文件");
map.put("rdb_last_save_time", "离最近一次成功创建rdb文件的时间戳。当前时间戳 - rdb_last_save_time=多少秒未成功生成rdb文件");
map.put("rdb_last_bgsave_status", "最近一次rdb持久化是否成功");
map.put("rdb_last_bgsave_time_sec", "最近一次成功生成rdb文件耗时秒数");
map.put("rdb_current_bgsave_time_sec", "如果服务器正在创建rdb文件那么这个域记录的就是当前的创建操作已经耗费的秒数");
map.put("aof_enabled", "是否开启了aof");
map.put("aof_rewrite_in_progress", "标识aof的rewrite操作是否在进行中");
map.put("aof_rewrite_scheduled", "rewrite任务计划当客户端发送bgrewriteaof指令如果当前rewrite子进程正在执行那么将客户端请求的bgrewriteaof变为计划任务待aof子进程结束后执行rewrite ");
map.put("aof_last_rewrite_time_sec", "最近一次aof rewrite耗费的时长");
map.put("aof_current_rewrite_time_sec", "如果rewrite操作正在进行则记录所使用的时间单位秒");
map.put("aof_last_bgrewrite_status", "上次bgrewrite aof操作的状态");
map.put("aof_last_write_status", "上次aof写入状态");
map.put("total_commands_processed", "redis处理的命令数");
map.put("total_connections_received", "新创建连接个数,如果新创建连接过多,过度地创建和销毁连接对性能有影响,说明短连接严重或连接池使用有问题,需调研代码的连接设置");
map.put("instantaneous_ops_per_sec", "redis当前的qpsredis内部较实时的每秒执行的命令数");
map.put("total_net_input_bytes", "redis网络入口流量字节数");
map.put("total_net_output_bytes", "redis网络出口流量字节数");
map.put("instantaneous_input_kbps", "redis网络入口kps");
map.put("instantaneous_output_kbps", "redis网络出口kps");
map.put("rejected_connections", "拒绝的连接个数redis连接个数达到maxclients限制拒绝新连接的个数");
map.put("sync_full", "主从完全同步成功次数");
map.put("sync_partial_ok", "主从部分同步成功次数");
map.put("sync_partial_err", "主从部分同步失败次数");
map.put("expired_keys", "运行以来过期的key的数量");
map.put("evicted_keys", "运行以来剔除(超过了maxmemory后)的key的数量");
map.put("keyspace_hits", "命中次数");
map.put("keyspace_misses", "没命中次数");
map.put("pubsub_channels", "当前使用中的频道数量");
map.put("pubsub_patterns", "当前使用的模式的数量");
map.put("latest_fork_usec", "最近一次fork操作阻塞redis进程的耗时数单位微秒");
map.put("role", "实例的角色是master or slave");
map.put("connected_slaves", "连接的slave实例个数");
map.put("master_repl_offset", "主从同步偏移量,此值如果和上面的offset相同说明主从一致没延迟");
map.put("repl_backlog_active", "复制积压缓冲区是否开启");
map.put("repl_backlog_size", "复制积压缓冲大小");
map.put("repl_backlog_first_byte_offset", "复制缓冲区里偏移量的大小");
map.put("repl_backlog_histlen", "此值等于 master_repl_offset - repl_backlog_first_byte_offset,该值不会超过repl_backlog_size的大小");
map.put("used_cpu_sys", "将所有redis主进程在核心态所占用的CPU时求和累计起来");
map.put("used_cpu_user", "将所有redis主进程在用户态所占用的CPU时求和累计起来");
map.put("used_cpu_sys_children", "将后台进程在核心态所占用的CPU时求和累计起来");
map.put("used_cpu_user_children", "将后台进程在用户态所占用的CPU时求和累计起来");
map.put("cluster_enabled", "实例是否启用集群模式");
map.put("db0", "db0的key的数量,以及带有生存期的key的数,平均存活时间");
}
private String key;
private String value;
private String description;
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
this.description = map.get(this.key);
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
@Override
public String toString() {
return "RedisInfo{" + "key='" + key + '\'' + ", value='" + value + '\'' + ", desctiption='" + description + '\'' + '}';
}
}

View File

@ -1,14 +0,0 @@
package org.jeecg.modules.monitor.exception;
/**
* Redis 连接异常
* @author: jeecg-boot
*/
public class RedisConnectException extends Exception {
private static final long serialVersionUID = 1639374111871115063L;
public RedisConnectException(String message) {
super(message);
}
}

View File

@ -0,0 +1,16 @@
package org.jeecg.modules.monitor.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Select;
import org.jeecg.modules.monitor.vo.DatabaseProportionInfo;
import java.util.List;
public interface DatabaseMonitorMapper extends BaseMapper {
@Select("SELECT " +
"datname AS databaseName," +
"pg_database_size(datname) AS dataSize " +
"FROM pg_database " +
"WHERE datistemplate = false")
List<DatabaseProportionInfo> getActiveSessionInfo();
}

View File

@ -0,0 +1,43 @@
package org.jeecg.modules.monitor.service;
import org.jeecg.modules.monitor.vo.DatabaseProportionInfo;
import java.util.List;
import java.util.Map;
public interface DatabaseMonitorService {
/**
* 获取CPU信息
*/
Map<String,Object> getCpuInfo();
/**
* 获取内存信息
*/
Map<String,Object> getMemoryInfo();
/**
* 获取表空间信息
* @return
*/
Map<String,Object> getTableSpaceInfo();
/**
* 获取活跃连接数信息
* @return
*/
Map<String,Object> getActiveSessionInfo();
/**
* 获取死锁信息
* @return
*/
Map<String,Object> getDeadlocksInfo();
/**
* 获取数据库占比信息
* @return
*/
List<DatabaseProportionInfo> getDatabaseProportionInfo();
}

View File

@ -0,0 +1,38 @@
package org.jeecg.modules.monitor.service;
import java.util.Map;
public interface HostMonitorService {
/**
* 获取CPU信息
*/
Map<String,Object> getCpuInfo();
/**
* 获取CPU核心数
*/
Map<String,Object> getCpuCoreInfo();
/**
* 获取内存信息
*/
Map<String,Object> getMemoryInfo();
/**
* 获取网络信息
*/
Map<String,Object> getNetworkInfo();
/**
* 获取磁盘使用率
*/
Map<String,Object> getDiskInfo();
/**
* 获取磁盘吞吐量
* @return
*/
Map<String,Object> getDiskThroughputInfo();
}

View File

@ -1,55 +0,0 @@
package org.jeecg.modules.monitor.service;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.alibaba.fastjson.JSONArray;
import org.jeecg.modules.monitor.domain.RedisInfo;
import org.jeecg.modules.monitor.exception.RedisConnectException;
/**
* @Description: redis信息service接口
* @author: jeecg-boot
*/
public interface RedisService {
/**
* 获取 redis 的详细信息
*
* @return List
* @throws RedisConnectException
*/
List<RedisInfo> getRedisInfo() throws RedisConnectException;
/**
* 获取 redis key 数量
*
* @return Map
* @throws RedisConnectException
*/
Map<String, Object> getKeysSize() throws RedisConnectException;
/**
* 获取 redis 内存信息
*
* @return Map
* @throws RedisConnectException
*/
Map<String, Object> getMemoryInfo() throws RedisConnectException;
/**
* 获取 报表需要个redis信息
* @param type
* @return Map
* @throws RedisConnectException
*/
Map<String, JSONArray> getMapForReport(String type) throws RedisConnectException ;
/**
* 获取历史性能指标
* @return
* @author chenrui
* @date 2024/5/14 14:57
*/
Map<String, List<Map<String, Object>>> getMetricsHistory();
}

View File

@ -0,0 +1,72 @@
package org.jeecg.modules.monitor.service.impl;
import lombok.RequiredArgsConstructor;
import org.jeecg.modules.monitor.mapper.DatabaseMonitorMapper;
import org.jeecg.modules.monitor.service.DatabaseMonitorService;
import org.jeecg.modules.monitor.vo.DatabaseProportionInfo;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
@Service
@RequiredArgsConstructor
public class DatabaseMonitorServiceImpl implements DatabaseMonitorService {
private final DatabaseMonitorMapper databaseMonitorMapper;
/**
* 获取CPU信息
*/
@Override
public Map<String, Object> getCpuInfo() {
return Map.of();
}
/**
* 获取内存信息
*/
@Override
public Map<String, Object> getMemoryInfo() {
return Map.of();
}
/**
* 获取表空间信息
*
* @return
*/
@Override
public Map<String, Object> getTableSpaceInfo() {
return Map.of();
}
/**
* 获取活跃连接数信息
*
* @return
*/
@Override
public Map<String, Object> getActiveSessionInfo() {
return Map.of();
}
/**
* 获取死锁信息
*
* @return
*/
@Override
public Map<String, Object> getDeadlocksInfo() {
//irate(pg_stat_database_deadlocks{instance="192.168.186.143:9187", datname=~"postgres"}[5m])
return Map.of();
}
/**
* 获取数据库占比信息
* @return
*/
@Override
public List<DatabaseProportionInfo> getDatabaseProportionInfo() {
return databaseMonitorMapper.getActiveSessionInfo();
}
}

View File

@ -0,0 +1,294 @@
package org.jeecg.modules.monitor.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.properties.PrometheusServerProperties;
import org.jeecg.modules.monitor.service.HostMonitorService;
import org.jeecg.modules.monitor.vo.PrometheusResponse;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Mono;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URI;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
/**
* 基于Prometheus的主机监控
*/
@Service
@RequiredArgsConstructor
@Slf4j
public class HostMonitorServiceImpl implements HostMonitorService {
private final WebClient webClient;
private final PrometheusServerProperties serverProperties;
/**
* 获取CPU信息
*/
@Override
public Map<String,Object> getCpuInfo() {
Map<String,Object> result = new HashMap<>();
try {
//Prometheus 服务器地址
String url = serverProperties.getServerUrl();
//目标主机实例node-exporter 的地址
String instance = serverProperties.getInstance();
//查询CPU利用率
String cpuQuery = "100 * (1 - avg(rate(node_cpu_seconds_total{mode=\"idle\", instance=\""+instance+"\"}[1m0s])))";
PrometheusResponse response = webClient.get()
.uri(buildUri(url,cpuQuery))
.retrieve()
.bodyToMono(PrometheusResponse.class)
.block();
if(Objects.nonNull(response) &&
Objects.nonNull(response.getData()) &&
CollUtil.isNotEmpty(response.getData().getResult())
) {
PrometheusResponse.Result cpuInfo = response.getData().getResult().get(0);
if(CollUtil.isNotEmpty(cpuInfo.getValue())) {
Date date = new Date(cpuInfo.getValue().get(0).longValue()*1000);
Double useRate = BigDecimal.valueOf(cpuInfo.getValue().get(1)).setScale(2, RoundingMode.HALF_UP).doubleValue();
result.put("date", DateUtil.format(date, "yyyy-MM-dd HH:mm:ss"));
result.put("usageRate", useRate);
}
}
}catch (Exception e){
log.error("获取CPU信息错误请检查Prometheus服务是否正常启动或Java请求参数是否正确,详细堆栈错误为:{}",e.getMessage());
}
return result;
}
/**
* 获取CPU核心数
*/
@Override
public Map<String,Object> getCpuCoreInfo() {
Map<String,Object> result = new HashMap<>();
try {
//Prometheus 服务器地址
String url = serverProperties.getServerUrl();
//目标主机实例node-exporter 的地址
String instance = serverProperties.getInstance();
//查询CPU核数
String cpuCoreQuery = "count(count by (cpu) (node_cpu_seconds_total{instance=\"" + instance + "\"}))";
PrometheusResponse response = webClient.get()
.uri(buildUri(url,cpuCoreQuery))
.retrieve()
.bodyToMono(PrometheusResponse.class)
.block();
if(Objects.nonNull(response) &&
Objects.nonNull(response.getData()) &&
CollUtil.isNotEmpty(response.getData().getResult())
) {
PrometheusResponse.Result cpuInfo = response.getData().getResult().get(0);
if(CollUtil.isNotEmpty(cpuInfo.getValue())) {
Integer cpuCores = cpuInfo.getValue().get(1).intValue();
result.put("cpuCores", cpuCores);
}
}
}catch (Exception e){
log.error("获取CPU核心数错误请检查Prometheus服务是否正常启动或Java请求参数是否正确,详细堆栈错误为:{}",e.getMessage());
}
return result;
}
/**
* 获取内存信息
*/
@Override
public Map<String,Object> getMemoryInfo() {
Map<String,Object> result = new HashMap<>();
try {
//Prometheus 服务器地址
String url = serverProperties.getServerUrl();
//目标主机实例node-exporter 的地址
String instance = serverProperties.getInstance();
//查询总内存
String totalMemoryQuery = "node_memory_MemTotal_bytes{instance=\"" + instance + "\"}";
PrometheusResponse totalMemoryResponse = webClient.get()
.uri(buildUri(url,totalMemoryQuery))
.retrieve()
.bodyToMono(PrometheusResponse.class)
.block();
if(Objects.nonNull(totalMemoryResponse) &&
Objects.nonNull(totalMemoryResponse.getData()) &&
CollUtil.isNotEmpty(totalMemoryResponse.getData().getResult())
) {
PrometheusResponse.Result totalMemoryInfo = totalMemoryResponse.getData().getResult().get(0);
if(CollUtil.isNotEmpty(totalMemoryInfo.getValue())) {
Double totalMemory = BigDecimal.valueOf(totalMemoryInfo.getValue().get(1)/1024/1024/1024).setScale(2, RoundingMode.HALF_UP).doubleValue();
result.put("totalMemory",totalMemory);
}
}
//剩余可用内存
String availableMemoryQuery = "node_memory_MemAvailable_bytes{instance=\"" + instance + "\"}";
PrometheusResponse availableMemoryResponse = webClient.get()
.uri(buildUri(url,availableMemoryQuery))
.retrieve()
.bodyToMono(PrometheusResponse.class)
.block();;
if(Objects.nonNull(availableMemoryResponse) &&
Objects.nonNull(availableMemoryResponse.getData()) &&
CollUtil.isNotEmpty(availableMemoryResponse.getData().getResult())
) {
PrometheusResponse.Result availableMemoryInfo = availableMemoryResponse.getData().getResult().get(0);
if(CollUtil.isNotEmpty(availableMemoryInfo.getValue())) {
Double availableMemory = BigDecimal.valueOf(availableMemoryInfo.getValue().get(1)/1024/1024/1024).setScale(2, RoundingMode.HALF_UP).doubleValue();
result.put("availableMemory",availableMemory);
}
}
//使用率
String usageRateQuery = "(1 - (node_memory_MemAvailable_bytes{instance=\""+instance+"\"} / node_memory_MemTotal_bytes{instance=\""+instance+"\"})) * 100";
PrometheusResponse usageRateResponse = webClient.get()
.uri(buildUri(url,usageRateQuery))
.retrieve()
.bodyToMono(PrometheusResponse.class)
.block();
if(Objects.nonNull(usageRateResponse) &&
Objects.nonNull(usageRateResponse.getData()) &&
CollUtil.isNotEmpty(usageRateResponse.getData().getResult())
) {
PrometheusResponse.Result usageRateInfo = usageRateResponse.getData().getResult().get(0);
if(CollUtil.isNotEmpty(usageRateInfo.getValue())) {
Date date = new Date(usageRateInfo.getValue().get(0).longValue()*1000);
Double usageRate = BigDecimal.valueOf(usageRateInfo.getValue().get(1)).setScale(2, RoundingMode.HALF_UP).doubleValue();
result.put("date", DateUtil.format(date, "yyyy-MM-dd HH:mm:ss"));
result.put("usageRate", usageRate);
}
}
}catch (Exception e){
log.error("获取内存信息错误请检查Prometheus服务是否正常启动或Java请求参数是否正确,详细堆栈错误为:{}",e.getMessage());
}
return result;
}
/**
* 获取网络信息
*/
@Override
public Map<String,Object> getNetworkInfo() {
Map<String,Object> result = new HashMap<>();
try {
//Prometheus 服务器地址
String url = serverProperties.getServerUrl();
//目标主机实例node-exporter 的地址
String instance = serverProperties.getInstance();
//接收带宽 (Kbps)
String receiveKbpsQuery = "rate(node_network_receive_bytes_total{instance=\"" + instance + "\", device=\"ens32\"}[1m]) * 8 / 1000";
PrometheusResponse receiveKbpsResponse = webClient.get()
.uri(buildUri(url,receiveKbpsQuery))
.retrieve()
.bodyToMono(PrometheusResponse.class)
.block();
if(Objects.nonNull(receiveKbpsResponse) &&
Objects.nonNull(receiveKbpsResponse.getData()) &&
CollUtil.isNotEmpty(receiveKbpsResponse.getData().getResult())
) {
PrometheusResponse.Result receiveKbpsInfo = receiveKbpsResponse.getData().getResult().get(0);
if(CollUtil.isNotEmpty(receiveKbpsInfo.getValue())) {
Date date = new Date(receiveKbpsInfo.getValue().get(0).longValue()*1000);
Double receiveKbps = BigDecimal.valueOf(receiveKbpsInfo.getValue().get(1)).setScale(2, RoundingMode.HALF_UP).doubleValue();
result.put("receiveDate", DateUtil.format(date, "yyyy-MM-dd HH:mm:ss"));
result.put("receiveKbps", receiveKbps);
}
}
//发送带宽 (Kbps)
String transmitKbpsQuery = "rate(node_network_transmit_bytes_total{instance=\"" + instance + "\", device=\"ens32\"}[1m]) * 8 / 1000";
PrometheusResponse transmitKbpsResponse = webClient.get()
.uri(buildUri(url,transmitKbpsQuery))
.retrieve()
.bodyToMono(PrometheusResponse.class)
.block();
if(Objects.nonNull(transmitKbpsResponse) &&
Objects.nonNull(transmitKbpsResponse.getData()) &&
CollUtil.isNotEmpty(transmitKbpsResponse.getData().getResult())
) {
PrometheusResponse.Result transmitKbpsInfo = transmitKbpsResponse.getData().getResult().get(0);
if(CollUtil.isNotEmpty(transmitKbpsInfo.getValue())) {
Date date = new Date(transmitKbpsInfo.getValue().get(0).longValue()*1000);
Double transmitKbps = BigDecimal.valueOf(transmitKbpsInfo.getValue().get(1)).setScale(2, RoundingMode.HALF_UP).doubleValue();
result.put("transmitDate", DateUtil.format(date, "yyyy-MM-dd HH:mm:ss"));
result.put("transmitKbps", transmitKbps);
}
}
}catch (Exception e){
log.error("获取网络信息错误请检查Prometheus服务是否正常启动或Java请求参数是否正确,详细堆栈错误为:{}",e.getMessage());
}
return result;
}
/**
* 获取磁盘使用率
*/
@Override
public Map<String,Object> getDiskInfo() {
Map<String,Object> result = new HashMap<>();
try {
//Prometheus 服务器地址
String url = serverProperties.getServerUrl();
//目标主机实例node-exporter 的地址
String instance = serverProperties.getInstance();
//磁盘使用率
String diskUsageQuery = "((node_filesystem_size_bytes{instance=\""+instance+"\", device!~\"rootfs\"} - node_filesystem_avail_bytes{instance=\""+instance+"\", device!~\"rootfs\"}) / node_filesystem_size_bytes{instance=\""+instance+"\", device!~\"rootfs\"}) * 100";
PrometheusResponse diskUsageResponse = webClient.get()
.uri(buildUri(url,diskUsageQuery))
.retrieve()
.bodyToMono(PrometheusResponse.class)
.block();
if(Objects.nonNull(diskUsageResponse) &&
Objects.nonNull(diskUsageResponse.getData()) &&
CollUtil.isNotEmpty(diskUsageResponse.getData().getResult())
) {
for (PrometheusResponse.Result responseData :diskUsageResponse.getData().getResult()){
String mountpoint = responseData.getMetric().getMountpoint();
Double usageRate = BigDecimal.valueOf(responseData.getValue().get(1)).setScale(2, RoundingMode.HALF_UP).doubleValue();
result.put(mountpoint,usageRate);
}
}
}catch (Exception e){
log.error("获取磁盘使用率错误请检查Prometheus服务是否正常启动或Java请求参数是否正确,详细堆栈错误为:{}",e.getMessage());
}
return result;
}
/**
* 获取磁盘吞吐量
*
* @return
*/
@Override
public Map<String, Object> getDiskThroughputInfo() {
//Expr: irate(node_disk_read_bytes_total{instance="192.168.186.143:9100",job="Prometheus服务器",device=~"[a-z]+|nvme[0-9]+n[0-9]+|mmcblk[0-9]+"}[1m0s])
//irate(node_disk_written_bytes_total{instance="192.168.186.143:9100",job="Prometheus服务器",device=~"[a-z]+|nvme[0-9]+n[0-9]+|mmcblk[0-9]+"}[1m0s])
return Map.of();
}
/**
* 构建URI
* @param url
* @param query
* @return
*/
private URI buildUri(String url,String query){
URI uri = UriComponentsBuilder.fromHttpUrl(url + "/api/v1/query")
.queryParam("query", query)
.build()
.toUri();
return uri;
}
public static void main(String[] args) {
Date date = new Date(1758868629*1000L);
System.out.println(DateUtil.format(date, "yyyy-MM-dd HH:mm:ss"));
}
}

View File

@ -1,29 +0,0 @@
package org.jeecg.modules.monitor.service.impl;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.stereotype.Component;
/**
* 功能说明:自定义邮件检测
*
* @author: 李波
* @email: 503378406@qq.com
* @date: 2019-06-29
*/
@Component
public class MailHealthIndicator implements HealthIndicator {
@Override public Health health() {
int errorCode = check();
if (errorCode != 0) {
return Health.down().withDetail("Error Code", errorCode) .build();
}
return Health.up().build();
}
int check(){
//可以实现自定义的数据库检测逻辑
return 0;
}
}

View File

@ -1,174 +0,0 @@
package org.jeecg.modules.monitor.service.impl;
import java.util.*;
import jakarta.annotation.Resource;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.monitor.domain.RedisInfo;
import org.jeecg.modules.monitor.exception.RedisConnectException;
import org.jeecg.modules.monitor.service.RedisService;
import org.springframework.cglib.beans.BeanMap;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import lombok.extern.slf4j.Slf4j;
/**
* Redis 监控信息获取
*
* @Author MrBird
*/
@Service("redisService")
@Slf4j
public class RedisServiceImpl implements RedisService {
@Resource
private RedisConnectionFactory redisConnectionFactory;
/**
* redis信息
*/
private static final String REDIS_MESSAGE = "3";
/**
* redis性能信息记录
*/
private static final Map<String,List<Map<String, Object>>> REDIS_METRICS = new HashMap<>(2);
/**
* Redis详细信息
*/
@Override
public List<RedisInfo> getRedisInfo() throws RedisConnectException {
Properties info = redisConnectionFactory.getConnection().info();
List<RedisInfo> infoList = new ArrayList<>();
RedisInfo redisInfo = null;
for (Map.Entry<Object, Object> entry : info.entrySet()) {
redisInfo = new RedisInfo();
redisInfo.setKey(oConvertUtils.getString(entry.getKey()));
redisInfo.setValue(oConvertUtils.getString(entry.getValue()));
infoList.add(redisInfo);
}
return infoList;
}
@Override
public Map<String, Object> getKeysSize() throws RedisConnectException {
Long dbSize = redisConnectionFactory.getConnection().dbSize();
Map<String, Object> map = new HashMap(5);
map.put("create_time", System.currentTimeMillis());
map.put("dbSize", dbSize);
log.debug("--getKeysSize--: " + map.toString());
return map;
}
@Override
public Map<String, Object> getMemoryInfo() throws RedisConnectException {
Map<String, Object> map = null;
Properties info = redisConnectionFactory.getConnection().info();
for (Map.Entry<Object, Object> entry : info.entrySet()) {
String key = oConvertUtils.getString(entry.getKey());
if ("used_memory".equals(key)) {
map = new HashMap(5);
map.put("used_memory", entry.getValue());
map.put("create_time", System.currentTimeMillis());
}
}
log.debug("--getMemoryInfo--: " + map.toString());
return map;
}
/**
* 查询redis信息for报表
* @param type 1redis key数量 2 占用内存 3redis信息
* @return
* @throws RedisConnectException
*/
@Override
public Map<String, JSONArray> getMapForReport(String type) throws RedisConnectException {
Map<String,JSONArray> mapJson=new HashMap(5);
JSONArray json = new JSONArray();
if(REDIS_MESSAGE.equals(type)){
List<RedisInfo> redisInfo = getRedisInfo();
for(RedisInfo info:redisInfo){
Map<String, Object> map= Maps.newHashMap();
BeanMap beanMap = BeanMap.create(info);
for (Object key : beanMap.keySet()) {
map.put(key+"", beanMap.get(key));
}
json.add(map);
}
mapJson.put("data",json);
return mapJson;
}
int length = 5;
for(int i = 0; i < length; i++){
JSONObject jo = new JSONObject();
Map<String, Object> map;
if("1".equals(type)){
map= getKeysSize();
jo.put("value",map.get("dbSize"));
}else{
map = getMemoryInfo();
Integer usedMemory = Integer.valueOf(map.get("used_memory").toString());
jo.put("value",usedMemory/1000);
}
String createTime = DateUtil.formatTime(DateUtil.date((Long) map.get("create_time")-(4-i)*1000));
jo.put("name",createTime);
json.add(jo);
}
mapJson.put("data",json);
return mapJson;
}
//update-begin---author:chenrui ---date:20240514 for[QQYUN-9247]系统监控功能优化------------
/**
* 获取历史性能指标
* @return
* @author chenrui
* @date 2024/5/14 14:57
*/
@Override
public Map<String, List<Map<String, Object>>> getMetricsHistory() {
return REDIS_METRICS;
}
/**
* 记录近一小时redis监控数据 <br/>
* 60s一次,,记录存储keysize和内存
* @throws RedisConnectException
* @author chenrui
* @date 2024/5/14 14:09
*/
@Scheduled(fixedRate = 60000)
public void recordCustomMetric() throws RedisConnectException {
List<Map<String, Object>> list= new ArrayList<>();
if(REDIS_METRICS.containsKey("dbSize")){
list = REDIS_METRICS.get("dbSize");
}else{
REDIS_METRICS.put("dbSize",list);
}
if(list.size()>60){
list.remove(0);
}
list.add(getKeysSize());
list= new ArrayList<>();
if(REDIS_METRICS.containsKey("memory")){
list = REDIS_METRICS.get("memory");
}else{
REDIS_METRICS.put("memory",list);
}
if(list.size()>60){
list.remove(0);
}
list.add(getMemoryInfo());
}
//update-end---author:chenrui ---date:20240514 for[QQYUN-9247]系统监控功能优化------------
}

View File

@ -0,0 +1,14 @@
package org.jeecg.modules.monitor.vo;
import lombok.Data;
/**
* 每个数据库数据量
*/
@Data
public class DatabaseProportionInfo {
private String databaseName;
private Long dataSize;
}

View File

@ -0,0 +1,167 @@
package org.jeecg.modules.monitor.vo;
import java.util.List;
import java.util.Map;
public class PrometheusResponse {
private String status;
private Data data;
public static class Data {
private String resultType;
private List<Result> result;
public String getResultType() {
return resultType;
}
public void setResultType(String resultType) {
this.resultType = resultType;
}
public List<Result> getResult() {
return result;
}
public void setResult(List<Result> result) {
this.result = result;
}
@Override
public String toString() {
return "Data{" +
"resultType=" + resultType +
", result=" + result +
'}';
}
}
public static class Result {
private Metric metric;
private List<Double> value; // 单值查询
public Metric getMetric() {
return metric;
}
public void setMetric(Metric metric) {
this.metric = metric;
}
public List<Double> getValue() {
return value;
}
public void setValue(List<Double> value) {
this.value = value;
}
@Override
public String toString() {
return "Result{" +
"metric=" + metric +
", value=" + value +
'}';
}
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public Data getData() {
return data;
}
public void setData(Data data) {
this.data = data;
}
@Override
public String toString() {
return "PrometheusResponse{" +
"status='" + status + '\'' +
", data=" + data +
'}';
}
public static class Metric {
private String app;
private String device;
private String fstype;
private String instance;
private String job;
private String mountpoint;
public String getApp() {
return app;
}
public void setApp(String app) {
this.app = app;
}
public String getDevice() {
return device;
}
public void setDevice(String device) {
this.device = device;
}
public String getFstype() {
return fstype;
}
public void setFstype(String fstype) {
this.fstype = fstype;
}
public String getInstance() {
return instance;
}
public void setInstance(String instance) {
this.instance = instance;
}
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
public String getMountpoint() {
return mountpoint;
}
public void setMountpoint(String mountpoint) {
this.mountpoint = mountpoint;
}
@Override
public String toString() {
return "Metric{" +
"app='" + app + '\'' +
", device='" + device + '\'' +
", fstype='" + fstype + '\'' +
", instance='" + instance + '\'' +
", job='" + job + '\'' +
", mountpoint='" + mountpoint + '\'' +
'}';
}
}
}

View File

@ -0,0 +1,62 @@
package org.jeecg.modules.system.config;
import io.netty.channel.ChannelOption;
import io.netty.handler.timeout.ReadTimeoutHandler;
import io.netty.handler.timeout.WriteTimeoutHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
import reactor.netty.http.client.HttpClient;
import reactor.netty.resources.ConnectionProvider;
import java.time.Duration;
@Slf4j
@Configuration
public class WebClientConfig {
@Bean
public WebClient webClient() {
// 配置HTTP连接池
ConnectionProvider provider = ConnectionProvider.builder("custom")
.maxConnections(100)
.maxIdleTime(Duration.ofSeconds(20))
.build();
// 配置HTTP客户端
HttpClient httpClient = HttpClient.create(provider)
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000)
.responseTimeout(Duration.ofSeconds(5))
.doOnConnected(conn ->
conn.addHandlerLast(new ReadTimeoutHandler(5))
.addHandlerLast(new WriteTimeoutHandler(5)));
// 构建WebClient实例
return WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(httpClient))
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.defaultHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
// 添加请求日志记录功能
.filter(ExchangeFilterFunction.ofRequestProcessor(
clientRequest -> {
log.debug("Request: {} {}",
clientRequest.method(),
clientRequest.url());
return Mono.just(clientRequest);
}
))
// 添加响应日志记录功能
.filter(ExchangeFilterFunction.ofResponseProcessor(
clientResponse -> {
log.debug("Response status: {}",
clientResponse.statusCode());
return Mono.just(clientResponse);
}
))
.build();
}
}

View File

@ -170,7 +170,7 @@ public class LoginController {
//3.设置登录用户信息
obj.put("userInfo", sysUser);
obj.put("auth",authUserService.getUserPermissionsSet(sysUser.getId()));
obj.put("menu",authUserService.getUserRoleSetById(sysUser.getId()));
obj.put("menu",authUserService.getUserMenuPaths(sysUser.getId()));
result.setResult(obj);
result.success("登录成功");
return result;

View File

@ -7,7 +7,6 @@ import org.jeecg.common.system.query.PageRequest;
import org.jeecg.modules.system.entity.SysLog;
import org.jeecg.modules.system.service.ISysLogService;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import com.baomidou.mybatisplus.core.metadata.IPage;
@ -29,7 +28,6 @@ public class SysLogController {
private final ISysLogService sysLogService;
@GetMapping(value = "page")
@PreAuthorize("@jps.requiresPermissions('system:log:page')")
public Result<?> page(PageRequest pageRequest,
@NotNull(message = "日志类型不能为空") Integer logType,
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate startDate,

View File

@ -29,7 +29,6 @@ public class SysPermissionController {
private final ISysPermissionService sysPermissionService;
@AutoLog(value = "查询菜单树")
@PreAuthorize("@jps.requiresPermissions('system:permission:tree')")
@GetMapping(value = "getPermissionTree")
public Result<?> getPermissionTree() {
return Result.ok(sysPermissionService.getPermissionTree());

View File

@ -36,8 +36,7 @@ public class SysRoleController {
private final ISysRoleService sysRoleService;
@AutoLog(value = "分页查询用户数据")
@PreAuthorize("@jps.requiresPermissions('system:role:page')")
@AutoLog(value = "分页查询角色数据")
@GetMapping(value = "page")
public Result<?> page(PageRequest pageRequest, String roleName, String roleCode) {
IPage<SysRole> page = sysRoleService.page(pageRequest, roleName, roleCode);
@ -46,8 +45,15 @@ public class SysRoleController {
rspData.put("total", page.getTotal());
return Result.OK(rspData);
}
@AutoLog(value = "查询所有角色数据")
@PreAuthorize("@jps.requiresPermissions('system:role:getAll')")
@GetMapping(value = "getAll")
public Result<?> getAll(PageRequest pageRequest, String roleName, String roleCode) {
return Result.OK(sysRoleService.getAll());
}
@AutoLog(value = "添加用户")
@AutoLog(value = "添加角色")
@PreAuthorize("@jps.requiresPermissions('system:role:create')")
@PostMapping("create")
public Result<?> create(@Validated(value = InsertGroup.class) @RequestBody SysRole role) {
@ -55,7 +61,7 @@ public class SysRoleController {
return Result.OK();
}
@AutoLog(value = "编辑用户")
@AutoLog(value = "编辑角色")
@PreAuthorize("@jps.requiresPermissions('system:role:update')")
@PutMapping("update")
public Result<SysRole> update(@Validated(value = UpdateGroup.class) @RequestBody SysRole role) {
@ -85,4 +91,11 @@ public class SysRoleController {
this.sysRoleService.saveRolePermissionRelation(authorisationVo);
return Result.OK();
}
@AutoLog(value = "查询指定角色已授权的信息")
@PreAuthorize("@jps.requiresPermissions('system:role:authorized')")
@GetMapping(value = "authorized")
public Result<?> authorized(@NotBlank(message = "roleId不能为空") String roleId) {
return Result.OK(this.sysRoleService.getAuthorizedInfo(roleId));
}
}

View File

@ -1,6 +1,5 @@
package org.jeecg.modules.system.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
@ -33,7 +32,6 @@ public class SysUserController {
private final IAuthUserService authUserService;
@AutoLog(value = "分页获取用户信息")
@PreAuthorize("@jps.requiresPermissions('system:user:page')")
@GetMapping(value = "page")
public Result<?> page(PageRequest pageRequest,String username,Integer status) {
IPage<SysUser> page = authUserService.page(pageRequest, username,status);
@ -100,4 +98,11 @@ public class SysUserController {
this.authUserService.updateStatus(userId,status);
return Result.ok();
}
@AutoLog(value = "查询用户有权限的菜单")
@PreAuthorize("@jps.requiresPermissions('system:user:selectUserPermissions')")
@GetMapping(value = "selectUserPermissions")
public Result<?> selectUserPermissions() {
return Result.ok(this.authUserService.selectUserPermissions());
}
}

View File

@ -37,9 +37,6 @@ public class SysUserRole implements Serializable {
*/
private String roleId;
/**租户ID*/
private java.lang.Integer tenantId;
public SysUserRole() {
}

View File

@ -32,6 +32,13 @@ public interface SysPermissionMapper extends BaseMapper<SysPermission> {
*/
List<SysPermission> queryByUserId(@Param("userId") String userId);
/**
* 根据用户id查询菜单路径
* @param userId
* @return
*/
List<String> getUserMenuPaths(@Param("userId") String userId);
/**
* 根据用户查询用户权限
* @param userName 用户ID
@ -61,5 +68,10 @@ public interface SysPermissionMapper extends BaseMapper<SysPermission> {
*/
List<SysPermission> getChildNodeInfo();
/**
* 获取用户拥有权限的菜单信息
* @param userId
* @return
*/
List<SysPermission> selectUserPermissions(@Param("userId") String userId);
}

View File

@ -1,14 +1,9 @@
package org.jeecg.modules.system.mapper;
import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.jeecg.modules.system.entity.SysRole;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import java.util.List;
/**
@ -20,23 +15,6 @@ import java.util.List;
* @since 2018-12-19
*/
public interface SysRoleMapper extends BaseMapper<SysRole> {
/**
* 查询全部的角色不做租户隔离
* @param page
* @param role
* @return
*/
@InterceptorIgnore(tenantLine = "true")
List<SysRole> listAllSysRole(@Param("page") Page<SysRole> page, @Param("role") SysRole role);
/**
* 查询角色是否存在不做租户隔离
*
* @param roleCode
* @return
*/
@InterceptorIgnore(tenantLine = "true")
SysRole getRoleNoTenant(@Param("roleCode") String roleCode);
/**
* 根据用户id查询用户拥有的角色Code
@ -64,4 +42,11 @@ public interface SysRoleMapper extends BaseMapper<SysRole> {
*/
@Delete("delete from sys_role_permission where role_id = #{roleId}")
void deleteRolePermissionRelation(@Param("roleId") String roleId);
/**
* 查询指定角色已授权的信息
* @param roleId
* @return
*/
List<String> getAuthorizedInfo(@Param("roleId") String roleId);
}

View File

@ -29,7 +29,7 @@
</select>
<select id="queryByUserId" parameterType="String">
select sp.perms from sys_permission_copy1 sp
select sp.perms from sys_permission sp
inner join sys_role_permission srp on sp.id = srp.permission_id
inner join sys_user_role sur on srp.role_id = sur.role_id
where sp.perms is not null
@ -37,4 +37,31 @@
and sur.user_id = #{userId}
</if>
</select>
<select id="getUserMenuPaths" parameterType="String" resultType="String">
select sp.url from sys_permission sp
inner join sys_role_permission srp on sp.id = srp.permission_id
inner join sys_user_role sur on srp.role_id = sur.role_id
<if test="userId != null and userId != ''">
where sur.user_id = #{userId}
</if>
</select>
<select id="selectUserPermissions" parameterType="String">
select
sp.id,
sp.parent_id as parentId,
sp.name,
sp.component,
sp.url,
sp.icon,
sp.menu_type as menuType,
sp.sort_no as sortNo
from sys_permission sp
inner join sys_role_permission srp on sp.id = srp.permission_id
inner join sys_user_role sur on srp.role_id = sur.role_id
<if test="userId != null and userId != ''">
where sur.user_id = #{userId}
</if>
</select>
</mapper>

View File

@ -2,54 +2,18 @@
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.jeecg.modules.system.mapper.SysRoleMapper">
<select id="listAllSysRole" resultType="org.jeecg.modules.system.entity.SysRole">
SELECT * from sys_role
WHERE 1=1
<if test="role.roleName!='' and role.roleName!=null">
<bind name="bindKeyword" value="'%'+role.roleName+'%'"/>
AND role_name like #{bindKeyword}
</if>
<if test="role.roleCode!='' and role.roleCode!=null">
<choose>
<when test="role.roleCode.indexOf(',') != -1">
AND role_code in
<foreach item="item" index="index" collection="role.roleCode.split(',')" open="(" separator="," close=")">
#{item}
</foreach>
</when>
<otherwise>
<bind name="bindRoleCode" value="'%'+role.roleCode+'%'"/>
AND role_code like #{bindRoleCode}
</otherwise>
</choose>
</if>
<!--增加id查询 for:【issues/7948】角色解决根据id查询回显不对-->
<if test="role.id!='' and role.id!=null">
<choose>
<when test="role.id.indexOf(',') != -1">
AND id in
<foreach item="item" index="index" collection="role.id.split(',')" open="(" separator="," close=")">
#{item}
</foreach>
</when>
<otherwise>
AND id = #{role.id}
</otherwise>
</choose>
</if>
order by create_time desc
</select>
<select id="getRoleNoTenant" resultType="org.jeecg.modules.system.entity.SysRole">
SELECT * from sys_role
WHERE role_code = #{roleCode}
</select>
<!-- 根据用户id查询用户拥有的角色 -->
<select id="getRoleCodeListByUserId" resultType="org.jeecg.modules.system.entity.SysRole">
SELECT id, role_code from sys_role
WHERE id in (SELECT role_id from sys_user_role WHERE user_id = #{userId})
</select>
<select id="getAuthorizedInfo" parameterType="String">
select
sp.id
from sys_role_permission srp
inner join sys_permission sp on srp.permission_id = sp."id"
where srp.role_id = #{roleId}
</select>
</mapper>

View File

@ -6,6 +6,7 @@ import org.jeecg.common.system.query.PageRequest;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.modules.system.entity.SysPermission;
import org.jeecg.modules.system.entity.SysUser;
import org.jeecg.modules.system.model.PermissionTreeModel;
import org.jeecg.modules.system.vo.SysUserVo;
import java.util.List;
import java.util.Set;
@ -88,6 +89,13 @@ public interface IAuthUserService extends IService<SysUser> {
*/
List<String> getUserPermissionsSet(String userId);
/**
* 获取用户所属菜单路径
* @param userId
* @return
*/
List<String> getUserMenuPaths(String userId);
/**
* 保存用户
* @param userVo 用户
@ -122,4 +130,9 @@ public interface IAuthUserService extends IService<SysUser> {
LoginUser getEncodeUserInfo(String username);
/**
* 查询用户有权限的菜单
*/
List<PermissionTreeModel<SysPermission>> selectUserPermissions();
}

View File

@ -1,17 +1,11 @@
package org.jeecg.modules.system.service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import org.apache.ibatis.annotations.Param;
import org.jeecg.common.api.vo.Result;
import jakarta.validation.constraints.NotBlank;
import org.jeecg.common.system.query.PageRequest;
import org.jeecg.modules.system.entity.SysRole;
import org.jeecg.modules.system.entity.SysUser;
import org.jeecg.modules.system.vo.SysRoleAuthorisationVo;
import org.jeecgframework.poi.excel.entity.ImportParams;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
/**
@ -33,6 +27,12 @@ public interface ISysRoleService extends IService<SysRole> {
*/
Page<SysRole> page(PageRequest pageRequest, String roleName, String roleCode);
/**
* 获取所有角色
* @return
*/
List<SysRole> getAll();
/**
* 查询单条角色数据
* @param roleId
@ -65,4 +65,9 @@ public interface ISysRoleService extends IService<SysRole> {
*/
void deleteRole(String roleid);
/**
* 查询指定角色已授权的信息
* @param id
*/
List<String> getAuthorizedInfo(@NotBlank(message = "id不能为空") String id);
}

View File

@ -1,5 +1,6 @@
package org.jeecg.modules.system.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
@ -10,7 +11,6 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.jeecg.common.constant.CacheConstant;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.constant.SymbolConstant;
import org.jeecg.config.JeecgBaseConfig;
@ -18,9 +18,13 @@ import org.jeecg.common.system.query.PageRequest;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.*;
import org.jeecg.config.datasource.DataSourceSwitcher;
import org.jeecg.config.security.utils.SecureUtil;
import org.jeecg.modules.system.entity.*;
import org.jeecg.modules.system.mapper.*;
import org.jeecg.modules.system.model.PermissionTreeModel;
import org.jeecg.modules.system.service.IAuthUserService;
import org.jeecg.modules.system.util.SecurityUtil;
import org.jeecg.modules.system.util.TreeUtil;
import org.jeecg.modules.system.vo.SysUserVo;
import org.jetbrains.annotations.Nullable;
import org.springframework.beans.BeanUtils;
@ -153,7 +157,8 @@ public class AuthUserServiceImpl extends ServiceImpl<AuthUserMapper, SysUser> im
if (!newpassword.equals(confirmpassword)) {
throw new RuntimeException("两次输入密码不一致");
}
user.setPassword(password);
String newPassword = PasswordUtil.encrypt(user.getUsername(),newpassword, user.getSalt());
user.setPassword(newPassword);
this.baseMapper.updateById(user);
this.transactionManager.commit(transactionStatus);
}catch (Exception e){
@ -296,6 +301,17 @@ public class AuthUserServiceImpl extends ServiceImpl<AuthUserMapper, SysUser> im
return Collections.emptyList();
}
/**
* 获取用户所属菜单路径
*
* @param userId
* @return
*/
@Override
public List<String> getUserMenuPaths(String userId) {
return this.sysPermissionMapper.getUserMenuPaths(userId);
}
/**
* 保存用户
* @param userVo 用户
@ -368,7 +384,6 @@ public class AuthUserServiceImpl extends ServiceImpl<AuthUserMapper, SysUser> im
user.setRealname(userVo.getRealname());
user.setEmail(userVo.getEmail());
user.setPhone(userVo.getPhone());
user.setStatus(userVo.getStatus());
this.updateById(user);
this.transactionManager.commit(authTransactionStatus);
}catch (Exception e){
@ -410,6 +425,13 @@ public class AuthUserServiceImpl extends ServiceImpl<AuthUserMapper, SysUser> im
DataSourceSwitcher.switchToAuth();
final TransactionStatus authTransactionStatus = this.transactionManager.getTransaction(this.transactionDefinition);
try {
SysUser sysUser = this.baseMapper.selectById(id);
if(Objects.isNull(sysUser)){
throw new RuntimeException("此用户不存在");
}
if(CommonConstant.ADMIN_USER.equals(sysUser.getUsername()) && CommonConstant.STATUS_DISABLE.equals(status)){
throw new RuntimeException("不允许修改管理员用户为禁用状态");
}
this.baseMapper.update(new SysUser().setStatus(status),
new UpdateWrapper<SysUser>().lambda().eq(SysUser::getId,id));
this.transactionManager.commit(authTransactionStatus);
@ -478,6 +500,38 @@ public class AuthUserServiceImpl extends ServiceImpl<AuthUserMapper, SysUser> im
return null;
}
/**
* 查询用户有权限的菜单
*/
@Override
public List<PermissionTreeModel<SysPermission>> selectUserPermissions() {
LoginUser loginUser = SecureUtil.currentUser();
//如果当前用户是超级管理员则返回所有
List<SysPermission> childNodeInfoList = null;
if(!CommonConstant.ADMIN_USER.equals(loginUser.getUsername())){
childNodeInfoList = this.sysPermissionMapper.selectUserPermissions(loginUser.getId());
}else {
childNodeInfoList = this.sysPermissionMapper.selectList(new QueryWrapper<>());
}
if (CollUtil.isNotEmpty(childNodeInfoList)) {
List<PermissionTreeModel<SysPermission>> treeList = new ArrayList<>();
for(SysPermission node : childNodeInfoList){
PermissionTreeModel<SysPermission> treeModel = new PermissionTreeModel<>();
treeModel.setId(node.getId());
treeModel.setParentId(node.getParentId());
treeModel.setTitle(node.getName());
treeModel.setComponent(node.getComponent());
treeModel.setPath(node.getUrl());
treeModel.setIcon(node.getIcon());
treeModel.setType(node.getMenuType());
treeModel.setOrderNum(node.getSortNo());
treeList.add(treeModel);
}
return TreeUtil.build(treeList);
}
return Collections.emptyList();
}
/**
* 查询用户的角色code多个逗号分割
*

View File

@ -33,7 +33,7 @@ public class SysPermissionServiceImpl extends ServiceImpl<SysPermissionMapper, S
*/
@Override
public List<PermissionTreeModel<SysPermission>> getPermissionTree() {
List<SysPermission> childNodeInfoList = this.baseMapper.getChildNodeInfo();
List<SysPermission> childNodeInfoList = this.list();
if (CollUtil.isNotEmpty(childNodeInfoList)) {
List<PermissionTreeModel<SysPermission>> treeList = new ArrayList<>();
for(SysPermission node : childNodeInfoList){
@ -42,6 +42,7 @@ public class SysPermissionServiceImpl extends ServiceImpl<SysPermissionMapper, S
treeModel.setParentId(node.getParentId());
treeModel.setTitle(node.getName());
treeModel.setComponent(node.getComponent());
treeModel.setPath(node.getUrl());
treeModel.setIcon(node.getIcon());
treeModel.setType(node.getMenuType());
treeModel.setOrderNum(node.getSortNo());

View File

@ -7,6 +7,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.jeecg.common.system.query.PageRequest;
import org.jeecg.modules.system.entity.SysPermission;
import org.jeecg.modules.system.entity.SysRole;
import org.jeecg.modules.system.entity.SysRolePermission;
import org.jeecg.modules.system.mapper.AuthRoleMapper;
@ -17,8 +18,8 @@ import org.jeecg.modules.system.service.ISysRoleService;
import org.jeecg.modules.system.vo.SysRoleAuthorisationVo;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
@ -51,6 +52,18 @@ public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> impl
return this.baseMapper.selectPage(page, queryWrapper);
}
/**
* 获取所有角色
*
* @return
*/
@Override
public List<SysRole> getAll() {
LambdaQueryWrapper<SysRole> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.select(SysRole::getId, SysRole::getRoleCode, SysRole::getRoleName);
return this.list(queryWrapper);
}
/**
* 查询单条角色数据
*
@ -147,4 +160,15 @@ public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> impl
//3.删除角色
this.removeById(roleid);
}
/**
* 查询指定角色已授权的信息
*
* @param id
*/
@Override
public List<String> getAuthorizedInfo(String id) {
List<String> permissionIds = sysRoleMapper.getAuthorizedInfo(id);
return CollUtil.isNotEmpty(permissionIds)?permissionIds: Collections.emptyList();
}
}

View File

@ -10,7 +10,7 @@ public class TreeUtil {
}
private final static Integer TOP_NODE_ID = 0;
private final static String TOP_NODE_ID = "0";
/**
* 用于构建菜单树