Webアプリケーションの静的リソースの管理

5822 ワード

Kevin M.Gillは、彼のブログPreprocessing CSS in GrailsおよびImprove Grails Performance With Static Resourcesで、GrailsアプリケーションのCSSで静的リソース管理をどのように簡素化するかを共有しました.
Web開発では、画像などの静的リソースのパスをCSSで変更する必要があります.リソースの数が大きい場合は、大量の置換作業が必要になり、エラーが発生しやすくなります.このときGroovyの${}を思い浮かべ,CSSで${}が使用可能であれば,画像の格納場所をプロファイルやデータベースに配置して統合管理する.画像の保存経路が変更された場合は、数箇所か1箇所の位置情報を修正するだけで便利ではないでしょうか.
CSSを使用する場合、背景図などの内容を設定すると、通常は以下のような書き方になります.

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

あるいは、画像の位置を相対的な位置に書きます.例えば、

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

具体的な実装手順を見てみましょう.
  • まず元のCSSファイルを改造し、以下のコードを参照してください.
    
    .some_div {
        ...
        background: url(${groovyq.staticResource(dir:"/img/",
    	file:"grails_logo.png")});
        ...
        
      }
      

  • %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
      }
    }
    

  • %GrailsApp%/grails-app/config.groovyファイルに追加:myapp.staticresources.url = "http://localhost:8080/GrailsUI/static「静的リソースのパスを指定します.
  • 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()
        }
    }
    

  • gspページのCSSへの参照を変更します.このコードは/staticResource/cssに基づいてStaticResourceControllerのcssという閉パケットを呼び出し、pcssはこの閉パケットで使用するfileの値です.これでいい!
  • 静的リソースが多い場合は、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と同様の処理を行い,アプリケーションにおける静的リソース管理を簡素化する目的を達成することができる.