1.首先利用maven压缩js 和css 等资源文件
1. <build>
2. <plugin>
3. <groupId>net.alchim31.maven</groupId>
4. <artifactId>yuicompressor-maven-plugin</artifactId>
5. <version>1.4.0</version>
6. <executions>
7. <execution>
8. <!-- 在真正的打包之前,执行一些准备打包压缩操作的操作 -->
9. <phase>prepare-package</phase>
10. <goals>
11. <goal>compress</goal>
12. </goals>
13. </execution>
14. </executions>
15. <configuration>
16. <encoding>UTF-8</encoding>
17. <!-- 忽视 js 错误警告 -->
18. <jswarn>false</jswarn>
19. <nosuffix>true</nosuffix>
20. <linebreakpos>-1</linebreakpos>
21. <!-- 压缩的文件 工程里面所有的 js css 后缀的都会压缩 -->
22. <includes>
23. <include>**/*.js</include>
24. <include>**/*.css</include>
25. </includes>
26. <!-- 不需要压缩的文件 -->
27. <excludes>
28. <exclude>**/style.css</exclude>
29. </excludes>
30. <failOnWarning>false</failOnWarning>
31. </configuration>
32. </plugin>
33. <!-- 当压缩没有填写输出目录 或者 输出目录和压缩目录是同一路径时 一定要配合下面的使用 -->
34. <plugin>
35. <groupId>org.apache.maven.plugins</groupId>
36. <artifactId>maven-war-plugin</artifactId>
37. <configuration>
38. <!--
39. 如果不增加此配置 src/main/webapp 下面的内容 会重新复制到target输出目录 覆盖掉编译后的内容
40. 这样编译的还是未压缩过的内容,增加上此过滤 打war包就不会内容覆盖
41. >
42. <warSourceExcludes>**/*.js,**/*.css</warSourceExcludes>
43. </configuration>
44. </plugin>
45. </plugins>
46. </build>
2.通过SpringMvc扩展通过一个请求获取多个JS文件的功能
2.1 spring MVC 配置
1. <bean id="simpleUrlHandlerMapping"
2. class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
3. <property name="urlMap">
4. <map>
5. <!-- 静态资源处理器 -->
6. <entry key="/r/**/**">
7. <!-- 自己扩展的SpingMVC ResourceHttpRequestHandler 类,增加了类是与淘宝CDN通过逗号(,)隔开
8. 访问多个js的效果 此功能不能压缩JS 如果想实现压缩功能可通过maven 或者 ant 在编译的时候进行压缩 -->
9. <bean class="com.yoro.core.springmvc.ResourceHttpRequestHandler">
10. <property name="locations">
11. <list>
12. <!-- 只有相同目录的JS文件才能实现淘宝CDN通过逗号(,)隔开 访问多个js的效果 如 /r/ 目录下的js|css 文件
13. 就能实现 /r/js/ 目录下的js文件也可以有同样的效果 但 /a/css 下面的文件 和 /r/css 就不能实现 有点小遗憾,因为时间关系待以后升级 -->
14. <value>/r/</value>
15. </list>
16. </property>
17. <!-- 启用静态资源浏览器缓存一个月 -->
18. <!-- 通过浏览器进行的缓存 根据可浏览器实现方式不同有所差异 按刷新按扭缓存不会起 当是页面跳转或者地址栏输入则缓存会起作用 -->
19. <!-- 更 过浏览器缓存的资料和特效 可 搜索 cachecontrol 设置 cacheSeconds 缓存时间单位是秒 2592000 表示缓存 30天 因为我自己每次新版本发布都会都js css 文件增加版本号 所以缓存时间我设置的比较长 -->
20. <property name="cacheSeconds" value="2592000"></property>
21. <property name="useExpiresHeader" value="true"></property>
22. <property name="useCacheControlNoStore" value="true"></property>
23. </bean>
24. </entry>
25. <entry key="/thirdparty/**/**">
26. <bean class="com.yoro.core.springmvc.ResourceHttpRequestHandler">
27. <property name="locations">
28. <list>
29. <value>/thirdparty/</value>
30. </list>
31. </property>
32. <!-- 启用静态资源浏览器缓存一个月 -->
33. <property name="cacheSeconds" value="2592000"></property>
34. <property name="useExpiresHeader" value="true"></property>
35. <property name="useCacheControlNoStore" value="true"></property>
36. </bean>
37. </entry>
38. </map>
39. </property>
40. <property name="order" value="1"></property>
41. </bean>
2.2 ResourceHttpRequestHandler 扩展类代码
1. package
2.
3. import
4. import
5. import
6. import
7. import
8. import
9.
10. import
11. import
12. import
13. import
14. import
15.
16. import
17. import
18. import
19. import
20. import
21. import
22. import
23. import
24. import
25. import
26. import
27. import
28. import
29. import
30. import
31.
32. public class
33. extends WebContentGenerator implements
34.
35.
36. private static final boolean
37. "javax.activation.FileTypeMap", ResourceHttpRequestHandler.class.getClassLoader());
38.
39. private final static Log logger = LogFactory.getLog(ResourceHttpRequestHandler.class);
40.
41.
42. private
43.
44.
45. public
46. super(METHOD_GET, METHOD_HEAD);
47. }
48.
49. /**
50. * Set a {@code List} of {@code Resource} paths to use as sources
51. * for serving static resources.
52. */
53. public void
54. "Locations list must not be empty");
55. this.locations = locations;
56. }
57.
58. @Override
59. public void afterPropertiesSet() throws
60. if (logger.isWarnEnabled() && CollectionUtils.isEmpty(this.locations)) {
61. "Locations list is empty. No resources will be served");
62. }
63. }
64.
65. @Override
66. public void
67. throws
68.
69. true);
70.
71. // check whether a matching resource exists
72. List<Resource> resources = getResources(request);
73. if (resources == null
74. "No matching resource found - returning 404");
75. response.sendError(HttpServletResponse.SC_NOT_FOUND);
76. return;
77. }
78.
79. // check the resource's media type
80. MediaType mediaType = getMediaType((String)request
81. .getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE));
82. if (mediaType != null) {
83. if
84. "Determined media type '" + mediaType + "' for "
85. 0));
86. }
87. else
88. if
89. "No media type found for " + resources.get(0)
90. " - not sending a content-type header");
91. }
92. }
93.
94. for
95. // header phase
96. if (!new
97. .checkNotModified(resource.lastModified())) {
98. "Resource not modified - returning 304");
99. break;
100. }
101. return;
102. }
103.
104. setHeaders(response, resources, mediaType);
105.
106. // content phase
107. if
108. "HEAD request - skipping content");
109. return;
110. }
111. writeContent(response, resources);
112. }
113.
114. protected
115. null;
116. String mimeType = getServletContext().getMimeType(filename);
117. if
118. mediaType = MediaType.parseMediaType(mimeType);
119. }
120. if (jafPresent && (mediaType == null
121. MediaType jafMediaType = ActivationMediaTypeFactory.getMediaType(filename);
122. if (jafMediaType != null
123. mediaType = jafMediaType;
124. }
125. }
126. return
127. }
128.
129. protected void
130. throws
131. long length = 0;
132. //Calculation of multiple file length
133. Iterator<Resource> iter = resources.iterator();
134. while
135. length += iter.next().contentLength();
136. }
137. if
138. throw new
139. "Resource content too long (beyond Integer.MAX_VALUE)");
140. }
141. int) length);
142. if (mediaType != null) {
143. response.setContentType(mediaType.toString());
144. }
145. }
146.
147. protected void
148. throws
149. OutputStream out = response.getOutputStream();
150. null;
151. try
152. for
153. try
154. in = resource.getInputStream();
155. StreamUtils.copy(in, out);
156. finally
157. try
158. in.close();
159. catch
160. }
161. }
162. }
163. finally
164. try
165. out.close();
166. catch
167. }
168. }
169. }
170.
171. protected
172. String path = (String) request
173. .getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
174. if (path == null) {
175. throw new IllegalStateException("Required request attribute '"
176. + HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE
177. "' is not set");
178. }
179.
180. if
181. if
182. "Ignoring invalid resource path [" + path + "]");
183. }
184. return null;
185. }
186.
187. for (Resource location : this.locations) {
188. try
189. if
190. "Trying relative path ["
191. "] against base location: "
192. }
193. new
194. ",");
195. for
196. Resource resource = location.createRelative(url);
197. if
198. rs.add(resource);
199. }
200. }
201. return
202. catch
203. logger.debug(
204. "Failed to create relative resource - trying next resource location",
205. ex);
206. }
207. }
208. return null;
209. }
210.
211. /**
212. * Validates the given path: returns {@code true} if the given path is not a valid resource path.
213. * <p>The default implementation rejects paths containing "WEB-INF" or "META-INF" as well as paths
214. * with relative paths ("../") that result in access of a parent directory.
215. * @param path the path to validate
216. * @return {@code true} if the path has been recognized as invalid, {@code false} otherwise
217. */
218. protected boolean
219. return (path.contains("WEB-INF") || path.contains("META-INF") || StringUtils.cleanPath(path).startsWith(".."));
220. }
221.
222. /**
223. * Inner class to avoid hard-coded JAF dependency.
224. */
225. private static class
226.
227. private static final
228.
229. static
230. fileTypeMap = loadFileTypeMapFromContextSupportModule();
231. }
232.
233. private static
234. // see if we can find the extended mime.types from the context-support module
235. new ClassPathResource("org/springframework/mail/javamail/mime.types");
236. if
237. null;
238. try
239. inputStream = mappingLocation.getInputStream();
240. return new
241. }
242. catch
243. // ignore
244. }
245. finally
246. if (inputStream != null) {
247. try
248. inputStream.close();
249. }
250. catch
251. // ignore
252. }
253. }
254. }
255. }
256. return
257. }
258.
259. public static
260. String mediaType = fileTypeMap.getContentType(filename);
261. return (StringUtils.hasText(mediaType) ? MediaType.parseMediaType(mediaType) : null);
262. }
263. }
264. }
2.3 资源文件目录结构
2.4 浏览器缓存效果
2.5
5.实现淘宝CDN JS 请求例子
JS例子:http://127.0.0.1/r/js/alert.js,/js/application.js,/js/bootstrap.js
CSS例子:http://127.0.1.1/r/css/activity_style.css,/css/bootstrap_responsive.css
通过逗号(,)分割他们现在就实现了通过一个请求加载多个资源文件的效果了