Skip to content

使用oshi监控java运行

约 5223 字大约 17 分钟

SpringBoot

2025-03-04

本文作者:程序员飞云

本站地址:https://www.flycode.icu

展示效果

oshi

oshi官网

oshiApi

引入依赖

还需要引入lombok

    <!-- https://mvnrepository.com/artifact/com.github.oshi/oshi-core -->
<dependency>
    <groupId>com.github.oshi</groupId>
    <artifactId>oshi-core</artifactId>
    <version>6.6.5</version>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.8.26</version>
</dependency>

编写监控对象实体类

包含Cpu、Disk、Jvm、Mem、Sys

import lombok.Data;

import java.io.Serializable;

/**
 *  CPU相关信息
 */
@Data
public class Cpu implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * 核心数
     */
    private int cpuNum;

    /**
     * CPU总的使用率
     */
    private double total;

    /**
     * CPU系统使用率
     */
    private double sys;

    /**
     * CPU用户使用率
     */
    private double used;

    /**
     * CPU当前等待率
     */
    private double wait;

    /**
     * CPU当前空闲率
     */
    private double free;

}

import lombok.Data;

import java.io.Serializable;

/**
 * 系统文件相关信息
 */
@Data
public class Disk implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * 盘符路径
     */
    private String dirName;

    /**
     * 盘符类型
     */
    private String sysTypeName;

    /**
     * 文件类型
     */
    private String typeName;

    /**
     * 总大小
     */
    private String total;

    /**
     * 剩余大小
     */
    private String free;

    /**
     * 已经使用量
     */
    private String used;

    /**
     * 资源的使用率
     */
    private double usage;

}

import lombok.Data;

import java.io.Serializable;

/**
 * JVM相关信息
 */
@Data
public class Jvm implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * 当前JVM占用的内存总数(M)
     */
    private double total;

    /**
     * JVM最大可用内存总数(M)
     */
    private double max;

    /**
     * JVM空闲内存(M)
     */
    private double free;

    /**
     * JVM内存使用率
     */
    private double usage;

    /**
     * JDK版本
     */
    private String version;

    /**
     * JDK路径
     */
    private String home;

    /**
     * JDK名称
     */
    private String name;

    /**
     * 运行参数
     */
    private String inputArgs;

    /**
     * JDK运行时间
     */
    private String runTime;

    /**
     * JDK启动时间
     */
    private String startTime;
}
import lombok.Data;

import java.io.Serializable;

/**
 * 內存相关信息
 */
@Data
public class Mem implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * 内存总量
     */
    private double total;

    /**
     * 已用内存
     */
    private double used;

    /**
     * 剩余内存
     */
    private double free;

    /**
     * 使用率
     */
    private double usage;

}
import lombok.Data;

import java.io.Serializable;

/**
 * 系统相关信息
 */
@Data
public class Sys implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * 服务器名称
     */
    private String computerName;

    /**
     * 服务器Ip
     */
    private String computerIp;

    /**
     * 项目路径
     */
    private String userDir;

    /**
     * 操作系统
     */
    private String osName;

    /**
     * 系统架构
     */
    private String osArch;

}

工具类

也可以不需要这些工具类

获取当前Ip信息

package com.sky.utils;

import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;

/**
 * IP工具类
 */
@Slf4j
public class IpUtils {

