SpringBoot+Vue项目打包成exe,含mysql,redis,nginx,Electron

 背景

        最近公司有个项目需要做单机的exe程序支持一些离线的功能,这些功能原本在Web端已经实现,为了应用快速开发出来没有考虑C#实现(主要是C#人手不够),决定将Web端应用阉割之后打包成离线运行。后续我将用RuoYi的前后端分离版来演示如何将RuoYi-Vue打包成单机应用。

        另外我找遍了全网也没有详细的介绍,仅有几篇文章也只是简单的涉及到前端项目或者后端项目,没有文章介绍将前后端项目一起打包至桌面客户端中,特此才写此篇文章详细讲解。

        转载请与我联系取得许可。

服务架构的介绍

后端采用SpringBoot框架,技术栈包含(Java8,MySQL,Redis)。

前端采用Vue框架实现,客户端框架使用Electron,采用Nginx启动静态页面。

需要准备的工具

Dev C++ 下载地址:Dev-C++ for Windows 10/8/7 download | SourceForge.net

Java8-JRE:可以在本地的Java安装目录中打包出来

Nginx:官方下载地址:nginx

Redis:官方下载地址:Redis 此处就需要自己去找Windows版本了

MySQL Windows 免安装版本,下载地址Oracle官网:MySQL Enterprise Edition | Oracle

Electron的官方骨架代码:GitHub – electron/electron-quick-start: Clone to try a simple Electron app

RuiYi-Vue的下载地址:RuoYi-Vue: 🎉 基于SpringBoot,Spring Security,JWT,Vue & Element 的前后端分离权限管理系统,同时提供了 Vue3 的版本

Inno_Setup:将exe程序转换成安装包,需要安装包的原因在于需要将MySQL和Redis注册成Windows服务,可以在注册的时候起别名,和自定义端口号,避免和客户电脑上的原本服务冲突,或者卸载的时候将客户电脑中的开发环境拆卸掉。这个软件最好下载汉化版,自己找一下下载地址。

服务架构图

就如上图所示,mysql和redis通过bat脚本(后文分享)安装至用户的系统当中,并设置自启动,每次在打开Electron骨架的时候绑定bat脚本启动Java服务,Nginx服务,Electron启动后直接重定向至Nginx的服务当中。

准备文件详讲

一:后端打包

将RuoYi后端打包成jar可执行文件,需要修改数据库地址和库名称以及redis服务地址和库名称。我这里数据库地址使用127.0.0.1,端口35592,库名 ruoyi_vue,我们修改下ruoyi项目的ruoyi-admin模块下的resource中的application.yml和application-druid.yml文件,后端服务启动端口为35589,端口跳转地址为 /ruoyi (后面nginx做反向代理使用),之后打包RuiYi后端文件为client-1.0-SNAPSHOT.jar

修改的地方如下图:(我已经使用红色的水印划了出来)

之后打包成jar文件

这个时候我们就得到了一个ruoyi的可执行jar文件,通过我们的jre环境就可以启动他运行,当然启动前还需要mysql和redis的支撑才可以启动项目。

环境总结,后端项目启动在端口35589,连接的mysql运行在35592端口,库名称ruoyi_vue,连接的redis运行在35594端口。到此Java服务已经准备好,下面开始准备Vue前端页面。

二:Vue打包

打包Vue项目到Dist目录当中,无需设置端口,因为使用了Nginx来做代理。

使用VSCode打开ruoyi-ui的前端代码,修改一下生产环境后端地址前缀如果你想再本地运行的话需要自己再修改一下开发环境中的后端地址前缀,我这里已经测试好了就不再修改了。

然后使用npm install命令安装包

然后使用 npm run build:prod 命令打包到dist文件夹当中

此时前后端均已准备完成,接下来就是准备nginx的配置了。

环境总结:无需修改任何东西直接使用 npm run build:prod 命令打包页面到dist文件夹当中。

三:准备Nginx

在官网下载完成后解压,打开html文件夹,将上面打包后的dist文件夹内的所有文件复制到html文件夹内,之后修改nginx的配置文件nginx.conf,修改点为服务地址,后端跳转地址。

我修改的地方如截图中画笔图的位置所示:

