热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

自己实现Linux系统任务管理器(附源码)

自己实现Linux系统任务管理器(附源码),Go语言社区,Golang程序员人脉社

一、前言

        之前在操作系统课程中,使用Java实现的任务管理器,使用了Swing界面、Runtime、Process相关类。文章总结和程序下载在下面:

        Java调用批处理或可执行文件和Runtime、Process类实现Java版进程管理器:http://blog.csdn.net/ljheee/article/details/52067690

        Java进程管理器MyProcess.rar----免积分下载:http://download.csdn.net/detail/ljheee/9598423

        虽然基本功能实现了,Java跨平台的特性,也使得这个应用在Linux上跑,但是在实现这个版本之后就已经感觉到Java对操作系统信息的提取与封装是有限的,Process包含的进程信息有限,且操作不方便。

        因此最近在Linux课程中,决定用Qt界面+Linux方式实现自己的Linux版任务管理器。在程序设计之前,有必要先了解下Linux系统进程信息提取方式,因为这种“Linux方式”不像Java的Process类封装那样,不管底层,只管调用  process.getInputStream();去读取流。

二、Linux下/proc目录简介

        Linux内核提供了一种通过 /proc 文件系统,在运行时访问内核内部数据结构、改变内核设置的机制。proc文件系统是一个伪文件系统,它只存在内存当中,而不占用外存空间。它以文件系统的方式为访问系统内核数据的操作提供接口。

        系统中当前运行的每一个进程都有对应的一个目录在/proc下,以进程的 PID号为目录名,它们是读取进程信息的接口。而self目录则是读取进程本身的信息接口,是一个link。

        直接打开自己安装的Linux系统,进入/proc,可以看到很多数字命名的文件夹;文件夹名的数字,代表当前运行的一个进程的PID,它是读取进程信息的接口。

Linux下/proc下其他重要目录

/proc/cpuinfo     --cpu的信息

/proc/devices     --已经加载的设备并分类

/proc/modules     --所有加载到内核的模块列表

/proc/stat        --所有的CPU活动信息,可采点计算cpu的利用率

/proc/version     --Linux内核版本和gcc版本

 

三、Qt实现Linux版任务管理器

        用户和应用程序可以通过/proc得到系统的信息,并可以改变内核的某些参数。由于系统的信息是动态改变的,所以用户或应用程序读取proc文件时,proc文件系统是动态从系统内核读出所需信息并提交的。

        我们要显示系统信息,只需进行相应的文件操作就行了。

        Qt的发展势头相当猛,qt的可移植性相当强,现在应用程序做界面基本都用Qt。Qt是诺基亚开发的一个跨平台的C++图形用户界面应用程序框架。Qt商业版只能试用30天,不过有GPL版的,可以免费使用。有一个非常不错的免费Qt集成开发环境QtCreator IDE。Linux版任务管理器采用的是Qt来实现图形界面。

步骤:

1、Linux下安装Qt Creator,打开新建一个工程,工程目录下,相关文件会有6个,具体见下图--工程文件夹:

 

编译完成后的实现效果:

“内存信息”模块:

 

“进程信息”模块:

 

“模块信息”模块:

 

“系统信息”模块:

 

“关于”模块:

 

 

完整源码如下:

main.cpp    工程运行的入口,创建工程时自动创建的,不需要修改。

#include #include "mainwindow.h" int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.show(); return a.exec(); }

mainwindow.h  工程头文件,定义资源和事件响应函数声明。

#ifndef MAINWINDOW_H #define MAINWINDOW_H #include #include #include #include #include namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); private: Ui::MainWindow *ui;//界面资源类,所有的界面元素都是通过该类来调用 QTimer *timer; //计时器 private slots: void on_pushButton_pkill_clicked(); void on_pushButton_prefresh_clicked(); void on_pushButton_Model_install_clicked(); void on_pushButton_Model_remove_clicked(); void on_pushButton_Model_refresh_clicked(); void on_pushButton_reboot_clicked(); void on_pushButton_halt_clicked(); void on_tabWidget_INFO_currentChanged(int index); void timer_update_currentTabInfo(); //显示tab中的内容 void show_tabWidgetInfo(int index); }; #endif // MAINWINDOW_H

mainwindow.cpp  工程最重要的源文件,完成主要的业务逻辑。

