有些時候,需要通過DOS批處理來編譯整個項目的JAVA文件;並且編譯后還要對Class文件進行打包成jar文件。。。
這還不是最煩的,最煩的是,編譯和打包的時候需要依賴其他多個jar文件,困難就這么來了。。。。
項目結構
App
|-dest
| |-libs(copy過來的依賴庫)
| |-bin(生成的class文件)
|
|-libs(依賴庫)
|-src(需要編譯的JAVA源文件)
如果需要對項目編譯,首先,需要清理dest文件夾
REM 刪除dest包
IF EXIST dest RMDIR /s /q dest
REM 創建 dest/libs和dest/bin文件夾
mkdir "dest/libs"
mkdir "dest/bin"
REM copy依賴庫
copy libs\*.jar dest\libs\ /y
然后,從JAVA的編譯命令用法入手:
javac <選項> <源文件>
其參數中,"-d <目錄>",指定存放生成的類文件的位置
"-cp <路徑>",指定查找用戶類文件和注釋處理程序的位置(個人理解就是所需要依賴的jar包)
"-encoding <編碼>", 指定源文件使用的字符編碼(我們使用UTF-8)
例如: javac -d dest\bin -cp libs\commons-logging-1.1.1.jar;freemarker-2.3.19.jar; -encoding UTF-8 src/a.java src/com.mycls/b.java src/com.mycls/c.java
上面Demo是加載其依賴庫並使用UTF-8編碼編譯指定java文件
繼續,對編譯好的class文件進行打成jar包
REM 需要在class的根目錄打包
cd dest/bin
REM 將當前目錄下所有文件打包到上級目錄的myjar.jar文件中
jar -cvf ../myjar.jar *
當然了,還可以通過對MANIFEST.MF的定制來指定默認運行的類
上面的內容,對於一個JAVA開發來說都不是事兒,接下來問題來了。。。。
在編譯的時候,javac加載依賴庫是指定的依賴庫,那如果有很多依賴庫,並且在開發過成功還會發生變動呢?難道要修改cmd(bat)批處理?
這個時候,就需要指定一個libs目錄,加載此目錄下的所有文件即可。可是怎么拼接這個參數呢?
如下所示(如果沒有依賴的jar,可將cp相關部分去除):
SETLOCAL enableDelayedExpansion
FOR %%i IN ("libs\*.jar") DO SET CP=%%i;!CP!
SET OPT=-d %OUTPUT_PATH%\bin -cp %CP% -encoding utf-8
EndLocal
這樣,所有的參數就形成了,
SETLOCAL enableDelayedExpansion是擴展本地環境變量延遲,是獲取CP參數的一個出錯點,如果沒有這個,for里面的賦值語句是無效的。
OUTPUT_PATH 變量是指定編譯后的class文件的位置,
CP 變量就是所有需要加載用的lib包
同理,循環src目錄下的所有文件和目錄並拼接所有的java文件(配置文件請自行處理),可以獲取所有的java文件:
CD %SRC_PATH%
FOR /R %%b IN ( . ) DO (
IF EXIST %%b/*.java SET JFILES=!JFILES! %%b/*.java
)
CD ..
REM 正在編譯...
javac %OPT% %JFILES%
REM 編譯結束
然后就是打包了,
CD %OUTPUT_PATH%\bin
REM 將所有文件打包為mylib.jar並存放到父目錄
jar -cvf ../mylib.jar *
REM 打包完畢
對於SHELL命令來說,這樣的批處理更為簡單:
#獲取所有的依賴lib
export libs=`find libs -name "*.jar" |xargs|sed "s/ /:/g"`
#獲取所有需要編譯的java文件
export jfiles=`find src -name "*.java" |xargs|sed "s/ / /g"`
#准備編譯
opt="-d $OUTPUT_PATH/bin -cp ${libs} -encoding utf-8"
javac $opt ${jfiles}
#打包
cd ${OUTPUT_PATH}/bin
jar -cvf ${CUR}/dest/mylib.jar *
cd ${CUR}/src
jar -cvf ${CUR}/dest/mylib-source.jar *
以下圖目錄結構為例:
里面的compile.sh和compile.cmd文件的內容分別為:
調用腳本的JAVA代碼:
1 package test.compile; 2 3 import java.io.File; 4 import java.text.SimpleDateFormat; 5 6 /** 7 * <p>編譯abc目錄下所有java文件</p> 8 * @author Ares 9 * @version $Id: CompileTool.java, v 0.1 2015年02月26日 上午10:41:32 Exp $ 10 */ 11 public class CompileTool { 12 13 // DOS: 第一個參數是 src、cmd的父目錄,第二個參數為最終壓縮包(mylib.jar,mylib-source.jar的目錄)所在目錄 14 15 private static String os_name = System.getProperty("os.name").toLowerCase(); 16 17 public static boolean compileAndJar(final String jarRootPath) throws Exception{ 18 String app_path = jarRootPath; // app_path是指定abc的絕對路徑,因為java文件執行目錄可能跟編譯目錄不一致,所以如果需要請使用此參數(腳本中第一步需要進入此目錄) 19 if(app_path !=null && (!app_path.endsWith("/") && !app_path.endsWith(File.separator))) 20 app_path += File.separator; 21 String compile_datetime = new SimpleDateFormat("yyyyMMddHHmmss").format(new java.util.Date()); 22 // 無后綴的jar名稱(cmd 會拼寫為 jarname.jar 和 jarname-source.jar) 23 String jar_name = "myjar_" + compile_datetime; // jar名稱格式,mylib_日期時間,以參數的形式傳入,下面的腳本中未使用,如若使用,請替代腳本中的mylib 24 String cmd = ""; 25 java.io.File cmdFile = null; 26 if(os_name.indexOf("windows") > -1){ 27 cmd = "cmd.exe /C start " + app_path + "compile.exe " + app_path + " " + jar_name; 28 cmdFile = new java.io.File(app_path + "compile.exe"); 29 }else { 30 cmd = app_path + "compile.sh " + app_path + " " + jar_name; 31 cmdFile = new java.io.File(app_path + "compile.sh"); 32 } 33 if(!cmd.equals("") && cmdFile != null && cmdFile.exists()){ 34 if(!cmdFile.canExecute()) cmdFile.setExecutable(true); 35 return callCmd(cmd); 36 }else { 37 throw new Exception("can't find compile command. command:"+cmdFile.getAbsolutePath()); 38 } 39 } 40 41 private static boolean callCmd(String cmdStr) { 42 try { 43 Process child = Runtime.getRuntime().exec(cmdStr); 44 java.io.InputStream in = child.getInputStream(); 45 while (in.read() != -1) {} 46 in.close(); 47 try { 48 child.waitFor(); 49 return true; 50 } catch (InterruptedException e) { 51 e.printStackTrace(); 52 } 53 return false; 54 } catch (java.io.IOException e) { 55 e.printStackTrace(); 56 } 57 return false; 58 } 59 }
下面是compile.sh文件內容:
#!/bin/bash CUR=$(pwd) ## reset dest folder OUTPUT_PATH=${CUR}/dest rm -rf $OUTPUT_PATH mkdir -p ${OUTPUT_PATH}/bin mkdir -p ${OUTPUT_PATH}/libs ## 獲取依賴庫和需要編譯的java文件 export libs=`find libs -name "*.jar" |xargs|sed "s/ /:/g"` export jfiles=`find src -name "*.java" |xargs|sed "s/ / /g"` ## 編譯 opt="-d $OUTPUT_PATH/bin -cp ${libs} -encoding utf-8" javac $opt ${jfiles} ## 打包 cd ${OUTPUT_PATH}/bin jar -cvf ${CUR}/dest/mylib.jar * cd ${CUR}/src jar -cvf ${CUR}/dest/mylib-source.jar *
下面是compile.cmd文件內容:
1 @ECHO OFF 2 SETLOCAL enableDelayedExpansion 3 4 REM Save Current Path(保存當前路徑) 5 SET CUR=%CD% 6 7 REM Dir Structure(設置目錄結構) 8 SET OUTPUT_PATH=dest 9 SET SRC_PATH=%CUR%\src 10 SET LIBS_PATH=%CUR%\libs 11 12 REM Reset Output Dir(重置清空輸出目錄) 13 IF EXIST %OUTPUT_PATH% RMDIR /s /q %OUTPUT_PATH% 14 IF NOT EXIST %OUTPUT_PATH% MKDIR %OUTPUT_PATH% 15 CD %OUTPUT_PATH% 16 IF NOT EXIST bin MKDIR bin 17 IF NOT EXIST libs MKDIR libs 18 19 REM Copy Files(復制jar文件) 20 CD %CUR% 21 SET CP=%OUTPUT_PATH%/libs 22 copy %LIBS_PATH%\*.jar %OUTPUT_PATH%\libs\ /y 23 24 CD %CUR% 25 FOR %%i IN ("libs\*.jar") DO SET CP=%%i;!CP! 26 SET OPT=-d %OUTPUT_PATH%\bin -cp %CP% -encoding utf-8 27 28 CD %SRC_PATH% 29 REM 獲取所有需要編譯的java源文件,並用空格鏈接 30 REM 此處需要開啟變量延遲(SETLOCAL enableDelayedExpansion不可缺少) 31 32 FOR /R %%b IN ( . ) DO ( 33 IF EXIST %%b/*.java SET JFILES=!JFILES! %%b/*.java 34 ) 35 36 CD %CUR% 37 REM 正在編譯... 38 javac %OPT% %JFILES% 39 40 IF "%errorlevel%" EQU "0" ( 41 ECHO 編譯成功,正在拷貝資源文件... 42 copy %CUR%/src/*.* %OUTPUT_PATH%\src\ /y 43 ) 44 45 REM 准備打包編譯文件和JAVA源文件 46 CD %OUTPUT_PATH%/bin 47 jar -cvf ../mylib.jar * 48 cd %SRC_PATH% 49 jar -cvf %CUR%/dest/mylib-source.jar * 50 51 EndLocal 52 exit