`

maven 打包生产环境 压缩 JS 利用SpirngMVC扩展解决减少资源的请求数

阅读更多


 1.首先利用maven压缩js 和css 等资源文件

<build>
							<plugin>
					<groupId>net.alchim31.maven</groupId>
					<artifactId>yuicompressor-maven-plugin</artifactId>
					<version>1.4.0</version>
					<executions>
						<execution>
							<!-- 在真正的打包之前,执行一些准备打包压缩操作的操作  -->
							<phase>prepare-package</phase>
							<goals>
								<goal>compress</goal>
							</goals>
						</execution>
					</executions>
					<configuration>
						<encoding>UTF-8</encoding>
						<!-- 忽视 js 错误警告 -->
						<jswarn>false</jswarn>
						<nosuffix>true</nosuffix>
						<linebreakpos>-1</linebreakpos>
						<!-- 压缩的文件 工程里面所有的 js css 后缀的都会压缩 -->
						<includes>
							<include>**/*.js</include>
							<include>**/*.css</include>
						</includes>
						<!-- 不需要压缩的文件 -->
						<excludes>
							<exclude>**/style.css</exclude>
						</excludes>
						<failOnWarning>false</failOnWarning>
					</configuration>
				</plugin>
				<!-- 当压缩没有填写输出目录 或者 输出目录和压缩目录是同一路径时 一定要配合下面的使用  -->
				<plugin>
					<groupId>org.apache.maven.plugins</groupId>
					<artifactId>maven-war-plugin</artifactId>
					<configuration>
						<!-- 
							如果不增加此配置   src/main/webapp 下面的内容 会重新复制到target输出目录 覆盖掉编译后的内容
							这样编译的还是未压缩过的内容,增加上此过滤  打war包就不会内容覆盖
						 -->
						<warSourceExcludes>**/*.js,**/*.css</warSourceExcludes>
					</configuration>
				</plugin>
			</plugins>
		</build>

 2.通过SpringMvc扩展通过一个请求获取多个JS文件的功能

    2.1 spring MVC 配置

<bean id="simpleUrlHandlerMapping"  
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">  
<property name="urlMap">  
<map>  
<!-- 静态资源处理器 -->  
<entry key="/r/**/**">  
<!-- 自己扩展的SpingMVC ResourceHttpRequestHandler 类,增加了类是与淘宝CDN通过逗号(,)隔开    
访问多个js的效果 此功能不能压缩JS 如果想实现压缩功能可通过maven 或者 ant 在编译的时候进行压缩 -->  
<bean class="com.yoro.core.springmvc.ResourceHttpRequestHandler">  
<property name="locations">  
<list>  
<!-- 只有相同目录的JS文件才能实现淘宝CDN通过逗号(,)隔开 访问多个js的效果 如 /r/ 目录下的js|css 文件    
就能实现 /r/js/ 目录下的js文件也可以有同样的效果 但 /a/css 下面的文件 和 /r/css 就不能实现 有点小遗憾,因为时间关系待以后升级 -->  
<value>/r/</value>  
</list>  
</property>  
<!-- 启用静态资源浏览器缓存一个月 -->  
<!-- 通过浏览器进行的缓存 根据可浏览器实现方式不同有所差异 按刷新按扭缓存不会起 当是页面跳转或者地址栏输入则缓存会起作用 -->  
<!-- 更过浏览器缓存的资料和特效 可 搜索 cachecontrol 设置   cacheSeconds 缓存时间单位是秒  2592000 表示缓存30天 因为我自己每次新版本发布都会都js css 文件增加版本号 所以缓存时间我设置的比较长 -->  
<property name="cacheSeconds" value="2592000"></property>  
<property name="useExpiresHeader" value="true"></property>  
<property name="useCacheControlNoStore" value="true"></property>  
</bean>  
</entry>  
<entry key="/thirdparty/**/**">  
<bean class="com.yoro.core.springmvc.ResourceHttpRequestHandler">  
<property name="locations">  
<list>  
<value>/thirdparty/</value>  
</list>  
</property>  
<!-- 启用静态资源浏览器缓存一个月 -->  
<property name="cacheSeconds" value="2592000"></property>  
<property name="useExpiresHeader" value="true"></property>  
<property name="useCacheControlNoStore" value="true"></property>  
</bean>  
</entry>  
</map>  
</property>  
<property name="order" value="1"></property>  
</bean>  

 2.2 ResourceHttpRequestHandler  扩展类代码

 

package com.yoro.core.springmvc;   
  
import java.io.IOException;   
import java.io.InputStream;   
import java.io.OutputStream;   
import java.util.ArrayList;   
import java.util.Iterator;   
import java.util.List;   
  
import javax.activation.FileTypeMap;   
import javax.activation.MimetypesFileTypeMap;   
import javax.servlet.ServletException;   
import javax.servlet.http.HttpServletRequest;   
import javax.servlet.http.HttpServletResponse;   
  
import org.apache.commons.logging.Log;   
import org.apache.commons.logging.LogFactory;   
import org.springframework.beans.factory.InitializingBean;   
import org.springframework.core.io.ClassPathResource;   
import org.springframework.core.io.Resource;   
import org.springframework.http.MediaType;   
import org.springframework.util.Assert;   
import org.springframework.util.ClassUtils;   
import org.springframework.util.CollectionUtils;   
import org.springframework.util.StreamUtils;   
import org.springframework.util.StringUtils;   
import org.springframework.web.HttpRequestHandler;   
import org.springframework.web.context.request.ServletWebRequest;   
import org.springframework.web.servlet.HandlerMapping;   
import org.springframework.web.servlet.support.WebContentGenerator;   
  
public class ResourceHttpRequestHandler    
extends WebContentGenerator implements HttpRequestHandler, InitializingBean  {   
  
       
    private static final boolean jafPresent =   
            ClassUtils.isPresent("javax.activation.FileTypeMap", ResourceHttpRequestHandler.class.getClassLoader());   
  
    private final static Log logger = LogFactory.getLog(ResourceHttpRequestHandler.class);   
  
  
    private List<Resource> locations;   
  
  
    public ResourceHttpRequestHandler() {   
        super(METHOD_GET, METHOD_HEAD);   
    }   
  
    /**  
     * Set a {@code List} of {@code Resource} paths to use as sources  
     * for serving static resources.  
     */  
    public void setLocations(List<Resource> locations) {   
        Assert.notEmpty(locations, "Locations list must not be empty");   
        this.locations = locations;   
    }   
  
    @Override  
    public void afterPropertiesSet() throws Exception {   
        if (logger.isWarnEnabled() && CollectionUtils.isEmpty(this.locations)) {   
            logger.warn("Locations list is empty. No resources will be served");   
        }   
    }   
  
    @Override  
    public void handleRequest(HttpServletRequest request,   
            HttpServletResponse response) throws ServletException, IOException {   
  
        checkAndPrepare(request, response, true);   
  
        // check whether a matching resource exists   
        List<Resource> resources = getResources(request);   
        if (resources == null || resources.isEmpty()) {   
            logger.debug("No matching resource found - returning 404");   
            response.sendError(HttpServletResponse.SC_NOT_FOUND);   
            return;   
        }   
  
        // check the resource's media type   
        MediaType mediaType = getMediaType((String)request   
                .getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE));   
        if (mediaType != null) {   
            if (logger.isDebugEnabled()) {   
                logger.debug("Determined media type '" + mediaType + "' for "  
                        + resources.get(0));   
            }   
        } else {   
            if (logger.isDebugEnabled()) {   
                logger.debug("No media type found for " + resources.get(0)   
                        + " - not sending a content-type header");   
            }   
        }   
  
        for (Resource resource : resources) {   
            // header phase   
            if (!new ServletWebRequest(request, response)   
                    .checkNotModified(resource.lastModified())) {   
                logger.debug("Resource not modified - returning 304");   
                break;   
            }   
            return;   
        }   
  
        setHeaders(response, resources, mediaType);   
  
        // content phase   
        if (METHOD_HEAD.equals(request.getMethod())) {   
            logger.trace("HEAD request - skipping content");   
            return;   
        }   
        writeContent(response, resources);   
    }   
       
    protected MediaType getMediaType(String filename) {   
        MediaType mediaType = null;   
        String mimeType = getServletContext().getMimeType(filename);   
        if (StringUtils.hasText(mimeType)) {   
            mediaType = MediaType.parseMediaType(mimeType);   
        }   
        if (jafPresent && (mediaType == null || MediaType.APPLICATION_OCTET_STREAM.equals(mediaType))) {   
            MediaType jafMediaType = ActivationMediaTypeFactory.getMediaType(filename);   
            if (jafMediaType != null && !MediaType.APPLICATION_OCTET_STREAM.equals(jafMediaType)) {   
                mediaType = jafMediaType;   
            }   
        }   
        return mediaType;   
    }   
  
    protected void setHeaders(HttpServletResponse response,   
            List<Resource> resources, MediaType mediaType) throws IOException {   
        long length = 0;   
        //Calculation of multiple file length   
        Iterator<Resource> iter = resources.iterator();   
        while (iter.hasNext()) {   
            length += iter.next().contentLength();   
        }   
        if (length > Integer.MAX_VALUE) {   
            throw new IOException(   
                    "Resource content too long (beyond Integer.MAX_VALUE)");   
        }   
        response.setContentLength((int) length);   
        if (mediaType != null) {   
            response.setContentType(mediaType.toString());   
        }   
    }   
  
    protected void writeContent(HttpServletResponse response,   
            List<Resource> resourcess) throws IOException {   
        OutputStream out = response.getOutputStream();   
        InputStream in = null;   
        try {   
            for (Resource resource : resourcess) {   
                try {   
                    in = resource.getInputStream();   
                    StreamUtils.copy(in, out);   
                } finally {   
                    try {   
                        in.close();   
                    } catch (IOException ex) {   
                    }   
                }   
            }   
        } finally {   
            try {   
                out.close();   
            } catch (IOException ex) {   
            }   
        }   
    }   
  
    protected List<Resource> getResources(HttpServletRequest request) {   
        String path = (String) request   
                .getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);   
        if (path == null) {   
            throw new IllegalStateException("Required request attribute '"  
                    + HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE   
                    + "' is not set");   
        }   
  
        if (!StringUtils.hasText(path) || isInvalidPath(path)) {   
            if (logger.isDebugEnabled()) {   
                logger.debug("Ignoring invalid resource path [" + path + "]");   
            }   
            return null;   
        }   
  
        for (Resource location : this.locations) {   
            try {   
                if (logger.isDebugEnabled()) {   
                    logger.debug("Trying relative path [" + path   
                            + "] against base location: " + location);   
                }   
                List<Resource> rs = new ArrayList<Resource>();   
                String[] paths = path.split(",");   
                for (String url : paths) {   
                    Resource resource = location.createRelative(url);   
                    if (resource.exists() && resource.isReadable()) {   
                        rs.add(resource);   
                    }   
                }   
                return rs;   
            } catch (IOException ex) {   
                logger.debug(   
                        "Failed to create relative resource - trying next resource location",   
                        ex);   
            }   
        }   
        return null;   
    }   
       
    /**  
     * Validates the given path: returns {@code true} if the given path is not a valid resource path.  
     * <p>The default implementation rejects paths containing "WEB-INF" or "META-INF" as well as paths  
     * with relative paths ("../") that result in access of a parent directory.  
     * @param path the path to validate  
     * @return {@code true} if the path has been recognized as invalid, {@code false} otherwise  
     */  
    protected boolean isInvalidPath(String path) {   
        return (path.contains("WEB-INF") || path.contains("META-INF") || StringUtils.cleanPath(path).startsWith(".."));   
    }   
  
    /**  
     * Inner class to avoid hard-coded JAF dependency.  
     */  
    private static class ActivationMediaTypeFactory {   
  
        private static final FileTypeMap fileTypeMap;   
  
        static {   
            fileTypeMap = loadFileTypeMapFromContextSupportModule();   
        }   
  
        private static FileTypeMap loadFileTypeMapFromContextSupportModule() {   
            // see if we can find the extended mime.types from the context-support module   
            Resource mappingLocation = new ClassPathResource("org/springframework/mail/javamail/mime.types");   
            if (mappingLocation.exists()) {   
                InputStream inputStream = null;   
                try {   
                    inputStream = mappingLocation.getInputStream();   
                    return new MimetypesFileTypeMap(inputStream);   
                }   
                catch (IOException ex) {   
                    // ignore   
                }   
                finally {   
                    if (inputStream != null) {   
                        try {   
                            inputStream.close();   
                        }   
                        catch (IOException ex) {   
                            // ignore   
                        }   
                    }   
                }   
            }   
            return FileTypeMap.getDefaultFileTypeMap();   
        }   
  
        public static MediaType getMediaType(String filename) {   
            String mediaType = fileTypeMap.getContentType(filename);   
            return (StringUtils.hasText(mediaType) ? MediaType.parseMediaType(mediaType) : null);   
        }   
    }   
}  

 2.3 资源文件目录结构



 2.4  浏览器缓存效果

 

 2.5

 5.实现淘宝CDN JS 请求例子

JS例子:http://127.0.0.1/r/js/alert.js,/js/application.js,/js/bootstrap.js

CSS例子:http://127.0.1.1/r/css/activity_style.css,/css/bootstrap_responsive.css

通过逗号(,)分割他们现在就实现了通过一个请求加载多个资源文件的效果了

 

   不介意的可以进入我的店铺看下增加点人气 http://qc5z.taobao.com/

  • 大小: 114.2 KB
  • 大小: 258.2 KB
  • 大小: 285.7 KB
5
1
分享到:
评论
9 楼 LinApex 2014-08-02  
huangpengpeng 写道
LinApex 写道
项目例子发个demo看看吧

最近有点忙,把博客放下了,过两天我整个demo放上来


错了,坐等代码..~~
8 楼 LinApex 2014-08-02  
huangpengpeng 写道
LinApex 写道
项目例子发个demo看看吧

最近有点忙,把博客放下了,过两天我整个demo放上来


朋友更新了吗? 坐等更新
7 楼 c15836 2014-08-01  
一个请求获取多个JS文件,这个我按照你的,怎么没用啊!浏览器里直接访问的是http://127.0.0.1/r/js/alert.js,/js/application.js,/js/bootstrap.js,而没有按,分隔,进行加载啊!
6 楼 LinApex 2014-07-23  
huangpengpeng 写道
LinApex 写道
项目例子发个demo看看吧

最近有点忙,把博客放下了,过两天我整个demo放上来


好的,等你哦。

大家对这个都很有兴趣.
5 楼 huangpengpeng 2014-07-23  
LinApex 写道
项目例子发个demo看看吧

最近有点忙,把博客放下了,过两天我整个demo放上来
4 楼 LinApex 2014-07-18  
项目例子发个demo看看吧
3 楼 LinApex 2014-07-18  
朋友,没有看懂
2 楼 asialee 2014-07-16  
原来yui自己实现插件了不错。
1 楼 njbble 2014-07-16  
一直很想研究如何做到压缩的,感谢分享,回去后研究研究

相关推荐

    maven打包使用yui压缩css和js文件

    在现代Web开发中,优化网页性能是至关重要的,其中一项策略就是对CSS和JavaScript文件进行压缩,以减少页面加载时间。Maven作为一个强大的Java项目管理工具,提供了与各种构建优化工具集成的能力,其中包括使用YUI ...

    maven打包出错解决办法,亲测绝对可以!

    本篇文章将详细阐述如何解决Maven打包出错的问题,并分享一些关于搭建Maven私服的知识。 一、Maven打包出错常见原因及解决办法 1. **依赖冲突**:当项目中的多个库引用了不同版本的同一个依赖时,可能导致冲突。...

    maven 过滤文件夹打包

    "maven 过滤文件夹打包"这个主题涉及到的是如何利用Maven的资源过滤功能来实现针对不同运行环境的配置文件打包。下面将详细解释这一过程。 在开发环境中,我们通常会有多种配置文件,比如`application-dev....

    springboot实现maven打包加载不同环境的方式二

    当前案例中包含一整套的代码和word文档,非常适合新手... 主要是通过maven打包加载不同环境的properties文件 然后将对于的属性绑定到指定的实体对象中;然后通过调用接口可以看到加载不同环境控制台打印的内容是不一样的

    maven打包 maven打jar包详细步骤

    本文将详细讲解如何使用Maven来打包一个Java项目,并创建JAR文件。 首先,Maven有三个主要生命周期阶段:`clean`、`default`(也称为`compile`)和`install`。每个阶段包含一系列的阶段(或者称为目标,如`compile`...

    Maven打包,指定classes路径

    以上就是关于"Maven打包,指定classes路径"的知识点,主要涉及到Maven的资源配置和插件定制。理解并掌握这些配置可以帮助开发者更高效地管理和构建Java Web应用。同时,记得在实际项目中根据实际情况调整`pom.xml`,...

    sprintboot maven 打包分离lib jar 资源文件 properties xml yml

    sprintboot maven 打包分离lib jar 资源文件 properties xml yml 详细信息查看我的博客 https://mp.csdn.net/postedit/80274087 java -jar -cp 启动

    maven+bat打包

    "maven+bat打包"是指使用Apache Maven,一个流行的Java项目管理工具,结合批处理脚本(BAT)来自动化项目的打包过程。这种方式可以极大地提高开发效率,确保每次构建的一致性和可重复性。下面将详细介绍这个过程及其...

    maven多环境配置打包

    【标题】:“maven多环境配置打包” 在Java开发中,常常需要针对不同的运行环境(如开发、测试、生产)进行不同的配置。Maven作为Java项目管理的重要工具,提供了强大的多环境配置打包功能,帮助开发者有效地管理和...

    Maven打包实战.zip

    本压缩包文件“Maven打包实战.zip”提供了关于Maven打包的实战教程,配合文章《Maven打包实战》(链接已提供)学习,将有助于深入理解Maven的打包流程。 首先,我们需要理解Maven的生命周期。Maven生命周期包括三个...

    springboot+maven打包demo【将依赖与配置文件打包到jar包外部】

    Maven的插件系统允许我们扩展其功能,例如打包、测试、部署等。 在Spring Boot项目中,通常依赖会被打包到最终的jar文件内部,这在大多数情况下是没问题的。但有时,为了方便部署和管理,我们希望依赖和配置文件...

    Maven发布Jar包中文乱码解决方法

    Maven发布Jar包中文乱码解决方法 Maven 是一个基于项目对象模型(Project Object Model,POM)的项目管理工具,广泛应用于 Java 项目的构建、测试和打包。然而,在使用 Maven 发布 Jar 包时,ometimes 中文字符会...

    如何用IntelliJ IDEA新建web项目,用maven打包成.jar

    idea新建maven web项目.zip Jetbrains IntelliJ IDEA创建基于maven打包工具的WEB网站项目 本项目使用的是SSM框架spring mvc,spring, mybatis.用maven打包成jar

    jasperreport maven打包后找不到字体解决方案

    jasperreport 用maven打包后找不到字体解决方案 net.sf.jasperreports.engine.JRRuntimeException: Could not load the following font

    Java+IDEA+Maven混淆打包

    本教程将详细讲解如何在IntelliJ IDEA(IDEA)中利用Maven进行混淆打包,确保代码的安全性并提高可维护性。 首先,让我们了解一下涉及的工具和技术: 1. **Java**: 一种广泛使用的面向对象的编程语言,用于构建跨...

    Java+IDEA+maven混淆打包

    本教程将详细介绍如何在IntelliJ IDEA(IDEA)中利用Maven进行混淆打包的步骤,确保整个过程顺利且有效。 首先,我们需要了解Maven,它是一个强大的项目管理和依赖管理工具。通过在`pom.xml`文件中配置,我们可以...

    maven+yui压缩js,css文件

    标题与描述概述的知识点是关于如何使用Maven与YUI Compressor插件来压缩JavaScript(JS)和CSS文件。在大型项目中,压缩这些文件可以显著减少加载时间,提高网站性能,同时也便于资源的管理。 ### Maven与YUI ...

    Maven自动升级版本号并打包上传的脚本

    总之,Maven自动升级版本号并打包上传的脚本是提高开发效率的有效手段,它减少了手动操作,确保了构建过程的可重复性和一致性。通过理解和运用这些知识点,开发者可以更好地管理和维护自己的Maven项目。

    maven3.5.4打包文件

    3. **插件系统**:Maven 插件机制允许扩展其功能,覆盖编译、测试、打包、部署等任务,例如使用 `maven-surefire-plugin` 进行单元测试,`maven-jar-plugin` 创建 JAR 包等。 4. **项目对象模型(POM)**:POM.xml ...

Global site tag (gtag.js) - Google Analytics