#include "mainwindow.h" #include "ui_mainwindow.h" #include #include #include int a0 = 0, a1 = 0, b0 = 0, b1 = 0; MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); timer = new QTimer(this); QWidget::connect( timer, SIGNAL( timeout() ), this, SLOT( timer_update_currentTabInfo() ) );//ui控件-事件响应 QWidget::connect( ui->tabWidget_INFO, SIGNAL( currentChanged() ), this, SLOT( on_tabWidget_currentChanged() ) ); timer->start(1000); } MainWindow::~MainWindow() { delete ui; delete timer; } void MainWindow::timer_update_currentTabInfo() { int index = ui->tabWidget_INFO->currentIndex(); //定时器只刷新内存tab页面,用于进度条动态显示 if (index == 0) { show_tabWidgetInfo(index); } } void MainWindow::show_tabWidgetInfo(int index) { QString tempStr; //读取文件信息字符串 QFile tempFile; //用于打开系统文件 int pos; //读取文件的位置 if (index == 0) //内存資源 { tempFile.setFileName("/proc/meminfo"); //打开内存信息文件 if ( !tempFile.open(QIODevice::ReadOnly) ) { QMessageBox::warning(this, tr("warning"), tr("The meminfo file can not open!"), QMessageBox::Yes); return ; } QString memTotal; QString memFree; QString memUsed; QString swapTotal; QString swapFree; QString swapUsed; int nMemTotal, nMemFree, nMemUsed, nSwapTotal, nSwapFree, nSwapUsed; while (1) { tempStr = tempFile.readLine(); pos = tempStr.indexOf("MemTotal"); if (pos != -1) { memTotal = tempStr.mid(pos+10, tempStr.length()-13); memTotal = memTotal.trimmed(); nMemTotal = memTotal.toInt()/1024; } else if (pos = tempStr.indexOf("MemFree"), pos != -1) { memFree = tempStr.mid(pos+9, tempStr.length()-12); memFree = memFree.trimmed(); nMemFree = memFree.toInt()/1024; } else if (pos = tempStr.indexOf("SwapTotal"), pos != -1) { swapTotal = tempStr.mid(pos+11, tempStr.length()-14); swapTotal = swapTotal.trimmed(); nSwapTotal = swapTotal.toInt()/1024; } else if (pos = tempStr.indexOf("SwapFree"), pos != -1) { swapFree = tempStr.mid(pos+10,tempStr.length()-13); swapFree = swapFree.trimmed(); nSwapFree = swapFree.toInt()/1024; break; } } nMemUsed = nMemTotal - nMemFree; nSwapUsed = nSwapTotal - nSwapFree; memUsed = QString::number(nMemUsed, 10); swapUsed = QString::number(nSwapUsed, 10); memFree = QString::number(nMemFree, 10); memTotal = QString::number(nMemTotal, 10); swapFree = QString::number(nSwapFree, 10); swapTotal = QString::number(nSwapTotal, 10); ui->label_RAM_Used->setText(memUsed+" MB"); ui->label_RAM_Left->setText(memFree+" MB"); ui->label_RAM_Total->setText(memTotal+" MB"); ui->label_SWAP_Used->setText(swapUsed+" MB"); ui->label_SWAP_Left->setText(swapFree+" MB"); ui->label_SWAP_Total->setText(swapTotal+" MB"); ui->progressBar_RAM->setValue(nMemUsed*100/nMemTotal); ui->progressBar_SWAP->setValue(nSwapUsed*100/nSwapTotal); tempFile.close(); //关闭内存信息文件 int tt = 2; //取2个点采样计算cpu当前利用律 int cpuInfo[2][7]; int cpuTotal[2][2]; while (tt) { tempFile.setFileName("/proc/stat"); //打开CPU使用状态信息 if ( !tempFile.open(QIODevice::ReadOnly) ) { QMessageBox::warning(this, tr("warning"), tr("The stat file can not open!"), QMessageBox::Yes); return; } tempStr = tempFile.readLine(); for (int i = 0; i <7; i++) { cpuInfo[2-tt][i] = tempStr.section(" ", i+1, i+1).toInt(); cpuTotal[1][2-tt] += cpuInfo[2-tt][i]; if (i == 3) { cpuTotal[0][2-tt] += cpuInfo[2-tt][i]; } } tt--; tempFile.close(); //关闭stat文件 } int a = cpuTotal[0][1] - cpuTotal[0][0]; int b = cpuTotal[1][1] - cpuTotal[1][0]; if (a <0) { a = -a; } if (b <0) { b = -b; } ui->progressBar_CPU->setValue(a*100/b); tempFile.setFileName("/proc/stat"); //linux下用/proc/stat文件来计算cpu的利用率 //这个文件包含了所有CPU活动的信息,该文件中的所有值都是从系统启动开始累计到当前时刻。 if ( !tempFile.open(QIODevice::ReadOnly) ) { QMessageBox::warning(this, tr("warning"), tr("The stat file can not open!"), QMessageBox::Yes); return; } tempStr = tempFile.readLine(); a0 = a1; b0 = b1; a1 = b1 = 0; int gg; for (int i = 0; i <7; i++) { b1 += tempStr.section(" ", i+2, i+2).toInt(); gg = b1; if (i == 3) { a1 += tempStr.section(" ", i+2, i+2).toInt(); } } int m, n; m = a1 - a0; n = b1 - b0; if (m <0) { m = -m; } if (n <0) { n = -n; } ui->progressBar_CPU->setValue( (n-m)*100/n ); tempFile.close(); //关闭stat文件 } else if (index == 1) //进程信息 { ui->listWidget_process->clear(); QDir qd("/proc"); QStringList qsList = qd.entryList(); QString qs = qsList.join("n"); QString id_of_pro; bool ok; int find_start = 3; int a, b; int nProPid; //进程PID int number_of_sleep = 0, number_of_run = 0, number_of_zombie = 0; int totalPrOnum= 0; //进程总数 QString proName; //进程名 QString proState; //进程状态 QString proPri; //进程优先级 QString proMem; //进程占用内存 QListWidgetItem *title = new QListWidgetItem("PIDt" + QString::fromUtf8("名称") + "tt" + QString::fromUtf8("状态") + "t" + QString::fromUtf8("优先级") + "t" + QString::fromUtf8("占用内存"), ui->listWidget_process); //循环读取进程 while (1) { //获取进程PID a = qs.indexOf("n", find_start); b = qs.indexOf("n", a+1); find_start = b; id_of_pro = qs.mid(a+1, b-a-1); totalProNum++; nProPid = id_of_pro.toInt(&ok, 10); if(!ok) { break; } //打开PID所对应的进程状态文件 tempFile.setFileName("/proc/" + id_of_pro + "/stat"); if ( !tempFile.open(QIODevice::ReadOnly) ) { QMessageBox::warning(this, tr("warning"), tr("The pid stat file can not open!"), QMessageBox::Yes); return; } tempStr = tempFile.readLine(); if (tempStr.length() == 0) { break; } a = tempStr.indexOf("("); b = tempStr.indexOf(")"); prOname= tempStr.mid(a+1, b-a-1); proName.trimmed(); //删除两端的空格 proState = tempStr.section(" ", 2, 2); proPri = tempStr.section(" ", 17, 17); proMem = tempStr.section(" ", 22, 22); switch ( proState.at(0).toLatin1() ) { case 'S': number_of_sleep++; break; //Sleep case 'R': number_of_run++; break; //Running case 'Z': number_of_zombie++; break; //Zombie default : break; } if (proName.length() >= 12) { QListWidgetItem *item = new QListWidgetItem(id_of_pro + "t" + proName + "t" + proState + "t" + proPri + "t" + proMem, ui->listWidget_process); } else { QListWidgetItem *item = new QListWidgetItem(id_of_pro + "t" + proName + "tt" + proState + "t" + proPri + "t" + proMem, ui->listWidget_process); } } QString temp; temp = QString::number(totalProNum, 10); ui->label_pNum->setText(temp); temp = QString::number(number_of_run, 10); ui->label_pRun->setText(temp); temp = QString::number(number_of_sleep, 10); ui->label_pSleep->setText(temp); temp = QString::number(number_of_zombie, 10); ui->label_pZombie->setText(temp); tempFile.close(); //关闭该PID进程的状态文件 } else if (index == 2) //模块信息 { ui->listWidget_model->clear(); //sys/module 是一个 sysfs 目录层次, 包含当前加载模块的信息. /proc/moudles 是旧式的, 那种信息的单个文件版本. 其中的条目包含了模块名, 每个模块占用的内存数量, 以及使用计数. 另外的字串追加到每行的末尾来指定标志, 对这个模块当前是活动的. tempFile.setFileName("/proc/modules"); //打开模块信息文件 if ( !tempFile.open(QIODevice::ReadOnly) ) { QMessageBox::warning(this, tr("warning"), tr("The modules file can not open!"), QMessageBox::Yes); return ; } //设置模块首行项目 QListWidgetItem *title = new QListWidgetItem( QString::fromUtf8("名称") + "ttt" + QString::fromUtf8("使用内存数") + "tt" + QString::fromUtf8("使用次數"), ui->listWidget_model); QString mod_Name, mod_Mem, mod_Num; //循环读取文件内容,查找需要的信息 while (1) { tempStr = tempFile.readLine(); if (tempStr.length() == 0) { break; } mod_Name = tempStr.section(" ", 0, 0); mod_Mem = tempStr.section(" ", 1, 1); mod_Num = tempStr.section(" ", 2, 2); if (mod_Name.length() > 10) { QListWidgetItem *item = new QListWidgetItem(mod_Name + "tt" + mod_Mem + "tt" + mod_Num, ui->listWidget_model); } else { QListWidgetItem *item = new QListWidgetItem(mod_Name + "ttt" + mod_Mem + "tt" + mod_Num, ui->listWidget_model); } } tempFile.close(); //关闭模块信息文件 } else if (index == 3) //系统信息 { //int ok; tempFile.setFileName("/proc/cpuinfo"); //打开CPU信息文件 if ( !tempFile.open(QIODevice::ReadOnly) ) { QMessageBox::warning(this, tr("warning"), tr("The cpuinfo file can not open!"), QMessageBox::Yes); return; } //循环读取文件内容,查找需要的信息 while (1) { tempStr = tempFile.readLine(); //QMessageBox::warning(this, tr("msg"), tempStr, QMessageBox::Yes); if(tempStr==NULL){//文件读完,跳出 break; } pos = tempStr.indexOf("model name"); if (pos != -1) { pos += 13; //跳过前面的"model name:"所占用的字符 QString *cpu_name = new QString( tempStr.mid(pos, tempStr.length()-13) ); ui->label_CPUName->setText(*cpu_name); } else if (pos = tempStr.indexOf("vendor_id"), pos != -1) { pos += 12; //跳过前面的"vendor_id:"所占用的字符 QString *cpu_type = new QString( tempStr.mid(pos, tempStr.length()-12) ); ui->label_CPUType->setText(*cpu_type); } else if (pos = tempStr.indexOf("cpu MHz"), pos != -1) { pos += 11; //跳过前面的"cpu MHz:"所占用的字符 QString *cpu_frq = new QString( tempStr.mid(pos, tempStr.length()-11) ); double cpufrq = cpu_frq->toDouble(); //4核CPU cpu_frq->setNum(cpufrq*4); ui->label_CPUFrequency->setText(*cpu_frq + " HZ"); } else if (pos = tempStr.indexOf("cache size"), pos!=-1) { pos += 13; //跳过前面的"cache size:"所占用的字符 QString *cache_size = new QString( tempStr.mid(pos, tempStr.length()-16) ); int cachesize = cache_size->toInt(); //4核CPU cache_size->setNum(cachesize*4); ui->label_CatheCapacity->setText(*cache_size + " KB"); } else //跳过其他的内容 { } } tempFile.close(); //关闭CPU信息文件 //打开操作系统信息文件 tempFile.setFileName("/proc/version"); if ( !tempFile.open(QIODevice::ReadOnly) ) { QMessageBox::warning(this, tr("warning"), tr("The version file can not open!"), QMessageBox::Yes); return ; } tempStr = tempFile.readLine(); pos = tempStr.indexOf("version"); QString *os_version = new QString( tempStr.mid(0, pos-1) ); ui->label_SystemType->setText(*os_version); int pos1 = tempStr.indexOf("("); QString *os_type = new QString( tempStr.mid(pos, pos1-pos-1) ); ui->label_SystemVersion->setText(*os_type); pos = tempStr.indexOf("gcc version"); pos1 = tempStr.indexOf("#"); QString *gcc_info = new QString( tempStr.mid(pos+12, pos1-pos-14) ); ui->label_GCCVersion->setText(*gcc_info); tempFile.close(); //关闭操作系统信息文件 } else //说明 { } return; } void MainWindow::on_pushButton_halt_clicked() { system("halt"); } void MainWindow::on_pushButton_reboot_clicked() { system("reboot"); } void MainWindow::on_tabWidget_INFO_currentChanged(int index) { show_tabWidgetInfo(index); //显示tab中的内容 return ; } //杀死进程 void MainWindow::on_pushButton_pkill_clicked() { //获得进程号 QListWidgetItem *item = ui->listWidget_process->currentItem(); QString pro = item->text(); pro = pro.section("t", 0, 0); system("kill " + pro.toLatin1()); QMessageBox::warning(this, tr("kill"), QString::fromUtf8("该进程已被杀死!"), QMessageBox::Yes); //回到进程信息tab表 show_tabWidgetInfo(1); } //刷新进程信息 void MainWindow::on_pushButton_prefresh_clicked() { show_tabWidgetInfo(1); } void MainWindow::on_pushButton_Model_install_clicked() { show_tabWidgetInfo(2); //安装模块还不知道如何实现 QMessageBox::warning(this, tr("tip"), tr("安装模块还不知道如何实现"), QMessageBox::Yes); } void MainWindow::on_pushButton_Model_remove_clicked() { show_tabWidgetInfo(2); //卸载模块还不知道如何实现 QMessageBox::warning(this, tr("tip"), tr("卸载模块还不知道如何实现"), QMessageBox::Yes); } void MainWindow::on_pushButton_Model_refresh_clicked() { show_tabWidgetInfo(2); QMessageBox::warning(this, tr("tip"), tr("刷新模块还不知道如何实现"), QMessageBox::Yes); }