    public static String getIpAddr(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("X-Forwarded-For");
        }
        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.getHeader("X-Real-IP");
        }

        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;
    }

    /**
     * 根据IP获取所在地址
     *
     * @param ip Ip地址
     * @return String (广州省 广州市)
     * @author fzr
     */
    public static String getRealAddressByIP(String ip) {
        String IP_URL = "https://whois.pconline.com.cn/ipJson.jsp";
        String UNKNOWN = "XX XX";

        // 内网不查询
        if (IpUtils.internalIp(ip)) {
            return "内网IP";
        }
        try {
            String rspStr = HttpUtil.get(IP_URL + "ip=" + ip + "&json=true" + "GBK");
            if (StringUtils.isEmpty(rspStr)) {
                log.error("获取地理位置异常 {}", ip);
                return UNKNOWN;
            }
            // 使用正则表达式提取 JSON 部分
            String jsonPart = rspStr.replaceAll(".*?\\{", "{").replaceAll("\\}.*", "}");
            JSONObject obj = JSONUtil.parseObj(jsonPart);
            String region = obj.getStr("pro");
            String city = obj.getStr("city");
            return String.format("%s %s", region, city);
        } catch (Exception e) {
            log.error("获取地理位置异常 {}", ip);
        }

        return UNKNOWN;
    }

    /**
     * 检查是否为内部IP地址
     *
     * @param ip IP地址
     * @return 结果
     */
    public static boolean internalIp(String ip) {
        byte[] address = textToNumericFormatV4(ip);
        return internalIp(address) || "127.0.0.1".equals(ip);
    }

    /**
     * 检查是否为内部IP地址
     *
     * @param address byte地址
     * @return 结果
     * @author fzr
     */
    private static boolean internalIp(byte[] address) {
        if (address == null || address.length < 2) {
            return true;
        }
        final byte b0 = address[0];
        final byte b1 = address[1];
        // 10.x.x.x/8
        final byte SECTION_1 = 0x0A;
        // 172.16.x.x/12
        final byte SECTION_2 = (byte) 0xAC;
        final byte SECTION_3 = (byte) 0x10;
        final byte SECTION_4 = (byte) 0x1F;
        // 192.168.x.x/16
        final byte SECTION_5 = (byte) 0xC0;
        final byte SECTION_6 = (byte) 0xA8;
        switch (b0) {
            case SECTION_1:
                return true;
            case SECTION_2:
                if (b1 >= SECTION_3 && b1 <= SECTION_4) {
                    return true;
                }
            case SECTION_5:
                if (b1 == SECTION_6) {
                    return true;
                }
            default:
                return false;
        }
    }

    /**
     * 将IPv4地址转换成字节
     *
     * @param text IPv4地址
     * @return byte 字节
     * @author fzr
     */
    public static byte[] textToNumericFormatV4(String text) {
        if (text.isEmpty()) {
            return null;
        }

        byte[] bytes = new byte[4];
        String[] elements = text.split("\\.", -1);
        try {
            long l;
            int i;
            switch (elements.length) {
                case 1:
                    l = Long.parseLong(elements[0]);
                    if ((l < 0L) || (l > 4294967295L)) {
                        return null;
                    }
                    bytes[0] = (byte) (int) (l >> 24 & 0xFF);
                    bytes[1] = (byte) (int) ((l & 0xFFFFFF) >> 16 & 0xFF);
                    bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);
                    bytes[3] = (byte) (int) (l & 0xFF);
                    break;
                case 2:
                    l = Integer.parseInt(elements[0]);
                    if ((l < 0L) || (l > 255L)) {
                        return null;
                    }
                    bytes[0] = (byte) (int) (l & 0xFF);
                    l = Integer.parseInt(elements[1]);
                    if ((l < 0L) || (l > 16777215L)) {
                        return null;
                    }
                    bytes[1] = (byte) (int) (l >> 16 & 0xFF);
                    bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);
                    bytes[3] = (byte) (int) (l & 0xFF);
                    break;
                case 3:
                    for (i = 0; i < 2; ++i) {
                        l = Integer.parseInt(elements[i]);
                        if ((l < 0L) || (l > 255L)) {
                            return null;
                        }
                        bytes[i] = (byte) (int) (l & 0xFF);
                    }
                    l = Integer.parseInt(elements[2]);
                    if ((l < 0L) || (l > 65535L)) {
                        return null;
                    }
                    bytes[2] = (byte) (int) (l >> 8 & 0xFF);
                    bytes[3] = (byte) (int) (l & 0xFF);
                    break;
                case 4:
                    for (i = 0; i < 4; ++i) {
                        l = Integer.parseInt(elements[i]);
                        if ((l < 0L) || (l > 255L)) {
                            return null;
                        }
                        bytes[i] = (byte) (int) (l & 0xFF);
                    }
                    break;
                default:
                    return null;
            }
        } catch (NumberFormatException e) {
            return null;
        }
        return bytes;
    }

    /**
     * 获取IP地址
     *
     * @return 本地IP地址
     * @author fzr
     */
    public static String getHostIp() {
        try {
            return InetAddress.getLocalHost().getHostAddress();
        } catch (UnknownHostException ignored) {
        }
        return "127.0.0.1";
    }

    /**
     * 获取主机名
     *
     * @return 本地主机名
     * @author fzr
     */
    public static String getHostName() {
        try {
            return InetAddress.getLocalHost().getHostName();
        } catch (UnknownHostException ignored) {
        }
        return "未知";
    }

    /**
     * 从多级反向代理中获得第一个非unknown IP地址
     *
     * @param ip 获得的IP地址
     * @return 第一个非unknown IP地址
     * @author fzr
     */
    public static String getMultistageReverseProxyIp(String ip) {
        if (ip != null && ip.indexOf(",") > 0) {
            final String[] ips = ip.trim().split(",");
            for (String subIp : ips) {
                if (!isUnknown(subIp)) {
                    ip = subIp;
                    break;
                }
            }
        }
        return ip;
    }

    /**
     * 检测给定字符串是否为未知,多用于检测HTTP请求相关
     *
     * @param checkString 被检测的字符串
     * @return 是否未知
     * @author fzr
     */
    public static boolean isUnknown(String checkString) {
        return StringUtils.isBlank(checkString) || "unknown".equalsIgnoreCase(checkString);
    }


    public static void main(String[] args) {
        String ip = "xxx";
        String address = getRealAddressByIP(ip);
        System.out.println(address);
    }
}

算术运算工具

package com.sky.utils;

import java.math.BigDecimal;
import java.math.RoundingMode;

/**
 * 算术运算工具
 */
public class ArithUtils {

    /** 默认除法运算精度 */
    private static final int DEF_DIV_SCALE = 10;

    /** 这个类不能实例化 */
    private ArithUtils() {}

    /**
     * 提供精确的加法运算
     *
     * @param v1 被加数
     * @param v2 加数
     * @return 两个参数的和
     */
    public static double add(double v1, double v2) {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.add(b2).doubleValue();
    }

    /**
     * 提供精确的减法运算
     *
     * @param v1 被减数
     * @param v2 减数
     * @return 两个参数的差
     */
    public static double sub(double v1, double v2) {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.subtract(b2).doubleValue();
    }

    /**
     * 提供精确的乘法运算
     *
     * @param v1 被乘数
     * @param v2 乘数
     * @return 两个参数的积
     */
    public static double mul(double v1, double v2) {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.multiply(b2).doubleValue();
    }

