第25章 认识更多Spring MVC家族成员(五)

第25章 认识更多Spring MVC家族成员(五)不管是使用Windows操作系统还是使用Linux操作系统,当我们对某种风格的桌面主题感到厌烦的时候,我们就会安装并切换到某种新的桌面主题上。对于Web应用程序来说,为了能够给用户提供更丰富的交互体验,也同样可以提供类似桌面主题的功能。实际上,不管是什么场景下的主题(Theme)功能,它们在本质上都是类似的,无非就是变更一下显示的材质风格对于操作系统的桌面主题,可能是鼠标样式或者工具条颜色等变更一下;对于Web应用程序来说,可能就是对影响整体风格显示的背景图片,或者某些固定部位的颜色做一些变更。…

第25章 认识更多Spring MVC家族成员

25.6 主题(Theme)与ThemeResolver

不管是使用Windows操作系统还是使用Linux操作系统,当我们对某种风格的桌面主题感到厌烦的时候,我们就会安装并切换到某种新的桌面主题上。对于Web应用程序来说,为了能够给用户提供更丰富的交互体验,也同样可以提供类似桌面主题的功能。实际上,不管是什么场景下的主题(Theme)功能,它们在本质上都是类似的,无非就是变更一下显示的材质风格:

  • 对于操作系统的桌面主题,可能是鼠标样式或者工具条颜色等变更一下;

  • 对于Web应用程序来说,可能就是对影响整体风格显示的背景图片,或者某些固定部位的颜色做一些变更。

这就好像我们人穿衣服一样,每天换上不同风格式样的衣服,实际上就是在变换主题啦!

Spring MVC框架提供了对Web应用程序所需要的主题功能的支持,下面具体介绍完成这一功能的几位角色。

25.6.1 提供主题资源的ThemeSource

通常,Web应用程序的主题是由一些能够影响整体应用显示的静态资源组成的,比如固定位置的背景图片、能够影响页面显示风格的CSS(层叠样式表)文件等。在Spring MVC中,org.springframework.ui.context.ThemeSource负责管理针对各个主题的那些静态资源,该接口定义如下:

public interface ThemeSource { 
   
  Theme getTheme(String themeName);
}

ThemeSource可以根据指定的主题名称(themeName)查找并返回对应的Theme实例。这样,客户端就可以使用Theme实例中的相应资源来定制视图的显示了。为了能够通过ThemeSource获取相应的主题资源,DispatcherServlet会在处理Web请求之前获取可用的ThemeSource实例,以便能够根据客户端的请求返回相应的主题资源。而实际上DispatcherServlet获取的ThemeSource实例就是它自身所使用的WebApplicationContext。因为WebApplicationContext本身就是一个ThemeSource(它自己实现了ThemeSource接口)。事情到这里并没有完,虽然WebApplicationContext身为ThemeSource,但它和它的实现类一概不干实事。当有主题相关的请求需要处理的时候,它们都是将工作委派给某个ThemeSource的具体实现类,比如org.springframework.ui.context.support.ResourceBundleThemeSource。

ResourceBundleThemeSource允许我们以properties文件来定义每个主题所持有的各项资源,比如:

# default.properties
theme.background.image = ../images/default-bg-image.jpg
theme.css = ...

# blue.properties
theme.background.image = ../images/blue-bg-image.jpg
theme.css = 

我们分别在default.properties和blue.properties中定义default和blue两个主题对应的材质资源。这样,在具体视图中,我们就可以根据这些主题资源文件中的代码,查找相应的主题资源并应用到视图。比如,如果我们使用JSP作为视图技术,那么可以直接使用Spring提供的theme自定义标签对主题资源进行访问,如下所示:

<%@ taglib prefix="spring" uri="http:1/www.springframework.org/tags" %>
...
<style type="text/css">
<!--
  body {
		background-image:url(<spring:theme code="theme.background.image"/>);
  }
-->
</style>
...

而如果是使用其他视图技术,比如Velocity/Freemarker等,就可以通过为相应视图公开RequestContext的方式来访问主题的相关信息。下方代码清单给出的是Velocity视图模板对应的情况。