server {
        # 服务地址为127.0.0.1 端口35595
        listen       35595;
        server_name  127.0.0.1;
        location / {
            root   html;
            index  index.html index.htm;
			# 浏览器刷新避免404问题
			try_files $uri $uri/ /index.html;
        }
		# 添加后端服务的代理功能
		location /ruoyi/{
            proxy_pass  http://127.0.0.1:35589/ruoyi/;
        }

        error_page  404              /404.html;
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
 
    }

然后准备两个bat脚本,分别是启动nginx服务和关闭nginx服务,脚本内容如下:

start_web.bat:

start /b ./nginx.exe

stop_web.bat:

start /b nginx.exe -s stop

写完后这个地方我们可以使用cmd命令尝试调用一下,看看服务是否可用,已经停止功能是否正常。

环境总结:将打包后的dist目录内的文件复制到nginx的html目录下,修改nginx.conf配置文件,书写两个脚本用于启动和停止nginx服务。后面我们开始准备java所需的mysql和redis服务。

四:准备MySQL

准备mysql的可执行文件,需要2个脚本,一个是安装mysql并初始化导入sql的脚本,第二个是卸载mysql的脚本,另外还需要导入mysql的表结构。

mysql_init.bat:作用用安装时在用户的系统中安装mysql服务并导入初始化mysql表结构。bat文件具体执行内容需要自己学习,不想写注解。

cd %~dp0
copy "vcruntime140.dll" "C:\Windows\System32\"
copy "vcruntime140_1.dll" "C:\Windows\System32\"
copy "msvcp140.dll" "C:\Windows\System32\"
cd ..
del %cd%\my.ini
echo 删除完成

echo [mysqld]>> my.ini
echo port=35592>> my.ini
echo basedir=%cd%>> my.ini
echo datadir=%cd%\data>> my.ini
echo max_connections=200>> my.ini
echo sql_mode = NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES>> my.ini
echo max_connect_errors=10>> my.ini
echo character-set-server=utf8>> my.ini
echo default-storage-engine=INNODB>> my.ini
echo default_authentication_plugin = mysql_native_password>> my.ini

echo [mysql]>> my.ini
echo default-character-set=utf8>> my.ini

echo [client]>> my.ini
echo port=35592>> my.ini
echo default-character-set=utf8>> my.ini

echo my.ini生成成功

set inipath=%cd%\my.ini

cd bin
"%cd%\mysqld.exe" -remove mysql35592
"%cd%\mysqld.exe" -install mysql35592 --defaults-file="%inipath%"
"%cd%\mysqld.exe" --initialize-insecure --console
net start mysql35592
sc config mysql35592 start=auto
net stop mysql35592
net start mysql35592
echo 安装完毕
"%cd%\mysqladmin.exe" -u root password 123456 -P35592
echo 修改密码完毕

"%cd%\mysql.exe" -uroot -p123456 -P35592< myInitSql.sql
echo 数据库初始化完成
echo 完成
exit

之后就是卸载时执行的脚本,执行后会将上面注册的mysql服务从系统中删除,并删除整个mysql的文件夹,用于卸载软件时使用。

cd %~dp0
net stop mysql35592
sc delete mysql35592-job
"%cd%\mysqld.exe" -remove mysql35592
cd ..
rmdir /s /q "%cd%\data
echo mysql卸载完成
exit

最后就是mysql的初始化表结构的脚本,这里我们打开RuoYi项目根目录下的sql文件夹,新建一个文件myInitSql.sql,其内容为创建数据库ruoyi_vue然后use ruoyi_vue数据库,并执行创建表的脚本。接下来是需要添加手写的内容,然后合并ruoyi提供的两个sql文件内容。

DROP DATABASE IF EXISTS ruoyi_vue;
CREATE DATABASE ruoyi_vue;
USE ruoyi_vue;

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

## quartz.sql 文件内的内容

## ry_20230706.sql 文件内的内容

之后将myInitSql.sql放在mysql/bin目录之下。

环境总结:需要提供初始化的bat脚本和卸载的脚本,另外需要准备初始化的sql表结构。另外我在测试时发现新安装的系统缺少3个dll文件,分别是vcruntime140.dll,vcruntime140_1.dll,msvcp140.dll,我在我的mysql_init.bat中将这3个文件拷贝到system32下面,请下载64位版本,并拷贝至mysql的bin文件夹下,我的脚本会处理这写dll,另外安装mysql如果无缘无故报错0x00xxxx之类的就是你下载了32的dll的缘故。在书写完成脚本后请尝试手动执行看是否可以成功安装和卸载,在此处我卡了1天才解决好。推荐再如下地址下载:

