优化前:
基本上所有的jsp都引用了这一大坨静态文件:

<link rel="stylesheet" type="text/css" href="${ctxPath}/css/skin.css"/>
<link rel="stylesheet" type="text/css" href="${ctxPath}/css/jquery-ui-1.8.23.custom.css"/>
<link rel="stylesheet" type="text/css" href="${ctxPath}/css/validationEngine.jquery.css"/><script type="text/javascript">var GV = {ctxPath: '${ctxPath}',imgPath: '${ctxPath}/css'};</script>
<script type="text/javascript" src="${ctxPath}/js/jquery-1.7.2.min.js"></script>
<script type="text/javascript" src="${ctxPath}/js/jquery-ui-1.8.23.custom.min.js"></script>
<script type="text/javascript" src="${ctxPath}/js/jquery.validationEngine.js"></script>
<script type="text/javascript" src="${ctxPath}/js/jquery.validationEngine-zh_CN.js"></script>
<script type="text/javascript" src="${ctxPath}/js/jquery.fixedtableheader.min.js"></script>
<script type="text/javascript" src="${ctxPath}/js/roll.js"></script>
<script type="text/javascript" src="${ctxPath}/js/jquery.pagination.js"></script>
<script type="text/javascript" src="${ctxPath}/js/jquery.rooFixed.js"></script>
<script type="text/javascript" src="${ctxPath}/js/jquery.ui.datepicker-zh-CN.js"></script>
<script type="text/javascript" src="${ctxPath}/js/json2.js"></script>
<script type="text/javascript" src="${ctxPath}/js/common.js"></script>

引用的文件很多,并且文件体积没有压缩,导致页面请求的时间非常长.

另外还有一个问题,就是为了能够充分利用浏览器的缓存,静态资源的文件名称最好能够做到版本化控制.

这样前端web服务器就可以放心大胆的开启缓存功能而不用担心缓存过期问题,因为如果一旦静态资源文件有修改的话,
会重新生成一个文件名称.

分两步进行.

第一步:引入wro4j,在编译时期将上述分散的多个文件整合成少数几个文件,并且将文件最小化.

第二步:在生成的静态资源文件的文件名称上加入时间信息

这是两步优化之后的引用情况:

${platform:cssFile("/wro/basic") }
<script type="text/javascript">var GV = {ctxPath: '${ctxPath}',imgPath: '${ctxPath}/css'};</script>
${platform:jsFile("/wro/basic") }
${platform:jsFile("/wro/custom") }

只引用了1个css文件,2个js文件.http请求从10几个减少到3个,并且整体文件体积缩小了近一半.

下面介绍优化流程.

第一步:合并并且最小化文件.

1.添加wro4j的maven依赖

 <wro4j.version>1.6.2</wro4j.version><dependency><groupId>ro.isdc.wro4j</groupId><artifactId>wro4j-core</artifactId><version>${wro4j.version}</version><exclusions><exclusion><!-- 因为项目中的其他jar包已经引入了不同版本的slf4j,所以这里避免jar重叠所以不引入 --><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId></exclusion></exclusions></dependency>

2.添加wro4j maven plugin

   <plugin><groupId>ro.isdc.wro4j</groupId><artifactId>wro4j-maven-plugin</artifactId><version>${wro4j.version}</version><executions><execution><phase>compile</phase><goals><goal>run</goal></goals></execution></executions><configuration><targetGroups>basic,custom</targetGroups><!-- 这个配置是告诉wro4j在打包静态资源的时候是否需要最小化文件,开发的时候可以设成false,方便调试 --><minimize>true</minimize><destinationFolder>${basedir}/src/main/webapp/wro/</destinationFolder><contextFolder>${basedir}/src/main/webapp/</contextFolder><!-- 这个配置是第二步优化需要用到的,暂时忽略 --><wroManagerFactory>com.rootrip.platform.common.web.wro.CustomWroManagerFactory</wroManagerFactory></configuration></plugin>

如果开发环境是eclipse的话,可以下载m2e-wro4j这个插件.

