springboot實(shí)現(xiàn)jar運(yùn)行復(fù)制resources文件到指定的目錄(思路詳解)
springboot實(shí)現(xiàn)jar運(yùn)行復(fù)制resources文件到指定的目錄
1. 需求
在項(xiàng)目開發(fā)過程中需要將項(xiàng)目resources/static/目錄下所有資源資源復(fù)制到指定目錄。公司項(xiàng)目中需要下載視頻文件,由于下載的有個html頁面,對多路視頻進(jìn)行畫面加載,用到對應(yīng)的靜態(tài)資源文件,如js,css.jwplayer,jquery.js等文件
maven打成的jar和平時發(fā)布的項(xiàng)目路徑不通,所以在讀取路徑的時候獲取的是jar的路徑,無法獲取jar里面的文件路徑
2. 思路
根據(jù)我的需求,復(fù)制的思路大概是,先獲取到resources/static/blog目錄下文件清單,然后通過清單,循環(huán)將文件復(fù)制到指定位置(相對路徑需要確保一致)
因?yàn)轫?xiàng)目會被打成jar包,所以不能用傳統(tǒng)的目錄文件復(fù)制方式,這里需要用到Spring Resource:
Resource接口,簡單說是整個Spring框架對資源的抽象訪問接口。它繼承于InputStreamSource接口。后續(xù)文章會詳細(xì)的分析。
Resource接口的方法說明:
| 方法 | 說明 |
|---|---|
| exists() | 判斷資源是否存在,true表示存在。 |
| isReadable() | 判斷資源的內(nèi)容是否可讀。需要注意的是當(dāng)其結(jié)果為true的時候,其內(nèi)容未必真的可讀,但如果返回false,則其內(nèi)容必定不可讀。 |
| isOpen() | 判斷當(dāng)前Resource代表的底層資源是否已經(jīng)打開,如果返回true,則只能被讀取一次然后關(guān)閉以避免資源泄露;該方法主要針對于InputStreamResource,實(shí)現(xiàn)類中只有它的返回結(jié)果為true,其他都為false。 |
| getURL() | 返回當(dāng)前資源對應(yīng)的URL。如果當(dāng)前資源不能解析為一個URL則會拋出異常。如ByteArrayResource就不能解析為一個URL。 |
| getURI() | 返回當(dāng)前資源對應(yīng)的URI。如果當(dāng)前資源不能解析為一個URI則會拋出異常。 |
| getFile() | 返回當(dāng)前資源對應(yīng)的File。 |
| contentLength() | 返回當(dāng)前資源內(nèi)容的長度 |
| lastModified() | 返回當(dāng)前Resource代表的底層資源的最后修改時間。 |
| createRelative() | 根據(jù)資源的相對路徑創(chuàng)建新資源。[默認(rèn)不支持創(chuàng)建相對路徑資源] |
| getFilename() | 獲取資源的文件名。 |
| getDescription() | 返回當(dāng)前資源底層資源的描述符,通常就是資源的全路徑(實(shí)際文件名或?qū)嶋HURL地址)。 |
| getInputStream() | 獲取當(dāng)前資源代表的輸入流。除了InputStreamResource實(shí)現(xiàn)類以外,其它Resource實(shí)現(xiàn)類每次調(diào)用getInputStream()方法都將返回一個全新的InputStream。 |
獲取Resource清單,我需要通過ResourceLoader接口獲取資源,在這里我選擇了
org.springframework.core.io.support.PathMatchingResourcePatternResolver
3. 實(shí)現(xiàn)代碼
/**
* 只復(fù)制下載文件中用到的js
*/
private void copyJwplayer() {
//判斷指定目錄下文件是否存在
ApplicationHome applicationHome = new ApplicationHome(getClass());
String rootpath = applicationHome.getSource().getParentFile().toString();
String realpath=rootpath+"/vod/jwplayer/"; //目標(biāo)文件
String silderrealpath=rootpath+"/vod/jwplayer/silder/"; //目標(biāo)文件
String historyrealpath=rootpath+"/vod/jwplayer/history/"; //目標(biāo)文件
String jwplayerrealpath=rootpath+"/vod/jwplayer/jwplayer/"; //目標(biāo)文件
String layoutrealpath=rootpath+"/vod/jwplayer/res/layout/"; //目標(biāo)文件
/**
* 此處只能復(fù)制目錄中的文件,不能多層目錄復(fù)制(目錄中的目錄不能復(fù)制,如果循環(huán)復(fù)制目錄中的目錄則會提示cannot be resolved to URL because it does not exist)
*/
//不使用getFileFromClassPath()則報[static/jwplayerF:/workspace/VRSH265/target/classes/static/jwplayer/flvjs/] cannot be resolved to URL because it does not exist
//jwplayer
File fileFromClassPath = FreeMarkerUtil.getFileFromClassPath("/static/jwplayer/"); //復(fù)制目錄
FreeMarkerUtil.BatCopyFileFromJar(fileFromClassPath.toString(),realpath);
//silder
File flvjspath = FreeMarkerUtil.getFileFromClassPath("/static/jwplayer/silder/"); //復(fù)制目錄
FreeMarkerUtil.BatCopyFileFromJar(flvjspath.toString(),silderrealpath);
//history
File historypath = FreeMarkerUtil.getFileFromClassPath("/static/jwplayer/history/"); //復(fù)制目錄
FreeMarkerUtil.BatCopyFileFromJar(historypath.toString(),historyrealpath);
//jwplayer
File jwplayerpath = FreeMarkerUtil.getFileFromClassPath("/static/jwplayer/jwplayer/"); //復(fù)制目錄
FreeMarkerUtil.BatCopyFileFromJar(jwplayerpath.toString(),jwplayerrealpath);
//layout
File layoutpath = FreeMarkerUtil.getFileFromClassPath("/static/jwplayer/res/layout/"); //復(fù)制目錄
FreeMarkerUtil.BatCopyFileFromJar(layoutpath.toString(),layoutrealpath);
}
4. 工具類FreeMarkerUtil
package com.aio.util;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import java.io.*;
/**
* @author:hahaha
* @creattime:2021-12-02 10:33
*/
public class FreeMarkerUtil {
/**
* 復(fù)制path目錄下所有文件
* @param path 文件目錄 不能以/開頭
* @param newpath 新文件目錄
*/
public static void BatCopyFileFromJar(String path,String newpath) {
if (!new File(newpath).exists()){
new File(newpath).mkdir();
}
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
try {
//獲取所有匹配的文件
Resource[] resources = resolver.getResources(path+"/*");
//打印有多少文件
for(int i=0;i<resources.length;i++) {
Resource resource=resources[i];
try {
//以jar運(yùn)行時,resource.getFile().isFile() 無法獲取文件類型,會報異常,抓取異常后直接生成新的文件即可;以非jar運(yùn)行時,需要判斷文件類型,避免如果是目錄會復(fù)制錯誤,將目錄寫成文件。
if(resource.getFile().isFile()) {
makeFile(newpath+"/"+resource.getFilename());
InputStream stream = resource.getInputStream();
write2File(stream, newpath+"/"+resource.getFilename());
}
}catch (Exception e) {
makeFile(newpath+"/"+resource.getFilename());
InputStream stream = resource.getInputStream();
write2File(stream, newpath+"/"+resource.getFilename());
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 創(chuàng)建文件
* @param path 全路徑 指向文件
* @return
*/
public static boolean makeFile(String path) {
File file = new File(path);
if(file.exists()) {
return false;
}
if (path.endsWith(File.separator)) {
return false;
}
if(!file.getParentFile().exists()) {
if(!file.getParentFile().mkdirs()) {
return false;
}
}
try {
if (file.createNewFile()) {
return true;
} else {
return false;
}
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
/**
* 輸入流寫入文件
*
* @param is
* 輸入流
* @param filePath
* 文件保存目錄路徑
* @throws IOException
*/
public static void write2File(InputStream is, String filePath) throws IOException {
OutputStream os = new FileOutputStream(filePath);
int len = 8192;
byte[] buffer = new byte[len];
while ((len = is.read(buffer, 0, len)) != -1) {
os.write(buffer, 0, len);
}
os.close();
is.close();
}
/**
*處理異常報錯(springboot讀取classpath里的文件,解決打jar包java.io.FileNotFoundException: class path resource cannot be opened)
**/
public static File getFileFromClassPath(String path){
File targetFile = new File(path);
if(!targetFile.exists()){
if(targetFile.getParent()!=null){
File parent=new File(targetFile.getParent());
if(!parent.exists()){
parent.mkdirs();
}
}
InputStream initialStream=null;
OutputStream outStream =null;
try {
Resource resource=new ClassPathResource(path);
//注意通過getInputStream,不能用getFile
initialStream=resource.getInputStream();
byte[] buffer = new byte[initialStream.available()];
initialStream.read(buffer);
outStream = new FileOutputStream(targetFile);
outStream.write(buffer);
} catch (IOException e) {
} finally {
if (initialStream != null) {
try {
initialStream.close(); // 關(guān)閉流
} catch (IOException e) {
}
}
if (outStream != null) {
try {
outStream.close(); // 關(guān)閉流
} catch (IOException e) {
}
}
}
}
return targetFile;
}
}
5.效果

到此這篇關(guān)于springboot實(shí)現(xiàn)jar運(yùn)行復(fù)制resources文件到指定的目錄的文章就介紹到這了,更多相關(guān)springboot運(yùn)行復(fù)制resources文件到指定的目錄內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
關(guān)于Java創(chuàng)建線程的2種方式以及對比
這篇文章主要給大家介紹了關(guān)于Java創(chuàng)建線程的2種方式以及對比的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2022-01-01
java控制臺實(shí)現(xiàn)學(xué)生管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了java控制臺實(shí)現(xiàn)簡單的學(xué)生管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-02-02
sprinboot項(xiàng)目啟動一半到圖形化界面卡住了的解決
這篇文章主要介紹了sprinboot項(xiàng)目啟動一半到圖形化界面卡住了的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-10-10
java實(shí)現(xiàn)消息隊列的兩種方式(小結(jié))
本文主要介紹了兩種java實(shí)現(xiàn)消息隊列的方式,利用Spring消息模板發(fā)送消息和Apache ActiveMQ官方實(shí)例發(fā)送消息,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-12-12
Springboot實(shí)現(xiàn)獲取實(shí)時天氣
這篇文章主要為大家詳細(xì)介紹了如何使用Springboot實(shí)現(xiàn)獲取實(shí)時天氣功能,文中的示例代碼講解詳細(xì),有需要的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-04-04
SpringCloud?Gateway讀取Request?Body方式
這篇文章主要介紹了SpringCloud?Gateway讀取Request?Body方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-03-03

