問題
最近項目中需要調用海康的攝像頭然後進行抓拍圖片,由於使用的是 spring-boot
框架,然後將 DLL 動態鏈接庫打包到 jar
包,導致 JNA
獲取不到 DLL 的路徑。
疑問
爲什麼在開發的時候可以加載到DLL,打包後就會獲取不到?
經過檢查,發現打包後,系統會將 jar
包當成一個文件,這時候我們使用 class
的 getResource()
就會獲取不到DLL的絕對路徑。這主要是因爲jar包是一個單獨的文件而非文件夾,絕對不可能通過 file:/e:/.../ResourceJar.jar/resource /res.txt
這種形式的文件URL來定位文件。所以即使是相對路徑,也無法定位到jar
文件內的文件。我們不能用常規操作文件的方法來讀取jar
中的資源文件。
可能這塊的東西有些童鞋不太懂,可以去搜索相關的知識或者自己讀取一個資源文件,打成 jar 包試試就明白了。
解決方法一
這時候就有辦法了,那麼獲取不到怎麼辦,我們是不是可以將DLL放在 jar
包外面,然後給一個絕對路徑,答案是可以的。
上圖中 HCNetSDK
文件夾中放的是海康的DLL文件,hcnet-0.0.1-SNAPSHOT.jar
是項目的 jar
包。
還有一個問題,我們在部署的時候不知道運維人員到底會將項目部署到哪裏,我們不能限定運維人員說必須部署到哪個盤哪個位置。這樣的話,估計運維小夥伴會跟我們兵戎相見
。那麼我們可以在運行的時候指定 JNA
的運行路徑。
@echo off
TITLE 拍照服務
set JAVA_HOME=C:\Program Files\Java\jdk1.8.0_111
path path;C:\Program Files\Java\jdk1.8.0_111\bin
java -Dfile.encoding=UTF-8 -Djna.library.path=C:\cam -jar hcnet-0.0.1-SNAPSHOT.jar
pause
腳本中第二行是設置標題,第二行和第三行是設置運行的 JDK
環境。-Djna.library.path=C:\cam
是設置 JNA
的運行路徑爲 C:\cam
文件夾。這樣我們在開發的時候 load
方法中直接寫DLL的名稱即可。
獲取文件路徑 DllLoad
類
import java.io.UnsupportedEncodingException;
public class DllLoad {
public static String DLL_PATH;
static {
String root = DllLoad.class.getResource("/").getPath();
if (root.startsWith("file:/")) { // jar包中獲取到的路徑
DLL_PATH = "";
} else { // 實際開發中獲取到的路徑不帶 file:/
root = root.replaceAll("%20", " ").substring(1);
try {
DLL_PATH = java.net.URLDecoder.decode(root, "utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
}
在引用的地方使用:
HCNetSDK INSTANCE = (HCNetSDK) Native.loadLibrary(DllLoad.DLL_PATH + "HCNetSDK\\Win32\\HCNetSDK",
HCNetSDK.class);
這樣就解決了打 jar
後獲取不到文件的尷尬情況。
解決方法二
這個方法很簡單,直接打成 war
一了百了。spring-boot
如何打包成 war
網上有太多的文章,此處不在贅述。
結語
其實打成 war
包是我當初沒研究成打成 jar
的方法,最後將項目上線後,自己也反思了,回去花了半晚上的時間研究了打成 jar
包的方法,如果哪位大神有更好的方法也可以借鑑。
最後說一些題外話吧,我覺得,幹技術行業,沒有鑽研精神是不行的,而且當一個具有挑戰性難題解決的時候,相信心中的成就感對於每一個幹技術的都不言而喻。可能這個問題對於大神來說都是很簡單的事情。說了這麼多,還是希望大家讀到我文章的兄弟們都能具有鑽研解決問題的精神,人人都成爲大佬。
Keep Calm And Make Epic Shit.