Mainwindow.ui 工程界面文件。

MainWindow

0 0 605 438

MainWindow

0 -10 611 341

WaitCursor

QTabWidget::Triangular

3

false

内存信息

内存信息

内存信息

0 0 591 81

CPU

50 30 431 23

24

0 30 66 17

CPU:

0 80 591 231

内存和交换分区

50 50 431 23

24

50 140 431 23

24

0 50 66 17

内存:

0 140 66 17

交换

50 80 66 17

Used:

200 80 66 17

Left:

380 80 66 17

Total:

380 170 66 17

Total:

50 170 66 17

Used:

200 170 66 17

Left:

90 80 66 17

0

240 80 66 17

0

420 80 66 17

0

420 170 66 17

0

90 170 66 17

0

240 170 66 17

0 进程信息

0 0 421 271

20 280 98 27

kill

170 280 98 27

refresh

430 30 66 17

进程数:

490 30 66 17

0

430 60 66 17

运行数:

430 100 66 17

睡眠数:

430 140 66 17

浆死数:

490 60 66 17

0

490 100 66 17

0

490 140 66 17

0 模块信息

20 280 98 27

Install

180 280 98 27

Romove

350 280 98 27

refresh

0 0 561 271 系统信息

0 0 591 171

处理器信息

50 30 66 17

