当前位置: 首页 > news >正文

QtApplets-SystemInfo

头图

QtApplets-SystemInfo

​ 今天是2024年1月3日09:18:44,这也是2024年的第一篇博客,今天我们主要两件事,第一件,获取系统CPU使用率,第二件,获取系统内存使用情况。

​ 这里因为写博客的这个本本的环境配置不是全的,没有VS编译套件,也没有对应的环境,我尝试在Windows下查找对应的pdh.lib没有找到,所以不能跑起来截图了,我今天分享的代码如果是基于Vs的编译环境,那可以直接跑起来,如果是基于mingW的环境,那需要手动指定一下pdh.lib的路径,并且吧dll拷贝到运行根目录。


文章目录

  • QtApplets-SystemInfo
    • Windows 平台获取 CPU 使用率
      • 关于 PDH库
    • Qt 开发
      • 引入 pdh 库
      • 抄代码
      • QString 转 LPCWSTR
    • Windows 平台下获取内存使用情况
      • 关于 psapi库
    • Qt 实现
    • mingW环境使用 PDH库
    • 程序运行效果
    • ☞ 源码

关键字: pdhpsapicpumemoryqt

Windows 平台获取 CPU 使用率

在Windows平台上,Qt没有提供直接的API来获取CPU使用率。不过,我们可以使用Windows API来获取这些信息。这里需要使用一个win的库,PDH库

关于 PDH库

PDH(Performance Data Helper)库是Windows操作系统提供的一个编程接口,用于访问计算机性能数据。这个库允许开发者收集和使用性能监视数据,这些数据是由Windows系统提供的性能计数器所采集的。

性能计数器可以提供有关系统或应用程序状态的各种指标,如CPU使用率、磁盘I/O、网络流量和内存使用情况等。PDH库提供了一系列的函数,使得开发者能够:

  • 枚举系统上可用的性能计数器和它们的实例。
  • 收集一次或定期收集性能数据。
  • 从本地或远程计算机上的实时数据或日志文件中检索性能数据。
  • 计算和格式化性能数据的计数器值。

使用PDH库的常见步骤包括:

  1. 打开一个查询: 创建一个查询句柄,以便开始收集性能数据。
  2. 添加计数器: 为你想要监控的性能指标添加一个或多个计数器。
  3. 收集数据: 定期收集性能数据,这可以是实时的,也可以是从性能日志中提取的。
  4. 获取计数器值: 提取特定计数器的当前值。
  5. 关闭查询: 收集完成后关闭和销毁查询。

PDH库是通过动态链接库pdh.dll实现的,开发者可以在C、C++等编程语言中使用这个库。在Visual Studio等开发环境中,通常可以直接包含Pdh.h头文件并链接Pdh.lib库文件以调用PDH函数。

例如,以下是一个使用PDH库获取CPU使用率的简单例子:

#include <windows.h>
#include <pdh.h>#pragma comment(lib, "pdh.lib")PDH_HQUERY cpuQuery;
PDH_HCOUNTER cpuTotal;void init() {PdhOpenQuery(NULL, NULL, &cpuQuery);// 这里的计数器路径可能因系统的语言和版本而异PdhAddEnglishCounter(cpuQuery, "\\Processor(_Total)\\% Processor Time", NULL, &cpuTotal);PdhCollectQueryData(cpuQuery);
}double getCurrentCpuUsage() {PDH_FMT_COUNTERVALUE counterVal;PdhCollectQueryData(cpuQuery);PdhGetFormattedCounterValue(cpuTotal, PDH_FMT_DOUBLE, NULL, &counterVal);return counterVal.doubleValue;
}void cleanup() {PdhCloseQuery(cpuQuery);
}

在这个例子中,init函数初始化了一个查询,并添加了一个计数器来监控整个处理器时间的百分比。getCurrentCpuUsage函数收集并提供了当前的CPU使用率。最后,cleanup函数关闭了查询。

PDH库是系统监控和性能分析工具中常用的组件,它提供了一种相对简易的方法来获取和使用Windows系统的性能数据。

Qt 开发

引入 pdh 库

首先,我们需要在.pro文件中添加pdh.lib库:

LIBS += -lpdh

抄代码

然后把上面的代码放到Qt里面调试同就可以

代码片段如下:

