最近正在开发一个 Java & Vue.js 全栈项目,该项目由以下几部分组成:Java 后端服务器、基于 Vue.js 的单页应用、基于 JavaFX 的 GUI 客户端以及其他辅助工具等。
其中 Java 服务端及客户端均依赖公共的 Jar 包,基于 Vue.js 构建生成的静态文件亦须转移至后端模块的相关目录中,由后端模块附带的 Web 服务器管理。如果对项目中的某个子模块进行修改,需要对其手动编译、移动,再对父模块进行编译,操作繁琐,本文探讨通过 Windows 10 的 Linux 子系统运行 Shell 脚本简化上述操作并进行扩展。
之前的一篇文章已探讨过 Linux 子系统的使用及在该系统下,Java、Node.js、Gradle 等工具的配置,本文不再赘述。本文开篇首先优化 Linux 子系统「Windows Subsystem for Linux (WSL) 」的使用体验,
1. 使用 wsl-terminal 增强 WSL 的使用体验
wsl-terminal 是专门为 WSL 准备的终端模拟器,主体是 mintty,另外整合了一些相当友好的特性,使用起来非常方便,也是目前用户体验最好的,推荐使用。
感觉自从用上了 wsl-terminal,完全同时获得了 Windows 10 优异的界面效果和娱乐性,以及 Linux 的专业性和效率,并且两者能够完美融合在一起,完全可以取得好于 macOS 的使用体验「此处为 YY,我未深度使用过 macOS,坐等打脸」。
wsl-terminal 主要具有如下特性:
- 优秀的兼容性(中文显示/输入、 24 位颜色、命令输出等都正常了)。
- 体积小巧,压缩包仅 1.7 M 多,解压后不到 10 M 。
- 配置简单, mintty 可以直接在标题栏右键配置, wsl-terminal 的配置文件也很简单。
- 可以直接在资源管理器右键打开终端模拟器并定位到当前目录。
- 可以将 .sh/.py/.pl 脚本关联到用 wsl-terminal 运行。
- 可以将文本文件关联到用 wsl-terminal 里的 vim 运行。
- 支持 tmux ,可以在 tmux 里打开新目录,恢复已有的 tmux 会话等。
- 支持在 WSL 里直接运行 Windows 程序。
注: 本小节摘抄了 这篇博客 的部分内容。
2. 全栈项目的整体架构
项目的整体架构如下图所示:
3. 特定脚本指令及其含义
3.1 获取当前 Shell 脚本所在的绝对路径
dirname file # 获取 file 文件的相对路径
echo $0 # 获取当前执行的脚本文件名
pwd # 显示当前工作目录
由以上命令可总结出,获取当前 Shell 脚本所在的绝对路径的命令如下:
SH_PATH=$(cd `dirname $0`; pwd)
3.2 Web 静态文件
Gradle / Spring 工程中,./src/main/resources/static
目录下可存放静态文件,在服务端程序运行时,即可获取此目录下的静态文件,所以需要将通过 Webpack 编译、构建生成的静态文件存放在该目录下。
cp -r ./dist/* $SERVER_PATH/src/main/resources/static # 将静态文件复制到指定位置
3.3 获取 Gradle 构建生成的目标 Jar 文件的文件名
运行 gradle build
后,即可在 $PROJECT/build/libs
中生成目标 Jar 文件,获取该文件的文件名,以备之后生成 Jar 运行脚本所用:
NAME=`ls $PROJECT/build/libs` # 获取当前目录下唯一的文件的文件名
3.4 获取该脚本执行时的时间
各工程模块均编译、构建完毕后,需要统一存放在同一个目录中,各个时期生成的目录以时间命名进行区分。
BUILD_TIME=`date "+%Y-%m-%d_%H-%M"` # 获取脚本执行时的时间
4. 该项目的一键构建、打包 Shell 脚本
4.1 脚本具体执行流程
- 清理各个工程的历史构建缓存
- 编译 Web 工程生成静态文件,移入后端工程相应目录。
- 编译公共依赖 Jar 包,移入后端工程、客户端工程相应目录。
- 编译后端工程、客户端工程。
- 后端工程、客户端工程编译后生成的 Jar 文件移入打包目录中,该目录以脚本运行时的时间作为区分。
该脚本的具体执行流程如下图所示,具体步骤如下:
4.2 一键构建、打包脚本
本文已经将脚本的重点、流程等内容进行了详细的介绍,现在贴出脚本具体内容,如下所示:
#!/bin/bash
# 集群设备管理系统工程的 web 端、模拟客户端、服务器端等的整体清理、构建、打包、发布
PROJECT_PATH=/mnt/d/project/ClusterDevicePlatform; # 主工程所在目录
WEB_PATH=/mnt/d/project/cluster-device-platform-web; # Web 模块所在目录
SH_PATH=$(cd `dirname $0`; pwd) # 脚本所在目录
BUILD_TIME=`date "+%Y-%m-%d_%H-%M"` # 脚本运行时间
UTIL_JAR_PATH=$PROJECT_PATH/messageUtils; # 公共 Jar 模块所在目录
SERVER_PATH=$PROJECT_PATH/ClusterDevicePlatform-server; # 服务器模块所在目录
CLIENT_PATH=$PROJECT_PATH/ClusterDevicePlatform-client; # 硬件模拟客户端模块所在目录
# 项目已编译历史文件的清理
cd $UTIL_JAR_PATH;
rm -rf ./build;
cd $CLIENT_PATH;
rm -rf ./build;
cd $SERVER_PATH;
rm -rf ./build;
rm -rf ./src/main/resources/static;
cd $WEB_PATH;
rm -rf ./dist;
# Web 编译并将静态页面文件移入服务器项目中
npm run build
if [ ! $? -eq 0 ]
then echo "Web 编译出错"
exit 1
fi
echo Web 编译完毕
mkdir $SERVER_PATH/src/main/resources/static
cp -r ./dist/* $SERVER_PATH/src/main/resources/static
# Client、Server 的编译
cd $UTIL_JAR_PATH;
gradle build
cd $CLIENT_PATH;
gradle build
cd $SERVER_PATH;
gradle build
# 组织并集中编译生成的待发布文件
mkdir -p $PROJECT_PATH/publish/release/serverRelease_$BUILD_TIME
cd $PROJECT_PATH/publish/release/serverRelease_$BUILD_TIME
cp $CLIENT_PATH/build/libs/* .
cp $SERVER_PATH/build/libs/* .
cp $SH_PATH/template/* .
# 组装 Client、Server 的运行脚本
CLIENT_NAME=`ls $CLIENT_PATH/build/libs`
SERVER_NAME=`ls $SERVER_PATH/build/libs`
echo chcp 65001 >> run-client.ps1
echo java -jar -\'Dfile.encoding\'=UTF-8 .\\$CLIENT_NAME cdg-pc 100 >> run-client.ps1
echo '$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")' >> run-client.ps1
echo chcp 65001 >> run-server.ps1
echo java -jar -\'Dfile.encoding\'=UTF-8 .\\$SERVER_NAME >> run-server.ps1
echo '$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")' >> run-server.ps1
参考链接
- Shell 获取当前工作目录绝对路径
- 淘宝 NPM 镜像
- 进入 WSL 环境的多种方法比较
- 更好地使用 WSL 终端环境
- wsl-terminal 官方 GitHub 仓库