文档章节

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

闪电
 闪电
发布于 2015/05/16 20:32
字数 1447
阅读 83
收藏 1


 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://huangpengpeng.iteye.com/blog/2092189?utm_source=tuicool

闪电
粉丝 74
博文 392
码字总数 6789
作品 0
海淀
技术主管
私信 提问
ASP.NET Core Web 资源打包与压缩

在ASP.Net中可以使用打包与压缩这两种技术来提高Web应用程序页面加载的性能。通过减少从服务器请求的次数和减少资源文件的体积来提高加载性能。 打包是一地将多个文件(CSS,JavaScript等资源...

whltian
2018/12/29
0
0
记一次 React 项目的优化(webpack4 插件的使用)

这里记录了自己在开发一个 React 项目时使用 Webpack 优化项目的过程,欢迎大家围观点赞或吐槽。 学习 React 时候,写了个个人博客站点。使用 webpack 作为打包工具,在这之前学习 webpack ...

a独家记忆
2018/06/30
0
0
AspNetCore 静态资源的打包与压缩

以 Visual Studio Community 2017 15.5.1 为例 配置文件 bundleconfig.json 新建一个AspNetCore MVC项目,项目中会有一个文件,该文件就是静态资源打包与压缩的配置文件.通常文件的默认内容如下...

taadis
2017/12/08
0
0
如何利用webpack来提升前端开发效率(二)?

查漏补缺 通过如何利用webpack来提升前端开发效率(一)的学习,我们已经能够通过的和机制来处理各种文件资源。细心的小伙伴们发现了缺少了对字体文件和中标签的资源处理,那让我们先来解决这...

B2D1
01/21
0
0
SpringBoot 缓存&资源优化

页面缓存 1. freemarker 的页面静态化 application.properties 配置实现浏览器缓存 这段配置是用来启用资源缓存处理。 借鉴官方文档:https://docs.spring.io/spring-boot/docs/1.5.4.RELEA...

FantJ
2018/06/11
0
0

没有更多内容

加载失败,请刷新页面

加载更多

以太坊私有链搭建

https://blog.csdn.net/Blockchain_lemon/article/details/80589123

Moks角木
36分钟前
1
0
自律给我自信-为什么要自律

为什么要自律 混一天和努力一天 看不到任何差别 3天看不到任何变化 7天也看不到任何效果 但是 1个月后, 会看到话题不同 3个月后, 会看到气场不同 6个月后, 会看到距离不同 3年后, 会看到...

周大壮
36分钟前
1
0
读书replay计划说明

突然脑袋一闪,我有了这样一个主意:通过写博客的方式,将我阅读的书中的内容replay出来。 我一般会找着我感兴趣的书去读,一般也会读书中我感兴趣的章节,或者当下对我有用的章节,所以这个...

wanxiangming
38分钟前
0
0
CentOS7安装xrdp环境可实现远程桌面访问

CentOS7安装xrdp环境可实现远程桌面访问 2018-07-14 06:39:28 分类:运维 阅读(2051) 评论(0) 在"Ubuntu系统安装xrdp桌面客户端及实现远程连接桌面"文章中有分享过在Ubuntu系统中安装XRDP环境...

linjin200
今天
4
0
ConfigurationProperties

package cn.enjoy.config; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; @ConfigurationProperties(pr......

少年已不再年少
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部