    /**
     * 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到
     * 小数点以后10位,以后的数字四舍五入
     *
     * @param v1 被除数
     * @param v2 除数
     * @return 两个参数的商
     */
    public static double div(double v1, double v2) {
        return div(v1, v2, DEF_DIV_SCALE);
    }

    /**
     * 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指
     * 定精度,以后的数字四舍五入。
     *
     * @param v1 被除数
     * @param v2 除数
     * @param scale 表示表示需要精确到小数点以后几位。
     * @return 两个参数的商
     */
    public static double div(double v1, double v2, int scale) {
        if (scale < 0)
        {
            throw new IllegalArgumentException(
                    "The scale must be a positive integer or zero");
        }
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        if (b1.compareTo(BigDecimal.ZERO) == 0)
        {
            return BigDecimal.ZERO.doubleValue();
        }
        return b1.divide(b2, scale, RoundingMode.HALF_UP).doubleValue();
    }

    /**
     * 提供精确的小数位四舍五入处理
     *
     * @param v 需要四舍五入的数字
     * @param scale 小数点后保留几位
     * @return 四舍五入后的结果
     */
    public static double round(double v, int scale) {
        if (scale < 0)
        {
            throw new IllegalArgumentException(
                    "The scale must be a positive integer or zero");
        }
        BigDecimal b = new BigDecimal(Double.toString(v));
        BigDecimal one = BigDecimal.ONE;
        return b.divide(one, scale, RoundingMode.HALF_UP).doubleValue();
    }

}

时间工具类

package com.mdd.common.util;


import java.lang.management.ManagementFactory;
import java.text.DateFormat;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Pattern;

public class TimeUtils {

