SpringBoot+Vue+MySQL+Redis在Windows机器上一键安装部署

整体安装部署流程:

  1. 初始化依赖服务和程序目录;
  2. 编写安装及卸载bat脚本;
  3. 通过Inno Setup将程序目录打包成exe;

Inno Setup下载地址:https://jrsoftware.org/isdl.php
Inno Setup文档:https://jrsoftware.org/ishelp/

1、初始化目录

将所需依赖和程序放入install目录,所需依赖尽量选择解压版,这样注册服务即可直接使用。如下图示,JDK、Nginx、MySQL、Redis等均为解压版。

初始化目录初始化目录

2、安装及卸载bat脚本

安装脚本install.bat内容:
(1)将依赖和程序注册成Windows服务;
(2)执行数据库脚本初始化;
(3)创建Windows任务计划;

2.1 注册服务

JDK
JDK可以选择配置环境变量,也可以通过相对路径执行java运行命令。本文使用相对路径方式,避免注册环境变量影响机器的其他java服务。

SpringBoot打完的jar包,使用winsw方式注册成Windows服务,具体命令如下:

cd app

"%cd%\business_service.exe" install

sc config business start=auto

net start business

Nginx
Nginx注册服务同样使用winsw方式,命令如下:

cd nginx-1.21.6

"%cd%\nginx_service.exe" install

sc config nginx start=auto

net start nginx

具体可参考:Windows服务器上Nginx注册服务及设置开机启动

Vue打包后的静态资源默认放在Nginx下的html目录。

MySQL
mysql.exe支持注册Windows服务,直接使用install命令即可,具体命令如下:

::安装vcredist_x64依赖
bin\vcredist_x64.exe

::注册mysql服务
bin\mysqld.exe -install mysql --defaults-file="%cd%\my.ini"

bin\mysqld.exe --initialize-insecure --user=mysql

::配置服务开机自启动
sc config mysql start=auto

::启动mysql服务
net start mysql

Redis
redis-server.exe也提供了直接注册服务的方式, 具体命令如下:

cd Redis-x64-5.0.14

set inipath=%cd%\redis.windows.conf

"%cd%\redis-server.exe" --service-install "%inipath%" --service-name redis --loglevel verbose

sc config redis start=auto

net start redis

2.2 数据库初始化

::创建数据库
"bin\mysql.exe" -uroot < "%cd%\sql\create_db.sql"
::数据库初始化
"bin\mysql.exe" -ubusiness < "%cd%\sql\business-admin.sql"

注意:需交互式输入对应用户的密码;

2.3 创建Windows任务计划
每天定时备份数据或文件,具体bat命令如下:

::添加MySQL自动备份任务计划
schtasks /create /F /tn "mysql-backup" /tr %cd%\bin\mysql_backup.bat /sc daily /st 02:00

卸载uninstall.bat脚本内容:
(1)删除服务和任务计划。

@echo off
::关闭服务
net stop business
net stop redis
net stop nginx

::删除服务
sc delete redis
sc delete nginx
sc delete business

::删除任务计划
schtasks /delete /tn "mysql-backup" /f

3、Inno Setup打包

从Inno Setup下载最新版本,本文使用的版本为:innosetup-6.2.1.exe

下载安装完毕后,在安装目录\Inno Setup 6\Examples下,有官方提供的一些Example示例,可以参考并编写自己的打包脚本。如下图示:

Example1Example1

可以根据AllPagesExample.iss示例,了解所有安装页面,并组织自己的安装流程页面。

Inno Setup打包配置可参考以下Demo:

; Script generated by the Inno Setup Script Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!

#define MyAppId "business-app-release"
#define MyAppName "商务云平台"
#define MyAppVersion "V1.1.5"
#define MyAppPublisher "AppBusinessCloud,Inc."
#define MyAppURL ""
#define MyAppExeName "商务云平台.exe"

[Setup]

