配置文件
spring:
redis:
host: localhost
username: root
password:
port: 6379
datasource:
url: jdbc:mysql://localhost:3306/base-admin?Unicode=true&&allowPublicKeyRetrieval=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false&serverTimezone=GMT%2B8
username: root
password: root1234
server:
port: 8080
servlet:
context-path: /manage
ip:
local-parsing: true
pom文件:
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.5.12
com.example
Manage
0.0.1-SNAPSHOT
Manage
Manage
1.8
2.9.2
5.3.4
1.2.70
org.springframework.boot
spring-boot-starter-actuator
net.dreamlu
mica-ip2region
2.5.6
nl.basjes.parse.useragent
yauaa
5.23
org.springframework.boot
spring-boot-starter-data-redis
com.github.oshi
oshi-core
5.7.1
org.apache.commons
commons-lang3
cn.hutool
hutool-all
${hutool.version}
org.springframework.boot
spring-boot-starter-jdbc
org.springframework.boot
spring-boot-starter-quartz
org.springframework.boot
spring-boot-starter-security
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-websocket
org.springframework.boot
spring-boot-devtools
runtime
true
mysql
mysql-connector-java
runtime
org.projectlombok
lombok
true
org.springframework.boot
spring-boot-starter-test
test
org.springframework.restdocs
spring-restdocs-mockmvc
test
org.springframework.security
spring-security-test
test
io.springfox
springfox-swagger2
${swagger.version}
io.swagger
swagger-annotations
io.swagger
swagger-models
io.springfox
springfox-swagger-ui
${swagger.version}
io.swagger
swagger-annotations
1.5.21
io.swagger
swagger-models
1.5.21
org.apache.poi
poi
3.17
org.apache.poi
poi-ooxml
3.17
xerces
xercesImpl
2.12.2
com.alibaba
fastjson
${fastjson.version}
org.asciidoctor
asciidoctor-maven-plugin
1.5.8
generate-docs
prepare-package
process-asciidoc
html
book
org.springframework.restdocs
spring-restdocs-asciidoctor
${spring-restdocs.version}
org.springframework.boot
spring-boot-maven-plugin
org.projectlombok
lombok
更换喜欢的banner
m
启动Spring Boot时,会默认展示如下图案及Spring Boot的版本信息,可以看到默认中的图案字体为Spring
在Spring Boot工程的resource目录下新建一个文本文件banner.txt用于存放自定义图案
接下来我们需要生成一个自定义图案,如果手动去编辑图案则会比较麻烦,我们可以利用如下网址根据输入的字符直接生成字符图案。
http://patorjk.com/software/taag
然后重启服务就好了
//首先获取系统的监控信息
配置类
package com.example.manage.config; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; /** * @author xushuai * @date 2022年04月04日 20:38 */ @Component public class Ipconfig { public static Boolean ipLocal; @Value("${ip.local-parsing}") public void setIpLocal(Boolean ipLocal) { this.ipLocal = ipLocal; } }
package com.example.manage.Enum; public class ElAdminConstant { /** * 用于IP定位转换 */ public static final String REGION = "内网IP|内网IP"; /** * win 系统 */ public static final String WIN = "win"; /** * mac 系统 */ public static final String MAC = "mac"; /** * 常用接口 */ public static class Url { // IP归属地查询 public static final String IP_URL = "http://whois.pconline.com.cn/ipJson.jsp?ip=%s&json=true"; } }
工具类
package com.example.manage.utils; /** * @since: 1.0 * @see {@link SpringContextHolder} * 针对某些初始化方法,在SpringContextHolder 初始化前时,
* 可提交一个 提交回调任务。
* 在SpringContextHolder 初始化后,进行回调使用 */ public interface CallBack { /** * 回调执行方法 */ void executor(); /** * 本回调任务名称 * @return / */ default String getCallBackName() { return Thread.currentThread().getId() + ":" + this.getClass().getName(); } }package com.example.manage.utils; import java.io.Closeable; /** * @description 用于关闭各种连接,缺啥补啥 * **/ public class CloseUtil { public static void close(Closeable closeable) { if (null != closeable) { try { closeable.close(); } catch (Exception e) { // 静默关闭 } } } public static void close(AutoCloseable closeable) { if (null != closeable) { try { closeable.close(); } catch (Exception e) { // 静默关闭 } } } }
package com.example.manage.utils; import cn.hutool.core.io.IoUtil; import cn.hutool.core.util.IdUtil; import cn.hutool.poi.excel.BigExcelWriter; import cn.hutool.poi.excel.ExcelUtil; import com.example.manage.Exception.BadRequestException; import org.apache.poi.util.IOUtils; import org.apache.poi.xssf.streaming.SXSSFSheet; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.multipart.MultipartFile; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.*; import java.security.MessageDigest; import java.text.DecimalFormat; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; import java.util.Map; public class FileUtil extends cn.hutool.core.io.FileUtil { private static final Logger log = LoggerFactory.getLogger(FileUtil.class); /** * 系统临时目录 *
* windows 包含路径分割符,但Linux 不包含, * 在windows \\==\ 前提下, * 为安全起见 同意拼装 路径分割符, ** java.io.tmpdir * windows : C:\Users/xxx\AppData\Local\Temp\ * linux: /temp **/ public static final String SYS_TEM_DIR = System.getProperty("java.io.tmpdir") + File.separator; /** * 定义GB的计算常量 */ private static final int GB = 1024 * 1024 * 1024; /** * 定义MB的计算常量 */ private static final int MB = 1024 * 1024; /** * 定义KB的计算常量 */ private static final int KB = 1024; /** * 格式化小数 */ private static final DecimalFormat DF = new DecimalFormat("0.00"); public static final String IMAGE = "图片"; public static final String TXT = "文档"; public static final String MUSIC = "音乐"; public static final String VIDEO = "视频"; public static final String OTHER = "其他"; /** * MultipartFile转File */ public static File toFile(MultipartFile multipartFile) { // 获取文件名 String fileName = multipartFile.getOriginalFilename(); // 获取文件后缀 String prefix = "." + getExtensionName(fileName); File file = null; try { // 用uuid作为文件名,防止生成的临时文件重复 file = new File(SYS_TEM_DIR + IdUtil.simpleUUID() + prefix); // MultipartFile to File multipartFile.transferTo(file); } catch (IOException e) { log.error(e.getMessage(), e); } return file; } /** * 获取文件扩展名,不带 . */ public static String getExtensionName(String filename) { if ((filename != null) && (filename.length() > 0)) { int dot = filename.lastIndexOf('.'); if ((dot > -1) && (dot < (filename.length() - 1))) { return filename.substring(dot + 1); } } return filename; } /** * Java文件操作 获取不带扩展名的文件名 */ public static String getFileNameNoEx(String filename) { if ((filename != null) && (filename.length() > 0)) { int dot = filename.lastIndexOf('.'); if ((dot > -1) && (dot < (filename.length()))) { return filename.substring(0, dot); } } return filename; } /** * 文件大小转换 */ public static String getSize(long size) { String resultSize; if (size / GB >= 1) { //如果当前Byte的值大于等于1GB resultSize = DF.format(size / (float) GB) + "GB "; } else if (size / MB >= 1) { //如果当前Byte的值大于等于1MB resultSize = DF.format(size / (float) MB) + "MB "; } else if (size / KB >= 1) { //如果当前Byte的值大于等于1KB resultSize = DF.format(size / (float) KB) + "KB "; } else { resultSize = size + "B "; } return resultSize; } /** * inputStream 转 File */ static File inputStreamToFile(InputStream ins, String name){ File file = new File(SYS_TEM_DIR + name); if (file.exists()) { return file; } OutputStream os = null; try { os = new FileOutputStream(file); int bytesRead; int len = 8192; byte[] buffer = new byte[len]; while ((bytesRead = ins.read(buffer, 0, len)) != -1) { os.write(buffer, 0, bytesRead); } } catch (Exception e) { e.printStackTrace(); } finally { CloseUtil.close(os); CloseUtil.close(ins); } return file; } /** * 将文件名解析成文件的上传路径 */ public static File upload(MultipartFile file, String filePath) { Date date = new Date(); SimpleDateFormat format = new SimpleDateFormat("yyyyMMddhhmmssS"); String name = getFileNameNoEx(file.getOriginalFilename()); String suffix = getExtensionName(file.getOriginalFilename()); String nowStr = "-" + format.format(date); try { String fileName = name + nowStr + "." + suffix; String path = filePath + fileName; // getCanonicalFile 可解析正确各种路径 File dest = new File(path).getCanonicalFile(); // 检测是否存在目录 if (!dest.getParentFile().exists()) { if (!dest.getParentFile().mkdirs()) { System.out.println("was not successful."); } } // 文件写入 file.transferTo(dest); return dest; } catch (Exception e) { log.error(e.getMessage(), e); } return null; } /** * 导出excel */ public static void downloadExcel(List/* * Copyright 2019-2020 Zheng Jie * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.example.manage.utils; import cn.hutool.http.HttpUtil; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; import com.example.manage.Enum.ElAdminConstant; import com.example.manage.config.Ipconfig; import lombok.extern.slf4j.Slf4j; import net.dreamlu.mica.ip2region.core.Ip2regionSearcher; import net.dreamlu.mica.ip2region.core.IpInfo; import nl.basjes.parse.useragent.UserAgent; import nl.basjes.parse.useragent.UserAgentAnalyzer; import javax.servlet.http.HttpServletRequest; import java.net.InetAddress; import java.net.NetworkInterface; import java.net.UnknownHostException; import java.util.Calendar; import java.util.Date; import java.util.Enumeration; /** * * 字符串工具类, 继承org.apache.commons.lang3.StringUtils类 */ @Slf4j public class StringUtils extends org.apache.commons.lang3.StringUtils { private static final char SEPARATOR = '_'; private static final String UNKNOWN = "unknown"; /** * 注入bean */ private final static Ip2regionSearcher IP_SEARCHER = SpringContextHolder.getBean(Ip2regionSearcher.class); private static final UserAgentAnalyzer USER_AGENT_ANALYZER = UserAgentAnalyzer .newBuilder() .hideMatcherLoadStats() .withCache(10000) .withField(UserAgent.AGENT_NAME_VERSION) .build(); /** * 驼峰命名法工具 * * @return toCamelCase(" hello_world ") == "helloWorld" * toCapitalizeCamelCase("hello_world") == "HelloWorld" * toUnderScoreCase("helloWorld") = "hello_world" */ public static String toCamelCase(String s) { if (s == null) { return null; } s = s.toLowerCase(); StringBuilder sb = new StringBuilder(s.length()); boolean upperCase = false; for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); if (c == SEPARATOR) { upperCase = true; } else if (upperCase) { sb.append(Character.toUpperCase(c)); upperCase = false; } else { sb.append(c); } } return sb.toString(); } /** * 驼峰命名法工具 * * @return toCamelCase(" hello_world ") == "helloWorld" * toCapitalizeCamelCase("hello_world") == "HelloWorld" * toUnderScoreCase("helloWorld") = "hello_world" */ public static String toCapitalizeCamelCase(String s) { if (s == null) { return null; } s = toCamelCase(s); return s.substring(0, 1).toUpperCase() + s.substring(1); } /** * 驼峰命名法工具 * * @return toCamelCase(" hello_world ") == "helloWorld" * toCapitalizeCamelCase("hello_world") == "HelloWorld" * toUnderScoreCase("helloWorld") = "hello_world" */ static String toUnderScoreCase(String s) { if (s == null) { return null; } StringBuilder sb = new StringBuilder(); boolean upperCase = false; for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); boolean nextUpperCase = true; if (i < (s.length() - 1)) { nextUpperCase = Character.isUpperCase(s.charAt(i + 1)); } if ((i > 0) && Character.isUpperCase(c)) { if (!upperCase || !nextUpperCase) { sb.append(SEPARATOR); } upperCase = true; } else { upperCase = false; } sb.append(Character.toLowerCase(c)); } return sb.toString(); } /** * 获取ip地址 */ public static String getIp(HttpServletRequest request) { String ip = request.getHeader("x-forwarded-for"); if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) { ip = request.getHeader("Proxy-Client-IP"); } if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) { ip = request.getHeader("WL-Proxy-Client-IP"); } if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) { ip = request.getRemoteAddr(); } String comma = ","; String localhost = "127.0.0.1"; if (ip.contains(comma)) { ip = ip.split(",")[0]; } if (localhost.equals(ip)) { // 获取本机真正的ip地址 try { ip = InetAddress.getLocalHost().getHostAddress(); } catch (UnknownHostException e) { log.error(e.getMessage(), e); } } return ip; } /** * 根据ip获取详细地址 */ public static String getCityInfo(String ip) { if (Ipconfig.ipLocal) { return getLocalCityInfo(ip); } else { return getHttpCityInfo(ip); } } /** * 根据ip获取详细地址 */ public static String getHttpCityInfo(String ip) { String api = String.format(ElAdminConstant.Url.IP_URL, ip); JSONObject object = JSONUtil.parseObj(HttpUtil.get(api)); return object.get("addr", String.class); } /** * 根据ip获取详细地址 */ public static String getLocalCityInfo(String ip) { IpInfo ipInfo = IP_SEARCHER.memorySearch(ip); if(ipInfo != null){ return ipInfo.getAddress(); } return null; } public static String getBrowser(HttpServletRequest request) { UserAgent.ImmutableUserAgent userAgent = USER_AGENT_ANALYZER.parse(request.getHeader("User-Agent")); return userAgent.get(UserAgent.AGENT_NAME_VERSION).getValue(); } /** * 获得当天是周几 */ public static String getWeekDay() { String[] weekDays = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; Calendar cal = Calendar.getInstance(); cal.setTime(new Date()); int w = cal.get(Calendar.DAY_OF_WEEK) - 1; if (w < 0) { w = 0; } return weekDays[w]; } /** * 获取当前机器的IP * * @return / */ public static String getLocalIp() { try { InetAddress candidateAddress = null; // 遍历所有的网络接口 for (Enumeration
interfaces = NetworkInterface.getNetworkInterfaces(); interfaces.hasMoreElements();) { NetworkInterface anInterface = interfaces.nextElement(); // 在所有的接口下再遍历IP for (Enumeration inetAddresses = anInterface.getInetAddresses(); inetAddresses.hasMoreElements();) { InetAddress inetAddr = inetAddresses.nextElement(); // 排除loopback类型地址 if (!inetAddr.isLoopbackAddress()) { if (inetAddr.isSiteLocalAddress()) { // 如果是site-local地址,就是它了 return inetAddr.getHostAddress(); } else if (candidateAddress == null) { // site-local类型的地址未被发现,先记录候选地址 candidateAddress = inetAddr; } } } } if (candidateAddress != null) { return candidateAddress.getHostAddress(); } // 如果没有发现 non-loopback地址.只能用最次选的方案 InetAddress jdkSuppliedAddress = InetAddress.getLocalHost(); if (jdkSuppliedAddress == null) { return ""; } return jdkSuppliedAddress.getHostAddress(); } catch (Exception e) { return ""; } } } package com.example.manage.utils; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeansException; import org.springframework.beans.factory.DisposableBean; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.core.env.Environment; import java.util.ArrayList; import java.util.List; @Slf4j public class SpringContextHolder implements ApplicationContextAware, DisposableBean { private static ApplicationContext applicationContext = null; private static final List
CALL_BACKS = new ArrayList<>(); private static boolean addCallback = true; /** * 针对 某些初始化方法,在SpringContextHolder 未初始化时 提交回调方法。 * 在SpringContextHolder 初始化后,进行回调使用 * * @param callBack 回调函数 */ public synchronized static void addCallBacks(CallBack callBack) { if (addCallback) { SpringContextHolder.CALL_BACKS.add(callBack); } else { log.warn("CallBack:{} 已无法添加!立即执行", callBack.getCallBackName()); callBack.executor(); } } /** * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型. */ @SuppressWarnings("unchecked") public static T getBean(String name) { assertContextInjected(); return (T) applicationContext.getBean(name); } /** * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型. */ public static T getBean(Class requiredType) { assertContextInjected(); return applicationContext.getBean(requiredType); } /** * 获取SpringBoot 配置信息 * * @param property 属性key * @param defaultValue 默认值 * @param requiredType 返回类型 * @return / */ public static T getProperties(String property, T defaultValue, Class requiredType) { T result = defaultValue; try { result = getBean(Environment.class).getProperty(property, requiredType); } catch (Exception ignored) {} return result; } /** * 获取SpringBoot 配置信息 * * @param property 属性key * @return / */ public static String getProperties(String property) { return getProperties(property, null, String.class); } /** * 获取SpringBoot 配置信息 * * @param property 属性key * @param requiredType 返回类型 * @return / */ public static T getProperties(String property, Class requiredType) { return getProperties(property, null, requiredType); } /** * 检查ApplicationContext不为空. */ private static void assertContextInjected() { if (applicationContext == null) { throw new IllegalStateException("applicaitonContext属性未注入, 请在applicationContext" + ".xml中定义SpringContextHolder或在SpringBoot启动类中注册SpringContextHolder."); } } /** * 清除SpringContextHolder中的ApplicationContext为Null. */ private static void clearHolder() { log.debug("清除SpringContextHolder中的ApplicationContext:" + applicationContext); applicationContext = null; } @Override public void destroy() { SpringContextHolder.clearHolder(); } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { if (SpringContextHolder.applicationContext != null) { log.warn("SpringContextHolder中的ApplicationContext被覆盖, 原有ApplicationContext为:" + SpringContextHolder.applicationContext); } SpringContextHolder.applicationContext = applicationContext; if (addCallback) { for (CallBack callBack : SpringContextHolder.CALL_BACKS) { callBack.executor(); } CALL_BACKS.clear(); } SpringContextHolder.addCallback = false; } } Controller
package com.example.manage.controller.monitor; import com.example.manage.service.monitor.MonitorService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * @author xushuai * @date 2022年04月04日 20:12 */ @RestController @RequiredArgsConstructor @Api(tags = "系统-服务监控管理") @RequestMapping("/api/monitor") public class MonitorController { @Autowired private MonitorService serverService; @GetMapping @ApiOperation("查询服务监控") @PreAuthorize("@el.check('monitor:list')") public ResponseEntity
Service
package com.example.manage.serviceImpl.monitor; import cn.hutool.core.date.BetweenFormater; import cn.hutool.core.date.DateUtil; import com.example.manage.Enum.ElAdminConstant; import com.example.manage.service.monitor.MonitorService; import com.example.manage.utils.FileUtil; import com.example.manage.utils.StringUtils; import org.springframework.stereotype.Service; import oshi.SystemInfo; import oshi.hardware.CentralProcessor; import oshi.hardware.GlobalMemory; import oshi.hardware.HardwareAbstractionLayer; import oshi.hardware.VirtualMemory; import oshi.software.os.FileSystem; import oshi.software.os.OSFileStore; import oshi.software.os.OperatingSystem; import oshi.util.FormatUtil; import oshi.util.Util; import java.lang.management.ManagementFactory; import java.text.DecimalFormat; import java.util.Date; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; /** * @author xushuai * @date 2022年04月04日 20:19 */ @Service public class MonitorServiceImpl implements MonitorService { private final DecimalFormat df = new DecimalFormat("0.00"); /** * 获取磁盘信息 * @return / */ private Map
getDiskInfo(OperatingSystem os) { Map diskInfo = new LinkedHashMap<>(); FileSystem fileSystem = os.getFileSystem(); List fsArray = fileSystem.getFileStores(); String osName = System.getProperty("os.name"); long available = 0, total = 0; for (OSFileStore fs : fsArray){ // windows 需要将所有磁盘分区累加,linux 和 mac 直接累加会出现磁盘重复的问题,待修复 if(osName.toLowerCase().startsWith(ElAdminConstant.WIN)) { available += fs.getUsableSpace(); total += fs.getTotalSpace(); } else { available = fs.getUsableSpace(); total = fs.getTotalSpace(); break; } } long used = total - available; diskInfo.put("total", total > 0 ? FileUtil.getSize(total) : "?"); diskInfo.put("available", FileUtil.getSize(available)); diskInfo.put("used", FileUtil.getSize(used)); if(total != 0){ diskInfo.put("usageRate", df.format(used/(double)total * 100)); } else { diskInfo.put("usageRate", 0); } return diskInfo; } /** * 获取交换区信息 * @param memory / * @return / */ private Map getSwapInfo(GlobalMemory memory) { Map swapInfo = new LinkedHashMap<>(); VirtualMemory virtualMemory = memory.getVirtualMemory(); long total = virtualMemory.getSwapTotal(); long used = virtualMemory.getSwapUsed(); swapInfo.put("total", FormatUtil.formatBytes(total)); swapInfo.put("used", FormatUtil.formatBytes(used)); swapInfo.put("available", FormatUtil.formatBytes(total - used)); if(used == 0){ swapInfo.put("usageRate", 0); } else { swapInfo.put("usageRate", df.format(used/(double)total * 100)); } return swapInfo; } /** * 获取内存信息 * @param memory / * @return / */ private Map getMemoryInfo(GlobalMemory memory) { Map memoryInfo = new LinkedHashMap<>(); memoryInfo.put("total", FormatUtil.formatBytes(memory.getTotal())); memoryInfo.put("available", FormatUtil.formatBytes(memory.getAvailable())); memoryInfo.put("used", FormatUtil.formatBytes(memory.getTotal() - memory.getAvailable())); memoryInfo.put("usageRate", df.format((memory.getTotal() - memory.getAvailable())/(double)memory.getTotal() * 100)); return memoryInfo; } /** * 获取Cpu相关信息 * @param processor / * @return / */ private Map getCpuInfo(CentralProcessor processor) { Map cpuInfo = new LinkedHashMap<>(); cpuInfo.put("name", processor.getProcessorIdentifier().getName()); cpuInfo.put("package", processor.getPhysicalPackageCount() + "个物理CPU"); cpuInfo.put("core", processor.getPhysicalProcessorCount() + "个物理核心"); cpuInfo.put("coreNumber", processor.getPhysicalProcessorCount()); cpuInfo.put("logic", processor.getLogicalProcessorCount() + "个逻辑CPU"); // CPU信息 long[] prevTicks = processor.getSystemCpuLoadTicks(); // 等待1秒... Util.sleep(1000); long[] ticks = processor.getSystemCpuLoadTicks(); long user = ticks[CentralProcessor.TickType.USER.getIndex()] - prevTicks[CentralProcessor.TickType.USER.getIndex()]; long nice = ticks[CentralProcessor.TickType.NICE.getIndex()] - prevTicks[CentralProcessor.TickType.NICE.getIndex()]; long sys = ticks[CentralProcessor.TickType.SYSTEM.getIndex()] - prevTicks[CentralProcessor.TickType.SYSTEM.getIndex()]; long idle = ticks[CentralProcessor.TickType.IDLE.getIndex()] - prevTicks[CentralProcessor.TickType.IDLE.getIndex()]; long iowait = ticks[CentralProcessor.TickType.IOWAIT.getIndex()] - prevTicks[CentralProcessor.TickType.IOWAIT.getIndex()]; long irq = ticks[CentralProcessor.TickType.IRQ.getIndex()] - prevTicks[CentralProcessor.TickType.IRQ.getIndex()]; long softirq = ticks[CentralProcessor.TickType.SOFTIRQ.getIndex()] - prevTicks[CentralProcessor.TickType.SOFTIRQ.getIndex()]; long steal = ticks[CentralProcessor.TickType.STEAL.getIndex()] - prevTicks[CentralProcessor.TickType.STEAL.getIndex()]; long totalCpu = user + nice + sys + idle + iowait + irq + softirq + steal; cpuInfo.put("used", df.format(100d * user / totalCpu + 100d * sys / totalCpu)); cpuInfo.put("idle", df.format(100d * idle / totalCpu)); return cpuInfo; } /** * 获取系统相关信息,系统、运行天数、系统IP * @param os / * @return / */ private Map getSystemInfo(OperatingSystem os){ Map systemInfo = new LinkedHashMap<>(); // jvm 运行时间 long time = ManagementFactory.getRuntimeMXBean().getStartTime(); Date date = new Date(time); // 计算项目运行时间 String formatBetween = DateUtil.formatBetween(date, new Date(), BetweenFormater.Level.HOUR); // 系统信息 systemInfo.put("os", os.toString()); systemInfo.put("day", formatBetween); systemInfo.put("ip", StringUtils.getLocalIp()); return systemInfo; } @Override public Map getServers() { Map resultMap = new LinkedHashMap<>(8); try { SystemInfo si = new SystemInfo(); OperatingSystem os = si.getOperatingSystem(); HardwareAbstractionLayer hal = si.getHardware(); // 系统信息 resultMap.put("sys", getSystemInfo(os)); // cpu 信息 resultMap.put("cpu", getCpuInfo(hal.getProcessor())); // 内存信息 resultMap.put("memory", getMemoryInfo(hal.getMemory())); // 交换区信息 resultMap.put("swap", getSwapInfo(hal.getMemory())); // 磁盘 resultMap.put("disk", getDiskInfo(os)); resultMap.put("time", DateUtil.format(new Date(), "HH:mm:ss")); } catch (Exception e) { e.printStackTrace(); } return resultMap; } } package com.example.manage.Exception; import lombok.Getter; import org.springframework.http.HttpStatus; import static org.springframework.http.HttpStatus.BAD_REQUEST; /** * 统一异常处理 */ @Getter public class BadRequestException extends RuntimeException{ private Integer status = BAD_REQUEST.value(); public BadRequestException(String msg){ super(msg); } public BadRequestException(HttpStatus status,String msg){ super(msg); this.status = status.value(); } }
/* * Copyright 2019-2020 Zheng Jie * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.example.manage.Exception; import com.example.manage.utils.ThrowableUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; import java.util.Objects; import static org.springframework.http.HttpStatus.NOT_FOUND; @Slf4j @RestControllerAdvice public class GlobalExceptionHandler { /** * 处理所有不可知的异常 */ @ExceptionHandler(Throwable.class) public ResponseEntity
handleException(Throwable e){ // 打印堆栈信息 log.error(ThrowableUtil.getStackTrace(e)); return buildResponseEntity(ApiError.error(e.getMessage())); } /** * BadCredentialsException */ @ExceptionHandler(BadCredentialsException.class) public ResponseEntity badCredentialsException(BadCredentialsException e){ // 打印堆栈信息 String message = "坏的凭证".equals(e.getMessage()) ? "用户名或密码不正确" : e.getMessage(); log.error(message); return buildResponseEntity(ApiError.error(message)); } /** * 处理自定义异常 */ @ExceptionHandler(value = BadRequestException.class) public ResponseEntity badRequestException(BadRequestException e) { // 打印堆栈信息 log.error(ThrowableUtil.getStackTrace(e)); return buildResponseEntity(ApiError.error(e.getStatus(),e.getMessage())); } /** * 处理 EntityExist */ @ExceptionHandler(value = EntityExistException.class) public ResponseEntity entityExistException(EntityExistException e) { // 打印堆栈信息 log.error(ThrowableUtil.getStackTrace(e)); return buildResponseEntity(ApiError.error(e.getMessage())); } /** * 处理 EntityNotFound */ @ExceptionHandler(value = EntityNotFoundException.class) public ResponseEntity entityNotFoundException(EntityNotFoundException e) { // 打印堆栈信息 log.error(ThrowableUtil.getStackTrace(e)); return buildResponseEntity(ApiError.error(NOT_FOUND.value(),e.getMessage())); } /** * 处理所有接口数据验证异常 */ @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity handleMethodArgumentNotValidException(MethodArgumentNotValidException e){ // 打印堆栈信息 log.error(ThrowableUtil.getStackTrace(e)); String[] str = Objects.requireNonNull(e.getBindingResult().getAllErrors().get(0).getCodes())[1].split("\\."); String message = e.getBindingResult().getAllErrors().get(0).getDefaultMessage(); String msg = "不能为空"; if(msg.equals(message)){ message = str[1] + ":" + message; } return buildResponseEntity(ApiError.error(message)); } /** * 统一返回 */ private ResponseEntity buildResponseEntity(ApiError apiError) { return new ResponseEntity<>(apiError, HttpStatus.valueOf(apiError.getStatus())); } } /* * Copyright 2019-2020 Zheng Jie * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.example.manage.Exception; import org.springframework.util.StringUtils; public class EntityNotFoundException extends RuntimeException { public EntityNotFoundException(Class clazz, String field, String val) { super(EntityNotFoundException.generateMessage(clazz.getSimpleName(), field, val)); } private static String generateMessage(String entity, String field, String val) { return StringUtils.capitalize(entity) + " with " + field + " "+ val + " does not exist"; } }
package com.example.manage.Exception; import org.springframework.util.StringUtils; public class EntityExistException extends RuntimeException { public EntityExistException(Class clazz, String field, String val) { super(EntityExistException.generateMessage(clazz.getSimpleName(), field, val)); } private static String generateMessage(String entity, String field, String val) { return StringUtils.capitalize(entity) + " with " + field + " "+ val + " existed"; } }
package com.example.manage.Exception; public class BadConfigurationException extends RuntimeException { /** * Constructs a new runtime exception with {@code null} as its * detail message. The cause is not initialized, and may subsequently be * initialized by a call to {@link #initCause}. */ public BadConfigurationException() { super(); } /** * Constructs a new runtime exception with the specified detail message. * The cause is not initialized, and may subsequently be initialized by a * call to {@link #initCause}. * * @param message the detail message. The detail message is saved for * later retrieval by the {@link #getMessage()} method. */ public BadConfigurationException(String message) { super(message); } /** * Constructs a new runtime exception with the specified detail message and * cause.
Note that the detail message associated with * {@code cause} is not automatically incorporated in * this runtime exception's detail message. * * @param message the detail message (which is saved for later retrieval * by the {@link #getMessage()} method). * @param cause the cause (which is saved for later retrieval by the * {@link #getCause()} method). (A {@code null} value is * permitted, and indicates that the cause is nonexistent or * unknown.) * @since 1.4 */ public BadConfigurationException(String message, Throwable cause) { super(message, cause); } /** * Constructs a new runtime exception with the specified cause and a * detail message of {@code (cause==null ? null : cause.toString())} * (which typically contains the class and detail message of * {@code cause}). This constructor is useful for runtime exceptions * that are little more than wrappers for other throwables. * * @param cause the cause (which is saved for later retrieval by the * {@link #getCause()} method). (A {@code null} value is * permitted, and indicates that the cause is nonexistent or * unknown.) * @since 1.4 */ public BadConfigurationException(Throwable cause) { super(cause); } /** * Constructs a new runtime exception with the specified detail * message, cause, suppression enabled or disabled, and writable * stack trace enabled or disabled. * * @param message the detail message. * @param cause the cause. (A {@code null} value is permitted, * and indicates that the cause is nonexistent or unknown.) * @param enableSuppression whether or not suppression is enabled * or disabled * @param writableStackTrace whether or not the stack trace should * be writable * @since 1.7 */ protected BadConfigurationException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { super(message, cause, enableSuppression, writableStackTrace); } }
package com.example.manage.Exception; import com.fasterxml.jackson.annotation.JsonFormat; import lombok.Data; import java.time.LocalDateTime; @Data class ApiError { private Integer status = 400; @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime timestamp; private String message; private ApiError() { timestamp = LocalDateTime.now(); } public static ApiError error(String message){ ApiError apiError = new ApiError(); apiError.setMessage(message); return apiError; } public static ApiError error(Integer status, String message){ ApiError apiError = new ApiError(); apiError.setStatus(status); apiError.setMessage(message); return apiError; } }