下载地址:http://download.jboss.org/jbosstools/updates/m2e-wro4j/

这个插件的主要功能是能够帮助我们在开发环境下修改对应的静态文件,或者pom.xml文件的时候能够自动生成打包好的js和css文件.

对开发来说就会方便很多.只要修改源文件就能看见修改后的结果.

3.在WEB-INF目录下添加wro.xml文件,这个文件的作用就是告诉wro4j需要以怎样的策略打包jss和css文件.

<?xml version="1.0" encoding="UTF-8"?>
<groups xmlns="http://www.isdc.ro/wro" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.isdc.ro/wro wro.xsd"><group name="basic"><css>/css/basic.css</css><css>/css/skin.css</css><css>/css/jquery-ui-1.8.23.custom.css</css><css>/css/validationEngine.jquery.css</css><js>/js/jquery-1.7.2.min.js</js><js>/js/jquery-ui-1.8.23.custom.min.js</js><js>/js/jquery.validationEngine.js</js><js>/js/jquery.fixedtableheader.min.js</js><js>/js/roll.js</js><js>/js/jquery.pagination.js</js><js>/js/jquery.rooFixed.js</js><js>/js/jquery.ui.datepicker-zh-CN.js</js><js>/js/json2.js</js></group><group name="custom"><js>/js/jquery.validationEngine-zh_CN.js</js><js>/js/common.js</js></group></groups>

官方文档:http://code.google.com/p/wro4j/wiki/WroFileFormat

其实这个配置文件很好理解,如果不愿看官方文档的朋友我在这简单介绍下.

上面这样配置的目的就是告诉wro4j要将

/css/basic.css
/css/skin.css
/css/jquery-ui-1.8.23.custom.css
/css/validationEngine.jquery.css

这四个文件整合到一起,生成一个叫basic.css的文件到指定目录(wro4j-maven-plugin里配置的),将

/js/jquery-1.7.2.min.js
/js/jquery-ui-1.8.23.custom.min.js
/js/jquery.validationEngine.js
/js/jquery.fixedtableheader.min.js
/js/roll.js
/js/jquery.pagination.js
/js/jquery.rooFixed.js
/js/jquery.ui.datepicker-zh-CN.js
/js/json2.js

这几个文件整合到一起,生成一个叫basic.js的文件到指定目录.

最后将

/js/jquery.validationEngine-zh_CN.js
/js/common.js

这两个文件整合到一起,,生成一个叫custom.js的文件到指定目录.

第一步搞定,这时候如果你的开发环境是eclipse并且安装了插件的话,应该就能在你工程的%your webapp%/wor/目录下看见生成好的

basic.css,basic.js和custom.js这三个文件了.

然后你再将你的静态资源引用路径改成

<link rel="stylesheet" type="text/css" href="${ctxPath}/wro/basic.css"/>
<script type="text/javascript" src="${ctxPath}/wro/basic.js"></script>
<script type="text/javascript" src="${ctxPath}/wro/custom.js"></script>

就ok了.每次修改被引用到的css或js文件的时候,这些文件都将重新生成.

如果开发环境是eclipse但是没有安装m2e-wro4j插件的话,pom.xml可能需要额外配置.

第二步:给生成的文件名称中加入时间信息并通过el自定义函数引用脚本文件.

  1. 创建DailyNamingStrategy类
public class DailyNamingStrategy extends TimestampNamingStrategy {protected final Logger log = LoggerFactory.getLogger(DailyNamingStrategy.class);@Overrideprotected long getTimestamp() {String dateStr = DateUtil.formatDate(new Date(), "yyyyMMddHH");return Long.valueOf(dateStr);}}

2.创建CustomWroManagerFactory类

//这个类就是在wro4j-maven-plugin里配置的wroManagerFactory参数
public class CustomWroManagerFactory extendsDefaultStandaloneContextAwareManagerFactory {public CustomWroManagerFactory() {setNamingStrategy(new DailyNamingStrategy());}
}