    /**
     * 时间戳转日期(默认格式)
     *
     * @author fzr
     * @param time 时间戳
     * @return String
     */
    public static String timestampToDate(Long time) {
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(time * 1000));
    }

    /**
     * 时间戳转日期(默认格式)
     *
     * @author fzr
     * @param time 时间戳
     * @return String
     */
    public static String timestampToDate(String time) {
        if (time == null) {
            time = "0";
        }
        long longTime = Long.parseLong(time);
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(longTime * 1000));
    }

    /**
     * 时间戳转日期(指定格式)
     *
     * @author fzr
     * @param time 时间戳
     * @param format 格式串
     * @return String
     */
    public static String timestampToDate(Long time, String format) {
        return new SimpleDateFormat(format).format(new Date(time * 1000));
    }

    /**
     * 时间戳转日期(指定格式)
     *
     * @author fzr
     * @param time 时间戳
     * @param format 格式串
     * @return String
     */
    public static String timestampToDate(String time, String format) {
        long longTime = Long.parseLong(time);
        return new SimpleDateFormat(format).format(new Date(longTime * 1000));
    }

    /**
     * 日期转时间戳
     *
     * @author fzr
     * @param date 日期
     * @return Long
     */
    public static Long dateToTimestamp(String date) {
        String dateTime = TimeUtils.formatDate(date);
        return (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")).parse(dateTime, new ParsePosition(0)).getTime() / 1000;
    }

    /**
     * 毫秒转日期时间
     *
     * @author fzr
     * @param time 毫秒
     * @return String
     */
    public static String millisecondToDate(Long time) {
        Date date = new Date();
        date.setTime(time);
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date);
    }

    /**
     * 毫秒转日期时间
     *
     * @author fzr
     * @param time 毫秒
     * @return String
     */
    public static String millisecondToDate(String time) {
        Date date = new Date();
        date.setTime(Long.parseLong(time));
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date);
    }

    /**
     * 毫秒转日期时间
     *
     * @author fzr
     * @param time 毫秒
     * @param format 格式串
     * @return String
     */
    public static String millisecondToDate(Long time, String format) {
        Date date = new Date();
        date.setTime(time);
        return new SimpleDateFormat(format).format(date);
    }

    /**
     * 毫秒转日期时间
     *
     * @author fzr
     * @param time 毫秒
     * @param format 格式串
     * @return String
     */
    public static String millisecondToDate(String time, String format) {
        Date date = new Date();
        date.setTime(Long.parseLong(time));
        return new SimpleDateFormat(format).format(date);
    }

    /**
     * 日期转固定格式 yyyy-MM-dd HH:mm:ss
     *
     * @author fzr
     * @param dateStr 日期时间
     * @return String
     */
    public static String formatDate(String dateStr){
        dateStr = dateStr.trim();
        HashMap<String, String> dateRegFormat = new HashMap<>();
        dateRegFormat.put("^\\d{4}\\D+\\d{1,2}\\D+\\d{1,2}\\D+\\d{1,2}\\D+\\d{1,2}\\D+\\d{1,2}\\D*$", "yyyy-MM-dd-HH-mm-ss");//2014年3月12日 13时5分34秒,2014-03-12 12:05:34,2014/3/12 12:5:34
        dateRegFormat.put("^\\d{4}\\D+\\d{2}\\D+\\d{2}\\D+\\d{2}\\D+\\d{2}$", "yyyy-MM-dd-HH-mm");//2014-03-12 12:05
        dateRegFormat.put("^\\d{4}\\D+\\d{2}\\D+\\d{2}\\D+\\d{2}$", "yyyy-MM-dd-HH");//2014-03-12 12
        dateRegFormat.put("^\\d{4}\\D+\\d{2}\\D+\\d{2}$", "yyyy-MM-dd");//2014-03-12
        dateRegFormat.put("^\\d{4}\\D+\\d{2}$", "yyyy-MM");//2014-03
        dateRegFormat.put("^\\d{4}$", "yyyy");//2014
        dateRegFormat.put("^\\d{14}$", "yyyyMMddHHmmss");//20140312120534
        dateRegFormat.put("^\\d{12}$", "yyyyMMddHHmm");//201403121205
        dateRegFormat.put("^\\d{10}$", "yyyyMMddHH");//2014031212
        dateRegFormat.put("^\\d{8}$", "yyyyMMdd");//20140312
        dateRegFormat.put("^\\d{6}$", "yyyyMM");//201403
        dateRegFormat.put("^\\d{2}\\s*:\\s*\\d{2}\\s*:\\s*\\d{2}$", "yyyy-MM-dd-HH-mm-ss");//13:05:34 拼接当前日期
        dateRegFormat.put("^\\d{2}\\s*:\\s*\\d{2}$", "yyyy-MM-dd-HH-mm");//13:05 拼接当前日期
        dateRegFormat.put("^\\d{2}\\D+\\d{1,2}\\D+\\d{1,2}$", "yy-MM-dd");//14.10.18(年.月.日)
        dateRegFormat.put("^\\d{1,2}\\D+\\d{1,2}$", "yyyy-dd-MM");//30.12(日.月) 拼接当前年份
        dateRegFormat.put("^\\d{1,2}\\D+\\d{1,2}\\D+\\d{4}$", "dd-MM-yyyy");//12.21.2013(日.月.年)

        String curDate = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        DateFormat formatter1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        DateFormat formatter2;
        String dateReplace;
        String strSuccess = "";
        try {
            for (String key : dateRegFormat.keySet()) {
                if (Pattern.compile(key).matcher(dateStr).matches()) {
                    formatter2 = new SimpleDateFormat(dateRegFormat.get(key));
                    if (key.equals("^\\d{2}\\s*:\\s*\\d{2}\\s*:\\s*\\d{2}$") || key.equals("^\\d{2}\\s*:\\s*\\d{2}$")) {
                        // 13:05:34  13:05 拼接当前日期
                        dateStr = curDate + "-" + dateStr;
                    } else if (key.equals("^\\d{1,2}\\D+\\d{1,2}$")) {
                        //21.1 (日.月) 拼接当前年份
                        dateStr = curDate.substring(0, 4) + "-" + dateStr;
                    }
                    dateReplace = dateStr.replaceAll("\\D+", "-");
                    strSuccess = formatter1.format(formatter2.parse(dateReplace));
                    break;
                }
            }
            return strSuccess;
        } catch (Exception ignored) { }
        return "";
    }

    /**
     * 返回当前时间戳
     *
     * @author fzr
     * @return Long
     */
    public static Long timestamp() {
        return System.currentTimeMillis() / 1000;
    }

    /**
     * 返回当前Date型日期
     *
     *  @author fzr
     * @return Date() 当前日期
     */
    public static Date nowDate() {
        return new Date();
    }

    /**
     * 返回今日开始和结束的时间戳
     *
     * @author fzr
     * @return List
     */
    public static List<Long> today() {
        List<Long> list = new ArrayList<>();
        // 开始时间
        Calendar todayStart = Calendar.getInstance();
        todayStart.set(Calendar.HOUR, 0);
        todayStart.set(Calendar.MINUTE, 0);
        todayStart.set(Calendar.SECOND, 0);
        todayStart.set(Calendar.MILLISECOND, 0);
        list.add(todayStart.getTime().getTime() / 1000 - 43200);

        // 结束时间
        Calendar todayEnd = Calendar.getInstance();
        todayEnd.set(Calendar.HOUR_OF_DAY, 23);
        todayEnd.set(Calendar.MINUTE, 59);
        todayEnd.set(Calendar.SECOND, 59);
        todayEnd.set(Calendar.MILLISECOND, 999);
        list.add(todayEnd.getTime().getTime() / 1000);

        return list;
    }

    /**
     * 返回昨日开始和结束的时间戳
     *
     * @author fzr
     * @return List
     */
    public static List<Long> yesterday() {
        List<Long> today = TimeUtils.today();
        List<Long> list = new ArrayList<>();
        list.add(today.get(0) - 86400);
        list.add(today.get(1) - 86400);
        return list;
    }

    /**
     * 返回本周开始和结束的时间戳
     *
     * @author fzr
     * @return List
     */
    public static List<Long> week() {
        List<Long> list = new ArrayList<>();
        // 开始时间
        Calendar cal = Calendar.getInstance();
        cal.set(cal.get(Calendar.YEAR),cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH), 0, 0,0);
        cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
        list.add(cal.getTimeInMillis() / 1000);
        // 结束时间
        list.add(list.get(0) + ((7 * 24 * 60 * 60 * 1000) / 1000)-1);
        return list;
    }

    /**
     * 返回上周开始和结束的时间戳
     *
     * @author fzr
     * @return List
     */
    public static List<Long> lastWeek() {
        List<Long> week = TimeUtils.week();
        List<Long> list = new ArrayList<>();
        list.add(week.get(0) - 604800);
        list.add(week.get(1) - 604800);
        return list;
    }

    /**
     * 返回今天是周几
     *
     * @author fzr
     * @return Long
     */
    public static Long dayOfWeek() {
        Date date = new Date();
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        boolean isFirstSunday = (cal.getFirstDayOfWeek() == Calendar.SUNDAY);
        long week = cal.get(Calendar.DAY_OF_WEEK);
        if(isFirstSunday){
            week = (week -1) == 0? 7:(week - 1);
        }
        return week;
    }

    /**
     * 返回本月开始和结束的时间戳
     *
     * @author fzr
     * @return List
     */
    public static List<Long> month() {
        List<Long> list = new ArrayList<>();
        // 开始时间
        Calendar calStart = Calendar.getInstance();
        calStart.set(calStart.get(Calendar.YEAR),calStart.get(Calendar.MONTH), calStart.get(Calendar.DAY_OF_MONTH), 0, 0,0);
        calStart.set(Calendar.DAY_OF_MONTH,calStart.getActualMinimum(Calendar.DAY_OF_MONTH));
        list.add(calStart.getTimeInMillis() / 1000);

        // 结束时间
        Calendar calEnd = Calendar.getInstance();
        calEnd.set(calEnd.get(Calendar.YEAR),calEnd.get(Calendar.MONTH), calEnd.get(Calendar.DAY_OF_MONTH), 0, 0,0);
        calEnd.set(Calendar.DAY_OF_MONTH, calEnd.getActualMaximum(Calendar.DAY_OF_MONTH));
        calEnd.set(Calendar.HOUR_OF_DAY, 24);
        list.add(calEnd.getTimeInMillis() / 1000 - 1);
        return list;
    }

    /**
     * 返回上个月开始和结束的时间戳
     *
     * @author fzr
     * @return List
     */
    public static List<Long> lastMonth() {
        List<Long> list = new ArrayList<>();
        // 开始时间
        Calendar calStart = Calendar.getInstance();
        calStart.add(Calendar.MONTH, -1);
        calStart.set(Calendar.DAY_OF_MONTH,1);
        calStart.set(Calendar.HOUR, 0);
        calStart.set(Calendar.MINUTE, 0);
        calStart.set(Calendar.SECOND, 0);
        calStart.set(Calendar.MILLISECOND, 0);
        list.add((calStart.getTimeInMillis() / 1000) - 43200);

        // 结束时间
        Calendar calEnd = Calendar.getInstance();
        calEnd.set(calEnd.get(Calendar.YEAR),calEnd.get(Calendar.MONTH), calEnd.get(Calendar.DAY_OF_MONTH), 0, 0,0);
        calEnd.set(Calendar.DAY_OF_MONTH,calEnd.getActualMinimum(Calendar.DAY_OF_MONTH));
        list.add((calEnd.getTimeInMillis() / 1000)-1);
        return list;
    }

    /**
     * 返回今年开始和结束的时间戳
     *
     * @author fzr
     * @return List
     */
    public static List<Long> year() {
        List<Long> list = new ArrayList<>();
        // 开始时间
        Calendar calStart = Calendar.getInstance();
        calStart.add(Calendar.YEAR, 0);
        calStart.add(Calendar.DATE, 0);
        calStart.add(Calendar.MONTH, 0);
        calStart.set(Calendar.DAY_OF_YEAR, 1);
        calStart.set(Calendar.HOUR_OF_DAY, 0);
        calStart.set(Calendar.MINUTE, 0);
        calStart.set(Calendar.SECOND, 0);
        calStart.set(Calendar.MILLISECOND, 0);
        list.add(calStart.getTimeInMillis() / 1000);

        // 结束时间
        Calendar calEnd = Calendar.getInstance();
        int year = calEnd.get(Calendar.YEAR);
        calEnd.clear();
        calEnd.set(Calendar.YEAR, year);
        calEnd.set(Calendar.HOUR_OF_DAY, 23);
        calEnd.set(Calendar.MINUTE, 59);
        calEnd.set(Calendar.SECOND, 59);
        calEnd.set(Calendar.MILLISECOND, 999);
        calEnd.roll(Calendar.DAY_OF_YEAR, -1);
        list.add(calEnd.getTimeInMillis() / 1000);
        return list;
    }

    /**
     * 返回去年开始和结束的时间戳
     *
     * @author fzr
     * @return List
     */
    public static List<Long> lastYear() {
        List<Long> list = new ArrayList<>();
        // 开始时间
        Calendar calStart = Calendar.getInstance();
        calStart.add(Calendar.YEAR, -1);
        calStart.set(Calendar.HOUR_OF_DAY, 0);
        calStart.set(Calendar.DAY_OF_YEAR, 1);
        calStart.set(Calendar.MINUTE, 0);
        calStart.set(Calendar.SECOND, 0);
        calStart.set(Calendar.MILLISECOND, 0);
        list.add(calStart.getTimeInMillis() / 1000);

        // 结束时间
        Calendar calEnd = Calendar.getInstance();
        calEnd.add(Calendar.YEAR, -1);
        calEnd.set(Calendar.MONTH, calEnd.getActualMaximum(Calendar.MONTH));
        calEnd.set(Calendar.DAY_OF_MONTH, calEnd.getActualMaximum(Calendar.DAY_OF_MONTH));
        calEnd.set(Calendar.HOUR_OF_DAY, 23);
        calEnd.set(Calendar.MINUTE, 59);
        calEnd.set(Calendar.SECOND, 59);
        calEnd.set(Calendar.MILLISECOND, 999);
        list.add(calEnd.getTimeInMillis() / 1000);
        return list;
    }

    /**
     * 获取几天前零点到现在/昨日结束的时间戳
     *
     * @author fzr
     * @return List
     */
    public static List<Long> dayToNow(int day) {
        List<Long> today = TimeUtils.today();
        List<Long> list = new ArrayList<>();
        list.add(today.get(0) - day * 86400L);
        list.add(today.get(0) -1);
        return list;
    }

    /**
     * 返回几天前的时间戳
     *
     * @author fzr
     * @param day (天)
     * @return Long
     */
    public Long daysAgo(long day) {
        long currTime = System.currentTimeMillis() / 1000;
        return currTime - (day * 86400);
    }

    /**
     * 返回几天后的时间戳
     *
     * @author fzr
     * @param day (天)
     * @return Long
     */
    public Long daysAfter(long day) {
        long currTime = System.currentTimeMillis() / 1000;
        return currTime + (day * 86400);
    }

    /**
     * 返回月份第几天
     *
     * @author fzr
     * @return int
     */
    public static Integer monthDay(){
        Date date = new Date();
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return cal.get(Calendar.DAY_OF_MONTH);
    }

    /**
     * 获取几天前的日期列表
     *
     * @author fzr
     * @param day 获取多少天
     * @return [2022-03-29, 2022-03-30, 2022-03-31, 2022-04-01]
     */
    public static List<String> daysAgoDate(Integer day) {
        long time = TimeUtils.today().get(0);

        List<String> data = new ArrayList<>();
        for (int i=0; i<day; i++) {
            if (i != 0) {
                time -= 86400;
            }

            data.add(TimeUtils.timestampToDate(time, "yyyy-MM-dd"));
        }

        Collections.reverse(data);
        return data;
    }

    /**
     * 获取几天前的日期列表
     *
     * @author fzr
     * @param day 获取多少天
     * @return [1648483200, 1648569600, 1648656000, 1648742400]
     */
    public static List<Long> daysAgoTime(Integer day) {
        long time = TimeUtils.today().get(0);

        List<Long> data = new ArrayList<>();
        for (int i=0; i<day; i++) {
            if (i != 0) {
                time -= 86400;
            }

            data.add(time);
        }

        Collections.reverse(data);
        return data;
    }

    /**
     * 返回服务器启动时间
     */
    public static Date serverStartDate() {
        long time = ManagementFactory.getRuntimeMXBean().getStartTime();
        return new Date(time);
    }

    /**
     * 计算两个时间差
     *
     * @author fzr
     * @param endDate 结束时间
     * @param nowDate 开始时间
     * @return String
     */
    public static String datePoor(Date endDate, Date nowDate) {
        long nd = 1000 * 24 * 60 * 60;
        long nh = 1000 * 60 * 60;
        long nm = 1000 * 60;
        // long ns = 1000;
        // 获得两个时间的毫秒时间差异
        long diff = endDate.getTime() - nowDate.getTime();
        // 计算差多少天
        long day = diff / nd;
        // 计算差多少小时
        long hour = diff % nd / nh;
        // 计算差多少分钟
        long min = diff % nd % nh / nm;
        // 计算差多少秒//输出结果
        // long sec = diff % nd % nh % nm / ns;
        return day + "天" + hour + "小时" + min + "分钟";
    }
}

