13.7. 使用主题

13.7.1. 简介

Sping的web MVC框架允许你通过主题(theme)来控制网页的风格,这将进一步改善用户的体验。 简单来说,一个主题就是一组静态的资源(比如样式表和图片),它们可以影响应用程序的视觉效果。

13.7.2. 如何定义主题

为了在web应用中使用主题,需要设置org.springframework.ui.context.ThemeSourceWebApplicationContext是从ThemeSource扩展而来, 但是它本身并没有实现ThemeSource定义的方法,它把这些任务转交给别的专用模块。 如果没有明确设置,真正实现ThemeSource的类是org.springframework.ui.context.support.ResourceBundleThemeSource。 这个类在classpath的根部(比如在/WEB-INF/classes目录下)寻找合适的属性文件来完成配置。 如果想自己实现ThemeSource接口, 或者需要配置ResourceBundleThemeSource所需的属性文件的前缀名(basename prefix), 可以在应用上下文中定义一个名为"themeSource"的bean(注意,必须用这个名字)。 web application context会自动检测并使用这个bean。

在使用ResourceBundleThemeSource时,每个主题是用一个属性文件来配置的。 这个属性文件中列举了构成一个主题所需的资源。比如:

styleSheet=/themes/cool/style.css
background=/themes/cool/img/coolBg.jpg

这些属性的名字应该和视图中的某些主题元素(themed element)一一对应。 在JSP视图中,这些元素通常用spring:theme标签声明(这个标签的用法和spring:message很相似)。 下文这个JSP片段使用了我们在前面定义的主题:

<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<html>
   <head>
      <link rel="stylesheet" href="<spring:theme code="styleSheet"/>" type="text/css"/>
   </head>
   <body background="<spring:theme code="background"/>">
      ...
   </body>
</html>

除非有特殊配置,当ResourceBundleThemeSource寻找所需的属性文件时,它默认在配置的属性文件名中没有任何前缀, 也就是说,它只会在classpath的根部寻找。举例来说,如果一个主题的定义包含在cool.properties这个属性文件中, 需要把这个文件放在classpath的根部,比如在/WEB-INF/classes目录下。 同时,ResourceBundleThemeSource 使用标准的Java resource bundle管理机制, 这意味着实现主题的国际化是很容易的。 比如,/WEB-INF/classes/cool_nl.properties这个属性文件中可以指向一个显示荷兰文字的图片。

译者注:如果对ResourceBundle和它的属性文件名的规范不熟悉,请参阅JavaDoc中关于ResourceBundle.getBundle(String baseName,Locale locale)这个API。 这个baseName参数和属性文件名有一定关系。 比如,如果cool.properties这个属性文件放置在了/WEB-INF/classes/com/aa/bb/cc目录下, 那么这个baseName的值应该为com.aa.bb.cc.cool。 在这里,com.aa.bb.cc就是这个属性文件名的前缀(basename prefix)。 支持前缀的API会在前缀所声明的目录下寻找相应的文件,比如getBundle()。 如果没有特殊的配置,ResourceBundleThemeSource不支持前缀, 在这种情况下你要把它所需要的属性文件放在/WEB-INF/classes目录下。

13.7.3. 主题解析器

现在我们已经知道如何定义主题了,剩下的事就是决定该用哪个主题。 DispatcherServlet会寻找一个叫“themeResolver”的bean, 这个bean应该实现了ThemeResolver接口。 主题解析器的工作流程和LocaleResolver差不多。 它可以解析每个请求所对应的主题,也可以动态地更换主题。下面是Spring提供的几个主题解析器:

表 13.6. ThemeResolver的实现

Java类 描述
FixedThemeResolver 选用一个固定的主题,这个主题由“defaultThemeName”属性决定。
SessionThemeResolver 主题保存在用户的HTTP session。在每个session中,这个主题只需要被设置一次,但是每个新session的主题都要重新设置。
CookieThemeResolver 用户所选择的主题以cookie的形式存在客户端的机器上面。

Spring 也支持一个叫ThemeChangeInterceptor 的请求拦截器。它可以根据请求中包含的参数来动态地改变主题。