<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    posts - 36, comments - 419, trackbacks - 0, articles - 0
      BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

    前言:    

         上一篇隨筆中網(wǎng)友 skyaspnet 問我如何壓縮HTML,當(dāng)時回答是推薦他使用gzip,后來想想,要是能把所有的html,jsp(aspx)在運行前都壓縮成1行未免不是一件好事啊。一般我們啟動gzip都比較少對html啟動gzip,因為現(xiàn)在的html都是動態(tài)的,不會使用瀏覽器緩存,而啟用gzip的話每次請求都需要壓縮,會比較消耗服務(wù)器資源,對js,css啟動gzip比較好是因為js,css都會使用緩存。我個人覺得的壓縮html的最大好處就是一本萬利,只要寫好了一次,以后所有程序都可以使用,不會增加任何額外的開發(fā)工作。

     

         在“JS、CSS的合并、壓縮、緩存管理”一文中說到自己寫過的1個自動合并、壓縮JS,CSS,并添加版本號的組件。這次把壓縮html的功能也加入到該組件中,流程很簡單,就是在程序啟動(contextInitialized or Application_Start)的時候掃描所有html,jsp(aspx)進行壓縮。

     

    壓縮的注意事項:

         實現(xiàn)的方式主要是用正則表達式去查找,替換。在html壓縮的時候,主要要注意下面幾點:

              1. pre,textarea 標(biāo)簽里面的內(nèi)容格式需要保留,不能壓縮。

              2. 去掉html注釋的時候,有些注釋是不能去掉的,比如:<!--[if IE 6]> ..... <![endif]-->

              3. 壓縮嵌入式j(luò)s中的注釋要注意,因為可能注釋符號會出現(xiàn)在字符串中,比如: var url = "http://www.cnblogs.com";    // 前面的//不是注釋

                  去掉JS換行符的時候,不能直接跟一下行動內(nèi)容,需要有空格,考慮下面的代碼:

                  else

                     return;

                 如果不帶空格,則變成elsereturn。

              4. jsp(aspx) 中很有可能會使用<% %>嵌入一些服務(wù)器代碼,這個時候也需要單獨處理,里面注釋的處理方法跟js的一樣。

     

    源代碼:

        下面是java實現(xiàn)的源代碼,也可以 猛擊此處 下載該代碼,相信大家都看的懂,也很容易改成net代碼:
          1 import java.io.StringReader;

      2 import java.io.StringWriter;
      3 import java.util.*;
      4 import java.util.regex.*;
      5 
      6 /*******************************************
      7  * 壓縮jsp,html中的代碼,去掉所有空白符、換行符
      8  * @author  bearrui(ak-47)
      9  * @version 0.1
     10  * @date     2010-5-13
     11  *******************************************/
     12 public class HtmlCompressor {
     13     private static String tempPreBlock = "%%%HTMLCOMPRESS~PRE&&&";
     14     private static String tempTextAreaBlock = "%%%HTMLCOMPRESS~TEXTAREA&&&";
     15     private static String tempScriptBlock = "%%%HTMLCOMPRESS~SCRIPT&&&";
     16     private static String tempStyleBlock = "%%%HTMLCOMPRESS~STYLE&&&";
     17     private static String tempJspBlock = "%%%HTMLCOMPRESS~JSP&&&";
     18     
     19     private static Pattern commentPattern = Pattern.compile("<!--\\s*[^\\[].*?-->", Pattern.DOTALL | Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
     20     private static Pattern itsPattern = Pattern.compile(">\\s+?<", Pattern.DOTALL | Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
     21     private static Pattern prePattern = Pattern.compile("<pre[^>]*?>.*?</pre>", Pattern.DOTALL | Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); 
     22     private static Pattern taPattern = Pattern.compile("<textarea[^>]*?>.*?</textarea>", Pattern.DOTALL | Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
     23     private static Pattern jspPattern = Pattern.compile("<%([^-@][\\w\\W]*?)%>", Pattern.DOTALL | Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
     24     // <script></script>
     25     private static Pattern scriptPattern = Pattern.compile("(?:<script\\s*>|<script type=['\"]text/javascript['\"]\\s*>)(.*?)</script>", Pattern.DOTALL | Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
     26     private static Pattern stylePattern = Pattern.compile("<style[^>()]*?>(.+)</style>", Pattern.DOTALL | Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
     27 
     28     // 單行注釋,
     29     private static Pattern signleCommentPattern = Pattern.compile("//.*");
     30     // 字符串匹配
     31     private static Pattern stringPattern = Pattern.compile("(\"[^\"\\n]*?\"|'[^'\\n]*?')");
     32     // trim去空格和換行符
     33     private static Pattern trimPattern = Pattern.compile("\\n\\s*",Pattern.MULTILINE);
     34     private static Pattern trimPattern2 = Pattern.compile("\\s*\\r",Pattern.MULTILINE);
     35     // 多行注釋
     36     private static Pattern multiCommentPattern = Pattern.compile("/\\*.*?\\*/", Pattern.DOTALL | Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
     37 
     38     private static String tempSingleCommentBlock = "%%%HTMLCOMPRESS~SINGLECOMMENT&&&";  // //占位符
     39     private static String tempMulitCommentBlock1 = "%%%HTMLCOMPRESS~MULITCOMMENT1&&&";  // /*占位符
     40     private static String tempMulitCommentBlock2 = "%%%HTMLCOMPRESS~MULITCOMMENT2&&&";  // */占位符
     41     
     42     
     43     public static String compress(String html) throws Exception {
     44         if(html == null || html.length() == 0) {
     45             return html;
     46         }
     47         
     48         List<String> preBlocks = new ArrayList<String>();
     49         List<String> taBlocks = new ArrayList<String>();
     50         List<String> scriptBlocks = new ArrayList<String>();
     51         List<String> styleBlocks = new ArrayList<String>();
     52         List<String> jspBlocks = new ArrayList<String>();
     53         
     54         String result = html;
     55         
     56         //preserve inline java code
     57         Matcher jspMatcher = jspPattern.matcher(result);
     58         while(jspMatcher.find()) {
     59             jspBlocks.add(jspMatcher.group(0));
     60         }
     61         result = jspMatcher.replaceAll(tempJspBlock);
     62         
     63         //preserve PRE tags
     64         Matcher preMatcher = prePattern.matcher(result);
     65         while(preMatcher.find()) {
     66             preBlocks.add(preMatcher.group(0));
     67         }
     68         result = preMatcher.replaceAll(tempPreBlock);
     69         
     70         //preserve TEXTAREA tags
     71         Matcher taMatcher = taPattern.matcher(result);
     72         while(taMatcher.find()) {
     73             taBlocks.add(taMatcher.group(0));
     74         }
     75         result = taMatcher.replaceAll(tempTextAreaBlock);
     76         
     77         //preserve SCRIPT tags
     78         Matcher scriptMatcher = scriptPattern.matcher(result);
     79         while(scriptMatcher.find()) {
     80             scriptBlocks.add(scriptMatcher.group(0));
     81         }
     82         result = scriptMatcher.replaceAll(tempScriptBlock);
     83         
     84         // don't process inline css 
     85         Matcher styleMatcher = stylePattern.matcher(result);
     86         while(styleMatcher.find()) {
     87             styleBlocks.add(styleMatcher.group(0));
     88         }
     89         result = styleMatcher.replaceAll(tempStyleBlock);
     90         
     91         //process pure html
     92         result = processHtml(result);
     93         
     94         //process preserved blocks
     95         result = processPreBlocks(result, preBlocks);
     96         result = processTextareaBlocks(result, taBlocks);
     97         result = processScriptBlocks(result, scriptBlocks);
     98         result = processStyleBlocks(result, styleBlocks);
     99         result = processJspBlocks(result, jspBlocks);
    100         
    101         preBlocks = taBlocks = scriptBlocks = styleBlocks = jspBlocks = null;
    102         
    103         return result.trim();
    104     }
    105     
    106     private static String processHtml(String html) {
    107         String result = html;
    108         
    109         //remove comments
    110 //        if(removeComments) {
    111             result = commentPattern.matcher(result).replaceAll("");
    112 //        }
    113         
    114         //remove inter-tag spaces
    115 //        if(removeIntertagSpaces) {
    116             result = itsPattern.matcher(result).replaceAll("><");
    117 //        }
    118         
    119         //remove multi whitespace characters
    120 //        if(removeMultiSpaces) {
    121             result = result.replaceAll("\\s{2,}"," ");
    122 //        }
    123                 
    124         return result;
    125     }
    126     
    127     private static String processJspBlocks(String html, List<String> blocks){
    128         String result = html;
    129         for(int i = 0; i < blocks.size(); i++) {
    130             blocks.set(i, compressJsp(blocks.get(i)));
    131         }
    132         //put preserved blocks back
    133         while(result.contains(tempJspBlock)) {
    134             result = result.replaceFirst(tempJspBlock, Matcher.quoteReplacement(blocks.remove(0)));
    135         }
    136         
    137         return result;
    138     }
    139     private static String processPreBlocks(String html, List<String> blocks) throws Exception {
    140         String result = html;
    141         
    142         //put preserved blocks back
    143         while(result.contains(tempPreBlock)) {
    144             result = result.replaceFirst(tempPreBlock, Matcher.quoteReplacement(blocks.remove(0)));
    145         }
    146         
    147         return result;
    148     }
    149     
    150     private static String processTextareaBlocks(String html, List<String> blocks) throws Exception {
    151         String result = html;
    152         
    153         //put preserved blocks back
    154         while(result.contains(tempTextAreaBlock)) {
    155             result = result.replaceFirst(tempTextAreaBlock, Matcher.quoteReplacement(blocks.remove(0)));
    156         }
    157         
    158         return result;
    159     }
    160     
    161     private static String processScriptBlocks(String html, List<String> blocks) throws Exception {
    162         String result = html;
    163         
    164 //        if(compressJavaScript) {
    165             for(int i = 0; i < blocks.size(); i++) {
    166                 blocks.set(i, compressJavaScript(blocks.get(i)));
    167             }
    168 //        }
    169         
    170         //put preserved blocks back
    171         while(result.contains(tempScriptBlock)) {
    172             result = result.replaceFirst(tempScriptBlock, Matcher.quoteReplacement(blocks.remove(0)));
    173         }
    174         
    175         return result;
    176     }
    177     
    178     private static String processStyleBlocks(String html, List<String> blocks) throws Exception {
    179         String result = html;
    180         
    181 //        if(compressCss) {
    182             for(int i = 0; i < blocks.size(); i++) {
    183                 blocks.set(i, compressCssStyles(blocks.get(i)));
    184             }
    185 //        }
    186         
    187         //put preserved blocks back
    188         while(result.contains(tempStyleBlock)) {
    189             result = result.replaceFirst(tempStyleBlock, Matcher.quoteReplacement(blocks.remove(0)));
    190         }
    191         
    192         return result;
    193     }
    194     
    195     private static String compressJsp(String source)  {
    196         //check if block is not empty
    197         Matcher jspMatcher = jspPattern.matcher(source);
    198         if(jspMatcher.find()) {
    199             String result = compressJspJs(jspMatcher.group(1));
    200             return (new StringBuilder(source.substring(0, jspMatcher.start(1))).append(result).append(source.substring(jspMatcher.end(1)))).toString();
    201         } else {
    202             return source;
    203         }
    204     }    
    205     private static String compressJavaScript(String source)  {
    206         //check if block is not empty
    207         Matcher scriptMatcher = scriptPattern.matcher(source);
    208         if(scriptMatcher.find()) {
    209             String result = compressJspJs(scriptMatcher.group(1));
    210             return (new StringBuilder(source.substring(0, scriptMatcher.start(1))).append(result).append(source.substring(scriptMatcher.end(1)))).toString();
    211         } else {
    212             return source;
    213         }
    214     }
    215         
    216     private static String compressCssStyles(String source)  {
    217         //check if block is not empty
    218         Matcher styleMatcher = stylePattern.matcher(source);
    219         if(styleMatcher.find()) {
    220             // 去掉注釋,換行
    221             String result= multiCommentPattern.matcher(styleMatcher.group(1)).replaceAll("");
    222             result = trimPattern.matcher(result).replaceAll("");
    223             result = trimPattern2.matcher(result).replaceAll("");
    224             return (new StringBuilder(source.substring(0, styleMatcher.start(1))).append(result).append(source.substring(styleMatcher.end(1)))).toString();
    225         } else {
    226             return source;
    227         }
    228     }
    229     
    230     private static String compressJspJs(String source){
    231         String result = source;
    232         // 因注釋符合有可能出現(xiàn)在字符串中,所以要先把字符串中的特殊符好去掉
    233         Matcher stringMatcher = stringPattern.matcher(result);
    234         while(stringMatcher.find()){
    235             String tmpStr = stringMatcher.group(0);
    236             
    237             if(tmpStr.indexOf("//"!= -1 || tmpStr.indexOf("/*"!= -1 || tmpStr.indexOf("*/"!= -1){
    238                 String blockStr = tmpStr.replaceAll("//", tempSingleCommentBlock).replaceAll("/\\*", tempMulitCommentBlock1)
    239                                 .replaceAll("\\*/", tempMulitCommentBlock2);
    240                 result = result.replace(tmpStr, blockStr);
    241             }
    242         }
    243         // 去掉注釋
    244         result = signleCommentPattern.matcher(result).replaceAll("");
    245         result = multiCommentPattern.matcher(result).replaceAll("");
    246         result = trimPattern2.matcher(result).replaceAll("");
    247         result = trimPattern.matcher(result).replaceAll(" ");
    248         // 恢復(fù)替換掉的字符串
    249         result = result.replaceAll(tempSingleCommentBlock, "//").replaceAll(tempMulitCommentBlock1, "/*")
    250                 .replaceAll(tempMulitCommentBlock2, "*/");
    251         
    252         return result;
    253     }
    254 }
    255 

    使用注意事項

     

          使用了上面方法后,再運行程序,是不是發(fā)現(xiàn)每個頁面查看源代碼的時候都變成1行啦,還不錯吧,但是在使用的時候還是要注意一些問題:

               1. 嵌入js本來想調(diào)用yuicompressor來壓縮,yuicompressor壓縮JS前,會先編譯js是否合法,因我們嵌入的js中可能很多會用到一些服務(wù)器端代碼,比如 var now = <%=DateTime.now %> ,這樣的代碼會編譯不通過,所以無法使用yuicompressor。

                  最后只能自己寫壓縮JS代碼,自己寫的比較粗燥,所以有個問題還解決,就是如果開發(fā)人員在一句js代碼后面沒有加分號的話,壓縮成1行就很有可能出問題。所以使用這個需要保證每條語句結(jié)束后都必須帶分號。

     

               2. 因為是在程序啟動的時候壓縮所有jsp(aspx),所以如果是用戶請求的時候動態(tài)產(chǎn)生的html就無法壓縮。



        有需要請查看:高性能WEB開發(fā)系列


    [作者]:BearRui(AK-47)
    [博客]: http://m.tkk7.com/bearrui/
    [聲明]:本博所有文章版權(quán)歸作者所有(除特殊說明以外),轉(zhuǎn)載請注明出處.
    英雄,別走啊,幫哥評論下:  

    精彩推薦 好文要頂 水平一般 看不懂 還需努力

    評論

    # re: WEB高性能開發(fā)(10) - 瘋狂的HTML壓縮  回復(fù)  更多評論   

    2010-05-17 09:40 by BeanSoft
    頂下先!

    # re: WEB高性能開發(fā)(10) - 瘋狂的HTML壓縮  回復(fù)  更多評論   

    2010-05-17 09:53 by 麗可酷
    真不錯,謝謝

    # re: WEB高性能開發(fā)(10) - 瘋狂的HTML壓縮  回復(fù)  更多評論   

    2010-05-17 10:02 by BearRui(AK-47)
    呵呵,謝謝2位的支持。

    # re: WEB高性能開發(fā)(10) - 瘋狂的HTML壓縮  回復(fù)  更多評論   

    2010-05-17 13:58 by 16樓
    挺好就是注意事項挺多的!

    # re: WEB高性能開發(fā)(10) - 瘋狂的HTML壓縮  回復(fù)  更多評論   

    2010-05-17 14:14 by BearRui(AK-47)
    @16樓
    是啊,還有待完善啊,^_^

    # re: WEB高性能開發(fā)(10) - 瘋狂的HTML壓縮  回復(fù)  更多評論   

    2010-05-18 11:29 by 牙牙學(xué)語
    謝謝分享,學(xué)習(xí)!
    其實也可以用ant腳本在打包時對頁面文件做些處理

    # re: WEB高性能開發(fā)(10) - 瘋狂的HTML壓縮  回復(fù)  更多評論   

    2010-05-18 12:05 by BearRui(AK-47)
    @牙牙學(xué)語
    是可以,我最開始想寫maven插件,在部署的時候自動處理,但是寫的比較麻煩,感覺還是這樣寫比較簡單。

    # re: WEB高性能開發(fā)(10) - 瘋狂的HTML壓縮  回復(fù)  更多評論   

    2010-06-09 17:05 by panasia
    今天來到這里學(xué)到不少東西。。也下了不少好東西。呵呵。。感謝博主。。這個東西對我現(xiàn)在這個項目來說有點杯具。。因為我發(fā)現(xiàn)我們的程序員在寫代碼的時候。。有的地方?jīng)]有加分號。。。囧。。

    # re: WEB高性能開發(fā)(10) - 瘋狂的HTML壓縮  回復(fù)  更多評論   

    2010-06-09 17:08 by BearRui(AK-47)
    @panasia
    呵呵,也非常感謝你的支持,看到你的很多回復(fù)。

    我這個html壓縮做的確是有點簡單,因為JS分析比較復(fù)雜,所以目前暫時只能要求開發(fā)人員注意編寫JS的格式了。

    # re: WEB高性能開發(fā)(10) - 瘋狂的HTML壓縮  回復(fù)  更多評論   

    2010-06-10 18:47 by panasia
    http://www.cnblogs.com/sohighthesky/archive/2010/05/14/uedsky-html-compressor.html
    博主,我今天看到這篇文章。這個blog不知道是不是你的?我看了下。。好像是盜用了你的文章。。還被轉(zhuǎn)到http://www.ued163.com/?p=814上面了

    # re: WEB高性能開發(fā)(10) - 瘋狂的HTML壓縮  回復(fù)  更多評論   

    2010-06-10 23:13 by BearRui(AK-47)
    @panasia
    呵呵,看日期好像他還在我之前發(fā)布的。應(yīng)該只是巧合而已。

    另:我在cnblogs的博客地址是:
    http://www.cnblogs.com/BearsTaR/

    # re: WEB高性能開發(fā)(10) - 瘋狂的HTML壓縮  回復(fù)  更多評論   

    2010-06-24 13:37 by tiffany discount
    盡管看不懂,但可以看得出博主很有才。

    # re: WEB高性能開發(fā)(10) - 瘋狂的HTML壓縮  回復(fù)  更多評論   

    2010-06-24 13:55 by BearRui(AK-47)
    @tiffany discount
    呵呵,謝謝。

    # re: WEB高性能開發(fā)(10) - 瘋狂的HTML壓縮  回復(fù)  更多評論   

    2010-11-27 17:16 by Dylan
    寫的不錯
    主站蜘蛛池模板: 亚洲熟妇AV乱码在线观看| 亚洲日韩乱码久久久久久| 老司机午夜性生免费福利 | 亚洲人成网站在线播放vr| 黄色成人网站免费无码av| 亚洲日韩国产精品无码av| 亚洲一区二区三区无码中文字幕| 亚洲avav天堂av在线网毛片| 精品国产精品久久一区免费式| 亚洲人成7777影视在线观看| 91黑丝国产线观看免费| 亚洲小说区图片区| 1000部免费啪啪十八未年禁止观看| 91久久亚洲国产成人精品性色| 一级毛片免费播放| 亚洲1区1区3区4区产品乱码芒果| 日韩毛片免费无码无毒视频观看| 欧洲 亚洲 国产图片综合| 免费观看毛片视频| 免费无毒a网站在线观看| 亚洲乱码中文字幕久久孕妇黑人| 国产一区二区免费视频| 亚洲性色高清完整版在线观看| 久久不见久久见中文字幕免费| 亚洲乱色伦图片区小说 | 国产桃色在线成免费视频| 亚洲av片不卡无码久久| 国产成人无码a区在线观看视频免费 | 久久久久久毛片免费播放| 亚洲高清资源在线观看| 无码免费午夜福利片在线| 激情无码亚洲一区二区三区 | 男人的天堂亚洲一区二区三区 | 美女被免费视频网站a国产| 一级特黄a免费大片| 久久亚洲AV无码精品色午夜麻| 欧美日韩国产免费一区二区三区| 老司机免费午夜精品视频| 无码欧精品亚洲日韩一区| 日本免费人成黄页网观看视频| 国产精品永久免费|