获取系统信息

package com.sky.utils;

import com.sky.pono.server.*;
import oshi.SystemInfo;
import oshi.hardware.CentralProcessor;
import oshi.hardware.CentralProcessor.TickType;
import oshi.hardware.GlobalMemory;
import oshi.hardware.HardwareAbstractionLayer;
import oshi.software.os.FileSystem;
import oshi.software.os.OSFileStore;
import oshi.software.os.OperatingSystem;
import oshi.util.Util;

import java.lang.management.ManagementFactory;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 服务器相关信息
 */
public class ServerUtils {

    private static final int OSHI_WAIT_SECOND = 1000;
    private final Cpu cpu = new Cpu(); // CPU相关信息
    private final Mem mem = new Mem(); // 內存相关信息
    private final Jvm jvm = new Jvm(); // JVM相关信息
    private final Sys sys = new Sys(); // 服务器相关信息
    private final List<Disk> disk = new LinkedList<>(); // 磁盘相关信息

    /**
     * 拷贝数据
     */
    public Map<String, Object> copyTo() {
        SystemInfo si = new SystemInfo();
        HardwareAbstractionLayer hal = si.getHardware();
        setCpuInfo(hal.getProcessor());
        setMemInfo(hal.getMemory());
        setSysInfo();
        setJvmInfo();
        setSysFiles(si.getOperatingSystem());

        Map<String, Object> map = new LinkedHashMap<>();
        map.put("cpu", this.cpu);
        map.put("mem", this.mem);
        map.put("sys", this.sys);
        map.put("disk", this.disk);
        map.put("jvm", this.jvm);
        return map;
    }

