diff --git a/jeecg-boot-base-core/pom.xml b/jeecg-boot-base-core/pom.xml index 95c6bef..6ed39fc 100644 --- a/jeecg-boot-base-core/pom.xml +++ b/jeecg-boot-base-core/pom.xml @@ -333,17 +333,6 @@ edu.ucar netcdfAll ${netcdfAll.version} - - - - - - - - - - - \ No newline at end of file diff --git a/jeecg-boot-base-core/src/main/java/org/jeecg/common/properties/PrometheusServerProperties.java b/jeecg-boot-base-core/src/main/java/org/jeecg/common/properties/PrometheusServerProperties.java new file mode 100644 index 0000000..eeef974 --- /dev/null +++ b/jeecg-boot-base-core/src/main/java/org/jeecg/common/properties/PrometheusServerProperties.java @@ -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; +} diff --git a/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/JeecgPermissionService.java b/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/JeecgPermissionService.java index f338525..095b479 100644 --- a/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/JeecgPermissionService.java +++ b/jeecg-boot-base-core/src/main/java/org/jeecg/config/security/JeecgPermissionService.java @@ -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 permissionList; - if (Objects.nonNull(cache)) { - permissionList = (List) cache; - } else { + List permissionList = List.of(); + boolean flag = false; + if (Objects.nonNull(cache) && cache instanceof List) { + if(!((List) cache).isEmpty()){ + flag = true; + permissionList = (List) cache; + } + } + if(!flag){ permissionList = commonAPI.queryUserAuths(loginUser.getId()); redisUtil.set(buildKey("permission", loginUser.getId()), permissionList); } diff --git a/jeecg-module-system/jeecg-system-biz/pom.xml b/jeecg-module-system/jeecg-system-biz/pom.xml index cbc09c5..7c89f00 100644 --- a/jeecg-module-system/jeecg-system-biz/pom.xml +++ b/jeecg-module-system/jeecg-system-biz/pom.xml @@ -24,6 +24,10 @@ org.jeecgframework.boot3 hibernate-re + + org.springframework.boot + spring-boot-starter-webflux + diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/actuator/undertow/CustomUndertowMetricsHandler.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/config/init/CustomUndertowMetricsHandler.java similarity index 93% rename from jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/actuator/undertow/CustomUndertowMetricsHandler.java rename to jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/config/init/CustomUndertowMetricsHandler.java index f80e20a..de37d67 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/actuator/undertow/CustomUndertowMetricsHandler.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/config/init/CustomUndertowMetricsHandler.java @@ -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); }; } -} \ No newline at end of file +} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/config/init/UndertowConfiguration.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/config/init/UndertowConfiguration.java index 3fd059a..d0b1a81 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/config/init/UndertowConfiguration.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/config/init/UndertowConfiguration.java @@ -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; diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/actuator/CustomActuatorConfig.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/actuator/CustomActuatorConfig.java deleted file mode 100644 index a7c85b0..0000000 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/actuator/CustomActuatorConfig.java +++ /dev/null @@ -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(); - } - -} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/actuator/httptrace/CustomHttpTraceEndpoint.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/actuator/httptrace/CustomHttpTraceEndpoint.java deleted file mode 100644 index 71aebfc..0000000 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/actuator/httptrace/CustomHttpTraceEndpoint.java +++ /dev/null @@ -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 traces; - - private HttpTraceDescriptor(List traces) { - this.traces = traces; - } - - } -} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/actuator/httptrace/CustomInMemoryHttpTraceRepository.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/actuator/httptrace/CustomInMemoryHttpTraceRepository.java deleted file mode 100644 index 2c52cb5..0000000 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/actuator/httptrace/CustomInMemoryHttpTraceRepository.java +++ /dev/null @@ -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 findAll() { - return super.findAll(); - } - - public List findAll(String query) { - List allTrace = super.findAll(); - if (null != allTrace && !allTrace.isEmpty()) { - Stream stream = allTrace.stream(); - String[] params = query.split(","); - stream = filter(params, stream); - stream = sort(params, stream); - allTrace = stream.collect(Collectors.toList()); - } - return allTrace; - } - - private Stream sort(String[] params, Stream 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 filter(String[] params, Stream 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; - } - -} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/controller/ActuatorMemoryController.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/controller/ActuatorMemoryController.java deleted file mode 100644 index 69559fe..0000000 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/controller/ActuatorMemoryController.java +++ /dev/null @@ -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 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); - } - -} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/controller/ActuatorRedisController.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/controller/ActuatorRedisController.java deleted file mode 100644 index 89d90dc..0000000 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/controller/ActuatorRedisController.java +++ /dev/null @@ -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 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>> metricsHistory = this.redisService.getMetricsHistory(); - return Result.OK(metricsHistory); - } - //update-end---author:chenrui ---date:20240514 for:[QQYUN-9247]系统监控功能优化------------ - - @GetMapping("/keysSize") - public Map getKeysSize() throws Exception { - return redisService.getKeysSize(); - } - - /** - * 获取redis key数量 for 报表 - * @return - * @throws Exception - */ - @GetMapping("/keysSizeForReport") - public Map getKeysSizeReport() throws Exception { - return redisService.getMapForReport("1"); - } - /** - * 获取redis 内存 for 报表 - * - * @return - * @throws Exception - */ - @GetMapping("/memoryForReport") - public Map memoryForReport() throws Exception { - return redisService.getMapForReport("2"); - } - /** - * 获取redis 全部信息 for 报表 - * @return - * @throws Exception - */ - @GetMapping("/infoForReport") - public Map infoForReport() throws Exception { - return redisService.getMapForReport("3"); - } - - @GetMapping("/memoryInfo") - public Map getMemoryInfo() throws Exception { - return redisService.getMemoryInfo(); - } - - //update-begin--Author:zhangweijian Date:20190425 for:获取磁盘信息 - /** - * @功能:获取磁盘信息 - * @param request - * @param response - * @return - */ - @GetMapping("/queryDiskInfo") - public Result>> queryDiskInfo(HttpServletRequest request, HttpServletResponse response){ - Result>> res = new Result<>(); - try { - // 当前文件系统类 - FileSystemView fsv = FileSystemView.getFileSystemView(); - // 列出所有windows 磁盘 - File[] fs = File.listRoots(); - log.info("查询磁盘信息:"+fs.length+"个"); - List> list = new ArrayList<>(); - - for (int i = 0; i < fs.length; i++) { - if(fs[i].getTotalSpace()==0) { - continue; - } - Map 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:获取磁盘信息 -} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/controller/DatabaseMonitorController.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/controller/DatabaseMonitorController.java new file mode 100644 index 0000000..bd59f77 --- /dev/null +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/controller/DatabaseMonitorController.java @@ -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()); +// } +// +//} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/controller/ServiceMonitorController.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/controller/ServiceMonitorController.java new file mode 100644 index 0000000..b080619 --- /dev/null +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/controller/ServiceMonitorController.java @@ -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()); + } +} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/domain/RedisInfo.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/domain/RedisInfo.java deleted file mode 100644 index 2249221..0000000 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/domain/RedisInfo.java +++ /dev/null @@ -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 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当前的qps,redis内部较实时的每秒执行的命令数"); - 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 + '\'' + '}'; - } -} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/exception/RedisConnectException.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/exception/RedisConnectException.java deleted file mode 100644 index 0cc67b2..0000000 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/exception/RedisConnectException.java +++ /dev/null @@ -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); - } -} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/mapper/DatabaseMonitorMapper.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/mapper/DatabaseMonitorMapper.java new file mode 100644 index 0000000..6bbcbc0 --- /dev/null +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/mapper/DatabaseMonitorMapper.java @@ -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 getActiveSessionInfo(); +} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/service/DatabaseMonitorService.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/service/DatabaseMonitorService.java new file mode 100644 index 0000000..835c44a --- /dev/null +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/service/DatabaseMonitorService.java @@ -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 getCpuInfo(); + + /** + * 获取内存信息 + */ + Map getMemoryInfo(); + + /** + * 获取表空间信息 + * @return + */ + Map getTableSpaceInfo(); + + /** + * 获取活跃连接数信息 + * @return + */ + Map getActiveSessionInfo(); + + /** + * 获取死锁信息 + * @return + */ + Map getDeadlocksInfo(); + + /** + * 获取数据库占比信息 + * @return + */ + List getDatabaseProportionInfo(); +} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/service/HostMonitorService.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/service/HostMonitorService.java new file mode 100644 index 0000000..71b8e41 --- /dev/null +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/service/HostMonitorService.java @@ -0,0 +1,38 @@ +package org.jeecg.modules.monitor.service; + + +import java.util.Map; + +public interface HostMonitorService { + + /** + * 获取CPU信息 + */ + Map getCpuInfo(); + + /** + * 获取CPU核心数 + */ + Map getCpuCoreInfo(); + + /** + * 获取内存信息 + */ + Map getMemoryInfo(); + + /** + * 获取网络信息 + */ + Map getNetworkInfo(); + + /** + * 获取磁盘使用率 + */ + Map getDiskInfo(); + + /** + * 获取磁盘吞吐量 + * @return + */ + Map getDiskThroughputInfo(); +} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/service/RedisService.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/service/RedisService.java deleted file mode 100644 index 1eb17b5..0000000 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/service/RedisService.java +++ /dev/null @@ -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 getRedisInfo() throws RedisConnectException; - - /** - * 获取 redis key 数量 - * - * @return Map - * @throws RedisConnectException - */ - Map getKeysSize() throws RedisConnectException; - - /** - * 获取 redis 内存信息 - * - * @return Map - * @throws RedisConnectException - */ - Map getMemoryInfo() throws RedisConnectException; - /** - * 获取 报表需要个redis信息 - * @param type - * @return Map - * @throws RedisConnectException - */ - Map getMapForReport(String type) throws RedisConnectException ; - - /** - * 获取历史性能指标 - * @return - * @author chenrui - * @date 2024/5/14 14:57 - */ - Map>> getMetricsHistory(); -} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/service/impl/DatabaseMonitorServiceImpl.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/service/impl/DatabaseMonitorServiceImpl.java new file mode 100644 index 0000000..cfcda95 --- /dev/null +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/service/impl/DatabaseMonitorServiceImpl.java @@ -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 getCpuInfo() { + return Map.of(); + } + + /** + * 获取内存信息 + */ + @Override + public Map getMemoryInfo() { + return Map.of(); + } + + /** + * 获取表空间信息 + * + * @return + */ + @Override + public Map getTableSpaceInfo() { + return Map.of(); + } + + /** + * 获取活跃连接数信息 + * + * @return + */ + @Override + public Map getActiveSessionInfo() { + return Map.of(); + } + + /** + * 获取死锁信息 + * + * @return + */ + @Override + public Map getDeadlocksInfo() { + //irate(pg_stat_database_deadlocks{instance="192.168.186.143:9187", datname=~"postgres"}[5m]) + return Map.of(); + } + + /** + * 获取数据库占比信息 + * @return + */ + @Override + public List getDatabaseProportionInfo() { + return databaseMonitorMapper.getActiveSessionInfo(); + } +} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/service/impl/HostMonitorServiceImpl.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/service/impl/HostMonitorServiceImpl.java new file mode 100644 index 0000000..4099aba --- /dev/null +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/service/impl/HostMonitorServiceImpl.java @@ -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 getCpuInfo() { + Map 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 getCpuCoreInfo() { + Map 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 getMemoryInfo() { + Map 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 getNetworkInfo() { + Map 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 getDiskInfo() { + Map 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 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")); + } +} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/service/impl/MailHealthIndicator.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/service/impl/MailHealthIndicator.java deleted file mode 100644 index ea86410..0000000 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/service/impl/MailHealthIndicator.java +++ /dev/null @@ -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; - } -} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/service/impl/RedisServiceImpl.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/service/impl/RedisServiceImpl.java deleted file mode 100644 index bdeaa24..0000000 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/service/impl/RedisServiceImpl.java +++ /dev/null @@ -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>> REDIS_METRICS = new HashMap<>(2); - - /** - * Redis详细信息 - */ - @Override - public List getRedisInfo() throws RedisConnectException { - Properties info = redisConnectionFactory.getConnection().info(); - List infoList = new ArrayList<>(); - RedisInfo redisInfo = null; - for (Map.Entry 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 getKeysSize() throws RedisConnectException { - Long dbSize = redisConnectionFactory.getConnection().dbSize(); - Map map = new HashMap(5); - map.put("create_time", System.currentTimeMillis()); - map.put("dbSize", dbSize); - - log.debug("--getKeysSize--: " + map.toString()); - return map; - } - - @Override - public Map getMemoryInfo() throws RedisConnectException { - Map map = null; - Properties info = redisConnectionFactory.getConnection().info(); - for (Map.Entry 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 getMapForReport(String type) throws RedisConnectException { - Map mapJson=new HashMap(5); - JSONArray json = new JSONArray(); - if(REDIS_MESSAGE.equals(type)){ - List redisInfo = getRedisInfo(); - for(RedisInfo info:redisInfo){ - Map 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 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>> getMetricsHistory() { - return REDIS_METRICS; - } - - /** - * 记录近一小时redis监控数据
- * 60s一次,,记录存储keysize和内存 - * @throws RedisConnectException - * @author chenrui - * @date 2024/5/14 14:09 - */ - @Scheduled(fixedRate = 60000) - public void recordCustomMetric() throws RedisConnectException { - List> 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]系统监控功能优化------------ -} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/vo/DatabaseProportionInfo.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/vo/DatabaseProportionInfo.java new file mode 100644 index 0000000..80ab1f5 --- /dev/null +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/vo/DatabaseProportionInfo.java @@ -0,0 +1,14 @@ +package org.jeecg.modules.monitor.vo; + +import lombok.Data; + +/** + * 每个数据库数据量 + */ +@Data +public class DatabaseProportionInfo { + + private String databaseName; + + private Long dataSize; +} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/vo/PrometheusResponse.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/vo/PrometheusResponse.java new file mode 100644 index 0000000..f864e84 --- /dev/null +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/vo/PrometheusResponse.java @@ -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; + + public String getResultType() { + return resultType; + } + + public void setResultType(String resultType) { + this.resultType = resultType; + } + + public List getResult() { + return result; + } + + public void setResult(List result) { + this.result = result; + } + + @Override + public String toString() { + return "Data{" + + "resultType=" + resultType + + ", result=" + result + + '}'; + } + } + + public static class Result { + private Metric metric; + private List value; // 单值查询 + + public Metric getMetric() { + return metric; + } + + public void setMetric(Metric metric) { + this.metric = metric; + } + + public List getValue() { + return value; + } + + public void setValue(List 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 + '\'' + + '}'; + } + } +} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/config/WebClientConfig.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/config/WebClientConfig.java new file mode 100644 index 0000000..b116818 --- /dev/null +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/config/WebClientConfig.java @@ -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(); + } +} diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/LoginController.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/LoginController.java index bb792ed..56b075c 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/LoginController.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/LoginController.java @@ -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; diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysLogController.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysLogController.java index f20bd11..a56f73d 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysLogController.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysLogController.java @@ -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, diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysPermissionController.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysPermissionController.java index 58bde58..63665e5 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysPermissionController.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysPermissionController.java @@ -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()); diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysRoleController.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysRoleController.java index a30d964..f002c89 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysRoleController.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysRoleController.java @@ -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 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 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)); + } } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysUserController.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysUserController.java index db9a7e7..405811e 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysUserController.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysUserController.java @@ -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 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()); + } } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysUserRole.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysUserRole.java index 1998e3d..e6f9e50 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysUserRole.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/entity/SysUserRole.java @@ -37,9 +37,6 @@ public class SysUserRole implements Serializable { */ private String roleId; - /**租户ID*/ - private java.lang.Integer tenantId; - public SysUserRole() { } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysPermissionMapper.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysPermissionMapper.java index e5570a2..91cee26 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysPermissionMapper.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysPermissionMapper.java @@ -32,6 +32,13 @@ public interface SysPermissionMapper extends BaseMapper { */ List queryByUserId(@Param("userId") String userId); + /** + * 根据用户id查询菜单路径 + * @param userId + * @return + */ + List getUserMenuPaths(@Param("userId") String userId); + /** * 根据用户查询用户权限 * @param userName 用户ID @@ -61,5 +68,10 @@ public interface SysPermissionMapper extends BaseMapper { */ List getChildNodeInfo(); - + /** + * 获取用户拥有权限的菜单信息 + * @param userId + * @return + */ + List selectUserPermissions(@Param("userId") String userId); } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysRoleMapper.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysRoleMapper.java index 96c7745..8c47394 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysRoleMapper.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysRoleMapper.java @@ -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 { - /** - * 查询全部的角色(不做租户隔离) - * @param page - * @param role - * @return - */ - @InterceptorIgnore(tenantLine = "true") - List listAllSysRole(@Param("page") Page 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 { */ @Delete("delete from sys_role_permission where role_id = #{roleId}") void deleteRolePermissionRelation(@Param("roleId") String roleId); + + /** + * 查询指定角色已授权的信息 + * @param roleId + * @return + */ + List getAuthorizedInfo(@Param("roleId") String roleId); } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysPermissionMapper.xml b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysPermissionMapper.xml index defa829..3f22e8c 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysPermissionMapper.xml +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysPermissionMapper.xml @@ -29,7 +29,7 @@ + + + + \ No newline at end of file diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysRoleMapper.xml b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysRoleMapper.xml index b8fb607..ffb1ea9 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysRoleMapper.xml +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysRoleMapper.xml @@ -2,54 +2,18 @@ - - - - - + + \ No newline at end of file diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/IAuthUserService.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/IAuthUserService.java index b380919..e484308 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/IAuthUserService.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/IAuthUserService.java @@ -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 { */ List getUserPermissionsSet(String userId); + /** + * 获取用户所属菜单路径 + * @param userId + * @return + */ + List getUserMenuPaths(String userId); + /** * 保存用户 * @param userVo 用户 @@ -122,4 +130,9 @@ public interface IAuthUserService extends IService { LoginUser getEncodeUserInfo(String username); + + /** + * 查询用户有权限的菜单 + */ + List> selectUserPermissions(); } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/ISysRoleService.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/ISysRoleService.java index af562e8..18dd0d6 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/ISysRoleService.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/ISysRoleService.java @@ -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 { */ Page page(PageRequest pageRequest, String roleName, String roleCode); + /** + * 获取所有角色 + * @return + */ + List getAll(); + /** * 查询单条角色数据 * @param roleId @@ -65,4 +65,9 @@ public interface ISysRoleService extends IService { */ void deleteRole(String roleid); + /** + * 查询指定角色已授权的信息 + * @param id + */ + List getAuthorizedInfo(@NotBlank(message = "id不能为空") String id); } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/AuthUserServiceImpl.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/AuthUserServiceImpl.java index f584590..0bc66bf 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/AuthUserServiceImpl.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/AuthUserServiceImpl.java @@ -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 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 im return Collections.emptyList(); } + /** + * 获取用户所属菜单路径 + * + * @param userId + * @return + */ + @Override + public List getUserMenuPaths(String userId) { + return this.sysPermissionMapper.getUserMenuPaths(userId); + } + /** * 保存用户 * @param userVo 用户 @@ -368,7 +384,6 @@ public class AuthUserServiceImpl extends ServiceImpl 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 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().lambda().eq(SysUser::getId,id)); this.transactionManager.commit(authTransactionStatus); @@ -478,6 +500,38 @@ public class AuthUserServiceImpl extends ServiceImpl im return null; } + /** + * 查询用户有权限的菜单 + */ + @Override + public List> selectUserPermissions() { + LoginUser loginUser = SecureUtil.currentUser(); + //如果当前用户是超级管理员,则返回所有 + List 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> treeList = new ArrayList<>(); + for(SysPermission node : childNodeInfoList){ + PermissionTreeModel 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(多个逗号分割) * diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysPermissionServiceImpl.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysPermissionServiceImpl.java index 271be84..b9c0a29 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysPermissionServiceImpl.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysPermissionServiceImpl.java @@ -33,7 +33,7 @@ public class SysPermissionServiceImpl extends ServiceImpl> getPermissionTree() { - List childNodeInfoList = this.baseMapper.getChildNodeInfo(); + List childNodeInfoList = this.list(); if (CollUtil.isNotEmpty(childNodeInfoList)) { List> treeList = new ArrayList<>(); for(SysPermission node : childNodeInfoList){ @@ -42,6 +42,7 @@ public class SysPermissionServiceImpl extends ServiceImpl impl return this.baseMapper.selectPage(page, queryWrapper); } + /** + * 获取所有角色 + * + * @return + */ + @Override + public List getAll() { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.select(SysRole::getId, SysRole::getRoleCode, SysRole::getRoleName); + return this.list(queryWrapper); + } + /** * 查询单条角色数据 * @@ -147,4 +160,15 @@ public class SysRoleServiceImpl extends ServiceImpl impl //3.删除角色 this.removeById(roleid); } + + /** + * 查询指定角色已授权的信息 + * + * @param id + */ + @Override + public List getAuthorizedInfo(String id) { + List permissionIds = sysRoleMapper.getAuthorizedInfo(id); + return CollUtil.isNotEmpty(permissionIds)?permissionIds: Collections.emptyList(); + } } diff --git a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/util/TreeUtil.java b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/util/TreeUtil.java index 8eaec96..e6a0f24 100644 --- a/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/util/TreeUtil.java +++ b/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/util/TreeUtil.java @@ -10,7 +10,7 @@ public class TreeUtil { } - private final static Integer TOP_NODE_ID = 0; + private final static String TOP_NODE_ID = "0"; /** * 用于构建菜单树