五:准备Redis

准备Redis的可执行文件,需要2个脚本,同样是安装和卸载。

下载windows上的可执行redis,redis本身可以通过命令行运行,但是运行之后redis只能前台运行不能后台运行,一旦关闭redis运行的cmd窗口,redis就退出服务了,也没有很好的办法可以隐藏掉窗口,所以我就选择将redis和mysql一样直接注册到系统当中,并设置自启动。

下面是准备需要准备的安装和卸载脚本,以及修改配置文件。

首先修改配置文件,我的后端服务中redis运行的端口为:35594,所以我们需要修改对应的port参数。

准备两个bat脚本cache_init.bat 和 cache_stop.bat

cache_init.bat:初始化时将redis注册到系统当中

cd %~dp0
"%cd%\redis-server.exe" --service-install redis.windows.conf --service-name cacheredis
net start cacheredis
sc config cacheredis start=auto
net stop cacheredis
net start cacheredis
echo 安装完毕
exit

 cache_stop.bat:卸载软件时顺带卸载redis服务

cd %~dp0
net stop cacheredis
sc delete cacheredis
"%cd%\redis-server.exe" -remove cacheredis
echo cacheredis卸载完成
exit

环境总结:提供安装和卸载redis的脚本,另外修改配置文件中的port参数为35594 

六:准备JRE环境

打包本机的Java安装环境中的jre目录。

找到本机的Java安装目录,一般默认在 C:\Program Files\Java 下,把整个jre文件打包成压缩包。

环境总结:太简单了不予总结。

七:准备Electron

下载Electron做适当的修改,需要修改的地方如下:

使用git clone  GitHub – electron/electron-quick-start: Clone to try a simple Electron app命令从Electron官方下载Electron 骨架。

下载完成后通过VSCode打开,在命令行中敲入 npm i -g electron@latest 安装Electron依赖,如果失败请多次重试,安装完成后修改如下文件:

第①步修改:index.html

应用启动后会首先打开index.html页面,此时我们将页面总结重定向到nginx当中的服务,至于此处的35595端口是nginx的运行端口,不信可以会看第三步。

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="refresh" content="0;url=http://127.0.0.1:35595">
</head>
<body>
    <!-- 这里可以添加其他页面内容 -->
</body>
</html>

第②步修改:main.js

页面初始化时打开的静态页面

添加关闭时执行脚本

另外编写这个需要执行的bat脚本,脚本的作用是关闭java服务和nginx服务。

stop.bat :

@echo off
set java_port=35589
for /f "tokens=1-5" %%i in ('netstat -ano^|findstr ":%java_port%"') do taskkill /pid %%m -t -f
exit

start /b ../../../WebServer/nginx.exe stop

全部完成后就是打包,先执行:

npm install electron-packager --save-dev

命令拉取所有需要的包,然后通过:

npm run packager

命令将 Electron 打包成Windows下可执行的exe文件,文件生成的目录在 electron-quick-start下 javaclient-win32-x64 文件夹内。此javaclient-win32-x64是打包后的所有需要的文件。

另外需要注意的一点就是打包时这个 stop.bat 脚本并不会自动拷贝到打包的文件内,需要我们手动的放到 /electron-quick-start/javaclient-win32-x64/resources/app路径下,不然关闭Electron窗口后java和nginx的服务还在后台执行,下次打开的时候继续开启就会端口冲突报错。

到此处我们的所有文件都已经准备完成,接下来就是打包了。

测试

在打包之前我们先把本地的mysql,redis,nginx,后端jar,Electron都测试一下是否可以正常使用。

mysql

按下ctrl后用数据单击windows窗口图标,选择终端管理员

从终端中进入mysql的bin目录下后启动脚本,看mysql服务是否可以正常安装,以及sql脚本是否可以正常导入到其中。

可以看到mysql服务已经正常使用。后面再测试一下卸载脚本是否可以正常执行,我这里可以正常卸载我就不在截图了。

redis

nginx

jar

待上面的基础服务都启动好之后我们就启动java来看mysql和redis是否都可以执行成功,这里我将ruoyi打包后的java后端jar包的名称改了,各位看的时候别混淆了。此时我已将jre和jar放在同一目录下,并且使用jre的执行环境启动jar来运行。