上面这两个类的作用是使用wro4j提供的文件命名策略,这样生成的文件名就会带上时间信息了.

例如:basic-2013020217.js

但是现在又会发现一个问题:如果静态资源文件名称不固定的话,那怎么样引用呢?

这时候就需要通过动态生成script与link来解决了.

因为项目使用的是jsp页面,所以通过el自定义函数来实现标签生成.

3.创建PlatformFunction类

public class PlatformFunction {private static Logger log = LoggerFactory.getLogger(PlatformFunction.class);private static ConcurrentMap<String, String> staticFileCache = new ConcurrentHashMap<>();private static AtomicBoolean initialized = new AtomicBoolean(false);private static final String WRO_Path = "/wro/";private static final String JS_SCRIPT = "<script type=\"text/javascript\" src=\"%s\"></script>";private static final String CSS_SCRIPT = "<link rel=\"stylesheet\" type=\"text/css\" href=\"%s\">";private static String contextPath = null; /*** 该方法根据给出的路径,生成js脚本加载标签* 例如传入参数/wro/custom,该方法会寻找webapp路径下/wro目录中以custom开头,以js后缀结尾的文件名称名称.* 然后拼成<script type="text/javascript" src="${ctxPath}/wro/custom-20130201.js"></script>返回* 如果查找到多个文件,返回根据文件名排序最大的文件* @param str* @return*/public static String jsFile(String filePath) {String jsFile = staticFileCache.get(buildCacheKey(filePath, "js"));if(jsFile == null) {log.error("加载js文件失败,缓存中找不到对应的文件[{}]", filePath);}return String.format(JS_SCRIPT, jsFile);}/*** 该方法根据给出的路径,生成css脚本加载标签* 例如传入参数/wro/custom,该方法会寻找webapp路径下/wro目录中以custom开头,以css后缀结尾的文件名称名称.* 然后拼成<link rel="stylesheet" type="text/css" href="${ctxPath}/wro/basic-20130201.css">返回* 如果查找到多个文件,返回根据文件名排序最大的文件* @param str* @return*/public static String cssFile(String filePath) {String cssFile = staticFileCache.get(buildCacheKey(filePath, "css"));if(cssFile == null) {log.error("加载css文件失败,缓存中找不到对应的文件[{}]", filePath);}return String.format(CSS_SCRIPT, cssFile);}public static void init() throws IOException {if(initialized.compareAndSet(false, true)) {ServletContext sc = Platform.getInstance().getServletContext();if(sc == null) {throw new PlatformException("查找静态资源的时候的时候发现servlet context 为null");}contextPath = Platform.getInstance().getContextPath();File wroDirectory = new ServletContextResource(sc, WRO_Path).getFile();if(!wroDirectory.exists() || !wroDirectory.isDirectory()) {throw new PlatformException("查找静态资源的时候发现对应目录不存在[" + wroDirectory.getAbsolutePath() + "]");}//将wro目录下已有文件加入缓存for(File file : wroDirectory.listFiles()) {handleNewFile(file);}//监控wro目录,如果有文件生成,则判断是否是较新的文件,是的话则把文件名加入缓存new Thread(new WroFileWatcher(wroDirectory.getAbsolutePath())).start();}}private static void handleNewFile(File file) {String fileName = file.getName();Pattern p = Pattern.compile("^(\\w+)\\-\\d+\\.(js|css)$");Matcher m = p.matcher(fileName);if(!m.find() || m.groupCount() < 2) return;String fakeName = m.group(1);String fileType = m.group(2);//暂时限定只能匹配/wro/目录下的文件String key = buildCacheKey(WRO_Path + fakeName, fileType);if(staticFileCache.putIfAbsent(key, fileName) != null) {synchronized(staticFileCache) {String cachedFileName = staticFileCache.get(key);if(fileName.compareTo(cachedFileName) > 0) {staticFileCache.put(key, contextPath + WRO_Path + fileName);}}}}private static String buildCacheKey(String fakeName, String fileType) {return fakeName + "-" + fileType;}static class WroFileWatcher implements Runnable {private static Logger log = LoggerFactory.getLogger(WroFileWatcher.class);private String wroAbsolutePathStr;public WroFileWatcher(String wroPathStr) {this.wroAbsolutePathStr = wroPathStr;}@Overridepublic void run() {Path path = Paths.get(wroAbsolutePathStr);File wroDirectory = path.toFile();if(!wroDirectory.exists() || !wroDirectory.isDirectory()) {String message = "监控wro目录的时候发现对应目录不存在[" + wroAbsolutePathStr + "]";log.error(message);throw new PlatformException(message);}log.warn("开始监控wro目录[{}]", wroAbsolutePathStr);try {WatchService watcher = FileSystems.getDefault().newWatchService();path.register(watcher, StandardWatchEventKinds.ENTRY_CREATE);while (true) {WatchKey key = null;try {key = watcher.take();} catch (InterruptedException e) {log.error("", e);continue;}for (WatchEvent<?> event : key.pollEvents()) {if (event.kind() == StandardWatchEventKinds.OVERFLOW) {continue;}WatchEvent<Path> e = (WatchEvent<Path>) event;Path filePath = e.context();handleNewFile(filePath.toFile());}if (!key.reset()) {break;}}} catch (IOException e) {log.error("监控wro目录发生错误", e);}log.warn("停止监控wro目录[{}]", wroAbsolutePathStr);}}
}

对应的tld文件就不给出了,根据方法签名编写就行了.

其中的cssFile和jsFile方法分别实现引用css和js文件.

在页面使用的时候类似这样:

${platform:cssFile(“/wro/basic”) }

${platform:jsFile(“/wro/custom”) }

这个类的主要功能就是使用jdk7的WatchService监控wro目录的新增文件事件,

一旦有新的文件加到目录里,判断这个文件是不是最新的,如果是的话则使用这个文件名称引用.

这样一旦有新加的资源文件放到wro目录里,则能够自动被引用,不需要做任何代码上的修改,并且基本不影响性能.

到此为止功能已经实现.

但是我考虑到还有两个问题有待完善:

1.因为生成的文件名称精确到小时,如果这个小时之内有多次代码修改,生成的文件名都完全一样.

这样就算线上的代码有修改,对于已经有该文本缓存的浏览器来说,不会重新请求文件,也就看不到文件变化.

不过一般来说线上代码不会如此频繁改动,对于大多数应用来说影响不大.

2.在开发环境开发一段时间之后,wro目录下会生成一大堆的文件(因为m2e-wro4j插件在生成新的文件的时候不会删除旧文件,如果文件名相同会覆盖掉以前的文件),

这时候就需要手动删除时间靠前的旧文件,虽然系统会忽略旧文件,但是我相信大多数程序员和我一样是有些许洁癖的吧.

解决办法还是不少,比如可以写脚本定期清理掉旧文件.

wro4j和maven plugin在编译期间压缩静态资源.相关推荐