# in velocity templatefile
<html>
<style type="text/css">
<!--
body {
	background-image:url(${rc.getThemeMessage("theme.background.?mage")});
}
-->
</style>
...

不管怎么样,只要将当前使用的主题名称告知IResourceBundleThemeSource,它就能返回对应主题名的properties文件中的相应资源。因为ResourceBundleThemeSource是基于Java标准的ResourceBundle构建的,所以它同样也支持不同Locale下的主题。比如,同样是blue主题,在默认Locale下所使用的主题资源与在其他Locale下所使用的主题资源就可能不同,那么,我们可以按照ResourceBundle国际化支持规则,提供同一主题不同Locale下的主题资源定义,如下所示:

# blue.properties
theme.background.image = ../images/blue-bg-image.jpg
theme.css = ...
...

# blue_zh_CN.properties
theme.background.image = ../images/blue-bg-image-with-chinese-characters.jpg
theme.css = ...
...

现在,如果用户对应中文的Locale并且选择使用blue这一主题的话,ResourceBundleThemeSource将从blue_zh_CN.properties资源文件中为其返回对应的主题资源。

为了能让DispatcherServlet获取到ResourceBundleThemeSource的支持,我们需要将某一ResourceBundleThemeSource实例添加到DispatcherServlet的WebApplicationContext中,如下所示:

<bean id="themeSource" class="org.springframework.ui.context.support..ResourceBundleThemeSource" p:basenamePrefix="cn.spring21.simplefx.resources.themes.">
</bean>

所配置的ResourceBundleThemeSource实例的bean定义名称必须是“themeSource”,因为默认情况下,WebApplicationContext就是将所有主题相关的请求处理委派给拥有这一名称的ThemeSource实例。默认情况下,ResourceBundleThemeSource将根据主题名称到classpath的根路径下查找相应的properties文件,这当然就要求我们将所有主题properties资源文件放到classpath的根路径下。不过,我们可以通过其basenamePrefix属性定制查找起始路径,就像我们的代码示例所演示的那样,唯一需要注意的就是前缀需要以“.”结束。

在DispatcherServlet有了可用的ThemeSource之后,就会把它绑定到HttpServletRequest的属性上,等着后面谁来用了。那么到底是谁来用呢?

25.6.2 管理主题的ThemeResolver

现在,通过指定的主题名称,我们就能够从DispatcherServlet所使用的ThemeSource那里获取主题对应的各项资源,然后视图就能够根据这些主题资源来定制视图显示。ThemeSource已经准备就绪了,那主题名称又该如何定夺呢?显然,我们得通过某种方式获取用户当前所选择的主题才行,否则,我们怎么知道使用哪个主题名称到ThemeSource查找要用的主题资源呢?

为了获取并管理用户的Locale信息,Spring MVC提供了LocaleResolver与此类似,为了获取并管理用户所选择的主题,Spring MVC提供了ThemeResolver。

org.springframework.web.servlet.ThemeResolver的主要工作就是解析并获取对应当前请求的主题是什么。如果相应实现机制支持存储的话,也允许对当前请求相关的主题进行设置变更。ThemeResolver的定义如下:

public interface ThemeResolver { 
   
	String resolveThemeName(HttpServletRequest request);
	void setThemeName(HttpServletRequest request, HttpServletResponse response, String themeName);
}

有LocaleResolver在先,我想ThemeResolver并不难理解。显然,DispatcherServlet通过ThemeResolver的resolveThemeName(..)方法就能够获得用户所选择的主题是什么。那么剩下的工作,当然就是根据这个主题的名称到ThemeSource那里获取相应资源进行显示啦。不过,DispatcherServlet背定无法直接借助于ThemeResolver这一接口来完成工作,所以,还是来看一下Spring MVC都提供了哪些可用的ThemeResolver实现类吧!

