这么多年客户端一直只做Windows,所以初始化程序用C#写个Exe,按网站生成的下载清单文件一个个下载和部署客户端环境是可以的。新的由于设计目标就是支持多平台的,所以需要重新考虑初始化设计。
JRT-Linux初始化演示
JRT-Windows初始化演示
设计目标有以下:
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安装LISClient脚本
#20221125
#zlz
#----------------------------------------------------------
#检测安装dotnet5
mypath=$(cd $(dirname ${BASH_SOURCE[0]}); pwd )
echo "当前路径:${mypath}"
#没有在线标志文件,认为是本地执行初始化脚本
if [ ! -f /usr/share/JRTBase/linux/inlinecall.flag ];then
echo "执行本地安装"
echo "创建文件夹/usr/share/JRTBase"
mkdir /usr/share/JRTBase
echo "创建文件夹/usr/share/JRTBase/linux"
mkdir /usr/share/JRTBase/linux
echo "拷贝${mypath}/JRTBrowser-linux-x64到/usr/share/JRTBase/linux"
cp -r ${mypath}/JRTBrowser-linux-x64 /usr/share/JRTBase/linux
echo "拷贝${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
#给每个用户拷贝快捷方式
HOME_DIR="/home"
#使用find命令查找名为"桌面"或"Desktop"的目录
find "${HOME_DIR}" -type d \( -name "桌面" -o -name "Desktop" \) | while read -r DESKTOP_DIR; do
echo "${DESKTOP_DIR}/"
sudo cp /usr/share/JRTBase/linux/JRTBrowser-linux-x64/resources/app/JRTBrowser.desktop "${DESKTOP_DIR}/"
echo "授权快捷方式"
sudo chmod +777 ${DESKTOP_DIR}/JRTBrowser.desktop
done
#初始化打印导出客户端
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/JRTClient.desktop /usr/share/applications/
echo "授权快捷方式"
sudo chmod +777 /usr/share/applications/JRTClient.desktop
#给每个用户拷贝快捷方式
#使用find命令查找名为"桌面"或"Desktop"的目录
find "${HOME_DIR}" -type d \( -name "桌面" -o -name "Desktop" \) | while read -r DESKTOP_DIR; do
echo "${DESKTOP_DIR}/"
sudo cp /usr/share/JRTBase/linux/JRTClient-linux/app/lib/JRTClient.desktop "${DESKTOP_DIR}/"
echo "授权快捷方式"
sudo chmod +777 ${DESKTOP_DIR}/JRTClient.desktop
done
echo "初始化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, xml
cache: false, //
async: true, //为true时,异步,不等待后台返回值,为false时强制等待;-asir
url: '../ashx/ashDownLoad.ashx?Method=TryMakeInitScript',
data: {
RootPath: GetRootPath()
},
success: function (result, status) {
//结束等待
$.messager.progress('close');
//渲染可以下载的文件
$.ajax({
type: "GET",
dataType: "json", //text, json, xml
cache: false, //
async: false, //为true时,异步,不等待后台返回值,为false时强制等待;-asir
url: '../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"><img
src="../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"><img
src="../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"><img
src="../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"><img
src="../images/download.png" class="file_icon">
<div class="file_text">新谷歌浏览器下载</div>
</a>
</div>
</div>
</div>
</body>
</html>
这样就基本完成windows和linux的环境初始化设计,JRT从构想、到demo、到雏形、到1.0发布、到正式用水准推进。