1.修改对接过程中发现的系统管理相关功能接口问题
2.添加系统监控功能
This commit is contained in:
		
							parent
							
								
									fcec555a44
								
							
						
					
					
						commit
						67cad8b525
					
				|  | @ -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> | ||||
|  | @ -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; | ||||
| } | ||||
|  | @ -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); | ||||
|         } | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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); | ||||
|         }; | ||||
|     } | ||||
| } | ||||
| } | ||||
|  | @ -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; | ||||
|  |  | |||
|  | @ -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(); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | @ -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; | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| } | ||||
|  | @ -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; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | @ -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); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | @ -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:获取磁盘信息 | ||||
| } | ||||
|  | @ -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()); | ||||
| //    } | ||||
| // | ||||
| //} | ||||
|  | @ -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()); | ||||
|     } | ||||
| } | ||||
|  | @ -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当前的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 + '\'' + '}'; | ||||
| 	} | ||||
| } | ||||
|  | @ -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); | ||||
|     } | ||||
| } | ||||
|  | @ -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(); | ||||
| } | ||||
|  | @ -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(); | ||||
| } | ||||
|  | @ -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(); | ||||
| } | ||||
|  | @ -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(); | ||||
| } | ||||
|  | @ -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(); | ||||
|     } | ||||
| } | ||||
|  | @ -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")); | ||||
|     } | ||||
| } | ||||
|  | @ -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; | ||||
|     } | ||||
| } | ||||
|  | @ -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]系统监控功能优化------------ | ||||
| } | ||||
|  | @ -0,0 +1,14 @@ | |||
| package org.jeecg.modules.monitor.vo; | ||||
| 
 | ||||
| import lombok.Data; | ||||
| 
 | ||||
| /** | ||||
|  * 每个数据库数据量 | ||||
|  */ | ||||
| @Data | ||||
| public class DatabaseProportionInfo { | ||||
| 
 | ||||
|     private String databaseName; | ||||
| 
 | ||||
|     private Long dataSize; | ||||
| } | ||||
|  | @ -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 + '\'' + | ||||
|                     '}'; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -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(); | ||||
|     } | ||||
| } | ||||
|  | @ -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; | ||||
|  |  | |||
|  | @ -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, | ||||
|  |  | |||
|  | @ -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()); | ||||
|  |  | |||
|  | @ -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)); | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -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()); | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -37,9 +37,6 @@ public class SysUserRole implements Serializable { | |||
|      */ | ||||
|     private String roleId; | ||||
|      | ||||
|     /**租户ID*/ | ||||
|     private java.lang.Integer tenantId; | ||||
|      | ||||
| 	public SysUserRole() { | ||||
| 	} | ||||
| 
 | ||||
|  |  | |||
|  | @ -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); | ||||
| } | ||||
|  |  | |||
|  | @ -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); | ||||
| } | ||||
|  |  | |||
|  | @ -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> | ||||
|  | @ -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> | ||||
|  | @ -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(); | ||||
| } | ||||
|  |  | |||
|  | @ -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); | ||||
| } | ||||
|  |  | |||
|  | @ -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(多个逗号分割) | ||||
| 	 * | ||||
|  |  | |||
|  | @ -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()); | ||||
|  |  | |||
|  | @ -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(); | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -10,7 +10,7 @@ public class TreeUtil { | |||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     private final static Integer TOP_NODE_ID = 0; | ||||
|     private final static String TOP_NODE_ID = "0"; | ||||
| 
 | ||||
|     /** | ||||
|      * 用于构建菜单树 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 panbaolin
						panbaolin