    /**
     * 设置CPU信息
     */
    private void setCpuInfo(CentralProcessor processor) {
        long[] prevTicks = processor.getSystemCpuLoadTicks();
        Util.sleep(OSHI_WAIT_SECOND);
        long[] ticks = processor.getSystemCpuLoadTicks();
        long nice = ticks[TickType.NICE.getIndex()] - prevTicks[TickType.NICE.getIndex()];
        long irq = ticks[TickType.IRQ.getIndex()] - prevTicks[TickType.IRQ.getIndex()];
        long softer = ticks[TickType.SOFTIRQ.getIndex()] - prevTicks[TickType.SOFTIRQ.getIndex()];
        long steal = ticks[TickType.STEAL.getIndex()] - prevTicks[TickType.STEAL.getIndex()];
        long cSys = ticks[TickType.SYSTEM.getIndex()] - prevTicks[TickType.SYSTEM.getIndex()];
        long user = ticks[TickType.USER.getIndex()] - prevTicks[TickType.USER.getIndex()];
        long ioWait = ticks[TickType.IOWAIT.getIndex()] - prevTicks[TickType.IOWAIT.getIndex()];
        long idle = ticks[TickType.IDLE.getIndex()] - prevTicks[TickType.IDLE.getIndex()];
        long totalCpu = user + nice + cSys + idle + ioWait + irq + softer + steal;
        cpu.setCpuNum(processor.getLogicalProcessorCount());
        cpu.setTotal(ArithUtils.round(ArithUtils.mul(totalCpu, 100), 2));
        cpu.setSys(ArithUtils.round(ArithUtils.mul(cSys / cpu.getTotal(), 100), 2));
        cpu.setUsed(ArithUtils.round(ArithUtils.mul(user / cpu.getTotal(), 100), 2));
        cpu.setWait(ArithUtils.round(ArithUtils.mul(ioWait / cpu.getTotal(), 100), 2));
        cpu.setFree(ArithUtils.round(ArithUtils.mul(idle / cpu.getTotal(), 100), 2));
    }


