• java版的YUI3 combine服务-Combo Handler


    YUI3中,为了避免js文件过大,各个功能模块是拆分的。它有一个“种子”的概念:先下载一个小的核心的js文件到浏览器端,再通过这个小的js文件去加载其它所需的模块。

    这种按需加载虽然解决了单个js过大的问题,但是随之带来另外一个问题:如果一个页面使用了YUI的a、b、c功能,那么浏览器就要向服务器请求a.js、b.js、c.js三个文件,这样增加了浏览器向服务器的沟通次数。

    为了解决后面的问题,YUI3又有一个combine的概念,预先下载的那个核心的js,把页面上需要的a、b、c模块合并成一个请求发给服务器,类似这样:http://mydomain.com/conbine?a.js&b.js&c.js。

    这要求服务器接收到http://mydomain.com/conbine请求后,将参数取出来,找到对应的a、b、c的js文件,合并成一个js文件,返回给客户端。Combo Handler是Yahoo!开发的一个Apache模块,专门来干这个事情的。

    如果只用java的web容器,可以把这项工作委托给servlet:

    1
    2
    3
    4
    <servlet>
        <servlet-name>yuicombo</servlet-name>
        <servlet-class>org.siqisource.mozo.servlets.YuiCombineServlet</servlet-class>
    </servlet>

    对应的YUI配置为:

    1
    2
    3
    4
    5
    YUI.GlobalConfig = {
        combine: true,
        comboBase: '<mz:webRoot/>/yuicombo?',
        root: 'uilibrary/yui/',
    };

    在servlet代码中,我使用了YUI的yuicompressor来压缩js和css文件,下面是maven配置。

    1
    2
    3
    4
    5
    <dependency>
        <groupId>com.yahoo.platform.yui</groupId>
        <artifactId>yuicompressor</artifactId>
        <version>2.4.7</version>
    </dependency>

    其中的Path类只是为了获得web应用物理路径,在是用的时候替换一下即可。

    目前已知的缺陷:对于css的按需加载,浏览器会请求客户端两次,目前不清楚是不是YUI3(测试版本:3.7.2)的问题。

    具体代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    package org.siqisource.mozo.servlets;
     
    import java.io.File;
    import java.io.FileReader;
    import java.io.FileWriter;
    import java.io.IOException;
    import java.io.Reader;
    import java.io.Writer;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.UUID;
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
     
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
     
    import org.apache.commons.io.FileDeleteStrategy;
    import org.apache.commons.io.FileUtils;
    import org.siqisource.mozo.context.Path;
     
    import com.yahoo.platform.yui.compressor.CssCompressor;
    import com.yahoo.platform.yui.compressor.JavaScriptCompressor;
     
    public class YuiCombineServlet extends HttpServlet {
     
        private static Map<String, String> cachedResources = new HashMap<String, String>();
     
        private String cacheContextPath = "uilibrary/yui/cache/";
     
        private String cacheDir = Path.getPhysicalPath() + cacheContextPath;
     
        int linebreakpos = -1;
        boolean munge = true;
        boolean verbose = false;
        boolean preserveAllSemiColons = false;
        boolean disableOptimizations = false;
     
        @Override
        public void init() throws ServletException {
     
            // 重置缓存文件夹
            File catchedDir = new File(cacheDir);
     
            if (catchedDir.exists()) {
                FileDeleteStrategy strategy = FileDeleteStrategy.FORCE;
                try {
                    strategy.delete(catchedDir);
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            catchedDir.mkdirs();
     
            super.init();
        }
     
        @Override
        protected void doGet(HttpServletRequest request,
                HttpServletResponse response) throws ServletException, IOException {
     
            String queryString = request.getQueryString();
            String resourcePath = cachedResources.get(queryString);
            // 已缓存
            if (resourcePath == null) {
     
                String[] resources = queryString.split("&");
                String firstResource = resources[0];
     
                String fileName = UUID.randomUUID().toString();
     
                if (firstResource.endsWith(".js")) {
     
                    fileName += ".js";
                    Writer writer = new FileWriter(cacheDir + fileName);
                    for (String resource : resources) {
                        Reader reader = new FileReader(Path.getPhysicalPath()
                                + resource);
                        JavaScriptCompressor compressor = new JavaScriptCompressor(
                                reader, null);
                        compressor.compress(writer, linebreakpos, munge, verbose,
                                preserveAllSemiColons, disableOptimizations);
                        reader.close();
                    }
                    writer.flush();
                    writer.close();
     
                } else if (resources[0].endsWith(".css")) {
                    fileName += ".css";
                    Writer writer = new FileWriter(cacheDir + fileName);
                    for (String resource : resources) {
                        Reader reader = new FileReader(replacedUrlFile(resource));
                        CssCompressor compressor = new CssCompressor(reader);
                        compressor.compress(writer, linebreakpos);
                        reader.close();
                    }
                    writer.flush();
                    writer.close();
                }
     
                resourcePath = cacheContextPath + fileName;
                cachedResources.put(queryString, resourcePath);
            }
            request.getRequestDispatcher(resourcePath).forward(request, response);
            return;
        }
         
        public String replacedUrlFile(String fileName) throws IOException {
     
            String cssfilePath = Path.getPhysicalPath() + fileName;
            File cssFile = new File(cssfilePath);
     
            String tempCssFilePath = cacheDir + "tmp-css-" + cssFile.getName();
            File tempCssFile = new File(tempCssFilePath);
            if (tempCssFile.exists()) {
                return tempCssFilePath;
            }
     
            // 判断是否需要替换
            String css = FileUtils.readFileToString(cssFile);
            int maxIndex = css.length() - 1;
            int appendIndex = 0;
            Pattern p = Pattern.compile("url\(\s*(["']?)");
            if (!p.matcher(css).find()) {
                return cssfilePath;
            }
     
            // 真的需要替换
            Matcher m = p.matcher(css);
            String url = fileName.substring(0, fileName.lastIndexOf('/'));
            url = Path.getContextPath() + "/" + url + "/";
     
            StringBuffer replacedUrlCss = new StringBuffer();
     
            while (m.find()) {
                int startIndex = m.start() + 4; // "url(".length()
                String terminator = m.group(1); // ', " or empty (not quoted)
     
                if (terminator.length() == 0) {
                    terminator = ")";
                }
     
                boolean foundTerminator = false;
     
                int endIndex = m.end() - 1;
                while (foundTerminator == false && endIndex + 1 <= maxIndex) {
                    endIndex = css.indexOf(terminator, endIndex + 1);
     
                    if ((endIndex > 0) && (css.charAt(endIndex - 1) != '\')) {
                        foundTerminator = true;
                        if (!")".equals(terminator)) {
                            endIndex = css.indexOf(")", endIndex);
                        }
                    }
                }
     
                // Enough searching, start moving stuff over to the buffer
                replacedUrlCss.append(css.substring(appendIndex, m.start()));
     
                if (foundTerminator) {
                    String token = css.substring(startIndex, endIndex);
                    token = token.replaceAll("\s+", "");
                    String preserver = "url('" + url + token + "')";
                    replacedUrlCss.append(preserver);
     
                    appendIndex = endIndex + 1;
                } else {
                    // No end terminator found, re-add the whole match. Should we
                    // throw/warn here?
                    replacedUrlCss.append(css.substring(m.start(), m.end()));
                    appendIndex = m.end();
                }
            }
            FileUtils.writeStringToFile(tempCssFile, replacedUrlCss.toString());
            return tempCssFilePath;
     
        }
    }
  • 相关阅读:
    JavaScript npm/nrm 切换安装依赖的镜像源
    Vue Vuex中的严格模式/实例解析/dispatch/commit /state/getters
    Vuex mapGetter的基本使用
    Springboot 整合Mybatis-plus
    SEO基本功:站内优化的一些基本手段
    解决使用logstash中jdbc导入mysql中的数据到elasticsearch中tinyint类型被转成布尔型的问题的方法
    【重大好消息】elasticsearch 7.3版本已经可以免费使用x-pack就可以设置账号和密码了,让你的数据不再裸奔
    elasticsearch7.3版本已经不需要额外安装中文分词插件了
    网络案例分析之999皮炎平出鹤顶红色号的口红
    php框架symfony踩坑苦旅(1)
  • 原文地址:https://www.cnblogs.com/lhp2012/p/4994844.html
Copyright © 2020-2023  润新知