除了不能像LocaleResolver那样通过HTTP的Accept-Language协议头来获取主题信息之外,ThemeResolver可以使用LocaleResolver所使用的其他三种策略来获取并且管理用户的主题,如下所述。

  • org.springframework.web.gervlet.theme.FixedThemeResolver。如果我们不明确为DispatcherServlet指定任何ThemeResolver实例供其使用,DispatcherServlet将默认使用FixedThemeResolver来管理用户的主题。顾名思义,一旦使用FixedThemeResolver指定了主题之后,主题将保持不变。所以,对FixedThemeResolver进行setThemeName(..)操作显然是不行的。

  • org.springframework.web.servlet.theme.SessionThemeResolver。HttpSession是SessionThemeResolver得以生存的土壤,SessionThemeResolver将按照指定的属性名称到Session中获取用户的主题。如果找不到,则使用默认的主题。这可以通过其defaultThemeName属性进行指定。因为我们可以对Session的属性进行设置,所以,SessionThemeResolver可以通过setThemeName(..)方法重新设置用户主题。

  • org.springframework.web.servlet.theme.CookieThemeResolver。SessionThemeResolver以HttpSession作为主题信息的载体,而CookieThemeResolver则以Cookie作为主题信息的载体。只要用户端浏览器不禁止Cookie的使用,我们就可以使用CookieThemeResolver对用户选择的主题进行管理,包括获取和更新。

现在,只要将以上任一ThemeResolver实现添加到DispatcherServlet的WebApplicationContext中,DispatcherServlet就能够“左右逢源”了:

<bean id="themeResolver" class="org.springframework.Web.servlet.theme.SessionThemeResolver" p:defaultThemeName="default">
</bean>

我们这里使用了SessionThemeResolver。不管使用哪种ThemeResolver,注册到容器的bean定义的名称为“themeResolver”是必须的,因为DispatcherServlet初始化的时候将根据这一名称到其自己的WebApplicationContext中获取可用的ThemeResolver实例。

25.6.3 切换主题的ThemeChangeInterceptor

如果用户永远只能使用一种风格的主题,那么显然提供主题的功能就没有了任何的意义。只有允许用户根据喜好切换主题,才能够体现主题功能丰富用户体验的价值。

在Spring MVC中,用户要切换Locale有LocaleChangeInterceptor来相助,而用户要切换主题的时候,也同样有ThemeChangeInterceptor来帮忙。只要将用户选择要切换到的主题以某个参数提交到服务器端处理,ThemeChangeInterceptor就能够根据这一参数重新设置用户所使用的主题,之后,视图就可以获取切换后的主题来定制视图的显示了。当然,要让ThemeChangeInterceptor生效,我们自然需要将它与提交主题变更的Web请求联系到一起,如下方代码清单所示。

<bean id="handlerMapping" class="org.springframework.Web.servlet.hand1er.BeanNameUrlHandlerMapping">
	<property name="interceptors">
		<list>
			<ref bean="themeChangeInterceptor"/>
			<ref bean="marketAccessInterceptor"/>
			<ref bean="loca1eChangeInterceptor"/>
		</1ist>
	</property>
</bean>

<bean id="themeChangeInterceptor" c1ass="org.springframework.Web.gervlet.theme.ThemeChangeInterceptor">
</bean>

ThemeChangeInterceptor默认以名称为“theme”的参数作为要切换的主题名称。比如,以http://host:port/simplefx/anyrequest.do?theme=blue形式发送的Web请求,将最终被切换到blue主题显示风格。如果我们不想使用”theme”作为标志参数,那么可以通过设置ThemeChangeInterceptor的paramName属性变更这一默认使用的标志参数。

25.7 小结

至此,我们基本上已经认识了SpringMVC家族的所有成员,包括MultipartResolver、HandlerAdaptor、HandlerInterceptor、HandlerExceptionResolver、LocalResolver以及ThemeResolver,也了解了这些家族成员之间的关系和它们各自的功能。应该说,到此为止,整个Spring MVC的介绍就该打住了。但是,各种新的技术理念层出不穷,为了能够进一步简化基于Spring MVC的开发,Spring团队从来没有停下追求新理念的脚步。接下来,我们将看到SpringMVC框架是如何在现有框架结构的基础上支持各种新的开发理念的,首先映入眼帘的,则是Spring 2.5发布后新引入的基于注解的Controller。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/39315.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注