    /**
     * 设置内存信息
     */
    private void setMemInfo(GlobalMemory memory) {
        int number = (1024 * 1024 * 1024);
        mem.setTotal(ArithUtils.div(memory.getTotal(), number, 2));
        mem.setUsed(ArithUtils.div(memory.getTotal() - memory.getAvailable(), number, 2));
        mem.setFree(ArithUtils.div(memory.getAvailable(), number, 2));
        mem.setUsage(ArithUtils.mul(ArithUtils.div(mem.getUsed(), memory.getTotal(), 4), 100));
    }

    /**
     * 设置服务器信息
     */
    private void setSysInfo() {
        Properties props = System.getProperties();
        sys.setComputerName(IpUtils.getHostName());
        sys.setComputerIp(IpUtils.getHostIp());
        sys.setOsName(props.getProperty("os.name"));
        sys.setOsArch(props.getProperty("os.arch"));
        sys.setUserDir(props.getProperty("user.dir"));
    }

    /**
     * 设置Java虚拟机
     */
    private void setJvmInfo() {
        Properties props = System.getProperties();
        jvm.setTotal(ArithUtils.div(Runtime.getRuntime().totalMemory(), (1024 * 1024), 2));
        jvm.setMax(ArithUtils.div(Runtime.getRuntime().maxMemory(), (1024 * 1024), 2));
        jvm.setFree(ArithUtils.div(Runtime.getRuntime().freeMemory(), (1024 * 1024), 2));
        jvm.setUsage(ArithUtils.mul(ArithUtils.div(jvm.getTotal() - jvm.getFree(), jvm.getTotal(), 4), 100));
        jvm.setVersion(props.getProperty("java.version"));
        jvm.setHome(props.getProperty("java.home"));
        jvm.setName(ManagementFactory.getRuntimeMXBean().getVmName());
        jvm.setInputArgs(ManagementFactory.getRuntimeMXBean().getInputArguments().toString());
        jvm.setRunTime(TimeUtils.datePoor(TimeUtils.nowDate(), TimeUtils.serverStartDate()));
        jvm.setStartTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(TimeUtils.serverStartDate()));
    }

    /**
     * 设置磁盘信息
     */
    private void setSysFiles(OperatingSystem os) {
        FileSystem fileSystem = os.getFileSystem();
        List<OSFileStore> fsArray = fileSystem.getFileStores();
        for (OSFileStore fs : fsArray) {
            long free = fs.getUsableSpace();
            long total = fs.getTotalSpace();
            long used = total - free;
            Disk sysFile = new Disk();
            sysFile.setDirName(fs.getMount());
            sysFile.setSysTypeName(fs.getType());
            sysFile.setTypeName(fs.getName());
            sysFile.setTotal(convertFileSize(total));
            sysFile.setFree(convertFileSize(free));
            sysFile.setUsed(convertFileSize(used));
            sysFile.setUsage(ArithUtils.mul(ArithUtils.div(used, total, 4), 100));
            disk.add(sysFile);
        }
    }

    /**
     * 字节转换
     */
    public String convertFileSize(long size) {
        long kb = 1024;
        long mb = kb * 1024;
        long gb = mb * 1024;
        if (size >= gb) {
            return String.format("%.1f GB", (float) size / gb);
        } else if (size >= mb) {
            float f = (float) size / mb;
            return String.format(f > 100 ? "%.0f MB" : "%.1f MB", f);
        } else if (size >= kb) {
            float f = (float) size / kb;
            return String.format(f > 100 ? "%.0f KB" : "%.1f KB", f);
        } else {
            return String.format("%d B", size);
        }
    }
}

编写接口

@RestController
@RequestMapping("/admin/monitor")
public class MonitorServerController {

    @GetMapping("/server")
    public Result<Map<String, Object>> info() {
        ServerUtils server = new ServerUtils();
        return Result.success(server.copyTo());
    }

}

接口测试

前端代码

