这么多年客户端一直只做Windows,所以初始化程序用C#写个Exe,按网站生成的下载清单文件一个个下载和部署客户端环境是可以的。新的由于设计目标就是支持多平台的,所以需要重新考虑初始化设计。
介绍和演示视频
设计目标有以下:
1.方便更新客户端程序的单个文件
2.多平台初始化体验接近
3.不能运行脚本的电脑也要让手工能下载压缩包自己放程序
4.尽可能少占用服务器空间
5.服务器上程序修改之后要能自动更新下载的zip包
文件布局
压缩包生成目录,在加载环境下载页面时候会检查是否需要生成压缩包文件,下列情况会触发生成新压缩包:
1.download/clienttmp目录没windows.zip或linux.zip
2.download/data目录没linuxinitjrt.sh或windowsinitjrt.ps1
3.download/client下文件比download/clienttmp目录没windows.zip或linux.zip新
环境下载页检查之后生成的压缩包
在线初始化脚本的模板
linux
#!/bin/bash
#shell在linux上初始化jrt
#20240413
#zlz
#initfile由程序构造初始化脚本时候替换成下载文件命令
#----------------------------------------------------------
rm -y /usr/share/JRTBase/linux.zip
${initfile}
cd /usr/share/JRTBase
unzip linux.zip
#调用本地初始化脚本
touch /usr/share/JRTBase/linux/inlinecall.flag
#调用本地初始化脚本
bash /usr/share/JRTBase/linux/install.sh
windows
#get-executionpolicy
#set-executionpolicy remotesigned
Add-Type -TypeDefinition @" using System.Net; using System.Security.Cryptography.X509Certificates; public class TrustAllCertsPolicy : ICertificatePolicy { public bool CheckValidationResult( ServicePoint srvPoint, X509Certificate certificate, WebRequest request, int certificateProblem) { return true; } }
"@ [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12
Write-Host "Welcome to the JRT-Windows initialization script, which will perform initialization operations"
Write-Host "downloading windows.zip please wait"
${initfile}
Write-Host "unzip windows.zip"
Expand-Archive -Path 'C:\JRTBase\windows.zip' -DestinationPath 'C:\JRTBase'
Write-Host "copy link to desktop"
$sourcePath = "C:\JRTBase\windows\JRTClient-win\JRTClient.lnk"
$desktopPath = [Environment]::GetFolderPath("Desktop")
Copy-Item -Path $sourcePath -Destination $desktopPath
$sourcePath = "C:\JRTBase\windows\JRTBrowser-win32-ia32\JRTLogin.lnk"
$desktopPath = [Environment]::GetFolderPath("Desktop")
Copy-Item -Path $sourcePath -Destination $desktopPath
& "C:\JRTBase\windows\JRTClient-win\JRTClient.exe"
& "C:\JRTBase\windows\JRTBrowser-win32-ia32\JRTBrowser.exe"
Remove-Item -Path "C:\JRTBase\windows.zip"
Write-Host "JRT InitEnd"
Pause
linux的install脚本,windows由于可以任意运行,只要发快捷方法,就不提供本地install了
#!/bin/bash
#shell安装JRT脚本
#20240413
#zlz
#----------------------------------------------------------mypath=$(cd $(dirname ${BASH_SOURCE[0]}); pwd )
echo "当前路径:${mypath}"
#没有在线标志文件,认为是本地执行初始化脚本
if [ ! -f /usr/share/JRTBase/linux/inlinecall.flag ];thenecho "执行本地安装"echo "创建文件夹/usr/share/JRTBase"mkdir /usr/share/JRTBaseecho "创建文件夹/usr/share/JRTBase/linux"mkdir /usr/share/JRTBase/linuxecho "拷贝${mypath}/JRTBrowser-linux-x64到/usr/share/JRTBase/linux"cp -r ${mypath}/JRTBrowser-linux-x64 /usr/share/JRTBase/linuxecho "拷贝${mypath}/JRTClient-linux到/usr/share/JRTBase/linux"cp -r ${mypath}/JRTClient-linux /usr/share/JRTBase/linux
fi
#删除在线调用标识
rm /usr/share/JRTBase/linux/inlinecall.flag#初始化浏览器
echo "授权执行权限"
sudo chmod -R +777 /usr/share/JRTBase/linux/JRTBrowser-linux-x64/*
echo "创建快捷方式到/usr/share/applications/JRTBrowser.desktop"
sudo cp /usr/share/JRTBase/linux/JRTBrowser-linux-x64/resources/app/JRTBrowser.desktop /usr/share/applications/
echo "授权快捷方式"
sudo chmod +777 /usr/share/applications/JRTBrowser.desktop
echo "让沙箱属于root"
sudo chown -R root:root /usr/share/JRTBase/linux/JRTBrowser-linux-x64/chrome-sandbox
echo "设置沙箱权限"
sudo chmod 4755 /usr/share/JRTBase/linux/JRTBrowser-linux-x64/chrome-sandbox
#给每个用户拷贝快捷方式
desk=`cat $HOME/.config/user-dirs.dirs | grep DESKTOP | tail -1 |cut -d '=' -f 2 | sed 's/\"//g'`
var=`eval echo $desk`
echo $var
cd $var
sudo cp /usr/share/JRTBase/linux/JRTBrowser-linux-x64/resources/app/JRTBrowser.desktop $var/
echo "授权快捷方式"
sudo chmod +777 $var/JRTBrowser.desktop#初始化打印导出客户端
echo "授权执行权限"
sudo chmod -R +777 /usr/share/JRTBase/linux/JRTClient-linux/*
echo "创建快捷方式到/usr/share/applications/JRTClient.desktop"
sudo cp /usr/share/JRTBase/linux/JRTClient-linux/app/lib/JRTBrowser.desktop /usr/share/applications/
echo "授权快捷方式"
sudo chmod +777 /usr/share/applications/JRTClient.desktop
#给每个用户拷贝快捷方式
desk=`cat $HOME/.config/user-dirs.dirs | grep DESKTOP | tail -1 |cut -d '=' -f 2 | sed 's/\"//g'`
var=`eval echo $desk`
echo $var
cd $var
sudo cp /usr/share/JRTBase/linux/JRTClient-linux/app/lib/JRTClient.desktop $var/
echo "授权快捷方式"
sudo chmod +777 $var/JRTClient.desktopecho "初始化JRT客户端环境完成"
环境下载页后台实现
import JRT.Core.MultiPlatform.JRTContext;
import JRT.Core.Util.DirUtil;
import JRT.Core.Util.TxtUtil;
import JRTBLLBase.BaseHttpHandlerNoSession;
import JRTBLLBase.Helper;import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;/*** 生成Linux和Windows下初始化环境的脚本,供用户用脚本初始化环境,环境下载页面初始化时候调用此逻辑检查并且生效初始化脚本*/
public class ashDownLoad extends BaseHttpHandlerNoSession {/*** 是否正在压缩文件*/private static boolean iszip = false;/*** 得到所有能下载的文件数据** @return* @throws Exception*/public String GetAllDataFiles() throws Exception {String basePath = Paths.get(JRTContext.WebBasePath, "download", "data").toString();File base = new File(basePath);List<File> allFile = new ArrayList<>();SeeFile(base, allFile);List<String> retList = new ArrayList<>();if (allFile != null && allFile.size() > 0) {for (File f : allFile) {retList.add(f.getName());}}return Helper.Object2Json(retList);}/*** 尝试生成初始化脚本** @return*/public String TryMakeInitScript() throws Exception {String RootPath = Helper.ValidParam(JRT.Core.MultiPlatform.JRTContext.GetRequest(Request, "RootPath"), "");//处理所有客户端程序存放目录String basePath = Paths.get(JRTContext.WebBasePath, "download", "client").toString();//存下载程序的临时目录,所有文件加上.jrt后缀,防止各种类型太多mime限制String basePathTmp = Paths.get(JRTContext.WebBasePath, "download", "clienttmp").toString();//文件下载目录,最后生成初始化脚本让人下载用String dataPath = Paths.get(JRTContext.WebBasePath, "download", "data").toString();File linuxZip = Paths.get(basePathTmp, "linux.zip").toFile();File windowsZip = Paths.get(basePathTmp, "windows.zip").toFile();File base = new File(basePath);List<File> allFile = new ArrayList<>();SeeFile(base, allFile);//是否需要构造新的初始化脚本boolean needMakeNewInit = false;//压缩文件不存在就需要更新if (!linuxZip.exists() || !windowsZip.exists()) {needMakeNewInit = true;} else {//检查并且拷贝文件,生成下载用的临时文件if (allFile != null && allFile.size() > 0) {for (File f : allFile) {if (f.lastModified() > linuxZip.lastModified() || f.lastModified() > windowsZip.lastModified()) {needMakeNewInit = true;}}}}//下载页面后台data文件夹没有下载脚本就生成File winInit = Paths.get(dataPath, "windowsinitjrt.ps1").toFile();File linuxInit = Paths.get(dataPath, "linuxinitjrt.sh").toFile();//构造初始化脚本if (needMakeNewInit == true || ((!winInit.exists()) || (!linuxInit.exists()))) {System.out.println("开始压缩");if (iszip != true) {iszip = true;try {//压缩linux文件ZipFolder(Paths.get(basePath, "linux").toFile(), linuxZip);//压缩windows文件ZipFolder(Paths.get(basePath, "windows").toFile(), windowsZip);System.out.println("压缩完成");StringBuilder winSB = new StringBuilder();//构造powershell脚本AddOneWinDownload(RootPath + "/download/clienttmp/windows.zip", "windows.zip", "", winSB);//读取win模板命令String winCmd = TxtUtil.ReadTextStr(Paths.get(basePath, "windowsinitjrt.ps1").toString());//替换占位符winCmd = winCmd.replace("${initfile}", winSB.toString());//把命令写入下载地址TxtUtil.WriteText2File(Paths.get(dataPath, "windowsinitjrt.ps1").toFile(), winCmd);StringBuilder liSB = new StringBuilder();//构造sh脚本AddOneLinDownload(RootPath + "/download/clienttmp/linux.zip", "linux.zip", "", liSB);//读取linux模板命令String linuxCmd = TxtUtil.ReadTextStr(Paths.get(basePath, "linuxinitjrt.sh").toString());//替换占位符linuxCmd = linuxCmd.replace("${initfile}", liSB.toString());//把命令写入下载地址TxtUtil.WriteText2File(Paths.get(dataPath, "linuxinitjrt.sh").toString(), linuxCmd);} finally {iszip = false;}}}return Helper.Success();}/*** 构造Windows下载脚本** @param url 路径* @param fileName 文件名* @param remoteAddrLocal 相对路径* @param sb 字符串*/private void AddOneWinDownload(String url, String fileName, String remoteAddrLocal, StringBuilder sb) {fileName = fileName.replace(".jrt", "");//下载路径sb.append("$url = \"" + url + "\" " + "\r\n");//本地路径sb.append("$localFolder = \"C:\\JRTBase\\" + remoteAddrLocal.replace("/", "\\") + "\" " + "\r\n");//本地文件名sb.append("$localFileName = \"" + fileName + "\" " + "\r\n");//拼接路径sb.append("$localFile = Join-Path $localFolder $localFileName" + "\r\n");//尝试创建目录sb.append("if (!(Test-Path -Path $localFolder -PathType Container)) { " + "\r\n");sb.append(" New-Item -ItemType Directory -Path $localFolder -Force | Out-Null " + "\r\n");sb.append("} " + "\r\n");//不显示现在进度sb.append("$ProgressPreference = 'SilentlyContinue'\n" + "\r\n");//执行下载sb.append("Invoke-WebRequest -Uri $url -OutFile $localFile" + "\r\n");}/*** 构造linux下载脚本** @param url 路径* @param fileName 文件名* @param remoteAddrLocal 相对路径* @param sb 字符串*/private void AddOneLinDownload(String url, String fileName, String remoteAddrLocal, StringBuilder sb) {fileName = fileName.replace(".jrt", "");//创建目录sb.append("mkdir -p /usr/share/JRTBase/" + remoteAddrLocal.replace("\\", "/") + " " + "\n");//删除老文件sb.append("rm -y /usr/share/JRTBase/" + remoteAddrLocal.replace("\\", "/") + fileName + " " + "\n");//下载新文件sb.append("curl " + url + " -o /usr/share/JRTBase/" + remoteAddrLocal.replace("\\", "/") + fileName + "\n");}/*** 要压缩的目录** @param folderToZip 路径* @param zipFile 输出文件名* @throws Exception*/public static void ZipFolder(File folderToZip, File zipFile) throws Exception {FileOutputStream fos = new FileOutputStream(zipFile);ZipOutputStream zos = new ZipOutputStream(fos);ZipFile(folderToZip, folderToZip.getName(), zos);zos.close();fos.close();}/*** 压缩文件** @param fileToZip 要压缩的文件* @param fileName 文件名* @param zos 输出流* @throws Exception*/private static void ZipFile(File fileToZip, String fileName, ZipOutputStream zos) throws Exception {if (fileToZip.isHidden()) {return;}if (fileToZip.isDirectory()) {if (fileName.endsWith("/")) {zos.putNextEntry(new ZipEntry(fileName));zos.closeEntry();} else {zos.putNextEntry(new ZipEntry(fileName + "/"));zos.closeEntry();}File[] children = fileToZip.listFiles();for (File childFile : children) {ZipFile(childFile, fileName + "/" + childFile.getName(), zos);}return;}FileInputStream fis = new FileInputStream(fileToZip);ZipEntry zipEntry = new ZipEntry(fileName);zos.putNextEntry(zipEntry);byte[] bytes = new byte[1024];int length;while ((length = fis.read(bytes)) >= 0) {zos.write(bytes, 0, length);}fis.close();zos.closeEntry();}/*** 扫描文件** @param dir* @param paths*/private static void SeeFile(File dir, List<File> paths) {File[] files = dir.listFiles();if (files != null) {for (File file : files) {if (file.isDirectory()) {SeeFile(file, paths);} else {paths.add(file);}}}}
}
页面代码
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="Content-Type" content="text/html;charset=utf-8"/><title>JRT环境下载页</title><link rel="shortcut icon" href="../../resource/common/images/favicon.ico"/><script src="../../resource/common/js/JRTBSBase.js" type="text/javascript"></script><script src="../../jrtprint/js/JRTPrint.js" type="text/javascript"></script><script type="text/javascript">var me = {//文件数组fileArray: []};//初始化入口$(function () {$.messager.progress({ text: TranslateDataMTHD("prepare download data,please wait","正在构造下载数据,第一次会比较慢,请耐心等待", ""), interval: 500 });setTimeout(function () {$.messager.progress('close');}, 80000);//生成下载清单$.ajax({type: "post",dataType: "text", //text, json, xmlcache: false, //async: true, //为true时,异步,不等待后台返回值,为false时强制等待;-asirurl: '../ashx/ashDownLoad.ashx?Method=TryMakeInitScript',data: {RootPath: GetRootPath()},success: function (result, status) {//结束等待$.messager.progress('close');//渲染可以下载的文件$.ajax({type: "GET",dataType: "json", //text, json, xmlcache: false, //async: false, //为true时,异步,不等待后台返回值,为false时强制等待;-asirurl: '../ashx/ashDownLoad.ashx?Method=GetAllDataFiles',success: function (result, status) {//对数据进行筛选,是后台抛的信息的话,就提示,以及决定是否继续if (!FilterBackData(result)) {return;}if (result != null && result.length > 0) {for (var i = 0; i < result.length; i++) {if (result[i] == "linuxinitjrt.sh") {continue;}if (result[i] == "windowsinitjrt.ps1") {continue;}AddFile("../..download/data/" + result[i], result[i]);}}}});LoadFileList();}});});//得到网站根路径function GetRootPath() {var curPageUrl = window.document.location.href;var rootPath = curPageUrl.split("//")[0] + "//" + curPageUrl.split("//")[1].split("/")[0] + "//" + curPageUrl.split("//")[1].split("/")[1];return rootPath + "/";}//初步的处理数据function AddFile(url, name) {var arr = name.split(".");// 获取文件后缀,根据后缀设置图标var ext = arr[arr.length - 1];var icon = "../images/download.png";var title = arr[0];me.fileArray.push({icon: icon,url: url,name: name,title: title});}//根据me.fileArray,加载页面文件列表function LoadFileList() {for (var i = 0; i < me.fileArray.length; i++) {var file = me.fileArray[i];var box = $("<a></a>");box.attr({class: "easyui-tooltip file_item",title: file.title,href: file.url,target: "_blank",});var img = $("<img/>");img.attr({src: file.icon,class: "file_icon",});var name = $("<div></div>");name.attr({class: "file_text",});name.text(file.name);box.append(img);box.append(name);$("#panel_Main").append(box);}}</script><style>.fileDiv {display: flex;flex-wrap: wrap;padding: 0 20px 36px 20px;}.fileDiv .file_item {display: flex;margin-right: 20px;height: 20px;margin-top: 20px;line-height: 20px;cursor: pointer;}.fileDiv .file_text {margin-left: 5px;color: #0670c6;width: 140px;overflow: hidden;display: -webkit-box;-webkit-box-orient: vertical;-webkit-line-clamp: 1;}.fileDiv .file_icon {width: 20px;height: 20px;}</style>
</head>
<body>
<div class="easyui-layout" fit="true"><div region="north" split="false" border="0" style="padding:10px;height:80px;"><div>欢迎使用JRT环境下载页,这里提供客户端所需要的环境及工具,请根据需要下载文件!</br>"linux初始化脚本"下载到linux后直接bash执行下载的脚步进行客户端环境初始化。windows初始化脚本用powershell执行,windows默认没开启执行脚本权限,用管理员打开powershell执行set-executionpolicy remotesigned开启。然后下载的脚步用powershell打开执行。对无法执行powershell的电脑直接下载window压缩包到本地解压,把客户端和浏览器快捷方式发送到桌面。对linux也可以下载压缩包到本地解压后运行目录的install.sh初始化。如果想把其他需要的软件放入下载页面让用户下载,那么把文件投入网站的download/data里即可。</div></div><div region="center" split="true" title="   环境以及工具下载"><div id="panel_Main" class="fileDiv"><a class="easyui-tooltip file_item" title="linux初始化脚本" href="../data/linuxinitjrt.sh" target="_blank"><imgsrc="../images/download.png" class="file_icon"><div class="file_text">linux初始化脚本</div></a><a class="easyui-tooltip file_item" title="windows初始化脚本" href="../data/windowsinitjrt.ps1"target="_blank"><img src="../images/download.png" class="file_icon"><div class="file_text">windows初始化脚本</div></a><a class="easyui-tooltip file_item" title="linux程序包" href="../clienttmp/linux.zip" target="_blank"><imgsrc="../images/download.png" class="file_icon"><div class="file_text">linux压缩包</div></a><a class="easyui-tooltip file_item" title="windows程序包" href="../clienttmp/windows.zip" target="_blank"><imgsrc="../images/download.png" class="file_icon"><div class="file_text">windows压缩包</div></a><a class="easyui-tooltip file_item" title="老版本谷歌安装包" href="../data/41.0.2272.101_chrome_installer.exe"target="_blank"><img src="../images/download.png" class="file_icon"><div class="file_text">谷歌浏览器下载</div></a><a class="easyui-tooltip file_item" title="新版本谷歌安装包" href="../data/chrome_installernew.exe" target="_blank"><imgsrc="../images/download.png" class="file_icon"><div class="file_text">新谷歌浏览器下载</div></a></div></div>
</div>
</body>
</html>
这样就基本完成windows和linux的环境初始化设计,JRT从构想、到demo、到雏形、到1.0发布、到正式用水准推进。