void Widget::initCpuUsage()
{PdhOpenQuery(NULL, NULL, &cpuQuery);// 这里使用了反斜杠转义QString str = "\\Processor(_Total)\\% Processor Time";PdhAddEnglishCounter(cpuQuery, (LPCWSTR)str.utf16(), NULL, &cpuTotal);PdhCollectQueryData(cpuQuery);
}void Widget::getCurrentCpuUsage()
{PDH_FMT_COUNTERVALUE counterVal;PdhCollectQueryData(cpuQuery);PdhGetFormattedCounterValue(cpuTotal, PDH_FMT_DOUBLE, NULL, &counterVal);ui->label_cpu->setText(QString::number( counterVal.doubleValue) + "%");
}

QString 转 LPCWSTR

在抄代码的时候,会发现遇到类型不匹配问题。这里就需要问下我的贴心小秘了。

在Qt中,可以使用QString的方法来将字符串转换为Windows平台特定的LPCWSTR类型。以下是如何进行转换的步骤:

  1. QString转换为QWchar数组。
  2. 使用QWchar数组来初始化LPCWSTR

下面是一个简单的示例:

#include <QString>
#include <QDebug>// 假设我们有以下QString
QString qString = "Hello World";// 将QString转换为宽字符串(UTF-16)
QByteArray utf16Array = qString.toUtf8();
LPCWSTR lpcwstr = reinterpret_cast<LPCWSTR>(utf16Array.constData());// 现在可以使用lpcwstr作为LPCWSTR类型

但是,需要注意的是,QByteArray的生命周期必须覆盖LPCWSTR的使用范围,因为LPCWSTR是指向QByteArray数据的指针。如果QByteArray被销毁或者超出作用域,LPCWSTR指针将指向无效的内存。

在实际使用中,最常见的是将QString转换为LPCWSTR以便于Windows API调用,这通常需要UTF-16编码。Qt内部使用UTF-16编码存储QString,因此可以更简单地转换,如下所示:

QString qString = "Hello World";#ifdef Q_OS_WIN
// 使用QString::utf16()转换为LPCWSTR
LPCWSTR lpcwstr = (LPCWSTR)qString.utf16();
#endif// 现在lpcwstr可以用在需要LPCWSTR类型的Windows API调用中

请注意,上述代码中的#ifdef Q_OS_WIN是为了确保只在Windows平台上执行转换,以保持代码的跨平台特性。

当你需要将QString传递给接受LPCWSTR参数的Windows API时,确保QString在调用该API期间保持未被修改和有效。

Windows 平台下获取内存使用情况

在Windows 10上获取内存使用大小可以通过多种方式完成,同样,今天我们将使用Windows 的API 来获取,需要使用一个psapi 的库。

关于 psapi库

PSAPI(Process Status API)是Windows操作系统中用于管理应用程序和服务的一个API集合。这个库主要用于检索与系统进程、运行的程序以及它们使用的内存相关的信息。它是系统资源监测和管理工具开发过程中的关键部分。

PSAPI提供了以下功能:

  1. 枚举进程: 列出当前系统上运行的所有进程。
  2. 查询进程信息: 获取进程的详细信息,比如它的执行映像、占用的内存量、句柄等。
  3. 枚举模块: 列出特定进程加载的所有DLL和内存映射文件。
  4. 获取模块信息: 提供模块的详细信息,如文件路径、模块的内存使用情况。
  5. 工作集信息: 获取特定进程的工作集信息,即进程当前使用的物理内存集。

这些功能可以帮助开发者诊断程序的内存问题,或者构建显示系统资源使用情况的应用程序。

使用PSAPI库时,通常需要包含psapi.h头文件,并且在项目中链接psapi.lib库。在Windows编程中,PSAPI函数通常用于配合其他系统API,如进程和线程函数,以收集并操作系统资源使用数据。

以下是一个使用PSAPI函数EnumProcesses列出所有进程ID的简单示例:

