管理Web应用静态资源一招鲜

在Grails应用的CSS中,通过使用Groovy中的${}

Kevin M. Gill在他的博文Preprocessing CSS in Grails以及Improve Grails Performance With Static Resources中,跟我们分享了在Grails应用的CSS中如何简化对静态资源管理的方法。

Web开发时,总会需要在CSS中修改静态资源的路径,比如图片。如果资源数量巨大,就需要大量的重复的替换工作,这样还容易出现错误。这时,想到Groovy中的${},如果CSS中能使用${},将图片的存放位置放在配置文件或者数据库中进行统一管理。一旦遇到图片存放路径发生改变的情况,只需要修改几处或者仅仅一处的位置信息就可以了,岂不是很方便?

在使用CSS时,如果设定背景图之类的内容,通常是如下写法:

.some_div {
    ...
    background: url('http://localhost:8080/GrailsUI/static/img/grails_logo.png');
    ...
  }

或者将图片的位置写成相对位置,比如:

.some_div {
    ...
    background: url('../static/img/grails_logo.png');
    ...
  }

下面来看看具体实现步骤!

  1. 先将原先的CSS文件进行改造,见如下代码:
    .some_div {
        ...
        background: url(${groovyq.staticResource(dir:"/img/",
    	file:"grails_logo.png")});
        ...
        
      }
  2. 在%GrailsApp%/grails-app/taglib目录下创建一个TagLib,来设定groovyq.staticResource要执行的内容,见如下代码:
    class StaticResourcesTagLib {
      static namespace = "groovyq"    
      def grailsApplication    
      def staticResource = { attrs, body ->
        def dir = (attrs.dir) ? attrs.dir : ""
        def file = (attrs.file) ? attrs.file : ""        
        def url="${grailsApplication.config.myapp.staticresources.url}" +
           "/${dir}/${file}"
         out << body() << url
      }
    }
  3. 在%GrailsApp%/grails-app/config.groovy文件中添加:myapp.staticresources.url = "http://localhost:8080/GrailsUI/static",用来指定静态资源的路径。
  4. 添加一个名为StaticResource的Controller,用来装入CSS和处理CSS文件中的${}中的内容。StaticResourceController的全部代码如下:
    class StaticResourceController {    
        def groovyPagesTemplateEngine     
        def css = {
            def file = params.id        
            def cssPath = servletContext.getRealPath("css/${file}.css")
            def resourceFile = new File(cssPath)
            if (!resourceFile.exists()) {
                // 404: Not Found
                render(text:"File Not Found",status:404)
                return
            }        
            def buffer = null
            try {
                buffer = processTemplate(resourceFile, params)
            } catch (Exception ex) {
                log.error "Failed to process template", ex
            }
            
            if (buffer != null) {
                render(text:buffer, contentType:"text/css")
            } else {
                // 500: Internal Server Error
                render(text:"Failed to process template", status:500)
            }        
        }    
        def processTemplate(resourceFile, model) {    
            def buffer = resourceFile.getText()
            def template = groovyPagesTemplateEngine.createTemplate(buffer,
    		"${resourceFile.getPath()}")
            def writer = new StringWriter()
            template.make(model).writeTo(writer)
            return writer.toString()
        }
    }
  5. 修改gsp页面中对CSS的引用: ,这句代码会根据/staticResource/css调用StaticResourceController中css这个闭包,而pcss则是这个闭包中需要用到的file的值。这样就可以了!
  6. 如果静态资源很多,通过StaticResourceController装入这些资源是很耗费内存的,可以在StaticResourceController中进行一些Cache的控制。见如下css闭包的代码:
    def css = {
        def file = params.id        
        def cssPath = servletContext.getRealPath("css/${file}.css")        
        def resourceFile = new File(cssPath)        
        if (!resourceFile.exists()) {
            render(text:"File Not Found",status:404)
            return
        }
            
        def ifModifiedSince = request.getHeader("If-Modified-Since")
        
        if (ifModifiedSince) {
            String[] formats = [DateUtils.PATTERN_ASCTIME,
    		DateUtils.PATTERN_RFC1036, DateUtils.PATTERN_RFC1123]
            def dt_ifModifiedSince = DateUtils.parseDate(ifModifiedSince,
    		formats)
                
            long lastMod = (long) (resourceFile.lastModified() / 1000)
            long isModSince = (long) (dt_ifModifiedSince.getTime() / 1000)
            if (lastMod <= isModSince) {
                render (status:304)
                return
            }
               
        }
            
        def now = new Date(System.currentTimeMillis() + (2693000L * 1000))
        
        response.setHeader("Expires", DateUtils.formatDate(now, 
    	DateUtils.PATTERN_RFC1123))
        response.setHeader("Cache-Control", "public")
        response.setHeader("Vary", "Accept-Encoding")
                   
        response.addHeader("Last-Modified", 
    	DateUtils.formatDate(new Date(resourceFile.lastModified()), 
    	DateUtils.PATTERN_RFC1123))
           
        def buffer = null
        try {
            buffer = processTemplate(resourceFile, params)
        } catch (Exception ex) {
            log.error "Failed to process template", ex
        }
            
        if (buffer != null) {
            render (text:buffer, contentType:"text/css")
        } else {
            render(text:"Failed to process template", status:500)
        }
    }

上述方式实际上书写的并不是纯正的CSS文件,而是一个Groovy Template文件。之后,利用groovyPagesTemplateEngine对其进行处理产生最终所需的CSS文件, 根据这个思路,我们可以对javascript、media作同样的处理,达到简化对应用中静态资源管理的目地。

转载于:https://my.oschina.net/groovyland/blog/3088

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值