日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

以Jar形式为Web项目提供资源文件(JS、CSS与图片)

發(fā)布時間:2025/3/16 javascript 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 以Jar形式为Web项目提供资源文件(JS、CSS与图片) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
  • 一、背景
  • 二、分析
  • 1、把我需要的JS、CSS與圖片等資源copy到Web工程中。
  • 2、通過程序采用流的方式讀取Jar中的資源流再輸出到頁面流。
  • 三、分析結果
  • 四、核心代碼開發(fā)(Jar端)
  • 1、org.noahx.jarresource.TagLibResourceFilter(程序內(nèi)邏輯詳見注釋)
  • 2、pom.xml
  • 五、核心代碼開發(fā)(Web端)
  • 1、web.xml
  • 2、index.jsp(資源使用樣例,JS、CSS與圖片)
  • 3、pom.xml
  • 六、Web工程兩種模式的Filter日志
  • 1、目錄部署方式
  • 2、War包部署方式
  • 七、總結
  • 八、源程序下載

一、背景

最近正在編寫TagLib,在開發(fā)的過程中遇到一個資源文件引用問題。因為我開發(fā)的TagLib最終是以Jar包的形式提供給項目來用的,所以Jar包中必須包含我開發(fā)TagLib所需的JS、CSS與圖片等資源。問題就是Tag是在項目的Web工程中運行,如何訪問到jar中的資源。

二、分析

我想了一下,應該有兩種方式:

1、把我需要的JS、CSS與圖片等資源copy到Web工程中。

? ? 好處:

  • 通過原生的Web服務器來訪問,速度與性能上講會好一些。

? ? 缺點:

  • Web工程必須以目錄方式部署。(非war)
  • 存放資源的目錄名需要與Web工程明確約定。(防止對原Web項目文件進行覆蓋)

2、通過程序采用流的方式讀取Jar中的資源流再輸出到頁面流。

? ? 好處:

  • 不依賴Web工程的部署方式。
  • 不會復制文件到Web工程。

? ? 缺點:

  • 以流的方式實時從Jar中讀取。(速度與性能上講并非最優(yōu))
  • 頁面流輸出時需要指定內(nèi)容類型Content-Type。(前者會由Web服務器來維護)

三、分析結果

最終我準備將1、2兩種情況接合使用,默認會采用1復制文件到Web工程的方式。如果發(fā)現(xiàn)Web工程無法復制文件則采用2流讀取方式。

四、核心代碼開發(fā)(Jar端)

為了進行兩種方式的切換定義一個Filter非常適合,可以攔截請求干擾行為,又可以在init初始化時進行資源文件的復制。

從下面的目錄結構可以看出主程序就是一個Filter類,org.noahx.jarresource.resource包下的內(nèi)容就是我需要的資源目錄。Filter會自動判斷Web工程的部署方式(目錄與War)來決定復制資源目錄還是直接流讀取。

1、org.noahx.jarresource.TagLibResourceFilter(程序內(nèi)邏輯詳見注釋)

