前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring MVC更多家族成员--主题(Theme)与ThemeResolver

Spring MVC更多家族成员--主题(Theme)与ThemeResolver

作者头像
大忽悠爱学习
发布2022-08-23 11:05:42
4890
发布2022-08-23 11:05:42
举报
文章被收录于专栏:c++与qt学习c++与qt学习

Spring MVC更多家族成员--Theme与ThemeResolver


引言

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

  • 对于操作系统的桌面主题,可能是鼠标样式或者工具条颜色等变更一下;
  • 对于Web应用程序来说,可能就是对影响整体风格显示的背景图片,或者某些固定部位的颜色做一些变更。

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

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


提供主题资源的 ThemeSource

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

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

ThemeSource可以根据指定的主题名称(themeName)查找并返回对应的Theme实例。这样,客户端就可以使用Theme实例中的相应资源来定制视图的显示了。

public interface Theme {
	String getName();
	MessageSource getMessageSource();
}

为了能够通过ThemeSource获取相应的主题资源,DispatcherServlet会在处理Web请求之前获取可用的ThemeSource实例,以便 能够根据客户端的请求返回相应的主题资源。

而实际上DispatcherServlet获取的ThemeSource 实例就是它自身所使用的WebApplicationContext。因为WebApplicationContext本身就是一个 ThemeSource(它自己实现了ThemeSource接口)。事情到这里并没有完,虽然WebApplicationContext身为ThemeSource,但它和它的实现类一概不干实事。当有主题相关的请求需要处理的时候,它们都是将工作委派给某个ThemeSource的具体实现类,比如ResourceBundleThemeSource。

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

#default.properties
theme.backgroud.image=../xx.jpg
theme.css=...
...

#blue.properties
theme.backgroud.image=../xx.jpg
theme.css=...
...

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

<*@ taglib prefix="spring"uri="http://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 template file

<html>

<style type="text/css"> <!--

body{

background-image:url($(rc.getThemeMeseage("theme.background.image")}); }

--> </style> 

不管怎么样,只要将当前使用的主题名称告知ResourceBundleThemeSource,它就能返回对应主题名的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."/>

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

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


管理主题的ThemeResolver

现在,通过指定的主题名称,我们就能够从DispatcherServlet所使用的ThemeSource那里获取 主题对应的各项资源,然后视图就能够根据这些主题资源来定制视图显示。ThemeSource已经准备就绪了,那主题名称又该如何定夺呢?

显然,我们得通过某种方式获取用户当前所选择的主题才行,否则,我们怎么知道使用哪个主题名称到ThemeSource查找要用的主题资源呢?

为了获取并管理用户的Locale信息,Spring MVC提供了LocaleResolver。与此类似,为了获取并管理用户所选择的主题,Spring MVC提供了ThemeResolver。ThemeResolver的主要工作就是解析并获取对应当前请求的主题是什么。如果相应实现机制支持存储的话,也允许对当前请求相关的主题进行设置变更。ThemeResolver的定义如下:

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

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

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

  • FixedThemeReвoLver。如果我们不明确为DispatcherServlet指定任何ThemeResolver实例供其使用,DispatcherServlet将 默认使用FixedThemeResolver来管理用户的主题。顾名思义,一旦使用FixedThemeResolver指定了主题之后,主题将保持不变。所以,对FixedThemeResolver进行setThemeName操作显然是不行的。
  • SessionThemeResolver 。 HttpSession 是 SessionThemeResolver得以生存的土壤,SessionThemeResolver将按照指定的属性名称到Session中获取用户的主题。如果找不到,则使用默认的主题。这可以通过其defaultThemeName属性进行指定。因为我们可以对Session的属性进行设置,所以,SessionThemeResolver可以通过setThemeName方法重新设置用户主题。
  • CookieThemeResolver。SessionThemeResolver以HttpSession作为主题信息的载体,而CookieThemeResolver则以Cookie作为主 题信息的载体。只要用户端浏览器不禁止Cookie的使用,我们就可以使用CookieThemeResolver对用户选择的主题进行管理,包括获取和更新。

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

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

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


切换主题的ThemeChangeInterceptor

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

在Spring MVC中,用户要切换Locale有LocaleChangeInterceptor来相助,而用户要切换主 题的时候,也同样有ThemeChangeInterceptor来帮忙。

只要将用户选择要切换到的主题以某个参数提交到服务器端处理,ThemeChangeInterceptor就能够根据这一参数重新设置用户所使用的主题,之后,视图就可以获取切换后的主题来定制视图的显示了。

当然,要让ThemeChangeInterceptor生效,我们自然需要将它与提交主题变更的Web请求联系到一起,如下所示:

<bean id="handlerMapping" class="org.springframework.Web.servlet.handler.BeanNameUr1HandlerMapping"> 
<property name="interceptors">
<list>
<ref bean="themeChangeInterceptor"/> 
<ref bean="marketAccessInterceptor"/> 
<ref bean="localeChangeInterceptor"/>
</list>
</property> 
</bean>

<bean id="themeChangeInterceptor"
class="org.springframework.Web.servlet.theme.ThemeChangeInterceptor"> </bean>

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

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-08-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Spring MVC更多家族成员--Theme与ThemeResolver
  • 引言
    • 提供主题资源的 ThemeSource
      • 管理主题的ThemeResolver
        • 切换主题的ThemeChangeInterceptor
        相关产品与服务
        容器服务
        腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档