`

基于Spring MVC的Web应用开发(3) - Resources

 
阅读更多

上一篇介绍了在基于Spring MVC的Web项目中加入日志,本文介绍Spring MVC如何处理资源文件。

注意到本项目的web.xml配置的DispatcherServlet对应的url-pattern为"/",即所有的URL请求都会经过Spring MVC的处理。实际的Web项目有大量的资源文件,如javascript文件,css文件,png,jpg等图片文件,甚至是Flash等等,我们没有必要对这些静态文件的访问都设置对应的URL,那样会造成大量重复性的劳动,以及维护上的复杂性。Spring MVC提供了一种机制,可以映射一种URL和一个location,此URL后面接的静态文件,对应着location目录下对应的静态文件。此配置为:

<resources mapping="/resources/**" location="/resources/" />

说明一下,

1. 访问http://localhost:8080/resources/test.png,浏览器显示webapp/resources/test.png

2. 访问http://localhost:8080/resources/scripts/test.js,浏览器显示webapp/resources/scripts/test.js

3. 访问http://localhost:8080/resources/css/2012/test.css,浏览器显示webapp/resources/css/2012/test.css

注意到mapping的值"/resources/**"有两个*,它表示映射resources/下所有的URL,包括子路径(即接多个/),如上面的1、2、3,如果只有一个*,将只能映射1级路径,即只能访问1,访问2、3将会报错。

很遗憾,如果只加这一行,带有@Controller类里面的@RequestMapping映射都不会生效。我是搜索到stackoverflow上的这个帖子联想到解决方案的,后来在stackoverflow搜到另外一个帖子有个还算比较详细的解释,帖子上说使用<mvc:resources/>时必须添加<mvc:annotation-driven/>,然后带有@Controller注解类的@RequestMapping映射信息才能被读取到。

现在servlet-context.xml为:

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:beans="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">

	<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
	
	<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources/ directory -->
	<resources mapping="/resources/**" location="/resources/" />
	
	<!-- Imports user-defined @Controller beans that process client requests -->
	<beans:import resource="controllers.xml" />
	
	<!-- You have to add this because you had a <resources/> declare -->
	<mvc:annotation-driven/>
	
</beans:beans>

访问http://localhost:8080/web/resources/test.js,浏览器上显示的正是test.js的内容。

 

下面解决HelloWorld那篇文章中遗留的一个问题,在那一篇文章中,@RequestMapping只有一个"/simple",但从日志中发现,有三种URL"/simple","/simple.*","/simple/"映射

INFO : org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping - Mapped URL path [/simple] onto handler 'simpleController'
INFO : org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping - Mapped URL path [/simple.*] onto handler 'simpleController'
INFO : org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping - Mapped URL path [/simple/] onto handler 'simpleController'

看看DefaultAnnotationHandlerMapping,这个类有个useDefaultSuffixPattern成员变量,默认为true,即默认识别一个URL的3种URL变种,在addUrlsForPath方法中如果if条件成立(useDefaultSuffixPattern=true),就加入了另外两种映射("/simple.*","/simple/"),

因此访问http://localhost:8080/web/simple/http://localhost:8080/web/simple.html,甚至http://localhost:8080/web/simple.foo(杜撰的后缀名)时,实际上和http://localhost:8080/web/simple这个URL是等效的。

 

处理完HelloWorld的遗留问题,很自然地,看看在增加了<mvc:resources/>后,启动日志中是如何映射的:

INFO : org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped "{[/simple],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.String org.springframework.samples.mvc.simple.SimpleController.simple()

不再是DefaultAnnotationHandlerMapping,而换成了RequestMappingHandlerMapping。

我们改变一下思路,从请求端看看SpringMVC如何处理上面说的三种URL。

访问http://localhost:8080/web/simple

DEBUG: org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Looking up handler method for path /simple
TRACE: org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Found 1 matching mapping(s) for [/simple] : [{[/simple],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}]

 访问http://lcoalhost:8080/web/simple.html

DEBUG: org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Looking up handler method for path /simple.html
TRACE: org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Found 1 matching mapping(s) for [/simple.html] : [{[/simple.*],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}]

 访问http://lcoalhost:8080/web/simple.foo(杜撰的后缀名

DEBUG: org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Looking up handler method for path /simple.foo
TRACE: org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Found 1 matching mapping(s) for [/simple.foo] : [{[/simple.*],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}]

  很奇妙,SpringMVC自动的识别了三种URL,这一切是怎么做到的呢?启动日志明明只Mapped了一个URL嘛。

还是要看看RequestMappingHandlerMapping的源代码,有两个属性useSuffixPatternMatch和useTrailingSlashMatch,

useSuffixPatternMatch(使用后缀模式匹配)默认为true,即可以识别"/simple.*",

useTrailingSlashMatch(末尾斜线匹配)默认为true,即可以识别"/simple/"。

最后注意到两次启动日志打印的类并不相同,

前面一个为DefaultAnnotationHandlerMapping,后面一个为RequestMappingHandlerMapping,这又是为什么呢?

原因就在加入了<mvc:resources/>后,Spring工厂对Bean的选型改变了,

没加<mvc:resouces/>前,SpringMVC使用默认策略,所以DefaultAnnotationHandlerMapping被使用了,

加了<mvc:resources/>后,SpringMVC不再使用默认策略,而是使用了RequestMappingHandlerMapping这个类,这应该是在源代码中写死的。

 

====================================================================

 

[补充说明,可不看,翻译的也很渣]Spring Reference Document(Spring官方手册)的16.14.5 Configuraing Serving of Resources这一节中对于Resources的介绍:

 

这个配置(<mvc:resources/>)给ResourceHttpRequestHandler配置了Resource位置,这样handler就可以处理一个特殊的URL模式对应的静态资源请求。它提供了一个很方便的方法直接从物理路径访问到静态资源,包括web应用的root路径和classpath上的路径。cache-period属性可以被用来设置未来可能会用上的实验性的header(可能一年以后吧,这要看诸如Page Speed和YSlow这样的优化工具的给力程度了),这样可以让它被客户端更有效的使用。这个handler也恰当地评估了Last-Modified这个header(如果有的话),因此304状态码(HTTP状态码,如我们常知道浏览器上返回的404错误 译者)会恰当的返回,避免已经被客户端缓存的资源再次访问服务端,造成负载。比如,要使用/resources/**这样的URL模式请求访问一个web应用的root内部public-resources目录下的服务端资源,你可以使用:

@EnableWebMvc
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
      
  @Override
  public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/resources/**").addResourceLocations("/public-resources/");
  }

}

XML中的相同配置在:

<mvc:resources mapping="/resources/**" location="/public-resources/"/>

下面对处理资源的配置可以满足刚才说的一年后的实验性特性,确保了浏览器缓存的最大化使用率和减少浏览器发起的HTTP请求:

@EnableWebMvc
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
      
  @Override
  public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/resources/**").addResourceLocations("/public-resources/").setCachePeriod(31556926);
  }

}

 同样在XML中:

<mvc:resources mapping="/resources/**" location="/public-resources/" cache-period="31556926"/>

 mapping这个属性必须是一个Ant模式(不太清楚什么是Ant模式 译者),该Ant模式可以被SimpleHandlerMapping使用,location属性必须指定一个或者多个有效的资源目录位置。多个资源位置可以通过使用逗号分隔符的列表值指定。指定的位置会根据任何给定的请求的资源的表现,按照一个特定的顺序被检查一遍。比如为了使我们即能访问web应用root路径又能访问classpath路径下任何一个jar包里一个已知的/META-INF/public-web-resources/路径,我们这样写:

@EnableWebMvc
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
      
  @Override
  public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/resources/**")
      .addResourceLocations("/", "classpath:/META-INF/public-web-resources/");
  }

}

 在XML中:

<mvc:resources mapping="/resources/**" location="/, classpath:/META-INF/public-web-resources/"/>

当资源有可能随着新版本的应用的发布而改变时,推荐你将一个版本字符串放进请求资源时使用的映射模式中,因此你可以强制客户端请求应用资源中部署的新版本。这样一个版本字符串使用SpEL配置,因此当部署新版本时,它可以很容易的在单个地方管理起来。

举个例子,我们考虑一个应用,它在生产环境使用一个性能优化过的定制的Dojo JavaScript库的构件,这个构件通常在一个web应用中的/public-resources/dojo/dojo.js路径下部署。因为对于应用的每个新版本,Dojo的不同部分可能会合并成一个定制构件,客户端浏览器需要强制性的重新下载定制构件dojo.js资源,只要一个新版本的应用被部署了。一个简单的打包方式就是在一个.properties配置文件中管理应用的版本,比如:

application.version=1.0.0

 然后在一个bean中使用<util:properties/>标签来让properties文件中的值可以被SpEL访问到:

<util:properties id="applicationProps" location="/WEB-INF/spring/application.properties"/>

现在通过SpEL,application.version可以访问了,我们可以将它合并到<resource/>标签里。

<mvc:resources mapping="/resources-#{applicationProps['application.version']}/**" location="/public-resources/"/>

 在Java类中,你可以使用@PropertiesSource注解,然后注入Environment抽象类,来访问到所有预定义的属性值:

@EnableWebMvc
@Configuration
@PropertySource("/WEB-INF/spring/application.properties")
public class WebConfig extends WebMvcConfigurerAdapter {

  @Inject Environment env;

  @Override
  public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/resources-" + env.getProperty("application.version") + "/**")
      .addResourceLocations("/public-resources/");
  }

}

最后,为了使用合适的URL请求资源,我们可以利用Spring JSP标签:(在JSP页面中使用的 译者)

<spring:eval expression="@applicationProps['application.version']" var="applicationVersion"/>

<spring:url value="/resources-{applicationVersion}" var="resourceUrl">
    <spring:param name="applicationVersion" value="${applicationVersion}"/>
</spring:url>

<script src="${resourceUrl}/dojo/dojo.js" type="text/javascript"> </script>
 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

分享到:
评论
2 楼 baso4233 2012-10-30  
  拜读
1 楼 karvenlin 2012-07-13  
如果把静态资源放入到WEB-INF中怎么进行配置,在页面中如何来引用?
[img][/img]

相关推荐

    Spring MVC step-by-step 源码

    Spring MVC 是一个强大的Java Web开发框架,用于构建高效、可维护的Web应用程序。它基于Spring框架,提供了模型-视图-控制器(MVC)架构,简化了开发过程。本资源"Spring MVC step-by-step 源码"是针对初学者准备的...

    spring-mvc-step-by-step(PDF)

    Spring MVC是Spring框架中的一个模块,主要用于构建Web应用。它基于MVC(Model-View-Controller)设计模式,使得开发者能够清晰地分离业务逻辑、数据处理和用户界面。本章节将详细介绍如何从零开始搭建一个Spring ...

    spring-mvc-step-by-step.pdf

    本文档将逐步引导你学习并理解Spring MVC框架的构建过程,从基础环境设置到实际应用开发,深入解析Spring MVC的核心概念和实践技巧。Spring MVC是Spring框架的一个重要组成部分,用于构建高性能、可维护的Web应用...

    spring+spring mvc+mybatis+x-admin搭建后台

    首先,Spring框架是一个全面的企业级应用开发框架,它提供了一个简化Java EE开发的环境,包括依赖注入(Dependency Injection, DI)、面向切面编程(Aspect-Oriented Programming, AOP)以及一系列的企业服务。...

    基于Spring框架的Java Web项目--问卷调查系统.zip

    Spring是一个强大的、开源的Java平台,它提供了全面的企业级应用开发解决方案,包括依赖注入(DI)、面向切面编程(AOP)以及丰富的MVC框架,使得开发高质量的Web应用变得更为简单。 1. **Spring框架基础**: - **...

    Developing a Spring Framework MVC application step-by-step

    在本文中,我们将深入探讨如何逐步开发一个基于Spring框架的MVC(Model-View-Controller)应用程序。Spring MVC是Spring框架的一个重要模块,它为构建Web应用提供了强大的支持,包括模型处理、视图渲染和控制器逻辑...

    spring-mvc-step-by-step

    Spring MVC是Spring框架中的一个模块,主要用于构建基于模型-视图-控制器(Model-View-Controller, MVC)设计模式的Web应用程序。该教程覆盖了从环境搭建到集成数据库的全过程,并提供了丰富的代码示例。 #### 1. ...

    spring-mvc-study.zip

    Spring MVC 是一个基于Java的轻量级Web应用框架,它为构建RESTful应用程序提供了强大的支持。在本项目"spring-mvc-study.zip"中,我们可以深入理解并实践Spring MVC的核心概念和技术。 首先,Spring MVC是Spring...

    Java Web工程demo 后端:spring + spring mvc + mybatis + -webbf.zip

    Java Web工程演示是一个基于Spring、Spring MVC和MyBatis框架的后端开发示例,名为"webbf"。这个项目提供了完整的开发环境配置,旨在帮助开发者理解和实践如何将这三个核心框架整合到一个Web应用程序中。下面我们将...

    基于spring mvc+spring data+Thymeleaf+mysql的简单工程

    这是一个基于Spring MVC、Spring Data、Thymeleaf和MySQL数据库构建的简单Web应用程序工程。这个项目的核心在于利用这些技术栈来实现数据的CRUD(创建、读取、更新和删除)操作,并通过Web界面进行交互。 **Spring ...

    一个基于spring mvc的论坛.zip

    通过深入学习和实践这个基于 Spring MVC 的论坛项目,你可以掌握 MVC 模式的应用,理解 Spring 框架的核心机制,并提升 Java Web 开发能力。同时,这也是一个很好的机会去熟悉项目管理和版本控制工具,例如 Git,这...

    一个完整的Spring MVC的CRUD操作实例

    Spring MVC 是一个强大的Java web开发框架,用于构建高效、可维护和模块化的Web应用程序。它基于Spring框架,提供了模型-视图-控制器(MVC)架构模式,简化了从前端到后端的数据处理流程。本实例将深入探讨如何实现...

    一个改进版的spring-mvc-showcase

    "一个改进版的spring-mvc-showcase"是一个项目示例,它基于Spring MVC框架进行了一些优化和增强。Spring MVC是Spring框架的一个模块,主要用于构建Web应用程序。它提供了一个灵活的模型-视图-控制器(MVC)架构,...

    Maven-Spring-Spring-MVC-MyBatis-MySQL

    3. **Spring MVC**:Spring MVC是Spring框架的一个模块,专门用于处理Web层的请求和响应。它提供了模型-视图-控制器(MVC)的设计模式,帮助开发者分离业务逻辑、数据处理和用户界面。在项目中,Spring MVC负责接收...

    spring4-mvc-gradle

    尤其是Spring MVC,作为Spring框架的一部分,为构建基于Java的Web应用程序提供了高效且易于使用的模型-视图-控制器(MVC)架构。而Gradle,作为一种强大的构建自动化工具,逐渐取代了传统的Maven,以其丰富的插件...

    SevenDay-Spring MVC(基于Spring MVC实现文件上传与下载)的源代码

    Spring MVC 是一个强大的Java web开发框架,用于构建可维护、高性能和灵活的Web应用程序。它在Spring框架的基础上提供了模型-视图-控制器(MVC)架构模式,简化了Web应用的开发。在这个"SevenDay-Spring MVC 实现...

    Spring MVC eclipse开发(Demo源码)

    Spring MVC 是一个基于Java的轻量级Web应用框架,它为构建模型-视图-控制器(MVC)架构的Web应用程序提供了强大的支持。Eclipse是一款广泛使用的集成开发环境(IDE),对于Java开发,包括Spring MVC项目,Eclipse 提供了...

    spring.mvc.hibernate231security-CRUD

    在这个项目中,我们将深入探讨这三大核心技术在Web应用开发中的整合与使用。 **Spring MVC** Spring MVC是Spring框架的一部分,它是一个模型-视图-控制器(MVC)架构模式的实现,用于构建可维护、可扩展的Web应用...

    基于Spring MVC+Spring+Mybatis+Mysql 客户关系管理系统 SSM毕业设计

    SSM框架是Java Web开发中常用的一种组合,由Spring MVC、Spring和Mybatis三个组件构成,用于构建高效、灵活的Web应用。这个基于SSM的客户关系管理系统(CRM)毕业设计,利用了Maven进行项目构建,确保了依赖管理的便捷...

    SixDay-Spring MVC(基于Spring MVC实现后台登陆系统验证)的源代码

    Spring MVC是Java Web开发中的一个强大框架,它提供了模型-视图-控制器(MVC)架构模式,帮助开发者构建可维护、可扩展的Web应用。我们将主要关注以下几个核心知识点: 1. **Spring MVC 框架结构** Spring MVC框架...

Global site tag (gtag.js) - Google Analytics