  1. wro4j和maven plugin在编译期间压缩静态资源

    优化前:  基本上所有的jsp都引用了这一大坨静态文件: <link rel="stylesheet" type="text/css" href=&quo ...

  2. maven js css 压缩,使用wro4j和maven在编译期间压缩js和css文件(经典)

    最近在对一个web系统做性能优化. 而对用到的静态资源文件的压缩整合则是前端性能优化中很重要的一环. 好处不仅在于能够减小请求的文件体积,而且能够减少浏览器的http请求数. 因为是基于java的we ...

  3. 使用wro4j和maven在编译期间压缩js和css文件

    最近在对一个web系统做性能优化. 而对用到的静态资源文件的压缩整合则是前端性能优化中很重要的一环. 好处不仅在于能够减小请求的文件体积,而且能够减少浏览器的http请求数. 因为是基于java的we ...

  4. ResourceDictionary主题资源替换(二) :编译期间,替换主题资源

    之前的ResourceDictionary主题资源替换(一)通过加载顺序来覆盖之前的主题资源,介绍了WPF框架对ResourceDictionary资源的合并规则. 此篇介绍一种在编译期间,实现资源替 ...

  5. Hexo瞎折腾系列(5) - 使用hexo-neat插件压缩页面静态资源

    为什么要压缩页面静态资源 对于个人博客来说,优化页面的访问速度是很有必要的,如果打开你的个人站点,加载个首页就要十几秒,页面长时间处于空白状态,想必没什么人能够忍受得了吧.我个人觉得,如果能把页面的加 ...