?
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246package org.noahx.jarresource;import org.apache.commons.io.FileUtils;import org.apache.commons.io.FilenameUtils;import org.apache.commons.io.IOUtils;import org.apache.commons.lang.StringUtils;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import sun.net.www.protocol.file.FileURLConnection;import javax.servlet.*;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.File;import java.io.IOException;import java.io.InputStream;import java.net.JarURLConnection;import java.net.URL;import java.net.URLConnection;import java.util.Enumeration;import java.util.HashMap;import java.util.Map;import java.util.jar.JarEntry;import java.util.jar.JarFile;/**?* Created with IntelliJ IDEA.?* User: noah?* Date: 6/24/13?* Time: 8:18 PM?* To change this template use File | Settings | File Templates.?*/public class TagLibResourceFilter implements Filter {????private static final String RESOURCE_PACKAGE_PATH = "/org/noahx/jarresource/resource";????private static final String RESOURCE_CHARSET = "UTF-8";????private static final String DEFAULT_MINE_TYPE = "application/octet-stream";????private static String resourcePath;????private final Logger logger = LoggerFactory.getLogger(this.getClass());????private ResourceMode resourceMode;????private static enum ResourceMode {????????Dir, Jar????}????private static final Map<String, String> MINE_TYPE_MAP;????static {????????MINE_TYPE_MAP = new HashMap<String, String>();????????MINE_TYPE_MAP.put("js", "application/javascript;charset=" + RESOURCE_CHARSET);????????MINE_TYPE_MAP.put("css", "text/css;charset=" + RESOURCE_CHARSET);????????MINE_TYPE_MAP.put("gif", "image/gif");????????MINE_TYPE_MAP.put("jpg", "image/jpeg");????????MINE_TYPE_MAP.put("jpeg", "image/jpeg");????????MINE_TYPE_MAP.put("png", "image/png");????}????public static String getResourcePath() {????????return TagLibResourceFilter.resourcePath;????}????private static void setResourcePath(String resourcePath) {????????TagLibResourceFilter.resourcePath = resourcePath;????}????@Override????public void init(FilterConfig filterConfig) throws ServletException {????????String resPath = filterConfig.getInitParameter("resourcePath");????????if (!resPath.startsWith("/")) {????????????resPath = "/" + resPath;????????}????????setResourcePath(resPath);????????String rootPath = filterConfig.getServletContext().getRealPath("/");????????if (rootPath != null) {?? //如果web工程是目錄方式運行????????????String dirPath = filterConfig.getServletContext().getRealPath(resPath);????????????File dir = null;????????????try {????????????????dir = new File(dirPath);????????????????FileUtils.deleteQuietly(dir); //清除老資源????????????????FileUtils.forceMkdir(dir);?? //重新創(chuàng)建資源目錄????????????????if(logger.isDebugEnabled()){????????????????????logger.debug("create dir '"+dirPath+"'");????????????????}????????????} catch (Exception e) {????????????????logger.error("Error creating TagLib Resource dir", e);????????????}????????????try {????????????????copyResourcesRecursively(this.getClass().getResource(RESOURCE_PACKAGE_PATH), dir); //復制classpath中的資源到目錄????????????} catch (Exception e) {????????????????logger.error(e.getMessage(), e);????????????}????????????resourceMode = ResourceMode.Dir;?? //設置為目錄模式????????} else {????????????resourceMode = ResourceMode.Jar;??? //設置為jar包模式????????}????????if(logger.isDebugEnabled()){????????????logger.debug("ResourceMode:"+resourceMode);????????}????}????@Override????public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {????????switch (resourceMode) {????????????case Dir:????????????????chain.doFilter(request, response);????????????????break;????????????case Jar: {????????????????HttpServletRequest req = (HttpServletRequest) request;????????????????String path = req.getRequestURI().substring(req.getContextPath().length());? //uri去掉web上下文????????????????HttpServletResponse rep = (HttpServletResponse) response;????????????????if (path.startsWith(getResourcePath() + "/")) {? //resourcePath必須與url-pattern一致????????????????????path = path.substring(getResourcePath().length());???? //uri去掉resourcePath????????????????????try {????????????????????????URL resource = this.getClass().getResource(RESOURCE_PACKAGE_PATH + path);??? //可能存在潛在安全問題????????????????????????if (resource == null) {????? //如果在類路徑中沒有找到資源->404????????????????????????????rep.sendError(HttpServletResponse.SC_NOT_FOUND);????????????????????????} else {????????????????????????????InputStream inputStream = readResource(resource);????????????????????????????if (inputStream != null) {? //有inputstream說明已經(jīng)讀到jar中內(nèi)容????????????????????????????????String ext = FilenameUtils.getExtension(path).toLowerCase();????????????????????????????????String contentType = MINE_TYPE_MAP.get(ext);????????????????????????????????if (contentType == null) {????????????????????????????????????contentType = DEFAULT_MINE_TYPE;????????????????????????????????}????????????????????????????????rep.setContentType(contentType);??? //設置內(nèi)容類型????????????????????????????????ServletOutputStream outputStream = rep.getOutputStream();????????????????????????????????try {????????????????????????????????????int size = IOUtils.copy(inputStream, outputStream);? //向輸出流輸出內(nèi)容????????????????????????????????????rep.setContentLength(size);????????????????????????????????} finally {????????????????????????????????????IOUtils.closeQuietly(inputStream);????????????????????????????????????IOUtils.closeQuietly(outputStream);????????????????????????????????}????????????????????????????} else {?? //沒有inputstream->404????????????????????????????????rep.sendError(HttpServletResponse.SC_NOT_FOUND);????????????????????????????}????????????????????????}????????????????????} catch (Exception e) {????????????????????????logger.error(e.getMessage(), e);????????????????????????rep.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);????????????????????}????????????????} else {????????????????????logger.error("MUST set url-pattern=\"" + resourcePath + "/*\"!!");????????????????????rep.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);????????????????}????????????}????????????break;????????}????}????@Override????public void destroy() {????}????private InputStream readResource(URL originUrl) throws Exception {????????InputStream inputStream = null;????????URLConnection urlConnection = originUrl.openConnection();????????if (urlConnection instanceof JarURLConnection) {????????????inputStream = readJarResource((JarURLConnection) urlConnection);????????} else if (urlConnection instanceof FileURLConnection) {????????????File originFile = new File(originUrl.getPath());????????????if (originFile.isFile()) {????????????????inputStream = originUrl.openStream();????????????}????????} else {????????????throw new Exception("URLConnection[" + urlConnection.getClass().getSimpleName() +????????????????????"] is not a recognized/implemented connection type.");????????}????????return inputStream;????}????private InputStream readJarResource(JarURLConnection jarConnection) throws Exception {????????InputStream inputStream = null;????????JarFile jarFile = jarConnection.getJarFile();????????if (!jarConnection.getJarEntry().isDirectory()) { //如果jar中內(nèi)容為目錄則不返回inputstream????????????inputStream = jarFile.getInputStream(jarConnection.getJarEntry());????????}????????return inputStream;????}????private void copyResourcesRecursively(URL originUrl, File destination) throws Exception {????????URLConnection urlConnection = originUrl.openConnection();????????if (urlConnection instanceof JarURLConnection) {????????????copyJarResourcesRecursively(destination, (JarURLConnection) urlConnection);????????} else if (urlConnection instanceof FileURLConnection) {????????????FileUtils.copyDirectory(new File(originUrl.getPath()), destination); //如果不是jar則采用目錄copy????????????if(logger.isDebugEnabled()){????????????????logger.debug("copy dir '"+originUrl.getPath()+"' --> '"+destination.getPath()+"'");????????????}????????} else {????????????throw new Exception("URLConnection[" + urlConnection.getClass().getSimpleName() +????????????????????"] is not a recognized/implemented connection type.");????????}????}????private void copyJarResourcesRecursively(File destination, JarURLConnection jarConnection) throws IOException {????????JarFile jarFile = jarConnection.getJarFile();????????Enumeration<JarEntry> entries = jarFile.entries();????????while (entries.hasMoreElements()) {??? //遍歷jar內(nèi)容逐個copy????????????JarEntry entry = entries.nextElement();????????????if (entry.getName().startsWith(jarConnection.getEntryName())) {????????????????String fileName = StringUtils.removeStart(entry.getName(), jarConnection.getEntryName());????????????????File destFile = new File(destination, fileName);????????????????if (!entry.isDirectory()) {????????????????????InputStream entryInputStream = jarFile.getInputStream(entry);????????????????????FileUtils.copyInputStreamToFile(entryInputStream, destFile);????????????????????if(logger.isDebugEnabled()){????????????????????????logger.debug("copy jarfile to file '"+entry.getName()+"' --> '"+destination.getPath()+"'");????????????????????}????????????????} else {????????????????????FileUtils.forceMkdir(destFile);????????????????????if(logger.isDebugEnabled()){????????????????????????logger.debug("create dir '"+destFile.getPath()+"'");????????????????????}????????????????}????????????}????????}????}}

補充:Filter中提供了靜態(tài)方法getResourcePath()來獲得當前的資源路徑,我的TagLib中就可以通過該方法獲得資源URI。

2、pom.xml

?
1234567891011121314151617181920212223242526272829303132333435363738394041<?xml version="1.0" encoding="UTF-8"?><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/xsd/maven-4.0.0.xsd">????<modelVersion>4.0.0</modelVersion>????<groupId>org.noahx.jarresource</groupId>????<artifactId>resource</artifactId>????<version>1.0-SNAPSHOT</version>????<packaging>jar</packaging>????<dependencies>????????<dependency>????????????<groupId>commons-io</groupId>????????????<artifactId>commons-io</artifactId>????????????<version>2.4</version>????????</dependency>????????<dependency>????????????<groupId>org.slf4j</groupId>????????????<artifactId>slf4j-api</artifactId>????????????<version>1.7.5</version>????????</dependency>????????<dependency>????????????<groupId>commons-lang</groupId>????????????<artifactId>commons-lang</artifactId>????????????<version>2.6</version>????????</dependency>????????<dependency>????????????<groupId>javax.servlet</groupId>????????????<artifactId>servlet-api</artifactId>????????????<version>2.5</version>????????????<scope>provided</scope>????????</dependency>????</dependencies></project>

使用了commons-io與commons-lang第三方類包

五、核心代碼開發(fā)(Web端)

作為Jar文件的使用端,只需要在web.xml中配置一個filter,就可以訪問到Jar中的資源。

1、web.xml

?
12345678910111213141516171819202122232425<web-app xmlns="http://java.sun.com/xml/ns/javaee"?????????xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"?????????xsi:schemaLocation="http://java.sun.com/xml/ns/javaee??????????http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"?????????version="2.5">????<display-name>jar resource web</display-name>????<filter>????????<filter-name>tagLibResourceFilter</filter-name>????????<filter-class>org.noahx.jarresource.TagLibResourceFilter</filter-class>????????<init-param>????????????<param-name>resourcePath</param-name>????????????<param-value>/tagres</param-value>????????</init-param>????</filter>????<filter-mapping>????????<filter-name>tagLibResourceFilter</filter-name>????????<url-pattern>/tagres/*</url-pattern>????</filter-mapping>????<welcome-file-list>????????<welcome-file>index.jsp</welcome-file>????</welcome-file-list></web-app>
注意:由于Servlet 3.0以下無法通過程序獲得url-pattern,所以在filter的參數(shù)中指定了一個同名路徑來使用。filter會用這個路徑名稱在Web工程下創(chuàng)建資源目錄(目錄部署)。

2、index.jsp(資源使用樣例,JS、CSS與圖片)

?
12345678910111213<%@ page contentType="text/html;charset=UTF-8" language="java" %><html><head>????<title></title>????<link rel="stylesheet" type="text/css" href="tagres/css.css" />????<script? type="text/javascript" src="tagres/example.js"></script></head><body>?????<img src="tagres/imgs/star-hover4.png" />star-hover4.png<br/>?????<button onclick="example();" >example.js (example)</button><br/>?????<div class="redbox">css.css redbox</div></body></html>

tagres/中的內(nèi)容就是Jar工程中所提供的資源。(下圖為顯示效果)

3、pom.xml

?
1234567891011121314151617181920212223242526272829<?xml version="1.0" encoding="UTF-8"?><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/xsd/maven-4.0.0.xsd">????<modelVersion>4.0.0</modelVersion>????<groupId>org.noahx.jarresource</groupId>????<artifactId>web</artifactId>????<version>1.0-SNAPSHOT</version>????<packaging>war</packaging>????<dependencies>????????<dependency>????????????<groupId>org.noahx.jarresource</groupId>????????????<artifactId>resource</artifactId>????????????<version>1.0-SNAPSHOT</version>????????</dependency>????????<dependency>????????????<groupId>org.slf4j</groupId>????????????<artifactId>slf4j-log4j12</artifactId>????????????<version>1.7.5</version>????????????<scope>runtime</scope>????????</dependency>????</dependencies></project>

六、Web工程兩種模式的Filter日志

1、目錄部署方式

?
1234567[JAR-RES] 2013-06-26 13:11:13,132 DEBUG [org.noahx.jarresource.TagLibResourceFilter] - create dir '/nautilus/develop/jar-resource/web/target/web-1.0-SNAPSHOT/tagres' (TagLibResourceFilter.java:93)[JAR-RES] 2013-06-26 13:11:13,146 DEBUG [org.noahx.jarresource.TagLibResourceFilter] - create dir '/nautilus/develop/jar-resource/web/target/web-1.0-SNAPSHOT/tagres/' (TagLibResourceFilter.java:240)[JAR-RES] 2013-06-26 13:11:13,147 DEBUG [org.noahx.jarresource.TagLibResourceFilter] - create dir '/nautilus/develop/jar-resource/web/target/web-1.0-SNAPSHOT/tagres/imgs' (TagLibResourceFilter.java:240)[JAR-RES] 2013-06-26 13:11:13,152 DEBUG [org.noahx.jarresource.TagLibResourceFilter] - copy jarfile to file 'org/noahx/jarresource/resource/imgs/star-hover4.png' --> '/nautilus/develop/jar-resource/web/target/web-1.0-SNAPSHOT/tagres' (TagLibResourceFilter.java:235)[JAR-RES] 2013-06-26 13:11:13,153 DEBUG [org.noahx.jarresource.TagLibResourceFilter] - copy jarfile to file 'org/noahx/jarresource/resource/example.js' --> '/nautilus/develop/jar-resource/web/target/web-1.0-SNAPSHOT/tagres' (TagLibResourceFilter.java:235)[JAR-RES] 2013-06-26 13:11:13,154 DEBUG [org.noahx.jarresource.TagLibResourceFilter] - copy jarfile to file 'org/noahx/jarresource/resource/css.css' --> '/nautilus/develop/jar-resource/web/target/web-1.0-SNAPSHOT/tagres' (TagLibResourceFilter.java:235)[JAR-RES] 2013-06-26 13:11:13,154 DEBUG [org.noahx.jarresource.TagLibResourceFilter] - ResourceMode:Dir (TagLibResourceFilter.java:111)

可以看到copy資源文件的過程

2、War包部署方式

?
1[JAR-RES] 2013-06-26 13:12:25,287 DEBUG [org.noahx.jarresource.TagLibResourceFilter] - ResourceMode:Jar (TagLibResourceFilter.java:111)
從Jar中直接讀取,并沒有copy資源的過程。

七、總結

這個Filter很好的解決了我在開發(fā)TagLib時遇到的資源引用問題,對我來說應該夠用了。

我們項目中一般采用目錄方式部署,我也更希望通過Web服務器來直接訪問資源。

并沒有采用maven來組織資源,因為我需要提供給非maven工程使用。

一些流行的mvc中也有類似的手法,可能是采用流方式讀取(猜測),感興趣的朋友可以查看這些mvc的代碼。

八、源程序下載

下載包中提供了源代碼以及打包后(target目錄)的工程。

http://sdrv.ms/11Mp5gF

總結

以上是生活随笔為你收集整理的以Jar形式为Web项目提供资源文件(JS、CSS与图片)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。