CPU名称:

50 60 66 17

CPU类型:

50 90 66 17

CPU频率:

50 120 81 17

Cache大小:

140 30 321 17

未知

140 60 151 17

未知

140 90 66 17

未知

140 120 66 17

未知

0 180 591 121

操作系统信息

70 30 111 17

操作系统类型:

70 60 111 17

操作系统版本:

70 90 111 17

GCC编译器:

190 30 151 17

未知

190 60 281 17

未知

190 90 291 17

未知 关于

20 30 66 17

项目名:

100 30 191 17

Linux下Qt实现任务管理器

100 70 191 17

ljheee

20 70 66 17

作者:

100 110 191 17

2017-4-10

20 110 66 17

时间:

100 150 191 17

QQ554278334

20 150 66 17

联系:

380 340 98 27

reboot

500 340 98 27

shutdown

0 0 605 26

SysMontior TopToolBarArea false

 Qt实现Linux任务管理器SysMonitor.ziphttp://download.csdn.net/detail/ljheee/9817990

 

 

 

 

 

 

 


推荐阅读
  • Android源码深入理解JNI技术的概述和应用
    本文介绍了Android源码中的JNI技术,包括概述和应用。JNI是Java Native Interface的缩写,是一种技术,可以实现Java程序调用Native语言写的函数,以及Native程序调用Java层的函数。在Android平台上,JNI充当了连接Java世界和Native世界的桥梁。本文通过分析Android源码中的相关文件和位置,深入探讨了JNI技术在Android开发中的重要性和应用场景。 ... [详细]
  • C++字符字符串处理及字符集编码方案
    本文介绍了C++中字符字符串处理的问题,并详细解释了字符集编码方案,包括UNICODE、Windows apps采用的UTF-16编码、ASCII、SBCS和DBCS编码方案。同时说明了ANSI C标准和Windows中的字符/字符串数据类型实现。文章还提到了在编译时需要定义UNICODE宏以支持unicode编码,否则将使用windows code page编译。最后,给出了相关的头文件和数据类型定义。 ... [详细]
  • linux进阶50——无锁CAS
    1.概念比较并交换(compareandswap,CAS),是原⼦操作的⼀种,可⽤于在多线程编程中实现不被打断的数据交换操作࿰ ... [详细]
  • 开发笔记:MyBatis学习之逆向工程
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了MyBatis学习之逆向工程相关的知识,希望对你有一定的参考价值。转载:http://w ... [详细]
  • go channel 缓冲区最大限制_Golang学习笔记之并发.协程(Goroutine)、信道(Channel)
    原文作者:学生黄哲来源:简书Go是并发语言,而不是并行语言。一、并发和并行的区别•并发(concurrency)是指一次处理大量事情的能力 ... [详细]
  • 本文介绍了使用kotlin实现动画效果的方法,包括上下移动、放大缩小、旋转等功能。通过代码示例演示了如何使用ObjectAnimator和AnimatorSet来实现动画效果,并提供了实现抖动效果的代码。同时还介绍了如何使用translationY和translationX来实现上下和左右移动的效果。最后还提供了一个anim_small.xml文件的代码示例,可以用来实现放大缩小的效果。 ... [详细]
  • flowable工作流 流程变量_信也科技工作流平台的技术实践
    1背景随着公司业务发展及内部业务流程诉求的增长,目前信息化系统不能够很好满足期望,主要体现如下:目前OA流程引擎无法满足企业特定业务流程需求,且移动端体 ... [详细]
  • 本文介绍了如何清除Eclipse中SVN用户的设置。首先需要查看使用的SVN接口,然后根据接口类型找到相应的目录并删除相关文件。最后使用SVN更新或提交来应用更改。 ... [详细]
  • 如何在跨函数中使用内存?
    本文介绍了在跨函数中使用内存的方法,包括使用指针变量、动态分配内存和静态分配内存的区别。通过示例代码说明了如何正确地在不同函数中使用内存,并提醒程序员在使用动态分配内存时要手动释放内存,以防止内存泄漏。 ... [详细]
  • Android系统源码分析Zygote和SystemServer启动过程详解
    本文详细解析了Android系统源码中Zygote和SystemServer的启动过程。首先介绍了系统framework层启动的内容,帮助理解四大组件的启动和管理过程。接着介绍了AMS、PMS等系统服务的作用和调用方式。然后详细分析了Zygote的启动过程,解释了Zygote在Android启动过程中的决定作用。最后通过时序图展示了整个过程。 ... [详细]
  • 本文介绍了一种轻巧方便的工具——集算器,通过使用集算器可以将文本日志变成结构化数据,然后可以使用SQL式查询。集算器利用集算语言的优点,将日志内容结构化为数据表结构,SPL支持直接对结构化的文件进行SQL查询,不再需要安装配置第三方数据库软件。本文还详细介绍了具体的实施过程。 ... [详细]
  • 如何实现JDK版本的切换功能,解决开发环境冲突问题
    本文介绍了在开发过程中遇到JDK版本冲突的情况,以及如何通过修改环境变量实现JDK版本的切换功能,解决开发环境冲突的问题。通过合理的切换环境,可以更好地进行项目开发。同时,提醒读者注意不仅限于1.7和1.8版本的转换,还要适应不同项目和个人开发习惯的需求。 ... [详细]
  • Java如何导入和导出Excel文件的方法和步骤详解
    本文详细介绍了在SpringBoot中使用Java导入和导出Excel文件的方法和步骤,包括添加操作Excel的依赖、自定义注解等。文章还提供了示例代码,并将代码上传至GitHub供访问。 ... [详细]
  • 本文介绍了Java调用Windows下某些程序的方法,包括调用可执行程序和批处理命令。针对Java不支持直接调用批处理文件的问题,提供了一种将批处理文件转换为可执行文件的解决方案。介绍了使用Quick Batch File Compiler将批处理脚本编译为EXE文件,并通过Java调用可执行文件的方法。详细介绍了编译和反编译的步骤,以及调用方法的示例代码。 ... [详细]
  • Tomcat安装与配置教程及常见问题解决方法
    本文介绍了Tomcat的安装与配置教程,包括jdk版本的选择、域名解析、war文件的部署和访问、常见问题的解决方法等。其中涉及到的问题包括403问题、数据库连接问题、1130错误、2003错误、Java Runtime版本不兼容问题以及502错误等。最后还提到了项目的前后端连接代码的配置。通过本文的指导,读者可以顺利完成Tomcat的安装与配置,并解决常见的问题。 ... [详细]
author-avatar
Yunir_944
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有