测试后端服务启动成功。

Electron

最后就是打开Electron的窗口看服务是否都正常,将electron-quick-start打包后的javaclient-win32-x64文件夹复制到需要的地方,然后打开其中的javaclient.exe

可以看到服务已经正常启动

此时可以看到已经可以正常使用了。接下来我们就需要依次停止Electron的窗口,nginx和java后端,然后进入管理员命令行,执行mysql8/bin目录下的卸载bat脚本,redis下的卸载bat脚本,将环境从系统中拆卸干净,避免等下和安装包环境中的安装脚本冲突。

mysql和redis的系统服务一定要卸载掉,如果卸载不成功就修改脚本,看那里出现了错误,或者手动从系统中卸载掉。

打包

对于打包我推荐使用C++语言执行bat脚本来启动项目,然后将C++语言编译成exe文件。我之前尝试过使用 Bat_To_Exe_Converter 工具将bat脚本直接打包成exe,但是我发现这东西打包出来的exe可执行文件居然被Windows11的Microsoft Defended报病毒,这可是系统默认的防病毒工具,没有办法绕过,随后尝试使用C++来做。

我的C++代码如下:

#include <iostream>
#include <cstdlib>
#include <string>

int main() {
    // 执行第一行脚本
    std::string script1 = "start \"Start Page\" /B cmd /c \"cd WebServer && .\\start_web.bat\"";
    system(script1.c_str());

    // 执行第二行脚本
    std::string script2 = "start /b ./jre1.8.0_361/bin/javaw -jar ./client-1.0-SNAPSHOT.jar";
    system(script2.c_str());

    // 执行第三行脚本
    std::string script3 = "start /b ./javaclient-win32-x64/javaclient.exe";
    system(script3.c_str());

    return 0;
}

打开Dev C++工具,新建一个文件粘贴如下的代码后编译,打开文件所在目录,就可以看到编译后的exe可执行文件。代码内容为启动nginx,启动java服务,打开 Electron 窗体。

到此位置所有文件已经准备好,后面就是将这写所有文件封装成Windows的SetUp安装程序。

打包成 Windows Set_up

 打包成Set_up之后就可以和安装普通软件一样去安装我们的桌面程序。

打包所需的软件为:Inno_Setup ,这个软件有汉化版,大家找一下汉化版比较好用。

将javaclient-win32-x64/resources/app 目录下的stop.bat文件复制一份到打包的根目录下,避免出现相对目录失效时找不到stop.bat脚本。

将C++语言打包的C_START_BAT.exe文件更名为testClient.exe

首先核对一下文件的结构:

ClientBuild:
|-- cache (Folder)
|   |-- cache_init.bat ---- redis安装脚本
|   |-- cache_stop.bat ---- redis卸载脚本
|   |-- redis.windows.conf ---- redis配置文件
|-- client-1.0-SNAPSHOT.jar ---- jar后端打包后的文件
|-- javaclient-win32-x64 (Folder) ---- Electron打包出来的文件夹(其中文件太多了,此处省略)
|   |-- resources (Folder)
|   |   |-- app (Folder)
|   |   |   |-- stop.bat ---- 停止脚本
|-- jre1.8.0_361 (Folder) --- java安装目录中的jre,其中详细内容省略
|-- mysql8 (Folder)
|   |-- bin (Folder)
|   |   |-- msvcp140.dll ---- 系统中可能缺少的DLL
|   |   |-- myInitSql.sql ---- 若依的初始化数据库文件,包含手写的新建库,use 库
|   |   |-- mysql_init.bat ---- mysql安装脚本
|   |   |-- mysql_stop.bat ---- mysql卸载脚本
|   |   |-- vcruntime140.dll  ---- 系统中可能缺少的脚本
|   |   |-- vcruntime140_1.dll  ---- 系统中可能缺少的脚本
|-- stop.bat ---- 同 javaclient-win32-x64/resources/app 中的stop.bat脚本,主要是避免相对路径不生效变成读取根目录下的stop.bat了
|-- testClient.exe ---- C++打包出来的可执行文件
|-- WebServer (Folder)
|   |-- conf (Folder) 
|   |   |-- nginx.conf ---- nginx的配置文件,需要配置端口和后端代理服务
|   |-- html (Folder)
|   |   |-- ...... vue打包出来的文件太多了,此处省略。
|   |-- start_web.bat ---- nginx启动脚本
|   |-- stop_web.bat ---- nginx停止脚本

