静态文件的处理及后续的发布
上文我们分析了一下源码,解决了只编译java类的问题,获得了precompiled/java中的所有内容,那么这一节我们需要解决剩下的几块内容:
- 生成precompiled\templates目录下的文件结构和内容
- 生成conf,app,public目录下的文件结构和内容
- 将app,precompiled,conf,public压缩为一个压缩文件以便上传至服务器更新
- 如何上传文件至服务器
- 上传完成后远程执行更新shell脚本
- 如何自动化
基本上前3步都是在构建我们的更新文件包,后3步属于自动化的运维操作,我们一个个问题分析.
首先我们需要在我们制定的目录下,生成和precompiled\templates相同的目录结构,然后我们需要在对应的目录中生成对应的空白文件.我们可以使用java代码遍历app\view目录,然后依次生成文件夹,但是我们优化打包的目的是优化速度,速度是关键.因此我们使用最高效的批处理命令的形式,来做后续的所有操作,以追求最高的速度.
接下来我们会使用一些简单的cmd命令来实现文件的目录拷贝,文件创建,遍历文件,创建文件等操作,这些命令都可以在这里和这里找到详细的说明.
- 生成precompiled\templates目录下的文件结构和内容
我们先定义几个文件路径和一些变量,因为涉及到项目路径和一些输出路径,使用的比较频繁
@echo off
::设置编码格式为UTF-8
chcp 65001
::循环中有赋值操作需要开启变量延迟
setlocal enabledelayedexpansion
::项目根路径
set root_dir=C:\Users\Administrator\Desktop\project\playTest
::输出文件根路径
set out_dir=C:\Users\Administrator\Desktop\PLAYOUT
set DIR=%root_dir%\app\views
set copyDir=%out_dir%\precompiled\templates\app\views
::远程服务器地址
set ssh_host=127.0.0.1
::远程服务器用户名
set ssh_user=ziya
::远程密码
set ssh_pwd=123456
定义好这些后我们就可以在后面的命令中直接使用这些变量.我们需要生成和原precompiled\templates对应的目录结构,查询资料后发现有一个命令XCOPY
.他可以帮助我们快速的镜像文件及文件夹的拷贝
echo *******************************
echo *生成precompiled\templates目录
echo *******************************
echo.
::拷贝编译文件
XCOPY %root_dir%\precompiled %out_dir%\precompiled\ /s/y
::创建templates\views文件目录
XCOPY %DIR% %copyDir%\ /T/y
::在创建的views目录中生成空的缓存文件
for /R %DIR% %%i IN (*.*) DO (
set str=%%~dpi
::文件名称
set file=%%~nxi
::文件夹目录
set str2=!str:%DIR%=%copyDir%!
::生成空的html缓存文件
cd.>!str2!!file!
)
::创建空的缓存的routes文件
md %out_dir%\precompiled\templates\conf
cd.>%out_dir%\precompiled\templates\conf\routes
这边先是将打包好的precompiled文件拷贝到了我们的输出路径,然后再precompiled中生成了templates\app\view目录,并且遍历了原app/views目录中的文件,在新的templates\app\view中创建了一个同名的空文件.
然后我们再把routes的空文件也创建好,这样precompiled的整个文件夹我们就搞定了,我们将上边的命令编辑保存到一个文本文档中,后缀改为.bat运行后,会在桌面看到一个文件夹
- 生成conf及app目录
同理,我们处理conf目录和app目录也是采用拷贝的方式
echo *******************************
echo * 生成conf及app目录
echo *******************************
echo.
::创建conf目录
md %out_dir%\conf
::拷贝routes
COPY %root_dir%\conf\routes %out_dir%\conf\routes
::拷贝app目录文件
XCOPY %root_dir%\app\views %out_dir%\app\views\ /s/y
我们先创建conf目录,然后再从原项目直接拷贝routes文件过来,app目录就从原项目中直接拷贝过来即可,执行后PLAYOUT又多出了2个文件夹
- 将app,precompiled,conf,public压缩为一个压缩文件以便上传至服务器更新
然后我们在桌生成一个名为application.zip压缩文件,将app,precompiled,conf和原文件中的public添加进去即可.
这边调用压缩命令时需要保证你的电脑上安装了WinRaR软件,并且需要将/WinRaR/Rar.exe文件拷贝到系统盘下Windows\System32中去才可以正常使用压缩命令(RAR.exe经过阅读文档发现,仅能压缩为rar格式,不支持压缩为zip格式,因此服务器中需要安装可以解压rar格式的工具)
echo *************************************************
echo *压缩precompiled,conf,app,原项目的public目录
echo *************************************************
echo.
::在桌面生成一个application.zip压缩文件(请注意:这边虽然名称为zip,其实还是一个rar格式的文件)
rar a -r -ep1 "C:\Users\Administrator\Desktop\application.zip" %out_dir%\app %out_dir%\conf %out_dir%\precompiled %root_dir%\public
::删除输出目录
if exist %out_dir% rd /s /q %out_dir%
执行完成后我们可以看到桌面多了一个压缩文件,且里面包含了我们所需的全部文件资源,桌面上临时生成的输出目录也被删除了
那么到此我们得到了一个压缩文件,这个压缩文件可以直接上传至服务器中的项目目录WEB-INF\application\中去,然后覆盖解压即可完成更新.那么接下来就是要把文件上传至服务器的操作.
- 上传application.zip至服务器
win原生的cmd命令是不带有sftp命令的,因此我们需要下载额外的工具来支持我们执行sftp上传和执行shell脚本命令,我们这边需要下载安装以下软件即可实现上传和执行远程脚本的操作.
下载并安装PUTTY: PUTTY下载界面
安装完毕后我们需要配置环境变量,将putty的地址写入Path中,完成之后我们就可以使用psftp命令了.
输入psftp -h
后会显示所有的参数指令,出现上面的内容就表示你已经配置正确了,那么我们可以开始继续操作了!
ECHO ************************
ECHO 开始上传文件
ECHO ************************
ECHO.
::用psftp上传文件至服务器
psftp %ssh_user%@%ssh_host% -pw %ssh_pwd% -b C:\Users\Administrator\Desktop\upload-cmd.txt
ECHO.
这边需要解释一下 -b
后面跟着的文件,因为我们使用psftp的上传功能时,是没办法写具体的操作指令的,操作指令只能先写入一个文件中,然后通过 -b 参数调用这个指令文件才可以正确的执行,那么C:\Users\Administrator\Desktop\upload-cmd.txt 中的内容就很好理解了,就是将桌面上的application.zip文件放入服务器的/WEB-INF/application/application.zip
upload-cmd.txt 中的内容可以这样:
put C:\Users\Administrator\Desktop\application.zip /test/WEB-INF/application/application.zip
执行完成后,我们可以登陆我们的服务器,在/test/WEB-INF/application/目录下查看上传是否成功了.
- 执行解压及重启服务的远程脚本
文件上传完毕后,我们需要覆盖解压文件,并且重启服务器,这里以tomcat为例,讲解一下重启tomcat的命令
ECHO ************************
ECHO 执行远程shell脚本
ECHO ************************
putty -ssh -pw %ssh_pwd% %ssh_user%@%ssh_host% -m C:\Users\Administrator\Desktop\ssh-cmd.txt
同样的我们需要把执行的命令写入一个文件中,然后调用,那么这边我们就比较好理解ssh-cmd.txt中需要执行哪些操作了.
C:\Users\Administrator\Desktop\ssh-cmd.txt中可以这样写:
#进入目录
cd /test/WEB-INF/application/
#覆盖解压项目
unzip -o application.zip
#进入tomcat目录
cd /usr/apache-tomcat/bin/
#执行重启脚本
sh restart.sh
这里需要注意有一个sh restart.sh
操作,这个restart.sh不是tomcat原生自带的,而是我们自己创建的一个重启的命令脚本.
restart.sh 内容:
#!/bin/sh
pid=`ps -ef|grep apache-tomcat|grep -v grep|awk '{print $2}'`
if [ -n "pid" ]
then
echo "kill -9 pid:" $pid
kill -9 $pid
fi
sh startup.sh
pid=`ps -ef|grep apache-tomcat|grep -v grep|awk '{print $2}'`
echo "new pid:" $pid
这边需要注意的是该文件的编码格式,必须是UTF-8且无BOM,若一直执行不了,可以将tomcat中自带的startup.sh拷贝下来,然后修改里面的内容和文件名,再上传回tomcat.上传完成后别忘了给文件赋予权限,我们直接使用
chmod 777 restart.sh
赋予一个最高权限(好孩子不要这样学哦)就可以正确执行了
最后贴出完整的cmd命令:
@echo off
::设置编码格式为UTF-8
chcp 65001
::循环中有赋值操作需要开启变量延迟
setlocal enabledelayedexpansion
::项目根路径
set root_dir=C:\Users\Administrator\Desktop\project\playTest
::输出文件根路径
set out_dir=C:\Users\Administrator\Desktop\PLAYOUT
set DIR=%root_dir%\app\views
set copyDir=%out_dir%\precompiled\templates\app\views
::远程服务器地址
set ssh_host=127.0.0.1
::远程服务器用户名
set ssh_user=ziya
::远程密码
set ssh_pwd=123456
echo *******************************
echo *生成precompiled\templates目录
echo *******************************
echo.
::拷贝编译文件
XCOPY %root_dir%\precompiled %out_dir%\precompiled\ /s/y
::创建templates\views文件目录
XCOPY %DIR% %copyDir%\ /T/y
::在创建的views目录中生成空的缓存文件
for /R %DIR% %%i IN (*.*) DO (
set str=%%~dpi
::文件名称
set file=%%~nxi
::文件夹目录
set str2=!str:%DIR%=%copyDir%!
::生成空的html缓存文件
cd.>!str2!!file!
)
::创建空的缓存的routes文件
md %out_dir%\precompiled\templates\conf
cd.>%out_dir%\precompiled\templates\conf\routes
echo *******************************
echo * 生成conf及app目录
echo *******************************
echo.
::创建conf目录
md %out_dir%\conf
::拷贝routes
COPY %root_dir%\conf\routes %out_dir%\conf\routes
::拷贝app目录文件
XCOPY %root_dir%\app\views %out_dir%\app\views\ /s/y
echo *************************************************
echo *压缩precompiled,conf,app,原项目的public目录
echo *************************************************
echo.
::在桌面生成一个application.zip压缩文件
rar a -r -ep1 "C:\Users\Administrator\Desktop\application.zip" %out_dir%\app %out_dir%\conf %out_dir%\precompiled %root_dir%\public
::删除输出目录
if exist %out_dir% rd /s /q %out_dir%
ECHO ************************
ECHO 开始上传文件
ECHO ************************
ECHO.
::用psftp上传文件至服务器
psftp %ssh_user%@%ssh_host% -pw %ssh_pwd% -b C:\Users\Administrator\Desktop\upload-cmd.txt
ECHO.
ECHO ************************
ECHO 文件上传完毕
ECHO ************************
ECHO.
ECHO ************************
ECHO 执行远程shell脚本
ECHO ************************
ECHO.
putty -ssh -pw %ssh_pwd% %ssh_user%@%ssh_host% -m C:\Users\Administrator\Desktop\ssh-cmd.txt
ECHO.
ECHO ************************
ECHO 更新完成!
ECHO ************************
::最后把生成的压缩包删除
if exist C:\Users\Administrator\Desktop\application.zip del /q C:\Users\Administrator\Desktop\application.zip
ECHO.
ECHO [33m/@
ECHO \ \
ECHO ___\ \
ECHO (__O) \
ECHO (____@) \
ECHO (____@) \
ECHO (__o)_ \
ECHO \ \
ECHO [32m希望您玩的愉快!
ECHO.
exit
到这里我们完成了后续对其余文件的拷贝创建,压缩,上传,解压,重启等操作了,我们最后需要做的,就是把前面所介绍的全部内容联系起来,制作一键更新工具.
import org.junit.Test;
import play.Logger;
import play.Play;
import play.classloading.ApplicationClasses;
import play.test.FunctionalTest;
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
/**
* 优化加速自动发版
*
* @author 子牙
* @date 2019年11月12日 下午15:55:40
*/
public class AutoUpdate extends FunctionalTest {
@Test
public void autoUpdate() throws Exception {
//删除precompiled文件夹
File precompiledFile = Play.getFile("/precompiled/");
String delCmd = "cmd /c if exist " + precompiledFile.getAbsolutePath() + " rd /s /q " + precompiledFile.getAbsolutePath();
Runtime.getRuntime().exec(delCmd);
// 进入编译状态
System.setProperty("precompile", "true");
//只需要将precompile/java打包即可,不需要编译html文件
for (ApplicationClasses.ApplicationClass applicationClass : Play.classes.all()) {
//过滤掉test目录下的文件
if (applicationClass.name.contains(".")) {
//这一步貌似不是必须的.暂时未发现什么异常
// applicationClass.compile();// 编译
applicationClass.enhance();// 输出
}
}
//执行cmd脚本
String cmd = "cmd /c " + Play.getFile("/test/AutoUpdate.cmd").getAbsolutePath();
Process p = Runtime.getRuntime().exec(cmd);
//在控制台输出
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
p.getInputStream().close();
p.destroy();
Logger.info("更新完毕~");
}
}
我们在项目的test目录中新建一个测试类,然后再把cmd脚本(列子中为AutoUpdate.cmd)保存到test目录中方便调用,最后我们执行一下这个test
最后完成整个打包发布过程仅需2m8s!
/@
\ \
___\ \
(__O) \
(____@) \
(____@) \
(__o)_ \
\ \
希望您玩的愉快!