1. SpringMVC XML 配置
<!-- 简单URLaction映射 -->
<bean id="simpleUrlHandlerMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <property name="urlMap"> <map> <!-- 静态资源处理器 --> <entry key="/r/**/**"> <!-- 自己扩展的SpingMVC ResourceHttpRequestHandler 类,增加了类是与淘宝CDN通过逗号(,)隔开 访问多个js的效果 此功能不能压缩JS 如果想实现压缩功能可通过maven 或者 ant 在编译的时候进行压缩 --> <bean class="com.yoro.core.springmvc.ResourceHttpRequestHandler"> <property name="locations"> <list> <!-- 只有相同目录的JS文件才能实现淘宝CDN通过逗号(,)隔开 访问多个js的效果 如 /r/ 目录下的js|css 文件 就能实现 /r/js/ 目录下的js文件也可以有同样的效果 但 /a/css 下面的文件 和 /r/css 就不能实现 有点小遗憾,因为时间关系待以后升级 --> <value>/r/</value> </list> </property> <!-- 启用静态资源浏览器缓存一个月 --> <!-- 通过浏览器进行的缓存 根据可浏览器实现方式不同有所差异 按刷新按扭缓存不会起 当是页面跳转或者地址栏输入则缓存会起作用 --> <!-- 更过浏览器缓存的资料和特效 可 搜索 cachecontrol 设置 cacheSeconds 缓存时间单位是秒 2592000 表示缓存30天 因为我自己每次新版本发布都会都js css 文件增加版本号 所以缓存时间我设置的比较长 --> <property name="cacheSeconds" value="2592000"></property> <property name="useExpiresHeader" value="true"></property> <property name="useCacheControlNoStore" value="true"></property> </bean> </entry> <entry key="/thirdparty/**/**"> <bean class="com.yoro.core.springmvc.ResourceHttpRequestHandler"> <property name="locations"> <list> <value>/thirdparty/</value> </list> </property> <!-- 启用静态资源浏览器缓存一个月 --> <property name="cacheSeconds" value="2592000"></property> <property name="useExpiresHeader" value="true"></property> <property name="useCacheControlNoStore" value="true"></property> </bean> </entry> </map> </property> <property name="order" value="1"></property> </bean>
2. 资源文件目录结构
3. 浏览器缓存效果
4.ResourceHttpRequestHandler 扩展类代码
package com.yoro.core.springmvc; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import javax.activation.FileTypeMap; import javax.activation.MimetypesFileTypeMap; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; import org.springframework.http.MediaType; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.CollectionUtils; import org.springframework.util.StreamUtils; import org.springframework.util.StringUtils; import org.springframework.web.HttpRequestHandler; import org.springframework.web.context.request.ServletWebRequest; import org.springframework.web.servlet.HandlerMapping; import org.springframework.web.servlet.support.WebContentGenerator; public class ResourceHttpRequestHandler extends WebContentGenerator implements HttpRequestHandler, InitializingBean { private static final boolean jafPresent = ClassUtils.isPresent("javax.activation.FileTypeMap", ResourceHttpRequestHandler.class.getClassLoader()); private final static Log logger = LogFactory.getLog(ResourceHttpRequestHandler.class); private List<Resource> locations; public ResourceHttpRequestHandler() { super(METHOD_GET, METHOD_HEAD); } /** * Set a {@code List} of {@code Resource} paths to use as sources * for serving static resources. */ public void setLocations(List<Resource> locations) { Assert.notEmpty(locations, "Locations list must not be empty"); this.locations = locations; } @Override public void afterPropertiesSet() throws Exception { if (logger.isWarnEnabled() && CollectionUtils.isEmpty(this.locations)) { logger.warn("Locations list is empty. No resources will be served"); } } @Override public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { checkAndPrepare(request, response, true); // check whether a matching resource exists List<Resource> resources = getResources(request); if (resources == null || resources.isEmpty()) { logger.debug("No matching resource found - returning 404"); response.sendError(HttpServletResponse.SC_NOT_FOUND); return; } // check the resource's media type MediaType mediaType = getMediaType((String)request .getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE)); if (mediaType != null) { if (logger.isDebugEnabled()) { logger.debug("Determined media type '" + mediaType + "' for " + resources.get(0)); } } else { if (logger.isDebugEnabled()) { logger.debug("No media type found for " + resources.get(0) + " - not sending a content-type header"); } } for (Resource resource : resources) { // header phase if (!new ServletWebRequest(request, response) .checkNotModified(resource.lastModified())) { logger.debug("Resource not modified - returning 304"); break; } return; } setHeaders(response, resources, mediaType); // content phase if (METHOD_HEAD.equals(request.getMethod())) { logger.trace("HEAD request - skipping content"); return; } writeContent(response, resources); } protected MediaType getMediaType(String filename) { MediaType mediaType = null; String mimeType = getServletContext().getMimeType(filename); if (StringUtils.hasText(mimeType)) { mediaType = MediaType.parseMediaType(mimeType); } if (jafPresent && (mediaType == null || MediaType.APPLICATION_OCTET_STREAM.equals(mediaType))) { MediaType jafMediaType = ActivationMediaTypeFactory.getMediaType(filename); if (jafMediaType != null && !MediaType.APPLICATION_OCTET_STREAM.equals(jafMediaType)) { mediaType = jafMediaType; } } return mediaType; } protected void setHeaders(HttpServletResponse response, List<Resource> resources, MediaType mediaType) throws IOException { long length = 0; //Calculation of multiple file length Iterator<Resource> iter = resources.iterator(); while (iter.hasNext()) { length += iter.next().contentLength(); } if (length > Integer.MAX_VALUE) { throw new IOException( "Resource content too long (beyond Integer.MAX_VALUE)"); } response.setContentLength((int) length); if (mediaType != null) { response.setContentType(mediaType.toString()); } } protected void writeContent(HttpServletResponse response, List<Resource> resourcess) throws IOException { OutputStream out = response.getOutputStream(); InputStream in = null; try { for (Resource resource : resourcess) { try { in = resource.getInputStream(); StreamUtils.copy(in, out); } finally { try { in.close(); } catch (IOException ex) { } } } } finally { try { out.close(); } catch (IOException ex) { } } } protected List<Resource> getResources(HttpServletRequest request) { String path = (String) request .getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE); if (path == null) { throw new IllegalStateException("Required request attribute '" + HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE + "' is not set"); } if (!StringUtils.hasText(path) || isInvalidPath(path)) { if (logger.isDebugEnabled()) { logger.debug("Ignoring invalid resource path [" + path + "]"); } return null; } for (Resource location : this.locations) { try { if (logger.isDebugEnabled()) { logger.debug("Trying relative path [" + path + "] against base location: " + location); } List<Resource> rs = new ArrayList<Resource>(); String[] paths = path.split(","); for (String url : paths) { Resource resource = location.createRelative(url); if (resource.exists() && resource.isReadable()) { rs.add(resource); } } return rs; } catch (IOException ex) { logger.debug( "Failed to create relative resource - trying next resource location", ex); } } return null; } /** * Validates the given path: returns {@code true} if the given path is not a valid resource path. * <p>The default implementation rejects paths containing "WEB-INF" or "META-INF" as well as paths * with relative paths ("../") that result in access of a parent directory. * @param path the path to validate * @return {@code true} if the path has been recognized as invalid, {@code false} otherwise */ protected boolean isInvalidPath(String path) { return (path.contains("WEB-INF") || path.contains("META-INF") || StringUtils.cleanPath(path).startsWith("..")); } /** * Inner class to avoid hard-coded JAF dependency. */ private static class ActivationMediaTypeFactory { private static final FileTypeMap fileTypeMap; static { fileTypeMap = loadFileTypeMapFromContextSupportModule(); } private static FileTypeMap loadFileTypeMapFromContextSupportModule() { // see if we can find the extended mime.types from the context-support module Resource mappingLocation = new ClassPathResource("org/springframework/mail/javamail/mime.types"); if (mappingLocation.exists()) { InputStream inputStream = null; try { inputStream = mappingLocation.getInputStream(); return new MimetypesFileTypeMap(inputStream); } catch (IOException ex) { // ignore } finally { if (inputStream != null) { try { inputStream.close(); } catch (IOException ex) { // ignore } } } } return FileTypeMap.getDefaultFileTypeMap(); } public static MediaType getMediaType(String filename) { String mediaType = fileTypeMap.getContentType(filename); return (StringUtils.hasText(mediaType) ? MediaType.parseMediaType(mediaType) : null); } } }
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
通过逗号(,)分割他们现在就实现了通过一个请求加载多个资源文件的效果了
相关推荐
通过在web.xml文件中对默认Servlet进行映射(通常是url-pattern为/*),可以让默认Servlet先于SpringMVC的DispatcherServlet处理静态资源的请求。这种方法的优点是不需要在SpringMVC的拦截器中进行繁琐的配置,而且...
在SpringMVC框架中,实现文件的上传与下载是常见的需求。IntelliJ IDEA作为流行的Java开发集成环境,为开发者提供了高效便捷的开发体验。在这个项目中,我们使用IDEA来构建一个基于SpringMVC的系统,实现了文件的...
在SpringMVC框架中,文件的上传和下载是常见的功能需求,主要用于处理用户的数据交互,例如用户上传图片、文档等,或者系统提供文件下载服务。本文将深入探讨如何使用SpringMVC来实现这一功能。 首先,我们需要理解...
SpringMVC的核心组件包括DispatcherServlet、ModelAndView、Controllers等,它们协同工作以实现高效的请求处理。 接下来,CDN(Content Delivery Network)是一种分布式网络服务,通过在网络的多个节点上缓存静态...
基于springmvc实现文件上传下载 基于AOP的日志功能基于springmvc实现文件上传下载 基于AOP的日志功能基于springmvc实现文件上传下载 基于AOP的日志功能基于springmvc实现文件上传下载 基于AOP的日志功能基于...
在本项目中,我们结合了SpringMVC、Hadoop和Maven这三个技术,构建了一个能够实现文件从Web端上传到HDFS(Hadoop Distributed File System)的系统。下面将详细阐述这三个技术及其在项目中的应用。 首先,SpringMVC...
`SpringMVC`作为Java后端的一个强大框架,提供了处理文件上传的能力。而`Ajax`技术则使得页面可以在不刷新的情况下与服务器进行交互,实现异步上传,极大地提升了用户体验。在本教程中,我们将探讨如何结合`...
在这个“SpringMVC文件上传,多文件上传实例”中,我们将深入探讨如何在SpringMVC环境中实现文件上传功能,包括单个文件上传以及多个文件的批量上传。 1. **文件上传原理**: 文件上传是通过HTTP协议的POST请求来...
以下将详细讲解SpringMVC如何实现单文件上传、多文件上传、文件列表显示以及文件下载。 1. **单文件上传** 在SpringMVC中,我们可以使用`@RequestParam("file") MultipartFile file`注解来接收前端提交的单个文件...
Netty 是一个高性能、异步事件驱动的网络应用程序框架,常用于开发高并发、低延迟的网络服务。SpringMVC 是 Spring 框架的一部分...这种整合方式尤其适用于大文件下载或高并发场景,能充分利用硬件资源,提升用户体验。
在本项目中,我们利用 SpringMVC 实现了文件上传的功能,并将这些文件存储到七牛云存储服务上。 首先,我们需要了解 SpringMVC 中的文件上传机制。在 SpringMVC 中,文件上传是通过 `CommonsMultipartResolver` ...
总结起来,使用SpringMVC实现登录功能涉及的知识点包括:SpringMVC的MVC架构、Controller的请求处理、模型绑定、服务层的业务逻辑、Session管理、Spring Security的安全控制、视图解析和错误处理。掌握这些知识点,...
SpringMVC提供了一种优雅的方式实现国际化,主要通过消息资源文件和`LocaleResolver`实现。 1. **创建消息资源文件**:在项目的`src/main/resources`目录下,创建对应不同语言的.properties文件,如`messages_en....
【标题】:“基于EasyUI+SpringMVC实现的文件管理系统” 在现代企业信息化管理中,文件管理系统扮演着至关重要的角色,它能够有效地组织、存储、检索和管理企业内部的各类文档,提高工作效率,保证信息的安全性。本...
springMvc 文件上传,springMvc 支持单文件和多文件上传,
总的来说,"springMVC整合MyBatis+sql文件"是一个包含用户登录、分页查询等功能的Web应用示例,它演示了如何将SpringMVC和MyBatis结合使用,通过SQL文件进行数据操作。开发者可以在这个基础上学习如何搭建类似的系统...
SpringMVC是Spring框架的一部分,专门用于处理Web应用程序的请求-响应模型。它是一个轻量级的、基于注解的模型-视图-控制器(MVC)架构,为Java开发者提供了一种简单而强大的方式来构建可维护的Web应用。在...
本篇将详细探讨如何利用SpringMVC结合EasyUI实现文件下载功能,并着重讲解SpringMVC中的注解技术。 首先,SpringMVC是Spring框架的一部分,它提供了模型-视图-控制器(MVC)架构模式的实现,简化了Java Web应用程序...
在SpringMVC中实现文件上传是一项常见的任务,它允许用户通过表单将本地文件发送到服务器进行存储或处理。这个"SpringMVC文件上传Demo代码"是一个实例,演示了如何配置和使用SpringMVC来实现这一功能。 首先,我们...
SpringMVC的拦截器是基于Servlet的Filter机制扩展而来的,它通过`HandlerInterceptor`接口实现。这个接口定义了三个方法:`preHandle()`、`postHandle()` 和 `afterCompletion()`。当一个请求到达时,SpringMVC会...