核对好之后接下来进入打包流程,打开Inno_Setup

随意填,如果打包公司的应用程序可以写公司的授权信息

指定C++语言打包出来的可执行文件,选择文件夹选中buildClient文件夹,将我们的所需文件都打包进入安装包中,后面再安装的时候会自动解压这些文件到用户选中的安装目录当中。

没有许可证可以不填,如果有公司的许可证可以写上公司的许可。

安装包语言支持,这个仅是安装包的语言,和内部程序的语言没有任何关系。

安装包的名称和ico图标,以及打包后的文件输出到那个目录当中

这个目前不知道有什么作用,所以推荐不选

一定要选择 “否”,应为后面我们还有别的东西需要修改的

后面会打开脚本,我的脚本如下:

; 脚本由 Inno Setup 脚本向导 生成!
; 有关创建 Inno Setup 脚本文件的详细资料请查阅帮助文档!

[Setup]
; 注: AppId的值为单独标识该应用程序。
; 不要为其他安装程序使用相同的AppId值。
; (生成新的GUID,点击 工具|在IDE中生成GUID。)
AppId={{85AC9526-2585-4379-BD8D-0A52FDA541F8}
AppName=ruoyi
AppVersion=1.0
;AppVerName=ruoyi 1.0
AppPublisher=ruoyi
AppPublisherURL=http://www.ruoyi.com/
AppSupportURL=http://www.ruoyi.com/
AppUpdatesURL=http://www.ruoyi.com/
DefaultDirName={pf}\ruoyiClient
DefaultGroupName=ruoyi
OutputDir=F:\javaWebToClient2
OutputBaseFilename=RuiYi_SetUp
SetupIconFile=C:\Users\lemon\Downloads\user_center.ico
Compression=lzma
SolidCompression=yes

[Languages]
Name: "chinesesimp"; MessagesFile: "compiler:Default.isl"
Name: "english"; MessagesFile: "compiler:Languages\English.isl"

[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked; OnlyBelowVersion: 0,6.1
Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked

[Files]
Source: "F:\javaWebToClient2\ClientBuild\testClient.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "F:\javaWebToClient2\ClientBuild\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
; 注意: 不要在任何共享系统文件上使用“Flags: ignoreversion”

[Icons]
Name: "{group}\ruoyi"; Filename: "{app}\testClient.exe"
Name: "{group}\{cm:ProgramOnTheWeb,ruoyi}"; Filename: "http://www.ruoyi.com/"
Name: "{group}\{cm:UninstallProgram,ruoyi}"; Filename: "{uninstallexe}"
Name: "{commondesktop}\ruoyi"; Filename: "{app}\testClient.exe"; Tasks: desktopicon
Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\ruoyi"; Filename: "{app}\testClient.exe"; Tasks: quicklaunchicon

[Run]
Filename: "{app}\testClient.exe"; Description: "{cm:LaunchProgram,ruoyi}"; Flags: nowait postinstall skipifsilent

下面开始修改脚本,以支持mysql和redis的自动安装注册成windows的服务。

主要是需要有如下两个地方的修改

其次为了判断系统中是否已经安装过程序,如果安装过就提示用户先卸载再安装软件

[Code]
// 自定义函数,判断软件是否运行,参数为需要判断的软件的exe名称
function CheckSoftRun(strExeName: String): Boolean;
// 变量定义
var ErrorCode: Integer;
var bRes: Boolean;
var strFileContent: AnsiString;
var strTmpPath: String;  // 临时目录
var strTmpFile: String;  // 临时文件,保存查找软件数据结果
var strCmdFind: String;  // 查找软件命令
var strCmdKill: String;  // 终止软件命令
begin
  strTmpPath := GetTempDir();
  strTmpFile := Format('%sfindSoftRes.txt', [strTmpPath]);
  strCmdFind := Format('/c tasklist /nh|find /c /i "%s" > "%s"', [strExeName, strTmpFile]);
  strCmdKill := Format('/c taskkill /f /t /im %s', [strExeName]);
  bRes := ShellExec('open', ExpandConstant('{cmd}'), strCmdFind, '', SW_HIDE, ewWaitUntilTerminated, ErrorCode);
  if bRes then begin
      bRes := LoadStringFromFile(strTmpFile, strFileContent);
      strFileContent := Trim(strFileContent);
      if bRes then begin
         if StrToInt(strFileContent) > 0 then begin
            if MsgBox(ExpandConstant('{cm:checkSoftTip}'), mbConfirmation, MB_OKCANCEL) = IDOK then begin
             // 终止程序
             ShellExec('open', ExpandConstant('{cmd}'), strCmdKill, '', SW_HIDE, ewNoWait, ErrorCode);
             Result:= true;// 继续安装
            end else begin
             Result:= false;// 安装程序退出
             Exit;
            end;
         end else begin
            // 软件没在运行
            Result:= true;
            Exit;
         end;
      end;
  end;
  Result :=true;
end;

// 重复安装检测
function InitializeSetup():boolean;
var
  MykeynotExist:boolean;
  ResultCode: Integer;
  uicmd: String;
begin
  MykeynotExist:= true;
  if RegQueryStringValue(HKEY_LOCAL_MACHINE, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{4A78DE64-0E3F-4EA1-BCE1-7A01E66BC1FF}_is1', 'UninstallString', uicmd) then
  begin
  MsgBox('{#MyAppName}已经安装,你确定要先卸载,再安装!', mbInformation, MB_OK)
  MyKeynotExist:= false;
  Exec(RemoveQuotes(uicmd), '', '', SW_SHOW, ewWaitUntilTerminated, ResultCode);
  end;
  Result:= MykeynotExist
end;

// 卸载时关闭软件
function InitializeUninstall(): Boolean;
begin
  Result := CheckSoftRun('{#MyAppExeName}');
end; 

procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
begin
    if CurUninstallStep = usDone then
    begin
       //删除 {app} 文件夹及其中所有文件
    DelTree(ExpandConstant('{app}'), True, True, True);
    end;
end;

[CustomMessages]
chinesesimp.checkSoftTip=检测到软件正在运行!%n%n点击"确定"终止软件后继续操作,否则点击"取消"。

我的完整脚本如下所示

; 脚本由 Inno Setup 脚本向导 生成!
; 有关创建 Inno Setup 脚本文件的详细资料请查阅帮助文档!


#define MyAppName "RuoYi"
#define MyAppVersion "1.0"
#define MyAppPublisher "RuoYi.Inc"
#define MyAppURL "http://www.ruoyi.com/"
#define MyAppExeName "testClient.exe"
#define MysqlName "mysql8"
#define MyRedis "cache"

[Setup]
; 注: AppId的值为单独标识该应用程序。
; 不要为其他安装程序使用相同的AppId值。
; (生成新的GUID,点击 工具|在IDE中生成GUID。)
AppId={{85AC9526-2585-4379-BD8D-0A52FDA541F8}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
;AppVerName=ruoyi 1.0
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName={pf}\{#MyAppName}
DefaultGroupName=RuoYi
AllowNoIcons=yes
OutputDir=F:\javaWebToClient2
OutputBaseFilename=RuiYi_SetUp
SetupIconFile=C:\Users\lemon\Downloads\user_center.ico
Compression=lzma
SolidCompression=yes

[Languages]
Name: "chinesesimp"; MessagesFile: "compiler:Default.isl"
Name: "english"; MessagesFile: "compiler:Languages\English.isl"

[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked; OnlyBelowVersion: 0,6.1
Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked

[Files]
Source: "F:\javaWebToClient2\ClientBuild\testClient.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "F:\javaWebToClient2\ClientBuild\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
; 注意: 不要在任何共享系统文件上使用“Flags: ignoreversion”

[Icons]
Name: "{group}\ruoyi"; Filename: "{app}\testClient.exe"
Name: "{group}\{cm:ProgramOnTheWeb,ruoyi}"; Filename: "http://www.ruoyi.com/"
Name: "{group}\{cm:UninstallProgram,ruoyi}"; Filename: "{uninstallexe}"
Name: "{commondesktop}\ruoyi"; Filename: "{app}\testClient.exe"; Tasks: desktopicon
Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\ruoyi"; Filename: "{app}\testClient.exe"; Tasks: quicklaunchicon

[Run]
Filename: "{app}\{#MysqlName}\bin\mysql_init.bat";
Filename: "{app}\{#MyRedis}\cache_init.bat";
Filename: "{app}\testClient.exe"; Description: "{cm:LaunchProgram,ruoyi}"; Flags: nowait postinstall skipifsilent


[UninstallRun]
Filename: "{app}\{#MysqlName}\bin\mysql_stop.bat";
Filename: "{app}\{#MyRedis}\cache_stop.bat";



[Code]
// 自定义函数,判断软件是否运行,参数为需要判断的软件的exe名称
function CheckSoftRun(strExeName: String): Boolean;
// 变量定义
var ErrorCode: Integer;
var bRes: Boolean;
var strFileContent: AnsiString;
var strTmpPath: String;  // 临时目录
var strTmpFile: String;  // 临时文件,保存查找软件数据结果
var strCmdFind: String;  // 查找软件命令
var strCmdKill: String;  // 终止软件命令
begin
  strTmpPath := GetTempDir();
  strTmpFile := Format('%sfindSoftRes.txt', [strTmpPath]);
  strCmdFind := Format('/c tasklist /nh|find /c /i "%s" > "%s"', [strExeName, strTmpFile]);
  strCmdKill := Format('/c taskkill /f /t /im %s', [strExeName]);
  bRes := ShellExec('open', ExpandConstant('{cmd}'), strCmdFind, '', SW_HIDE, ewWaitUntilTerminated, ErrorCode);
  if bRes then begin
      bRes := LoadStringFromFile(strTmpFile, strFileContent);
      strFileContent := Trim(strFileContent);
      if bRes then begin
         if StrToInt(strFileContent) > 0 then begin
            if MsgBox(ExpandConstant('{cm:checkSoftTip}'), mbConfirmation, MB_OKCANCEL) = IDOK then begin
             // 终止程序
             ShellExec('open', ExpandConstant('{cmd}'), strCmdKill, '', SW_HIDE, ewNoWait, ErrorCode);
             Result:= true;// 继续安装
            end else begin
             Result:= false;// 安装程序退出
             Exit;
            end;
         end else begin
            // 软件没在运行
            Result:= true;
            Exit;
         end;
      end;
  end;
  Result :=true;
end;

// 重复安装检测
function InitializeSetup():boolean;
var
  MykeynotExist:boolean;
  ResultCode: Integer;
  uicmd: String;
begin
  MykeynotExist:= true;
  if RegQueryStringValue(HKEY_LOCAL_MACHINE, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{4A78DE64-0E3F-4EA1-BCE1-7A01E66BC1FF}_is1', 'UninstallString', uicmd) then
  begin
  MsgBox('{#MyAppName}已经安装,你确定要先卸载,再安装!', mbInformation, MB_OK)
  MyKeynotExist:= false;
  Exec(RemoveQuotes(uicmd), '', '', SW_SHOW, ewWaitUntilTerminated, ResultCode);
  end;
  Result:= MykeynotExist
end;

// 卸载时关闭软件
function InitializeUninstall(): Boolean;
begin
  Result := CheckSoftRun('{#MyAppExeName}');
end; 

procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
begin
    if CurUninstallStep = usDone then
    begin
       //删除 {app} 文件夹及其中所有文件
    DelTree(ExpandConstant('{app}'), True, True, True);
    end;
end;

[CustomMessages]
chinesesimp.checkSoftTip=检测到软件正在运行!%n%n点击"确定"终止软件后继续操作,否则点击"取消"。

随后点击保存,然后选中构建,编译,编译的过程比较慢,需要5分钟左右

编译完成会在我们设置的输出目录生成一个RuoYi_SetUp.exe安装包程序,我们拷贝到测试机上测试一下是否可以使用

测试

通过测试,安装,使用,卸载程序均可以正常运行,至此一切均已完成,觉得不完美的地方可以修饰一下,比如程序的ico图标,我只设置了安装包的ico图标,另外Electron和vue程序可以合并到一起,但是proxy就会失效我目前没有想到比较好的解决方案,要不就是全局修改请求地址,加个统一的前缀,但是对于代码的侵入就比较大了,所以我才选中了nginx来做静态页面和代码服务。

全文如果有不通顺以及不懂的地方可以发邮件和我沟通:limeng-whu@qq.com

版权声明:本文为博主作者:limeng313原创文章,版权归属原作者,如果侵权,请联系我们删除!

原文链接:https://blog.csdn.net/qq_42168462/article/details/134202526

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
扎眼的阳光的头像扎眼的阳光普通用户
上一篇 2024年4月10日
下一篇 2024年4月10日

相关推荐