#include <windows.h>
#include <psapi.h>
#include <stdio.h>#pragma comment(lib, "psapi.lib")void PrintProcessNamesAndIDs() {DWORD aProcesses[1024], cbNeeded, cProcesses;// 获取进程ID列表if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded)) {return;}// 计算返回的进程数量cProcesses = cbNeeded / sizeof(DWORD);// 打印每个进程的名称和IDfor (unsigned int i = 0; i < cProcesses; i++) {if (aProcesses[i] != 0) {TCHAR szProcessName[MAX_PATH] = TEXT("<unknown>");// 获取进程句柄HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION |PROCESS_VM_READ,FALSE, aProcesses[i]);// 获取进程的可执行文件名称if (hProcess) {HMODULE hMod;DWORD cbNeeded;if (EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded)) {GetModuleBaseName(hProcess, hMod, szProcessName,sizeof(szProcessName) / sizeof(TCHAR));}}// 打印进程名称和IDprintf("%s (PID: %u)\n", szProcessName, aProcesses[i]);// 关闭进程句柄CloseHandle(hProcess);}}
}int main() {PrintProcessNamesAndIDs();return 0;
}

请注意,对系统资源的查询可能需要特定的权限,因此你可能需要以管理员权限运行你的程序才能获取所有进程的信息。

随着Windows版本的更新,PSAPI的一些功能可能会在其他库(如Kernel32.dll和NtDll.dll)中得到增强或替代。因此,在使用时,可能需要参考最新的官方文档以获取最佳实践。

Qt 实现

首先,你需要包含必要的头文件和库。在你的Qt项目中,需要在.pro文件中添加psapi.lib

LIBS += -lpsapi

代码片段如下:

void Widget::getMemory()
{
// 初始化MEMORYSTATUSEX结构MEMORYSTATUSEX memStatus;memStatus.dwLength = sizeof(memStatus);// 获取内存状态if (GlobalMemoryStatusEx(&memStatus)) {ui->label_memory_total->setText(QString::number((memStatus.ullTotalPhys / (1024 * 1024))));ui->label_memory_ava->setText(QString::number((memStatus.ullAvailPhys / (1024 * 1024))));ui->label_memory->setText(QString::number(memStatus.dwMemoryLoad)+"%");}
}

mingW环境使用 PDH库

