java版的YUI3 combine服务-Combo Handler

java

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

packageorg.siqisource.mozo.servlets;

 

importjava.io.File;

importjava.io.FileReader;

importjava.io.FileWriter;

importjava.io.IOException;

importjava.io.Reader;

importjava.io.Writer;

importjava.util.HashMap;

importjava.util.Map;

importjava.util.UUID;

importjava.util.regex.Matcher;

importjava.util.regex.Pattern;

 

importjavax.servlet.ServletException;

importjavax.servlet.http.HttpServlet;

importjavax.servlet.http.HttpServletRequest;

importjavax.servlet.http.HttpServletResponse;

 

importorg.apache.commons.io.FileDeleteStrategy;

importorg.apache.commons.io.FileUtils;

importorg.siqisource.mozo.context.Path;

 

importcom.yahoo.platform.yui.compressor.CssCompressor;

importcom.yahoo.platform.yui.compressor.JavaScriptCompressor;

 

publicclassYuiCombineServlet extendsHttpServlet {

 

    privatestaticMap<String, String> cachedResources = newHashMap<String, String>();

 

    privateString cacheContextPath = "uilibrary/yui/cache/";

 

    privateString cacheDir = Path.getPhysicalPath() + cacheContextPath;

 

    intlinebreakpos = -1;

    booleanmunge = true;

    booleanverbose = false;

    booleanpreserveAllSemiColons = false;

    booleandisableOptimizations = false;

 

    @Override

    publicvoidinit() throwsServletException {

 

        // 重置缓存文件夹

        File catchedDir = newFile(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

    protectedvoiddoGet(HttpServletRequest request,

            HttpServletResponse response) throwsServletException, 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 = newFileWriter(cacheDir + fileName);

                for(String resource : resources) {

                    Reader reader = newFileReader(Path.getPhysicalPath()

                            + resource);

                    JavaScriptCompressor compressor = newJavaScriptCompressor(

                            reader, null);

                    compressor.compress(writer, linebreakpos, munge, verbose,

                            preserveAllSemiColons, disableOptimizations);

                    reader.close();

                }

                writer.flush();

                writer.close();

 

            } elseif(resources[0].endsWith(".css")) {

                fileName += ".css";

                Writer writer = newFileWriter(cacheDir + fileName);

                for(String resource : resources) {

                    Reader reader = newFileReader(replacedUrlFile(resource));

                    CssCompressor compressor = newCssCompressor(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;

    }

     

    publicString replacedUrlFile(String fileName) throwsIOException {

 

        String cssfilePath = Path.getPhysicalPath() + fileName;

        File cssFile = newFile(cssfilePath);

 

        String tempCssFilePath = cacheDir + "tmp-css-"+ cssFile.getName();

        File tempCssFile = newFile(tempCssFilePath);

        if(tempCssFile.exists()) {

            returntempCssFilePath;

        }

 

        // 判断是否需要替换

        String css = FileUtils.readFileToString(cssFile);

        intmaxIndex = css.length() - 1;

        intappendIndex = 0;

        Pattern p = Pattern.compile("url\\(\\s*([\"']?)");

        if(!p.matcher(css).find()) {

            returncssfilePath;

        }

 

        // 真的需要替换

        Matcher m = p.matcher(css);

        String url = fileName.substring(0, fileName.lastIndexOf('/'));

        url = Path.getContextPath() + "/"+ url + "/";

 

        StringBuffer replacedUrlCss = newStringBuffer();

 

        while(m.find()) {

            intstartIndex = m.start() + 4; // "url(".length()

            String terminator = m.group(1); // ', " or empty (not quoted)

 

            if(terminator.length() == 0) {

                terminator = ")";

            }

 

            booleanfoundTerminator = false;

 

            intendIndex = 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());

        returntempCssFilePath;

 

    }

}

以上是 java版的YUI3 combine服务-Combo Handler 的全部内容, 来源链接: utcz.com/z/392762.html

回到顶部