<template>
  <div class="system-environment" v-loading="loading">
    <div class="cards-container">
      <el-card class="card mb-4 card-margin-right" shadow="never">
        <div>CPU</div>
        <div class="mt-4">
          <div class="flex flex-wrap">
            <div class="item mb-4">
              <div class="text-4xl mb-3">{{ info.cpu.cpuNum }}</div>
              <div class="text-tx-regular">核心数</div>
            </div>

            <div class="item mb-4">
              <div class="text-4xl mb-3">
                {{ info.cpu.used ? `${info.cpu.used}%` : '-' }}
              </div>
              <div class="text-tx-regular">用户使用率</div>
            </div>

            <div class="item mb-4">
              <div class="text-4xl mb-3">
                {{ info.cpu.sys ? `${info.cpu.sys}%` : '-' }}
              </div>
              <div class="text-tx-regular">系统使用率</div>
            </div>

            <div class="item mb-4">
              <div class="text-4xl mb-3">
                {{ info.cpu.free ? `${info.cpu.free}%` : '-' }}
              </div>
              <div class="text-tx-regular">当前空闲率</div>
            </div>
          </div>
        </div>
      </el-card>
      <el-card class="card mb-4" shadow="never">
        <div>内存</div>
        <div class="mt-4">
          <div class="flex flex-wrap">
            <div class="item mb-4">
              <div class="text-4xl mb-3">{{ info.mem.total }}</div>
              <div class="text-tx-regular">总内存</div>
            </div>

            <div class="item mb-4">
              <div class="text-4xl mb-3">
                {{ info.mem.used ? `${info.mem.used}%` : '-' }}
              </div>
              <div class="text-tx-regular">已用内存</div>
            </div>

            <div class="item mb-4">
              <div class="text-4xl mb-3">
                {{ info.mem.free ? `${info.mem.free}%` : '-' }}
              </div>
              <div class="text-tx-regular">剩余内存</div>
            </div>

            <div class="item mb-4">
              <div class="text-4xl mb-3">
                {{ info.mem.usage ? `${info.mem.usage}%` : '-' }}
              </div>
              <div class="text-tx-regular">使用率</div>
            </div>
          </div>
        </div>
      </el-card>
    </div>
    <el-card class="card mb-4" shadow="never">
      <div>服务器信息</div>
      <div class="mt-4">
        <el-table :data="[info.sys]" size="large">
          <el-table-column prop="computerName" label="服务器名称" min-width="150" />
          <el-table-column prop="computerIp" label="服务器IP" min-width="120" />
          <el-table-column prop="osName" label="操作系统" min-width="100" />
          <el-table-column prop="osArch" label="系统架构" min-width="100" />
          <el-table-column prop="userDir" label="项目路径" min-width="250" />
        </el-table>
      </div>
    </el-card>

    <el-card class="card mb-4" shadow="never">
      <div>Java虚拟机信息</div>
      <div class="mt-4">
        <el-table :data="[info.jvm]" size="large">
          <el-table-column prop="name" label="Java名称" min-width="120" />
          <el-table-column prop="startTime" label="启动时间" min-width="120" />
          <el-table-column prop="home" label="安装路径" min-width="120" />
          <el-table-column prop="inputArgs" label="运行参数" min-width="120" />
          <el-table-column prop="version" label="Java版本" min-width="120" />
          <el-table-column prop="runTime" label="运行时长" min-width="120" />
        </el-table>
      </div>
    </el-card>

    <el-card class="card mb-4" shadow="never">
      <div>硬盘状态</div>
      <div class="mt-4">
        <el-table :data="info.disk" size="large">
          <el-table-column prop="dirName" label="盘符路径" min-width="100" />
          <el-table-column prop="sysTypeName" label="文件系统" min-width="100" />
          <el-table-column prop="typeName" label="盘符类型" min-width="100" />
          <el-table-column prop="total" label="总大小" min-width="100" />
          <el-table-column prop="free" label="可用大小" min-width="100" />
          <el-table-column prop="used" label="已用大小" min-width="100" />
          <el-table-column prop="usage" label="已用百分比" min-width="100">
            <template #default="{ row }"> {{ row.usage }}%</template>
          </el-table-column>
        </el-table>
      </div>
    </el-card>
  </div>
</template>

<script lang="ts" setup name="environment">
import { getSystemInfos } from '@/api/environment'
import { ref } from 'vue'

const loading = ref(false)
const info = ref({
  cpu: {} as any,
  disk: [],
  jvm: {},
  mem: {} as any,
  sys: {}
})

const getSystemInfo = async () => {
  try {
    loading.value = true
    const data = await getSystemInfos()
    console.log(data.data.data)
    info.value = data.data.data

    loading.value = false
  } catch (error) {
    loading.value = false
  }
}

getSystemInfo()
</script>

<style lang="scss" scoped>
.system-environment {
  width: 100%;
}

.cards-container {
  display: flex;
  flex-wrap: wrap;
  width: 100%;
}

.card {
  border: none;
  flex: 1;
  margin-bottom: 16px;
  margin-right: 16px;

  &:last-child {
    margin-right: 0;
  }
}

.card-margin-right {
  margin-right: 16px;
}

.item {
  flex: 1;
  width: 50%;
}

.text-4xl {
  font-size: 2rem;
}

.mb-3 {
  margin-bottom: 0.75rem;
}

.text-tx-regular {
  font-size: 1rem;
}

.mt-4 {
  margin-top: 1rem;
}

@media (max-width: 1024px) {
  .card {
    width: 100%;
    margin-right: 0;
  }
}
</style>

贡献者

  • flycodeuflycodeu

公告板

2025-03-04正式迁移知识库到此项目