黄冈网站建设效果,wordpress影院插件,必应收录提交入口,聊城做网站推广找谁简介在规划的“springbootOSHIVueECharts”全栈监控系统中#xff0c;OSHI是一个专门用于Java平台的、跨平台的操作系统与硬件信息采集库#xff0c;它在系统中扮演着核心数据采集引擎的角色后端选择两个就够了#xff0c;其余的不够再添加把这个指标数据交给前端#xff0…简介在规划的“springbootOSHIVueECharts”全栈监控系统中OSHI是一个专门用于Java平台的、跨平台的操作系统与硬件信息采集库它在系统中扮演着核心数据采集引擎的角色后端选择两个就够了其余的不够再添加把这个指标数据交给前端让前端可视化展示就行输出里数组的每一项就是每一个逻辑处理器cpu的使用率//获取cpu 1s 内的负载double[] processorCpuLoad processor.getProcessorCpuLoad(1000);System.out.println(cpu一秒内的负载 Arrays.toString(processorCpuLoad));后端的包结构为PS C:\Java\oshi-app\src tree 卷 empty 的文件夹 PATH 列表 卷序列号为 8E61-6075 C:. ├─main │ ├─java │ │ └─com │ │ └─haha │ │ ├─common │ │ ├─controller │ │ └─service │ └─resources │ └─static └─test └─java └─com └─haha PS C:\Java\oshi-app\srccom.haha.common.Resultpackage com.haha.common; import lombok.Data; import lombok.NoArgsConstructor; //对接前端的Result,不用管范型 //可能对接后端做远程调用什么的需要精确获取Result的某种类型就需要做范型 Data NoArgsConstructor public class Result { private Integer code; private String msg; private Object data; public Result(Integer code, String msg) { this.code code; // 将参数code的值赋给当前对象的code成员变量 this.msg msg; } public Result(Integer code, String msg, Object data) { this.code code; this.msg msg; this.data data; } //快速的成功返回 public static Result success() { return new Result(200, success); } public static Result success(Object data) { return new Result(200, success, data); } //快速的失败返回 public static Result error() { return new Result(500, error); } public static Result error(Object data) { return new Result(500, error, data); } public static Result error(Integer code, String msg) { return new Result(code, msg); } }com.haha.controller.CpuLoadRestControllerpackage com.haha.controller; import com.haha.common.Result; import com.haha.service.CpuLoadMetricsService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; CrossOrigin //允许前端跨域访问后端是8080前端是5173地址不一样前端会有一个安全限制 RequestMapping(/metrics) RestController public class CpuLoadRestController { Autowired private CpuLoadMetricsService cpuLoadMetricsService; GetMapping(/cpuload) public Result getCpuLoad(){ double[] cpuLoad cpuLoadMetricsService.getCpuLoad(); return Result.success(cpuLoad); } }com.haha.service.CpuLoadMetricsServicepackage com.haha.service; import org.springframework.stereotype.Service; import oshi.SystemInfo; import oshi.hardware.CentralProcessor; import oshi.hardware.HardwareAbstractionLayer; Service public class CpuLoadMetricsService { //0SHI 提供的获取所有数据的入口 SystemInfo si new SystemInfo(); public double[] getCpuLoad() { //通过si (SystemInfo实例)获取硬件抽象层对象 HardwareAbstractionLayer hardware si.getHardware(); //拿到cpu信息 CentralProcessor processor hardware.getProcessor(); //获取cpu 1s 内的负载 double[] CpuLoad processor.getProcessorCpuLoad(1000); return CpuLoad; } }com.haha.OshiAppApplication 启动类和controller,service,common包同层后端这样就写完了后端这里只写了cpu 1s 内的负载的数据想返回其他数据自己通过看oshi api文档另加启动项目查看这样说明写的没有问题后端接口已经准备好了前端出现这个问题PS C:\Java\oshi-app\monitor-app npm install npm : 无法加载文件 C:\Nvm\nvm\v22.20.0\npm.ps1因为在此系统上禁止运行脚本。有关详细信息请参阅 https:/go.microsoft.com/fwlink/?LinkID135 170 中的 about_Execution_Policies。 所在位置 行:1 字符: 1 npm install ~~~ CategoryInfo : SecurityError: (:) []PSSecurityException FullyQualifiedErrorId : UnauthorizedAccess解决办法1. 检查当前策略 Get-ExecutionPolicy -List 2. 强制设置当前进程 Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process -Force改这里拿到服务器真正的响应C:\Java\oshi-app\monitor-app\src\http\index.js// 添加响应拦截器 http.interceptors.response.use(function (response) { // 2xx 范围内的状态码都会触发该函数。 // 对响应数据做点什么 //原生的响应对象中的 data 才是服务器返回的数据 return response.data; }, function (error) { // 超出 2xx 范围的状态码都会触发该函数。 // 对响应错误做点什么 return Promise.reject(error); // 将错误继续抛出让具体调用的地方能捕获处理 });前端的包结构为PS C:\Java\oshi-app\monitor-app\src tree 卷 empty 的文件夹 PATH 列表 卷序列号为 8E61-6075 C:. ├─api ├─http ├─router ├─stores └─views └─cpu PS C:\Java\oshi-app\monitor-app\srcsrc\api\cpuloadApi.js:import axios from axios; //用来发请求的 import http from /http; //获取cpu负载数据 const getCpuLoadApi (){ return http.get(/metrics/cpuload); } export{ //前端里面写的东西都得导出去凡是export导出的别人就能用 getCpuLoadApi }src\http\index.js:// 抽取 axios 发请求的方法 import axios from axios; const http axios.create({ baseURL: http://localhost:8080, //基础地址你后端Spring Boot服务的地址 timeout: 3000, // 超时时间3秒无响应则自动取消请求避免界面卡死 headers: {X-Custom-Header: foobar} // 默认请求头可以放一些后端约定的信息如应用标识 }); // 添加请求拦截器 http.interceptors.request.use(function (config) { // 在发送请求之前做些什么 return config; }, function (error) { // 对请求错误做些什么 return Promise.reject(error); }); // 添加响应拦截器 http.interceptors.response.use(function (response) { // 2xx 范围内的状态码都会触发该函数。 // 对响应数据做点什么 //原生的响应对象中的 data 才是服务器返回的数据 return response.data; }, function (error) { // 超出 2xx 范围的状态码都会触发该函数。 // 对响应错误做点什么 return Promise.reject(error); // 将错误继续抛出让具体调用的地方能捕获处理 }); export default http;src\router\index.js:import CpuLoad from /views/cpu/CpuLoad.vue import Home from /views/Home.vue import { createRouter, createWebHistory } from vue-router const router createRouter({ history: createWebHistory(import.meta.env.BASE_URL), routes: [ { path:/, name: home, component: Home, }, { path:/cpu, name: cpu, component: CpuLoad, }, ], }) export default routersrc\stores\counter.js:import { ref, computed } from vue import { defineStore } from pinia export const useCounterStore defineStore(counter, () { const count ref(0) const doubleCount computed(() count.value * 2) function increment() { count.value } return { count, doubleCount, increment } })src\views\cpu\CpuLoad.vue:template !--8个叫cpu-[1~8]-- a-space wraptrue div :idcpu-${i} styleheight: 230px; width: 294px; border: 1px solid black :keyi v-fori in 8 /div /a-space /template script setup import { TimelineItem } from arco-design/web-vue; import * as echarts from echarts; import { ref, onMounted } from vue; import { getCpuLoadApi } from /api/cpuloadApi; //保存所有初始化的图表 const chartDom ref([]); onMounted(() { //drawCpuLoad(); //初始化图标只需要进行一次 initChart(); getCpuData(); }); const initChart () { for (let i 1; i 8; i) { var dom document.getElementById(cpu- i); //得到一个chart对象 var myChart echarts.init(dom); chartDom.value.push(myChart); } }; //8核cpu 的所有数据 //每一核还是一个数组这个数组中保存的是每秒的数据 //在这个里面隐藏的是二维数组第一维是每一个cpu,每一个cpu里面又是一个数组代表它里面的所有的数据不然每个cpu只有一个数据 const cpuAllData ref([]); const getCpuData async () { //1.拿到服务器真正的响应 给服务器发送请求获取 let resp await getCpuLoadApi(); //等待 API 调用完成并将结果赋值给 resp 变量,await要配合async一起使用 //2.返回的是当前8核cpu当前的负载值 let data resp.data; for (let i 0; i 8; i) { //把当前请求到的这个cpu的使用率放进自己的数组中,第一次要初始化数组 if (!cpuAllData.value[i]) { cpuAllData.value[i] []; } //60s内的cpu负载监控图 if (cpuAllData.value[i].length 60) { //把最老的一个数据删除放入最新获取的这个数据 let arr cpuAllData.value[i].slice(-60); //移除了最前一个元素的数组 arr.push(data[i]) cpuAllData.value[i] arr; } else { cpuAllData.value[i].push(data[i]); } //这里会00M;这个数组最多放60个?超过60个删除最老的 drawCpuLoad(i 1, cpuAllData.value[i]); } await getCpuData(); }; //1、每个图显示CPU名 //2、每个图xy轴不显示(和windows一样) //3、显示为面积图 const drawCpuLoad (cpuIndex, cpuData) { //页面加载出来有div,dom元素才可以显示 //得到一个chart对象 var myChart chartDom.value[cpuIndex - 1]; var option; option { title: { text: cpu cpuIndex, }, xAxis: { show: false, type: category, data: cpuData.map((_, index) index 1) }, yAxis: { show: false, type: value, min: 0, max: 1 }, series: [ { data: cpuData, type: line, areaStyle: {}, smooth: true, symbol: none, }, ], }; option myChart.setOption(option); }; /script style scoped /stylesrc\views\NavBar.vue:script setup import { useRouter} from vue-router; //vue里面导航的跳转要用useRouter函数 const router useRouter(); //useRouter这个函数会给你返回一个路由器 const navTo (url){ //这个url是click按钮传进来的 router.push(url); } /script template div classmenu-demo a-menu modehorizontal :default-selected-keys[1] a-menu-item key0 :style{ padding: 0 } disabled div :style{ width: 80px, height: 30px, borderRadius: 2px, background: var(--color-fill-3), cursor: text, } / /a-menu-item a-menu-item key/ clicknavTo(/)首页/a-menu-item a-menu-item key/cpu clicknavTo(/cpu)CPU监控页/a-menu-item /a-menu /div /template style scoped .menu-demo { box-sizing: border-box; width: 100%; background-color: var(--color-neutral-2); } /stylesrc\App.vue:script setup import { RouterView } from vue-router; import NavBar from ./views/NavBar.vue; /script template div classlayout-demo a-layout styleheight: 100vh; a-layout-header NavBar/ /a-layout-header a-layout-content RouterView / !--表示内容是动态的 -- /a-layout-content a-layout-footerFooter/a-layout-footer /a-layout /div /template style scoped .layout-demo :deep(.arco-layout-header), .layout-demo :deep(.arco-layout-footer), .layout-demo :deep(.arco-layout-sider-children), .layout-demo :deep(.arco-layout-content) { display: flex; flex-direction: column; justify-content: center; font-size: 16px; font-stretch: condensed; text-align: center; } .layout-demo :deep(.arco-layout-header), .layout-demo :deep(.arco-layout-footer) { height: 64px; } .layout-demo :deep(.arco-layout-sider) { width: 206px; } .layout-demo :deep(.arco-layout-content) { } /stylesrc\views\Home.vue这个让前端最严厉的父亲来写template div classdashboard-container div classheader-box div classheader-left h2系统监控概览 - {{ deviceInfo.deviceName }}/h2 p classstatus-tag核心引擎Java OSHI | 数据源本地采集/p /div div classheader-right span classtime-label系统时间/span span classtime-value{{ currentTime }}/span /div /div div classcard-grid div classstat-card div classcard-icon cpu-themeCPU/div div classcard-content div classlabelCPU 平均负载 (实时)/div div classvalue{{ currentAvgLoad ! null ? currentAvgLoad % : 采集源连接中... }}/div div classprogress-container div classprogress-bar :style{ width: currentAvgLoad %, backgroundColor: getLoadColor(currentAvgLoad) }/div /div /div /div div classstat-card div classcard-icon mem-themeMEM/div div classcard-content div classlabel物理内存使用率/div div classvalue{{ sysMetrics.memUsage || 等待接口... }}/div div classsub-label总容量: {{ deviceInfo.ramTotal }}/div /div /div div classstat-card div classcard-icon device-themeID/div div classcard-content div classlabel设备产品 ID/div div classvalue small{{ deviceInfo.productId }}/div div classsub-label系统类型: {{ deviceInfo.osType }}/div /div /div /div div classchart-section div classchart-title span classdot/span CPU 核心负载变化趋势 (最近60秒) /div div idcpu-load-chart classchart-canvas/div /div div classtable-section div classchart-titlespan classdot/span 计算机硬件详细配置/div table classdata-table thead tr th width200配置项/th th详细参数内容/th /tr /thead tbody tr td classtd-label设备名称/td td{{ deviceInfo.deviceName }}/td /tr tr td classtd-label处理器 (CPU)/td td{{ deviceInfo.cpuModel }}/td /tr tr td classtd-label机带 RAM/td td{{ deviceInfo.ramTotal }} (15.7 GB 可用)/td /tr tr td classtd-label设备 ID/td td{{ deviceInfo.deviceId }}/td /tr tr td classtd-label产品 ID/td td{{ deviceInfo.productId }}/td /tr tr td classtd-label系统类型/td td{{ deviceInfo.osType }}/td /tr tr td classtd-label笔和触控/td td{{ deviceInfo.touchSupport }}/td /tr /tbody /table /div /div /template script setup import { ref, reactive, onMounted, onUnmounted } from vue; import * as echarts from echarts; import { getCpuLoadApi } from /api/cpuloadApi; // --- 你的真实电脑信息 (静态) --- const deviceInfo { deviceName: aixuexi, cpuModel: 11th Gen Intel(R) Core(TM) i5-1135G7 2.40GHz (2.42 GHz), ramTotal: 16.0 GB, deviceId: 123E150F-89F7-4E25-9A40-236BCEC9D001, productId: 00342-30560-26011-AAOEM, osType: 64 位操作系统, 基于 x64 的处理器, touchSupport: 没有可用于此显示器的笔或触控输入 }; // --- 运行时动态指标 --- const currentTime ref(); const currentAvgLoad ref(null); const loadHistory ref([]); // 存储最近60个数据点 // 预留接口数据占位不填入假数据 const sysMetrics reactive({ memUsage: null, upTime: null }); let cpuChart null; let dataTimer null; let clockTimer null; // --- 逻辑处理 --- // 获取 CPU 真实数据 const fetchRealCpuData async () { try { const res await getCpuLoadApi(); const loads res.data || []; if (loads.length 0) { // 计算所有核心的平均值并转为百分比 const avg (loads.reduce((a, b) a b, 0) / loads.length * 100).toFixed(1); currentAvgLoad.value avg; // 更新历史记录 const now new Date().toLocaleTimeString(zh-CN, { hour12: false }); if (loadHistory.value.length 60) loadHistory.value.shift(); loadHistory.value.push({ time: now, value: avg }); updateChart(); } } catch (err) { console.error(无法获取CPU负载数据请检查后端接口:, err); } }; const initChart () { const chartDom document.getElementById(cpu-load-chart); if (!chartDom) return; cpuChart echarts.init(chartDom); cpuChart.setOption({ tooltip: { trigger: axis, formatter: {b} br/ 负载: {c}% }, grid: { left: 3%, right: 3%, bottom: 3%, top: 5%, containLabel: true }, xAxis: { type: category, boundaryGap: false, data: [], axisLine: { lineStyle: { color: #ddd } } }, yAxis: { type: value, min: 0, max: 100, axisLabel: { formatter: {value}% } }, series: [{ name: CPU负载, type: line, smooth: true, symbol: none, areaStyle: { color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ { offset: 0, color: rgba(22, 119, 255, 0.3) }, { offset: 1, color: rgba(22, 119, 255, 0) } ]) }, lineStyle: { color: #1677ff, width: 2 }, data: [] }] }); }; const updateChart () { if (!cpuChart) return; cpuChart.setOption({ xAxis: { data: loadHistory.value.map(i i.time) }, series: [{ data: loadHistory.value.map(i i.value) }] }); }; const getLoadColor (val) { if (val 80) return #ff4d4f; // 红色高负载 if (val 50) return #faad14; // 黄色 return #52c41a; // 绿色正常 }; const tick () { currentTime.value new Date().toLocaleString(); }; onMounted(() { tick(); clockTimer setInterval(tick, 1000); initChart(); fetchRealCpuData(); dataTimer setInterval(fetchRealCpuData, 2000); // 2秒同步一次后端 OSHI 数据 window.addEventListener(resize, () cpuChart?.resize()); }); onUnmounted(() { clearInterval(dataTimer); clearInterval(clockTimer); if (cpuChart) cpuChart.dispose(); }); /script style scoped .dashboard-container { padding: 24px; background-color: #f0f2f5; min-height: 100vh; } .header-box { display: flex; justify-content: space-between; align-items: center; margin-bottom: 24px; padding: 16px 24px; background: #fff; border-radius: 8px; box-shadow: 0 1px 2px rgba(0,0,0,0.03); } .header-box h2 { margin: 0; font-size: 20px; color: #1f1f1f; } .status-tag { margin: 4px 0 0 0; font-size: 12px; color: #8c8c8c; } .time-value { font-family: Consolas, monospace; font-weight: bold; color: #1677ff; font-size: 16px; } .card-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 20px; margin-bottom: 24px; } .stat-card { background: #fff; border-radius: 8px; padding: 24px; display: flex; align-items: center; border: 1px solid #f0f0f0; } .card-icon { width: 48px; height: 48px; border-radius: 8px; display: flex; align-items: center; justify-content: center; font-weight: bold; margin-right: 16px; font-size: 12px; } .cpu-theme { background: #e6f4ff; color: #1677ff; } .mem-theme { background: #f6ffed; color: #52c41a; } .device-theme { background: #f9f0ff; color: #722ed1; } .card-content { flex: 1; overflow: hidden; } .label { font-size: 13px; color: #595959; margin-bottom: 8px; } .value { font-size: 24px; font-weight: bold; color: #262626; margin-bottom: 8px; } .value.small { font-size: 14px; white-space: nowrap; text-overflow: ellipsis; overflow: hidden; } .sub-label { font-size: 12px; color: #8c8c8c; } .progress-container { height: 4px; background: #f5f5f5; border-radius: 2px; overflow: hidden; } .progress-bar { height: 100%; transition: width 0.4s cubic-bezier(0.08, 0.82, 0.17, 1); } .chart-section { background: #fff; border-radius: 8px; padding: 24px; margin-bottom: 24px; border: 1px solid #f0f0f0; } .chart-title { font-weight: bold; font-size: 15px; color: #262626; margin-bottom: 20px; display: flex; align-items: center; } .dot { width: 6px; height: 6px; background: #1677ff; border-radius: 50%; margin-right: 8px; } .chart-canvas { height: 280px; width: 100%; } .table-section { background: #fff; border-radius: 8px; padding: 24px; border: 1px solid #f0f0f0; } .data-table { width: 100%; border-collapse: collapse; } .data-table th { text-align: left; padding: 12px 16px; background: #fafafa; color: #595959; font-size: 14px; border-bottom: 1px solid #f0f0f0; } .data-table td { padding: 12px 16px; border-bottom: 1px solid #f0f0f0; font-size: 14px; color: #262626; } .td-label { color: #8c8c8c; font-weight: 500; } /style最终效果