在MinGW环境中使用PDH库可能会比较困难,因为MinGW可能没有包含全部的Windows平台SDK。然而,你可以尝试以下几种方法来使用PDH库:

  1. 手动链接PDH库:

    尽管MinGW的标准库中可能不包含PdhAddEnglishCounter,但PDH库(pdh.dll)通常是安装在Windows系统中的。你可以尝试手动链接这个库。在Qt项目文件(.pro)中添加以下行来链接PDH库:

    LIBS += -L"C:/Path/To/Pdh/Lib" -lpdh
    

    需要把"C:/Path/To/Pdh/Lib"替换为实际的库文件路径,如果pdh.lib文件在标准的库路径中,那么你只需要添加-lpdh

  2. 动态加载PDH库:

    你可以在运行时动态加载pdh.dll,使用QLibrary或者Windows API函数LoadLibraryGetProcAddress来加载库并获取函数指针。

    QLibrary pdhLib("pdh");
    if (pdhLib.load()) {auto PdhAddEnglishCounterW =(PDH_STATUS(WINAPI*)(PDH_HQUERY, LPCWSTR, DWORD_PTR, PDH_HCOUNTER*))pdhLib.resolve("PdhAddEnglishCounterW");if (PdhAddEnglishCounterW) {// 使用 PdhAddEnglishCounterW}
    }
    

    在这个例子中,QLibrary用于加载pdh.dll,然后使用resolve方法查找PdhAddEnglishCounter函数。

  3. 使用LoadLibrary和GetProcAddress:

    如果你不想使用Qt的QLibrary,你可以直接使用Windows API。

    HMODULE hPdh = LoadLibrary(TEXT("pdh.dll"));
    if (hPdh) {auto PdhAddEnglishCounter = (PDH_STATUS(WINAPI*)(PDH_HQUERY, LPCSTR, DWORD_PTR, PDH_HCOUNTER*))GetProcAddress(hPdh, "PdhAddEnglishCounterA");if (PdhAddEnglishCounter) {// 使用 PdhAddEnglishCounter}FreeLibrary(hPdh);
    }
    

    使用LoadLibrary加载pdh.dll并使用GetProcAddress获取PdhAddEnglishCounterA函数的指针。

  4. 使用MSYS2或Cygwin:

    如果你使用的是MSYS2或Cygwin,它们可能会有自己的PDH封装或者更好的对Windows API的支持。你可能需要在这些环境中查找是否有PDH的封装。

如果以上方法都不可行,你可能需要考虑更换到支持完整Windows API的编译环境,例如Microsoft Visual Studio。或者,如果你需要的PDH功能比较简单,你可能可以通过直接读取系统文件或使用其他系统命令来代替PDH库的功能。

程序运行效果

☞ 源码

源码链接:GitHub仓库自取

使用方法:☟☟☟


博客签名2021

相关文章:

QtApplets-SystemInfo

QtApplets-SystemInfo ​ 今天是2024年1月3日09:18:44&#xff0c;这也是2024年的第一篇博客&#xff0c;今天我们主要两件事&#xff0c;第一件&#xff0c;获取系统CPU使用率&#xff0c;第二件&#xff0c;获取系统内存使用情况。 ​ 这里因为写博客的这个本本的环境配置不…...

vue3防抖函数封装与使用,以指令的形式使用

utils/debounce.js /*** 防抖函数* param {*} fn 函数* param {*} delay 暂停时间* returns */ export function debounce(fn, delay 500) {let timer nullreturn function (...args) {// console.log(arguments);// const args Array.from(arguments)if (timer) {clearTim…...

Hive学习(13)lag和lead函数取偏移量

hive里面lag函数 在数据处理和分析中&#xff0c;窗口函数是一种重要的技术&#xff0c;用于在数据集中执行聚合和分析操作。Hive作为一种大数据处理框架&#xff0c;也提供了窗口函数的支持。在Hive中&#xff0c;Lag函数是一种常用的窗口函数&#xff0c;可以用于计算前一行…...

Centos Unable to verify the graphical display setup

ERROR: Unable to verify the graphical display setup. 在Linux下安装Oracle时 运行 ./runInstaller 报错 ERROR: Unable to verify the graphical display setup. This application requires X display. Make sure that xdpyinfo exist under PATH variable. No X11 DISPL…...

Java 说一下 synchronized 底层实现原理?

Java 说一下 synchronized 底层实现原理&#xff1f; synchronized 是 Java 中用于实现同步的关键字&#xff0c;它保证了多个线程对共享资源的互斥访问。底层实现涉及到对象头的 Mark Word 和锁升级过程。 synchronized 可以用于方法上或代码块上&#xff0c;分别对应于方法…...

nginx访问路径匹配方法

目录 一&#xff1a;匹配方法 二&#xff1a;location使用: 三&#xff1a;rewrite使用 一&#xff1a;匹配方法 location和rewrite是两个用于处理请求的重要模块&#xff0c;它们都可以根据请求的路径进行匹配和处理。 二&#xff1a;location使用: 1&#xff1a;简单匹配…...

偌依 项目部署及上线步骤

准备实验环境&#xff0c;准备3台机器 1.作为前端服务器&#xff0c;mysql,redis服务器--同时临时作为代码打包服务器 192.168.2.65 nginx-server 2.作为后端服务器 192.168.2.66 java-server-1 192.168.2.67 java-server-2 安装nginx/mysql #安装nginx [rootweb-nginx ~]…...

PHP特性知识点扫盲 - 上篇

概述 之前在分析thinkphp源码的时候&#xff0c;对依赖注入等等php高级的特性一直想做一个梳理和总结&#xff0c;一直没有时间&#xff0c;好不容易抽一点时间对技术的盲点做一个扫盲和总结。 特性 1.命名空间 命名空间是在PHP5.3中引入&#xff0c;是一个很重要的工具&am…...

Docker一键极速安装Nacos,并配置数据库!

1 部署方式 1.1 DockerHub javaedgeJavaEdgedeMac-mini ~ % docker run --name nacos \ -e MODEstandalone \ -e JVM_XMS128m \ -e JVM_XMX128m \ -e JVM_XMN64m \ -e JVM_MS64m \ -e JVM_MMS64m \ -p 8848:8848 \ -d nacos/nacos-server:v2.2.3 a624c64a1a25ad2d15908a67316d…...

交换机04_远程连接

通过远程管理方式连接交换机 1、telnet简介 telnet 是应用层协议 基于传输层TCP协议的&#xff0c;默认端口&#xff1a;23 采用的是明文密码方式 不是很安全&#xff0c;一般用于内网管理。 2、ssh协议简介 ssh 是应用层的协议&#xff0c;基于传输层的TCP协议&#x…...

ES6定义一个类(函数内部定义属性,,原型定义方法 ), 实现继承?

ES6中使用class关键字定义一个类&#xff0c;使用extends关键字实现继承。下面是一个示例&#xff1a; class Animal {constructor(name) {this.name name;}sayHello() {console.log(Hello, my name is ${this.name});} }class Dog extends Animal {constructor(name, breed)…...

使用 Process Explorer 和 Windbg 排查软件线程堵塞案例分享

目录 1、问题说明 2、线程堵塞的可能原因分析 3、使用Windbg和Process Explorer确定线程中发生了死循环 4、根据Windbg中显示的函数调用堆栈去查看源码&#xff0c;找到问题 4.1、在Windbg定位发生死循环的函数的方法 4.2、在Windbg中查看变量的值去辅助分析 4.3、是循环…...

“智慧”千里眼助力水泵站

泵站是为水提供势能和压能&#xff0c;解决无自流条件下的排灌、供水和水资源调配问题的唯一动力来源&#xff0c;在工农业用水、防洪、排涝和抗旱减灾等方面发挥着重要作用。一旦出现异常&#xff0c;对经济生产将造成难以估量的损失&#xff0c;给水利安全管理造成负担。因此…...

C++多态性——(5)运算符重载(第二节)

归纳编程学习的感悟&#xff0c; 记录奋斗路上的点滴&#xff0c; 希望能帮到一样刻苦的你&#xff01; 如有不足欢迎指正&#xff01; 共同学习交流&#xff01; &#x1f30e;欢迎各位→点赞 &#x1f44d; 收藏⭐ 留言​&#x1f4dd; 身先才能率人&#xff0c;律己才能服人…...

ES -极客学习

Elasticsearch 简介及其发展历史 起源 Lucene 于 Java 语言开发的搜索引擎库类创建于 1999 年&#xff0c;2005 年成为 Apache 顶级开源项目Lucene 具有高性能、易扩展的优点Lucene 的局限性 只能基于 Java 语言开发类库的接口学习曲线陡峭原生并不支持水平扩展原生并不支持水…...

【大厂秘籍】系列 - Java多线程面试题

Java多线程面试题 友情提示&#xff0c;看完此文&#xff0c;在Java多线程这块&#xff0c;基本上可以吊打面试官了 线程和进程的区别 进程是资源分配的最小单位&#xff0c;线程是CPU调度的最小单位 线程是进程的子集&#xff0c;一个进程可以有很多线程&#xff0c;每条线…...

vue实现画笔回放,canvas转视频播放功能

示例图&#xff1a; 一、vue2版本 <template><div class"canvas-video"><canvasref"myCanvasByVideo"class"myCanvas"id"myCanvasByVideo":width"width":height"height"></canvas><d…...

Docker中镜像的相关操作

1.辅助操作 docker version&#xff1a;用查看docker客户端引擎和server端引擎版本信息。 docker info&#xff1a;用来查看docker引擎的详细信息。 docker --help&#xff1a;用来查看帮助信息。 2.镜像Image docker images&#xff1a;查看当前本地仓库中存在哪些镜像。 …...

[python]python利用pyaudio录制系统声音没有立体声混音怎么录制系统音频

当电脑没有立体声混音导致Python写代码无法使用pyaudio进行录制系统声音怎么办&#xff1f;查阅资料和安装驱动等方法都不行&#xff0c;难道没办法了吗&#xff1f;那为什么电脑其他软件可以做到呢&#xff1f;因此研究了一下pyaudio在没有立体声混音情况下确实无法录制声音&a…...

使用echarts的bmap配置项绘制区域轮廓遮罩

示例图 代码 <template><div id"map" style"width: 100%; height: 100vh"></div> </template><script> import * as echarts from "echarts"; import "echarts/extension/bmap/bmap"; export default…...

如何验证Qwen3-4B部署效果?MMLU基准测试实战指南

如何验证Qwen3-4B部署效果&#xff1f;MMLU基准测试实战指南 1. 为什么需要验证模型效果&#xff1f; 当你成功部署了Qwen3-4B模型后&#xff0c;最关心的问题肯定是&#xff1a;这个模型到底表现如何&#xff1f;能不能满足我的需求&#xff1f;这时候就需要一个客观的评估方…...

3步掌握PinWin效率工具:让窗口置顶操作效率提升10倍

3步掌握PinWin效率工具&#xff1a;让窗口置顶操作效率提升10倍 【免费下载链接】PinWin Pin any window to be always on top of the screen 项目地址: https://gitcode.com/gh_mirrors/pin/PinWin 你是否曾在视频会议时手忙脚乱地寻找被覆盖的会议窗口&#xff1f;在多…...

MTools开箱即用:5分钟在K8s部署Web版AI工具,图片音视频全能处理

MTools开箱即用&#xff1a;5分钟在K8s部署Web版AI工具&#xff0c;图片音视频全能处理 1. 为什么选择MTools Web版 MTools Web版是一款集成了图片处理、音视频编辑、AI智能工具和开发辅助功能的现代化工具套件。与传统的桌面软件不同&#xff0c;它可以直接在浏览器中运行&a…...

GLM-4.1V-9B-Base开源大模型:面向中文场景优化的轻量级视觉理解基座

GLM-4.1V-9B-Base开源大模型&#xff1a;面向中文场景优化的轻量级视觉理解基座 1. 模型概述 GLM-4.1V-9B-Base是智谱AI开源的一款专注于视觉多模态理解的基础模型&#xff0c;特别针对中文场景进行了优化。这个9B参数的轻量级模型在保持高效推理能力的同时&#xff0c;提供了…...

GLM-4.1V-9B-Base入门必看:中文提问技巧——如何写出高稳定度问题

GLM-4.1V-9B-Base入门必看&#xff1a;中文提问技巧——如何写出高稳定度问题 1. 认识GLM-4.1V-9B-Base GLM-4.1V-9B-Base是智谱开源的视觉多模态理解模型&#xff0c;专门用于处理图像内容识别、场景描述、目标问答等中文视觉理解任务。与普通聊天模型不同&#xff0c;它更擅…...

从MATLAB到C++:手把手教你将鱼眼相机标定结果(Scaramuzza模型)部署到OpenCV项目

从MATLAB到C&#xff1a;手把手教你将鱼眼相机标定结果&#xff08;Scaramuzza模型&#xff09;部署到OpenCV项目 鱼眼相机因其超广视角在机器人导航、虚拟现实等领域应用广泛。但MATLAB标定结果如何无缝迁移到C工程环境&#xff1f;本文将彻底解决这个痛点&#xff0c;带您完成…...

Linux音频音量太小?别急着改代码,试试amixer这个终端神器

Linux音频音量调整终极指南&#xff1a;告别代码级修改&#xff0c;掌握amixer命令行艺术 当你在深夜调试语音识别项目时&#xff0c;突然发现树莓派录制的样本几乎听不见&#xff1b;或是准备录制技术教程视频时&#xff0c;Ubuntu系统的输出音量小得可怜——这种场景下&#…...

告别GitHub下载卡顿:手把手教你配置Electron国内镜像(npmrc文件详解)

告别Electron下载困境&#xff1a;深度解析.npmrc配置与国内镜像实战指南 每次执行npm install electron时&#xff0c;看着进度条卡在node install.js阶段一动不动&#xff0c;或是突然蹦出RequestError: connect ETIMEDOUT的红色报错——这种体验对于国内开发者来说再熟悉不过…...

CYBER-VISION零号协议Markdown文档大师:替代Typora的智能写作体验

CYBER-VISION零号协议Markdown文档大师&#xff1a;替代Typora的智能写作体验 如果你和我一样&#xff0c;每天都要和Markdown文档打交道&#xff0c;那你肯定知道那种感觉&#xff1a;面对一个空白文档&#xff0c;脑子里有想法&#xff0c;但就是敲不出满意的句子&#xff1…...

Movie_Recommend推荐算法对比:ALS、ItemCF与热门推荐全面解析

Movie_Recommend推荐算法对比&#xff1a;ALS、ItemCF与热门推荐全面解析 【免费下载链接】Movie_Recommend 基于Spark的电影推荐系统&#xff0c;包含爬虫项目、web网站、后台管理系统以及spark推荐系统 项目地址: https://gitcode.com/gh_mirrors/mo/Movie_Recommend …...