AppId={#MyAppId}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
AppVerName={#MyAppName}{#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName=business
DisableProgramGroupPage=yes
WizardStyle=modern
OutputBaseFilename=business
Compression=lzma
SolidCompression=yes
SetupLogging=yes
;OutputDir=

DisableWelcomePage=no
LicenseFile=install/License.txt
SetupIconFile=D:\business\business-install\install\favicon.ico
AppCopyright=Copyright (C) 2022 AppBusinessCloud, Inc.



[Languages]
Name: "cn"; MessagesFile: "compiler:Languages\ChineseSimplified.isl"

[Files]
Source: "D:\business\business-install\install\*"; DestDir:"{app}";Flags: ignoreversion recursesubdirs createallsubdirs


[Icons]
Name: "{commondesktop}\{#MyAppName}"; IconFilename: "{app}\favicon.ico"


[INI]
Filename: "{app}\business.ini"; Section:"default"; Key: "app"; String: "{app}"
Filename: "{app}\business.ini"; Section:"default"; Key: "tenantName"; String: "{code:GetBusinessInfo|name}"
Filename: "{app}\business.ini"; Section:"default"; Key: "tenantCode"; String: "{code:GetBusinessInfo|code}"

[Code]

var
  CustomInputPage: TInputQueryWizardPage;
  tenantName, tenantCode, serialNumber: String;

procedure WriteFixmedinsInfoFile;
var
  fileName,tempStr:String;
  svArray: TArrayOfString;
  nLines,i:Integer; 
begin
  Log('WriteFixmedinsInfoFile...');
  fileName := ExpandConstant('{app}\sql\org.sql');
  LoadStringsFromFile(fileName, svArray);
  nLines := GetArrayLength(svArray);

  for i := 0 to nLines - 1 do
   begin
     tempStr := svArray[i];

     Log(tempStr);
     if (Pos('#{tenantName}', tempStr) > 0) then
     begin
       StringChangeEx(svArray[i], '#{tenantName}', tenantName, True);  //将[tenantName]占位符替换为tenantName对应值
     end;
     if (Pos('#{tenantCode}', tempStr) > 0) then
     begin
       StringChangeEx(svArray[i], '#{tenantCode}', tenantCode, True);  //将[tenantCode]占位符替换为tenantCode对应值
     end;
     if (Pos('#{serialNumber}', tempStr) > 0) then
     begin
       StringChangeEx(svArray[i], '#{serialNumber}', serialNumber, True);  //将[serialNumber]占位符替换为serialNumber对应值
     end;
   end;
   SaveStringsToUTF8File(fileName, svArray, false);

end;


var SerialNumberMemo: TNewMemo;

procedure InitializeWizard;
var
  Index: Integer; 
  CustomEdit: TCustomEdit; 

begin
  Log('InitializeWizard...');

  // Create the page
  CustomInputPage := CreateInputQueryPage(wpLicense,
    '租户信息', '提示信息:租户名称和租户编码请联系商务获取!',
    '请填写您的租户名称和租户编码信息');

  // Add items (False means it's not a password edit)
  CustomInputPage.Add('&租户名称:', False);
  CustomInputPage.Add('&租户编码:', False);
  Index := CustomInputPage.Add('&序列号:', False);

  CustomEdit := CustomInputPage.Edits[Index];

  SerialNumberMemo := TNewMemo.Create(WizardForm);
  SerialNumberMemo.Parent := CustomEdit.Parent;
  SerialNumberMemo.SetBounds(CustomEdit.Left, CustomEdit.Top, CustomEdit.Width, ScaleY(70)); 

  CustomEdit.Visible := False;
  CustomInputPage.PromptLabels[Index].FocusControl := SerialNumberMemo;

  // Set initial values (optional)
  CustomInputPage.Values[0] := ExpandConstant('');
  CustomInputPage.Values[1] := ExpandConstant('');
  CustomInputPage.Values[3] := ExpandConstant('');

end;

function GetBusinessInfo(Param: String): String;
begin
  Result := tenantName;
  if Param = 'name' then begin
    Result := tenantName;
    WriteFixmedinsInfoFile;
  end else if Param = 'code' then begin
    Result := tenantCode;
  end;
end;


function NextButtonClick(CurPageID: Integer): Boolean;
begin
  { Validate certain pages before allowing the user to proceed }
  Result :=True;

  if CurPageID = CustomInputPage.ID then begin
    if CustomInputPage.Values[0] = '' then begin
      MsgBox('租户名称不能为空!', mbError, MB_OK);
      Result := False;
    end else if CustomInputPage.Values[1] = '' then begin
      MsgBox('租户编码不能为空!', mbError, MB_OK);
      Result := False;
    end else if SerialNumberMemo.Text = '' then begin
      MsgBox('序列号不能为空!', mbError, MB_OK);
      Result := False;
    end

    // 非空格式校验
    else if CustomInputPage.Values[1] <> '' then begin
      if (Length(CustomInputPage.Values[1]) < 12) then
      begin
        MsgBox('租户格式编码错误!', mbError, MB_OK);
        Result := False;
      end;
    end;

    // Read values into variables
    tenantName := CustomInputPage.Values[0];
    tenantCode := CustomInputPage.Values[1];
    serialNumber := SerialNumberMemo.Text;

  end;

end;

[Run]
Filename: "{app}\install.bat"

[UninstallRun]
RunOnceId: "SmapleUnInstallService"; Filename: "{app}\uninstall.bat"

更多Inno Setup使用参见官方帮助文档:Inno Setup Help

添加新评论