客戶端web庫——WebJars
WebJars資源
WebJars官網地址:
搭建WebJars的官方文件:
使用WebJars官方文件:
下載WebJars的Maven外掛地址:
公共的CDN地址:
我的image-cut開源專案示例:
WebJars簡介
WebJars的特點:
在基於jvm的web應用程式中顯式地管理客戶端依賴關係
使用基於jvm的構建工具(如Maven、Gradle、sbt、…)來下載您的客戶端依賴項
瞭解您使用的客戶端依賴關係
傳遞依賴項會自動解析並可選地通過RequireJS載入
部署在Maven中央倉庫
公共CDN由
jsDelivr
提供。
為什麼要使用WebJars
傳統的Web資源管理方式:
現在的Javaweb專案大都是採用的Maven架構,在開發專案時,我們往往會將一個大專案拆分成許多分散的Maven模組,每個模組實現該專案的某一部分功能,當我們將各個模組開發完畢之後,直接將其組裝到一起即可構成一個大的完整專案。
它的優點:
由於將一個大專案拆分成眾多的小模組,這樣大大降低了程式開發的難度。
由於模組與模組間很多元件都是可以多個專案共用的,這樣就降低了所要編寫的程式碼量,提高了程式碼開發的速度與質量。
不同的Maven模組都是有不同的版本號,我們可以通過對版本號的管理,方便程式後續的管理和升級。
它的缺點:
由於現在的專案是由眾多的Maven模組組成的,其中含有Web前端資源的Maven就不在少數,而這些含有前端資源,比如說JS或CSS,諸如jQuery
Bootstrap
等的管理就成為了一個大問題。
比如說通過人工的方式進行管理,這可能會產生版本號誤差,拷貝版本錯誤,漏拷貝等諸多現象,而一旦該現象產生,那麼導致前端頁面無法正確顯示,版本混亂,而且這樣的錯誤往往會表現出一些莫名其妙的故障,導致後期的糾錯也相當的麻煩。畢竟前端的開發人員往往不懂後端的程式和框架,諸如Java,Spring,Maven之類的;而後端的開發人員也不清楚前端到底是個什麼情況,是bug?是版本錯誤?是檔案混亂?還是設計如此,留待後期完善?等麻煩不斷。
WebJars的優點
而我們採用WebJars的優點就是可以藉助Maven工具,以jar包的形式,通過對Web前端資源進行統一依賴管理,保證這些Web資源版本的唯一性。
建立WebJars專案
WebJars的jar檔案結構
在看WebJars的jar檔案結構時,我們以用途最廣泛的jquery
的WebJars為例來說明。如下就是jquery-3.2.1.jar
的檔案目錄結構。
META-INF
└─maven
└─org.webjars.bower
└─jquery
└─pom.properties
└─pom.xml
└─resources
└─webjars
└─jquery
└─3.2.1
└─(這裡是靜態資原始檔)
WebJars的靜態資原始檔存放位置
從上面的檔案結構可以看出,WebJars的靜態資源存放位置與普通的Javaweb靜態資源的存放位置是不同的,普通的Javaweb專案的靜態資原始檔往往是存放在webapp
檔案目錄下,而當我們要將靜態資源打進jar包時,我們就得采用WebJars的靜態資源存放原則,那就是將靜態資原始檔存放到src.main.resources.META-INF.resources.webjars
目錄下。如下是我所建立的image-cut
專案,該專案就是採用的WebJars的格式進行的封裝。
WebJars必須遵守的命名規範
- WebJar的內容的路徑必須是如下格式:
META-INF/resources/webjars/${name}/${version}
該格式是由WebJars官網明文規定的,是必須要遵守的規範格式。之所以選擇這個路徑結構,是因為它可以得到Java Web框架的廣泛支援,並且包含路徑中的版本號,因此可以很容易地使用具有侵略性的快取。
版本號必須在WebJar路徑中,而不是在檔案中。
版本號是上游版本,而不是WebJar版本。大多數情況下,這些都是一樣的。但有時,WebJar中有一些包裝錯誤,只會在WebJar版本中造成一個版本的顛簸。
上游的源必須是一個版本化的工件。如果上游源沒有提供釋出版本,那麼可以使用提交日期+git提交ID(例如。20140708-394bf29)或派生上游專案並應用語義版本控制。
artifactId應該始終是小寫的。它可以從(按優先順序)構建:
建立pom.xml檔案
pom.xml檔案原始碼:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<properties>
<projectName>image-cut</projectName>
<projectVersion>1.0-RELEASE</projectVersion>
<springframework.version>4.3.10.RELEASE</springframework.version>
</properties>
<groupId>com.lyc</groupId>
<artifactId>${projectName}</artifactId>
<version>${projectVersion}</version>
<packaging>jar</packaging>
<name>${projectName}</name>
<url>http://maven.apache.org</url>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-beans -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${springframework.version}</version>
</dependency>
<!--Spring MVC + Spring web -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${springframework.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.webjars.bower/jquery -->
<dependency>
<groupId>org.webjars.bower</groupId>
<artifactId>jquery</artifactId>
<version>3.2.1</version>
</dependency>
<!-- jsp api -->
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>jsp-api</artifactId>
<version>6.0.36</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.webjars/bootstrap -->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>webjars-taglib</artifactId>
<version>0.3</version>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>${project.basedir}/src/main/resources/META-INF/resources/webjars/${projectName}</directory>
<targetPath>META-INF/resources/webjars/${projectName}/${projectVersion}</targetPath>
</resource>
</resources>
</build>
</project>
這裡的注意點:
由於我們是將靜態資原始檔打入到jar包中,所以說我們要將
packaging
定義為jar
格式而非傳統的war
格式。由於WebJars的命名規範中,jar包的路徑名中必須含有版本號
${version}
,如下:
META-INF/resources/webjars/${name}/${version}
我們在新增靜態資原始檔時,肯定不想將資原始檔加入到含有${version}
的路徑中,因為隨著專案的發展,專案的jar版本會出現版本號的不同。比如說從1.0-SNAPSHOT
變更到2.0-SNAPSHOT
,亦或是從1.0-RELEASE
變更到2.0-RELEASE
。假如說我們將靜態檔案資源存放到含有版本號的路徑中,那麼Maven的版本變動直接帶來的結果就是專案的靜態資原始檔位置頻繁的遷移,但是專案的jar
中又明確的要求含有${version}
,我們的解決辦法是在pom.xml
檔案中加入如下程式碼:
<properties>
<projectName>image-cut</projectName>
<projectVersion>1.0-RELEASE</projectVersion>
<springframework.version>4.3.10.RELEASE</springframework.version>
</properties>
<build>
<resources>
<resource>
<directory>${project.basedir}/src/main/resources/META-INF/resources/webjars/${projectName}</directory>
<targetPath>META-INF/resources/webjars/${projectName}/${projectVersion}</targetPath>
</resource>
</resources>
</build>
通過上面的properties
來統一管理專案的專案名以及版本號。然後在下面的build
中,我們將靜態資原始檔打入到含有${version}
的jar包之中。
在頁面中訪問靜態資原始檔
在容器中的訪問方式
在Spring容器中訪問靜態資原始檔
由於我們想在的專案大都是採用的Spring框架,因而我就說說在Spring中的訪問方法。
在Spring容器中,我們如果要想成功的訪問jar中的靜態資原始檔,那麼我們得在訪問的路徑中加入CLASSPATH
,所以說最終的訪問路徑如下:
<mvc:resources location="classpath:/META-INF/resources/webjars/" mapping="/webjars/**"/>
在Servlet 3容器中訪問靜態資原始檔
如果是在Servlet 3容器中,那麼其訪問的路徑如下:
<mvc:resources mapping="/webjars/**" location="/webjars/"/>
或者在Java中加入如下配置資訊
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
}
}
在Servlet 3容器中的registry.addResourceHandler
的程式碼如下:
registry.addResourceHandler("/webjars/**").addResourceLocations("/webjars/");
由於我這裡採用的是第一個,這樣一來我只需要一行程式碼就可以了,這樣更加的簡便。
在頁面中的訪問方式
在頁面中的訪問方式比較的簡單,比如說我們訪問jQuery
的程式碼如下:
<script src="<%=basePath %>/webjars/jquery/3.2.1/dist/jquery.js"></script>
在瀏覽器中的訪問方式
如果專案啟動了的話,我們可以直接在瀏覽器中對jQuery
進行相應的訪問,其訪問路徑如下:
http://localhost:8080/image-cut/webjars/jquery/3.2.1/dist/jquery.js
當然在Tomcat中我們也是可以直接訪問該image-cut
的Jar
專案主頁的,如下:
Tomcat的類載入順序
Tomcat在載入靜態資源的時候,其實是以檔案流的形式進行載入的,而非以傳統的目錄方式進行載入,該檔案流的載入其實是和java類的載入是一樣的,這樣我們就可以從Tomcat的類載入順序得出jar包中靜態資原始檔的載入順序。
Tomcat在執行中,其類載入順序如下所示:
從上面我們不難看出其載入的順序如下:
- Bootstrap引導類
載入JVM啟動所需的類,以及標準擴充套件類(位於jre/lib/ext下)
- System系統類
載入tomcat啟動的類,比如bootstrap.jar,通常在catalina.bat或者catalina.sh中指定。位於CATALINA_HOME/bin下。
- Common通用類
載入tomcat使用以及應用通用的一些類,位於CATALINA_HOME/lib下,比如servlet-api.jar
- webapp應用類
在這裡,Tomcat會優先載入/WEB-INF/classes
然後再載入/WEB-INF/lib/*.jar。
也就是說,我們的靜態資原始檔其實是在最後Tomcat在載入jar包時才被載入進去的。