2

最近正在开发一个 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 脚本具体执行流程

  1. 清理各个工程的历史构建缓存
  2. 编译 Web 工程生成静态文件,移入后端工程相应目录。
  3. 编译公共依赖 Jar 包,移入后端工程、客户端工程相应目录。
  4. 编译后端工程、客户端工程。
  5. 后端工程、客户端工程编译后生成的 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

参考链接

  1. Shell 获取当前工作目录绝对路径
  2. 淘宝 NPM 镜像
  3. 进入 WSL 环境的多种方法比较 
  4. 更好地使用 WSL 终端环境
  5. wsl-terminal 官方 GitHub 仓库

bitkylin
161 声望13 粉丝

爱好技术、爱好开源、爱好分享。曾在 .NET、Android、Web 前端等领域搬砖,目前致力于 Java 后端工作与学习,靡不有初,鲜克有终。