项目初始化
This commit is contained in:
15
src/main/java/com/mini/capi/CApiApplication.java
Normal file
15
src/main/java/com/mini/capi/CApiApplication.java
Normal file
@@ -0,0 +1,15 @@
|
||||
package com.mini.capi;
|
||||
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
@MapperScan("com.mini.capi.biz.mapper")
|
||||
public class CApiApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(CApiApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
84
src/main/java/com/mini/capi/model/ApiResult.java
Normal file
84
src/main/java/com/mini/capi/model/ApiResult.java
Normal file
@@ -0,0 +1,84 @@
|
||||
package com.mini.capi.model;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
public class ApiResult<T> implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 状态码
|
||||
*/
|
||||
private int code;
|
||||
|
||||
/**
|
||||
* 提示信息
|
||||
*/
|
||||
private String message;
|
||||
|
||||
/**
|
||||
* 返回数据
|
||||
*/
|
||||
private T result;
|
||||
|
||||
/* ---------------- 构造方法 ---------------- */
|
||||
|
||||
public ApiResult() {
|
||||
}
|
||||
|
||||
public ApiResult(int code, String message, T data) {
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
this.result = data;
|
||||
}
|
||||
|
||||
/* ---------------- 静态工厂方法 ---------------- */
|
||||
|
||||
/**
|
||||
* 成功,仅返回状态码
|
||||
*/
|
||||
public static <T> ApiResult<T> success() {
|
||||
return new ApiResult<>(ResultCodeEnum.SUCCESS.getCode(), ResultCodeEnum.SUCCESS.getMessage(), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 成功,返回数据
|
||||
*/
|
||||
public static <T> ApiResult<T> success(T data) {
|
||||
return new ApiResult<>(ResultCodeEnum.SUCCESS.getCode(), ResultCodeEnum.SUCCESS.getMessage(), data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 成功,自定义提示
|
||||
*/
|
||||
public static <T> ApiResult<T> success(String message, T data) {
|
||||
return new ApiResult<>(ResultCodeEnum.SUCCESS.getCode(), message, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 失败,默认提示
|
||||
*/
|
||||
public static <T> ApiResult<T> error() {
|
||||
return new ApiResult<>(ResultCodeEnum.FAIL.getCode(), ResultCodeEnum.FAIL.getMessage(), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 失败,自定义状态码与提示
|
||||
*/
|
||||
public static <T> ApiResult<T> error(int code, String message) {
|
||||
return new ApiResult<>(code, message, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 失败,使用枚举
|
||||
*/
|
||||
public static <T> ApiResult<T> error(ResultCodeEnum codeEnum) {
|
||||
return new ApiResult<>(codeEnum.getCode(), codeEnum.getMessage(), null);
|
||||
}
|
||||
|
||||
}
|
||||
42
src/main/java/com/mini/capi/model/PageResult.java
Normal file
42
src/main/java/com/mini/capi/model/PageResult.java
Normal file
@@ -0,0 +1,42 @@
|
||||
package com.mini.capi.model;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class PageResult<T> implements Serializable {
|
||||
|
||||
private final int total; // 总记录数
|
||||
private final int pages; // 总页数
|
||||
private final int pageNum; // 当前页
|
||||
private final int pageSize; // 每页条数
|
||||
private final List<T> data; // 当前页数据
|
||||
|
||||
private PageResult(int total, int pages, int pageNum, int pageSize, List<T> data) {
|
||||
this.total = total;
|
||||
this.pages = pages;
|
||||
this.pageNum = pageNum;
|
||||
this.pageSize = pageSize;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public static <T> PageResult<T> of(List<T> listData, int pageNum, int pageSize) {
|
||||
if (listData == null || listData.isEmpty() || pageNum <= 0 || pageSize <= 0) {
|
||||
return new PageResult<>(0, 0, pageNum, pageSize, Collections.emptyList());
|
||||
}
|
||||
int total = listData.size();
|
||||
int pages = (int) Math.ceil((double) total / pageSize);
|
||||
|
||||
int from = (pageNum - 1) * pageSize;
|
||||
if (from >= total) {
|
||||
return new PageResult<>(total, pages, pageNum, pageSize, Collections.emptyList());
|
||||
}
|
||||
int to = Math.min(from + pageSize, total);
|
||||
List<T> list = new ArrayList<>(listData.subList(from, to));
|
||||
return new PageResult<>(total, pages, pageNum, pageSize, list);
|
||||
}
|
||||
}
|
||||
22
src/main/java/com/mini/capi/model/ResultCodeEnum.java
Normal file
22
src/main/java/com/mini/capi/model/ResultCodeEnum.java
Normal file
@@ -0,0 +1,22 @@
|
||||
package com.mini.capi.model;
|
||||
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public enum ResultCodeEnum {
|
||||
|
||||
SUCCESS(200, "Success"),
|
||||
FAIL(500, "Fail"),
|
||||
BAD_REQUEST(400, "Bad Request"),
|
||||
UNAUTHORIZED(401, "Unauthorized"),
|
||||
NOT_FOUND(404, "Not Found");
|
||||
|
||||
private final int code;
|
||||
private final String message;
|
||||
|
||||
ResultCodeEnum(int code, String message) {
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
}
|
||||
}
|
||||
53
src/main/java/com/mini/capi/mybatis/demo.java
Normal file
53
src/main/java/com/mini/capi/mybatis/demo.java
Normal file
@@ -0,0 +1,53 @@
|
||||
package com.mini.capi.mybatis;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
|
||||
import com.baomidou.mybatisplus.generator.config.OutputFile;
|
||||
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
|
||||
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
public class demo {
|
||||
|
||||
public static void main(String[] args) {
|
||||
FastAutoGenerator.create("jdbc:mysql://192.168.31.189:33069/work?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC", "dream", "info_dream")
|
||||
.globalConfig(builder -> {
|
||||
builder.author("gaoxq")
|
||||
.outputDir(System.getProperty("user.dir") + "/src/main/java")
|
||||
.disableOpenDir();
|
||||
})
|
||||
.packageConfig(builder -> {
|
||||
builder.parent("com.mini.capi")
|
||||
.moduleName("biz")
|
||||
.entity("domain")
|
||||
.mapper("mapper")
|
||||
.xml("mapper.xml")
|
||||
.service("service")
|
||||
.serviceImpl("service.impl")
|
||||
.controller("controller")
|
||||
.pathInfo(Collections.singletonMap(OutputFile.xml, System.getProperty("user.dir") + "/src/main/resources/mapper"));
|
||||
})
|
||||
.strategyConfig(builder -> {
|
||||
builder.addInclude("biz_combined_summary")
|
||||
.addTablePrefix("biz_")
|
||||
.entityBuilder()
|
||||
.enableLombok()
|
||||
.naming(NamingStrategy.underline_to_camel)
|
||||
.columnNaming(NamingStrategy.underline_to_camel)
|
||||
.idType(IdType.AUTO)
|
||||
.enableTableFieldAnnotation()
|
||||
.enableFileOverride()
|
||||
.controllerBuilder()
|
||||
.enableRestStyle()
|
||||
.serviceBuilder()
|
||||
.formatServiceFileName("%sService")
|
||||
.formatServiceImplFileName("%sServiceImpl")
|
||||
.mapperBuilder()
|
||||
.enableBaseResultMap()
|
||||
.enableBaseColumnList();
|
||||
})
|
||||
.templateEngine(new FreemarkerTemplateEngine())
|
||||
.execute();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.mini.capi.sys.controller;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest; // 注意这里
|
||||
import org.springframework.boot.web.servlet.error.ErrorController;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Controller
|
||||
public class CustomErrorController implements ErrorController {
|
||||
|
||||
@RequestMapping("/error")
|
||||
public ResponseEntity<Map<String, Object>> handleError(HttpServletRequest request) {
|
||||
HttpStatus status = getStatus(request);
|
||||
Map<String, Object> body = new HashMap<>();
|
||||
body.put("status", status.value());
|
||||
body.put("error", status.getReasonPhrase());
|
||||
body.put("message", "访问的资源不存在");
|
||||
body.put("path", request.getRequestURI());
|
||||
return ResponseEntity.status(status).body(body);
|
||||
}
|
||||
|
||||
private HttpStatus getStatus(HttpServletRequest request) {
|
||||
Integer code = (Integer) request.getAttribute("jakarta.servlet.error.status_code");
|
||||
return (code != null) ? HttpStatus.valueOf(code) : HttpStatus.INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
}
|
||||
119
src/main/java/com/mini/capi/sys/controller/sysController.java
Normal file
119
src/main/java/com/mini/capi/sys/controller/sysController.java
Normal file
@@ -0,0 +1,119 @@
|
||||
package com.mini.capi.sys.controller;
|
||||
|
||||
import com.mini.capi.model.ApiResult;
|
||||
import com.mini.capi.utils.HostRuntime;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/Sys/hosts")
|
||||
public class sysController {
|
||||
|
||||
|
||||
public static class SnapshotDTO {
|
||||
public String hostName;
|
||||
public String timestamp;
|
||||
public String cpuUsage;
|
||||
public String memTotal;
|
||||
public String memFree;
|
||||
public String memUsed;
|
||||
public String memUsage;
|
||||
public String swapTotal;
|
||||
public String swapUsed;
|
||||
public List<DiskDTO> disks;
|
||||
public String netRxBytes;
|
||||
public String netTxBytes;
|
||||
public double load1;
|
||||
public int processCount;
|
||||
public String uptimeSec;
|
||||
|
||||
public static SnapshotDTO from(HostRuntime.Snapshot s) {
|
||||
SnapshotDTO dto = new SnapshotDTO();
|
||||
dto.hostName = s.hostName;
|
||||
dto.timestamp = Instant.ofEpochMilli(s.timestamp)
|
||||
.atZone(ZoneId.systemDefault())
|
||||
.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
|
||||
dto.cpuUsage = String.format("%.2f %%", s.cpuUsage * 100);
|
||||
dto.memTotal = humanBytes(s.memTotal);
|
||||
dto.memFree = humanBytes(s.memFree);
|
||||
dto.memUsed = humanBytes(s.memUsed);
|
||||
dto.memUsage = String.format("%.2f %%", s.memUsage * 100);
|
||||
dto.swapTotal = humanBytes(s.swapTotal);
|
||||
dto.swapUsed = humanBytes(s.swapUsed);
|
||||
dto.disks = s.disks.stream()
|
||||
.map(d -> new DiskDTO(d.path,
|
||||
humanBytes(d.total),
|
||||
humanBytes(d.free),
|
||||
humanBytes(d.used),
|
||||
String.format("%.2f %%", d.usage * 100)))
|
||||
.collect(Collectors.toList());
|
||||
dto.netRxBytes = humanBytes(s.netRxBytes);
|
||||
dto.netTxBytes = humanBytes(s.netTxBytes);
|
||||
dto.load1 = s.load1;
|
||||
dto.processCount = s.processCount;
|
||||
dto.uptimeSec = uptimeToHuman(s.uptimeSec);
|
||||
return dto;
|
||||
}
|
||||
|
||||
private static String humanBytes(long bytes) {
|
||||
if (bytes < 1024) return bytes + " B";
|
||||
int exp = (int) (Math.log(bytes) / Math.log(1024));
|
||||
String pre = "KMGTPE".charAt(exp - 1) + "iB";
|
||||
return String.format("%.1f %s", bytes / Math.pow(1024, exp), pre);
|
||||
}
|
||||
|
||||
private static String uptimeToHuman(long sec) {
|
||||
long h = sec / 3600;
|
||||
long m = (sec % 3600) / 60;
|
||||
long s = sec % 60;
|
||||
if (h > 0) return String.format("%d 时 %d 分 %d 秒", h, m, s);
|
||||
if (m > 0) return String.format("%d 分 %d 秒", m, s);
|
||||
return String.format("%d 秒", s);
|
||||
}
|
||||
|
||||
public static class DiskDTO {
|
||||
public String path;
|
||||
public String total;
|
||||
public String free;
|
||||
public String used;
|
||||
public String usage;
|
||||
|
||||
public DiskDTO(String path, String total, String free, String used, String usage) {
|
||||
this.path = path;
|
||||
this.total = total;
|
||||
this.free = free;
|
||||
this.used = used;
|
||||
this.usage = usage;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static final int MAX_SIZE = 100;
|
||||
|
||||
|
||||
@GetMapping("/getApiInfo")
|
||||
public ApiResult<List<SnapshotDTO>> getApiInfo() {
|
||||
// 1. 新建一个一次性 List
|
||||
List<HostRuntime.Snapshot> snapshots =
|
||||
Collections.synchronizedList(new LinkedList<>());
|
||||
// 2. 采集并加入
|
||||
HostRuntime.Snapshot snap = HostRuntime.collect();
|
||||
snapshots.add(snap);
|
||||
// 3. 如果只想保留一条,直接清空多余
|
||||
while (snapshots.size() > MAX_SIZE) {
|
||||
((LinkedList<HostRuntime.Snapshot>) snapshots).removeFirst();
|
||||
}
|
||||
return ApiResult.success(Collections.singletonList(SnapshotDTO.from(snap)));
|
||||
}
|
||||
|
||||
}
|
||||
183
src/main/java/com/mini/capi/utils/HostRuntime.java
Normal file
183
src/main/java/com/mini/capi/utils/HostRuntime.java
Normal file
@@ -0,0 +1,183 @@
|
||||
package com.mini.capi.utils;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.lang.management.OperatingSystemMXBean;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class HostRuntime {
|
||||
|
||||
|
||||
/**
|
||||
* 统一的数据载体
|
||||
*/
|
||||
|
||||
public static class Snapshot {
|
||||
public String hostName; // 主机名
|
||||
public long timestamp; // 采集时间戳(毫秒)
|
||||
public double cpuUsage; // CPU 使用率 0~1
|
||||
public long memTotal; // 内存总量(Byte)
|
||||
public long memFree; // 空闲内存(Byte)
|
||||
public long memUsed; // 已用内存(Byte)
|
||||
public double memUsage; // 内存使用率 0~1
|
||||
public long swapTotal; // Swap 总量
|
||||
public long swapUsed; // Swap 已用
|
||||
public List<DiskUsage> disks; // 各挂载点磁盘
|
||||
public long netRxBytes; // 累计接收字节
|
||||
public long netTxBytes; // 累计发送字节
|
||||
public double load1; // 1 分钟平均负载
|
||||
public int processCount; // 进程数
|
||||
public long uptimeSec; // 开机时间(秒)
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Snapshot{" +
|
||||
"hostName='" + hostName + '\'' +
|
||||
", ts=" + Instant.ofEpochMilli(timestamp) +
|
||||
", cpu=" + String.format("%.2f", cpuUsage * 100) + "%" +
|
||||
", mem=" + String.format("%.2f", memUsage * 100) + "%" +
|
||||
", load=" + load1 +
|
||||
", uptime=" + uptimeSec + "s}";
|
||||
}
|
||||
}
|
||||
|
||||
public static class DiskUsage {
|
||||
public String path;
|
||||
public long total;
|
||||
public long free;
|
||||
public long used;
|
||||
public double usage;
|
||||
|
||||
public DiskUsage(String path, long total, long free, long used, double usage) {
|
||||
this.path = path;
|
||||
this.total = total;
|
||||
this.free = free;
|
||||
this.used = used;
|
||||
this.usage = usage;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 采集一次主机状态
|
||||
*/
|
||||
public static Snapshot collect() {
|
||||
Snapshot s = new Snapshot();
|
||||
s.timestamp = System.currentTimeMillis();
|
||||
try {
|
||||
s.hostName = InetAddress.getLocalHost().getHostName();
|
||||
} catch (UnknownHostException e) {
|
||||
s.hostName = "unknown";
|
||||
}
|
||||
|
||||
OperatingSystemMXBean os = ManagementFactory.getOperatingSystemMXBean();
|
||||
s.load1 = os.getSystemLoadAverage();
|
||||
s.uptimeSec = getUptimeSec();
|
||||
s.processCount = getProcessCount();
|
||||
|
||||
/* ------ CPU ------ */
|
||||
s.cpuUsage = getCpuUsage();
|
||||
|
||||
/* ------ Memory ------ */
|
||||
long[] mem = getMemInfo();
|
||||
s.memTotal = mem[0];
|
||||
s.memFree = mem[1];
|
||||
s.memUsed = s.memTotal - s.memFree;
|
||||
s.memUsage = s.memTotal == 0 ? 0 : (double) s.memUsed / s.memTotal;
|
||||
s.swapTotal = mem[2];
|
||||
s.swapUsed = mem[3];
|
||||
|
||||
/* ------ Disk ------ */
|
||||
s.disks = new ArrayList<>();
|
||||
java.io.File[] roots = java.io.File.listRoots();
|
||||
for (java.io.File f : roots) {
|
||||
long total = f.getTotalSpace();
|
||||
long free = f.getFreeSpace();
|
||||
long used = total - free;
|
||||
double usage = total == 0 ? 0 : (double) used / total;
|
||||
s.disks.add(new DiskUsage(f.getPath(), total, free, used, usage));
|
||||
}
|
||||
|
||||
/* ------ Network ------ */
|
||||
long[] net = getNetInfo();
|
||||
s.netRxBytes = net[0];
|
||||
s.netTxBytes = net[1];
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/* ----------------- 私有工具方法 ----------------- */
|
||||
|
||||
private static double getCpuUsage() {
|
||||
// 利用 com.sun.management.OperatingSystemMXBean(JDK 自带)
|
||||
com.sun.management.OperatingSystemMXBean sunOs =
|
||||
(com.sun.management.OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
|
||||
return sunOs.getProcessCpuLoad(); // 进程级
|
||||
// 若想系统级:sunOs.getSystemCpuLoad();
|
||||
}
|
||||
|
||||
private static long getUptimeSec() {
|
||||
// 通过 JVM 启动时间计算
|
||||
return ManagementFactory.getRuntimeMXBean().getUptime() / 1000;
|
||||
}
|
||||
|
||||
private static int getProcessCount() {
|
||||
// 简单实现:线程数,不够精确;若要精确需解析 /proc
|
||||
return ManagementFactory.getOperatingSystemMXBean().getAvailableProcessors(); // 仅作示例
|
||||
}
|
||||
|
||||
private static long[] getMemInfo() {
|
||||
long total = 0, free = 0, swapTotal = 0, swapUsed = 0;
|
||||
try (BufferedReader br = new BufferedReader(new FileReader("/proc/meminfo"))) {
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
if (line.startsWith("MemTotal:")) total = parseMemLine(line);
|
||||
if (line.startsWith("MemAvailable:")) free = parseMemLine(line);
|
||||
if (line.startsWith("SwapTotal:")) swapTotal = parseMemLine(line);
|
||||
if (line.startsWith("SwapFree:")) swapUsed = swapTotal - parseMemLine(line);
|
||||
}
|
||||
} catch (IOException | NumberFormatException ignore) {
|
||||
// fallback to OperatingSystemMXBean
|
||||
OperatingSystemMXBean os = ManagementFactory.getOperatingSystemMXBean();
|
||||
if (os instanceof com.sun.management.OperatingSystemMXBean) {
|
||||
com.sun.management.OperatingSystemMXBean sunOs =
|
||||
(com.sun.management.OperatingSystemMXBean) os;
|
||||
total = sunOs.getTotalMemorySize();
|
||||
free = sunOs.getFreeMemorySize();
|
||||
}
|
||||
}
|
||||
return new long[]{total, free, swapTotal, swapUsed};
|
||||
}
|
||||
|
||||
private static long parseMemLine(String line) {
|
||||
String[] parts = line.split("\\s+");
|
||||
return Long.parseLong(parts[1]) * 1024; // kB -> Byte
|
||||
}
|
||||
|
||||
private static long[] getNetInfo() {
|
||||
// 读取 /proc/net/dev 第一行即可拿到累计字节
|
||||
long rx = 0, tx = 0;
|
||||
try (BufferedReader br = new BufferedReader(new FileReader("/proc/net/dev"))) {
|
||||
br.readLine();
|
||||
br.readLine(); // 跳过表头
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
line = line.trim();
|
||||
if (line.startsWith("lo:")) continue; // 忽略回环
|
||||
String[] parts = line.split("\\s+");
|
||||
if (parts.length >= 10) {
|
||||
rx += Long.parseLong(parts[1]);
|
||||
tx += Long.parseLong(parts[9]);
|
||||
}
|
||||
}
|
||||
} catch (IOException | NumberFormatException ignore) {
|
||||
// 非 Linux 平台直接返回 0
|
||||
}
|
||||
return new long[]{rx, tx};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user