  6. Hexo文件压缩:使用hexo-neat插件压缩页面静态资源

    目录 为什么要压缩页面静态资源 hexo的压缩静态资源插件 如何使用hexo-neat 在站点根目录下安装hexo-neat 为站点配置文件添加相关配置 hexo-neat插件踩坑记录 跳过压缩文件的 ...

  7. nginx静态资源压缩

    概述 nginx作为一个代理服务器,可以进行很多比较灵活的优化措施,其中就包括了资源的压缩优化: 当客户端去请求服务器的资源时,是经过HTTP协议进行网络数据传输的,其中网络是客户端请求服务器的最大消 ...

  8. Versions maven plugin 修改版本

    文章目录 版本控制 修改全模块版本号 修改模块版本 修改指定模块版本号 参数介绍 代码经过长期修改后,版本号却从没有推进,导致个别release稳定版的模块更新代码之后,其他开发机器并不会自动更新本地 ...

  9. org.springframework.boot:spring boot maven plugin丢失---SpringCloud Alibaba_若依微服务框架改造_--工作笔记012

    警告]"build.plugins.plugin.version"for org.springframework.boot:spring boot maven plugin丢失. ...

最新文章

  1. 简单客户端服务器模型(C++、python和go语言示例)
  2. NYOJ 745 蚂蚁问题(两)
  3. (char*)x C语言中的和*的详解
  4. python tcp协议加代理_python实现简单的TCP代理服务器
  5. 一个设计错误导致的很那发现的错误
  6. 阿里云mysql 日志_mysql日志-阿里云开发者社区
  7. 【转】浮点数之间的比较
  8. redis 模糊查找keys
  9. 实例讲解Nginx下的rewrite规则 来源:Linux社区
  10. 又一个脑洞实现了!索尼将推出穿在身上的空调:夏日出门必备
  11. 条件编译#define、#undef、#if、#elif、#elif defined、#elif !defined 、#endif用法
  12. cass插件_第009期分享:Cass插件合集
  13. HDU4628+状态压缩DP
  14. Atitit Hadoop的MapReduce的执行过程、数据流的一点理解。 目录 1. Why 为什么使用hadoop 1 2. Hadoop的MapReduce的执行过程 1 2.1. Had
  15. 详解如何在数仓中管理元数据(文末彩蛋~)
  16. 几个最新免费开源的中文语音数据集
  17. 如何把桌面路径设置到D盘
  18. 使用nat123动态解析公网ip
  19. 传苹果将采用:夏普IGZO技术面板量产
  20. BugkuCTF_Web——“秋名山老司机”、“速度要快”、“cookies欺骗”

热门文章

  1. pythonDay5-基本语法-中文编码-多行语句连接-输入输出-个人名片制作-类型之间的转换-判断用户的年龄
  2. 潮水退去 你还是那个让HR离不开的猎头吗
  3. teradata ttu_【Teradata TTU】Windows TTU安装工具列表,
  4. docker+nginx+tomcat*3在华为云服务器上的负载均衡
  5. 腾讯与360诉讼陷入拉锯战:敬畏同时余火未熄
  6. 《Mysql实战45讲》学习笔记 1-22
  7. 白鲸开源代立冬:一年5个孵化项目来自于中国,佛系Apache如何帮助中国开源立足全球?
  8. python输出素数5个一排_python如何输出质数
  9. 白侠机器人_白侠微信多群直播机器人,引领全新直播潮流
  10. 三维叉乘怎么算_自然资源管理,三维GIS能做什么?