SpringBoot設(shè)置靜態(tài)資源訪問控制和封裝集成方案
背景
最近在著手公司框架優(yōu)化及項(xiàng)目實(shí)際應(yīng)用,原先方案是springboot+html前后端分離單獨(dú)部署,后端人員兼職前端開發(fā),后續(xù)產(chǎn)品線業(yè)務(wù)進(jìn)行優(yōu)化,面向企業(yè)使用部分由移動(dòng)網(wǎng)站人員負(fù)責(zé)設(shè)計(jì)開發(fā),內(nèi)部配置后臺(tái)管理還是由后端負(fù)責(zé),隨著框架不停迭代與使用的項(xiàng)目越來越多,項(xiàng)目升級(jí)框架變得十分麻煩,后端部分可以通過maven私服進(jìn)行版本迭代,后臺(tái)管理頁面升級(jí)則需要進(jìn)行各個(gè)項(xiàng)目拷貝,所以決定對(duì)框架進(jìn)行整合,將后臺(tái)管理頁面與框架后端代碼進(jìn)行整合發(fā)布。
結(jié)構(gòu)設(shè)計(jì)
- 框架打包后臺(tái)管理相關(guān)標(biāo)準(zhǔn)資源及頁面(框架public文件夾)
- 項(xiàng)目使用框架,開發(fā)具體業(yè)務(wù)配置管理頁面(項(xiàng)目static文件夾)
- 項(xiàng)目需要個(gè)性化框架頁面時(shí),在項(xiàng)目static文件夾建立與框架同目錄同名稱資源文件進(jìn)行覆蓋,訪問時(shí)優(yōu)先級(jí)高于框架目錄
SpringBoot靜態(tài)資源訪問
自定義訪問路徑
自定義WebConfig實(shí)現(xiàn)WebMvcConfigurer,重寫addResourceHandlers方法
@Configuration public class WebConfig implements WebMvcConfigurer { @Value("${system.projectName}") private String projectName; /** * 添加靜態(tài)資源文件,外部可以直接訪問地址 * * @param registry */ @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { //第一個(gè)方法設(shè)置訪問路徑前綴,第二個(gè)方法設(shè)置資源路徑 registry.addResourceHandler("/" + projectName + "/**").addResourceLocations("classpath:/static/","classpath:/public/","file:static/"); } }
圖標(biāo)與字體文件夾訪問失敗問題
將靜態(tài)文件拷貝到static/public/resource文件夾下訪問時(shí),圖標(biāo)與字體文件會(huì)進(jìn)行過濾導(dǎo)致?lián)p壞,需要在pom文件中進(jìn)行設(shè)置
<build> <resources> <resource> <filtering>true</filtering> <directory>src/main/resources</directory> <excludes> <exclude>**/*.woff</exclude> <exclude>**/*.ttf</exclude> <exclude>**/*.ico</exclude> </excludes> </resource> <resource> <filtering>false</filtering> <directory>src/main/resources</directory> <includes> <include>**/*.woff</include> <include>**/*.ttf</include> <include>**/*.ico</include> </includes> </resource> </resources> </build>
自定義歡迎頁面
在對(duì)靜態(tài)內(nèi)目錄設(shè)置自定義訪問路徑替換原有的/**后,無法找到目錄下的index頁面,需要建立攔截器手動(dòng)進(jìn)行判斷,效果為訪問http://localhost:port/projectName 會(huì)自動(dòng)跳轉(zhuǎn)到 http://localhost:port/projectName/index.html
@Component public class PageRedirectInterceptor implements HandlerInterceptor { @Value("${system.projectName}") private String projectName; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String requestURL = request.getRequestURL().toString(); String scheme = request.getScheme(); String servaerName = request.getServerName(); int port = request.getServerPort(); String rootPageURL = scheme + ":" + "http://" + servaerName + ":" + port + "/" + projectName; if (requestURL.equals(rootPageURL)) { response.sendRedirect(request.getContextPath() + "/"+projectName + "/index.html"); return false; } return true; } }
自定義頁面圖標(biāo)
在對(duì)靜態(tài)內(nèi)目錄設(shè)置自定義訪問路徑替換原有的/**后,無法找到目錄下的favcion.ico圖標(biāo),需要在頁面引用統(tǒng)一js統(tǒng)一設(shè)置,同時(shí)需要在配置文件中關(guān)閉默認(rèn)圖標(biāo),替換spring的小葉子
spring: mvc: favicon: enabled: false function GetRootPath() { var loc = window.location, host = loc.hostname, protocol = loc.protocol, port = loc.port ? (':' + loc.port) : ''; var path = location.pathname; if (path.indexOf('/') === 0) { path = path.substring(1); } var mypath = '/' + path.split('/')[0]; path = (mypath != undefined ? mypath : ('/' + loc.pathname.split('/')[1])) + '/'; var rootPath = protocol + '//' + host + port + path; return rootPath; } var iconurl = GetRootPath()+"favicon.ico" document.write('<link rel="shortcut icon" href= ' + iconurl + ' ></link>');
項(xiàng)目訪問框架靜態(tài)資源
框架靜態(tài)資源文件獲取
項(xiàng)目啟動(dòng)時(shí),因?yàn)槭且每蚣艿膉ar包,我們需要先找到指定jar包,再將jar包進(jìn)行解壓,找到對(duì)應(yīng)目錄將資源拷貝到我們需要的地方便于訪問
掃描jar包
public static void copyFrameStaticFile() { String packageName = "com.haopan.frame"; // 獲取包的名字 并進(jìn)行替換 String packageDirName = packageName.replace('.', '/'); // 定義一個(gè)枚舉的集合 并進(jìn)行循環(huán)來處理這個(gè)目錄下的things Enumeration<URL> dirs; try { dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName); // 循環(huán)迭代下去 while (dirs.hasMoreElements()) { // 獲取下一個(gè)元素 URL url = dirs.nextElement(); // 得到協(xié)議的名稱 String protocol = url.getProtocol(); if ("jar".equals(protocol)) { // 如果是jar包文件 // 定義一個(gè)JarFile JarFile jar; try { // 獲取jar jar = ((JarURLConnection) url.openConnection()).getJarFile(); String templateDecompressPath = "tempfiles/decompress/" + CommonUtil.getNewGuid() + "/"; File targetFile = new File(templateDecompressPath); if (!targetFile.exists()) { targetFile.mkdirs(); } decompressJarFile(jar, templateDecompressPath); String frameStaticPath = templateDecompressPath + "public/"; File frameStaticFile = new File(frameStaticPath); if (frameStaticFile.exists()) { String copyTargetPath = "static/"; File copyTargetFolder = new File(copyTargetPath); if (copyTargetFolder.exists()) { FileUtil.deleteDirectory(copyTargetPath); } copyTargetFolder.mkdirs(); FileUtil.copyFileFolder(frameStaticPath, copyTargetPath); } FileUtil.deleteDirectory(templateDecompressPath); System.out.println("框架靜態(tài)文件復(fù)制完畢!"); } catch (IOException e) { e.printStackTrace(); } } } } catch (IOException e) { e.printStackTrace(); } }
解壓jar包
對(duì)JarFile中的JarEntry對(duì)象進(jìn)行遍歷,判斷是文件還是目錄分類處理
public static synchronized void decompressJarFile(JarFile jf,String outputPath){ if (!outputPath.endsWith(File.separator)) { outputPath += File.separator; } File dir = new File(outputPath); if (!dir.exists()) { dir.mkdirs(); } try{ for (Enumeration<JarEntry> e = jf.entries(); e.hasMoreElements();) { JarEntry je = (JarEntry) e.nextElement(); String outFileName = outputPath + je.getName(); File f = new File(outFileName); if(je.isDirectory()){ if(!f.exists()){ f.mkdirs(); } }else{ File pf = f.getParentFile(); if(!pf.exists()){ pf.mkdirs(); } InputStream in = jf.getInputStream(je); OutputStream out = new BufferedOutputStream( new FileOutputStream(f)); byte[] buffer = new byte[2048]; int nBytes = 0; while ((nBytes = in.read(buffer)) > 0) { out.write(buffer, 0, nBytes); } out.flush(); out.close(); in.close(); } } }catch(Exception e){ System.out.println("解壓"+jf.getName()+"出錯(cuò)---"+e.getMessage()); }finally{ if(jf!=null){ try { jf.close(); File jar = new File(jf.getName()); if(jar.exists()){ jar.delete(); } } catch (IOException e) { e.printStackTrace(); } } } }
拷貝目錄到指定位置
public class FileUtil { private static void copy(String f1, String f2) throws IOException { File file1=new File(f1); /* File file2=new File(f2);*/ File[] flist=file1.listFiles(); for (File f : flist) { if(f.isFile()){ copyFile(f.getPath(),f2+"/"+f.getName()); //調(diào)用復(fù)制文件的方法 //System.out.println("原路徑["+f.getPath()+"] 被復(fù)制路徑["+f2+"/"+f.getName()+"]"); }else if(f.isDirectory()){ copyFileFolder(f.getPath(),f2+"/"+f.getName()); //調(diào)用復(fù)制文件夾的方法 //System.out.println("原路徑["+f.getPath()+"] 被復(fù)制路徑["+f2+"/"+f.getName()+"]"); } } } /** * 復(fù)制文件夾 * @throws IOException */ public static void copyFileFolder(String sourceFolderPath,String targetFolderPath) throws IOException { //創(chuàng)建文件夾 File file=new File(targetFolderPath); if(!file.exists()){ file.mkdirs(); } copy(sourceFolderPath,targetFolderPath); } /** * 復(fù)制文件 * @throws IOException */ public static void copyFile(String sourceFilePath, String tagretFilePath) throws IOException { try { InputStream in = new FileInputStream(sourceFilePath); OutputStream out = new FileOutputStream(tagretFilePath); byte[] buffer = new byte[2048]; int nBytes = 0; while ((nBytes = in.read(buffer)) > 0) { out.write(buffer, 0, nBytes); } out.flush(); out.close(); in.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } } public static boolean delete(String fileName) { File file =new File(fileName); if (!file.exists()) { //System.out.println("刪除文件失敗:" + fileName +"不存在!"); return false; }else { if (file.isFile()) return deleteFile(fileName); else return deleteDirectory(fileName); } } /** * 刪除單個(gè)文件 * * @param fileName:要?jiǎng)h除的文件的文件名 * @return 單個(gè)文件刪除成功返回true,否則返回false */ public static boolean deleteFile(String fileName) { File file =new File(fileName); // 如果文件路徑所對(duì)應(yīng)的文件存在,并且是一個(gè)文件,則直接刪除 if (file.exists() && file.isFile()) { if (file.delete()) { //System.out.println("刪除單個(gè)文件" + fileName +"成功!"); return true; }else { //System.out.println("刪除單個(gè)文件" + fileName +"失?。?); return false; } }else { //System.out.println("刪除單個(gè)文件失?。? + fileName +"不存在!"); return false; } } /** * 刪除目錄及目錄下的文件 * * @param dir:要?jiǎng)h除的目錄的文件路徑 * @return 目錄刪除成功返回true,否則返回false */ public static boolean deleteDirectory(String dir) { // 如果dir不以文件分隔符結(jié)尾,自動(dòng)添加文件分隔符 if (!dir.endsWith(File.separator)) dir = dir + File.separator; File dirFile =new File(dir); // 如果dir對(duì)應(yīng)的文件不存在,或者不是一個(gè)目錄,則退出 if ((!dirFile.exists()) || (!dirFile.isDirectory())) { System.out.println("刪除目錄失?。? + dir +"不存在!"); return false; } boolean flag =true; // 刪除文件夾中的所有文件包括子目錄 File[] files = dirFile.listFiles(); for (int i =0; i < files.length; i++) { // 刪除子文件 if (files[i].isFile()) { flag = deleteFile(files[i].getAbsolutePath()); if (!flag) break; } // 刪除子目錄 else if (files[i].isDirectory()) { flag = deleteDirectory(files[i].getAbsolutePath()); if (!flag) break; } } if (!flag) { //System.out.println("刪除目錄失?。?); return false; } // 刪除當(dāng)前目錄 if (dirFile.delete()) { //System.out.println("刪除目錄" + dir +"成功!"); return true; }else { return false; } } }
外部靜態(tài)資源訪問與優(yōu)先級(jí)設(shè)置
設(shè)置yml文件中的static-locations配置項(xiàng),多個(gè)使用,隔開,同時(shí)指定順序?yàn)樵L問的優(yōu)先級(jí)
spring: resources: static-locations: classpath:static/,classpath:public/,file:static/
最終目錄結(jié)構(gòu)圖如下,框架部分完全是項(xiàng)目啟動(dòng)時(shí)自動(dòng)解壓拷貝的,項(xiàng)目部分則是由具體項(xiàng)目進(jìn)行開發(fā),項(xiàng)目部分也可以很方便的進(jìn)行框架部分功能重構(gòu),例如登錄頁,主頁面修改等,本方式支持jar包和war包兩種打包方式
到此這篇關(guān)于SpringBoot靜態(tài)資源訪問控制和封裝集成方案的文章就介紹到這了,更多相關(guān)SpringBoot靜態(tài)資源訪問控制內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
關(guān)于Spring?Data?Jpa?自定義方法實(shí)現(xiàn)問題
這篇文章主要介紹了關(guān)于Spring?Data?Jpa?自定義方法實(shí)現(xiàn)問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12淺談byte和長度為8的boolean數(shù)組互相轉(zhuǎn)換
下面小編就為大家?guī)硪黄獪\談byte和長度為8的boolean數(shù)組互相轉(zhuǎn)換。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-11-11spring boot 測(cè)試單元修改數(shù)據(jù)庫不成功的解決
這篇文章主要介紹了spring boot 測(cè)試單元修改數(shù)據(jù)庫不成功的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09SpringBoot集成slf4j2日志配置的實(shí)現(xiàn)示例
本文主要介紹了SpringBoot集成slf4j2日志配置的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-08-08Java數(shù)組動(dòng)態(tài)增加容量過程解析
這篇文章主要介紹了Java數(shù)組動(dòng)態(tài)增加容量過程解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-09-09Debian 7 和 Debian 8 用戶安裝 Java 8的方法
Oracle Java 8 穩(wěn)定版本近期已發(fā)布,有很多新的特征變化。其中,有功能的程序支持通過“Lambda項(xiàng)目 ”,收到了一些安全更新和界面改進(jìn)上的bug修復(fù),使得開發(fā)人員的工作更容易。2014-03-03idea啟動(dòng)springmvc項(xiàng)目時(shí)報(bào)找不到類的解決方法
這篇文章主要介紹了idea啟動(dòng)springmvc項(xiàng)目時(shí)報(bào)找不到類的解決方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-09-09SpringBoot Redis緩存數(shù)據(jù)實(shí)現(xiàn)解析
這篇文章主要介紹了SpringBoot Redis緩存數(shù)據(jù)實(shí)現(xiàn)解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-01-01