【Spring】ThemeResolver主题解析器源码分析

编程

ThemeResolver 主题解析器

作用:相同页面切换不同样式显示,类似换主页皮肤操作

工作原理:本质和LocaleResolver无区别,都是将数据保存在Session、Cookie等位置且与请求绑定,实现JSP页面数据动态化处理

1. jsp 案例代码

主题资源文件配置

/**

* function: 主题配置

* author: zhiwei_yang

* time: 2020/6/21-23:50

*/

@Configuration

public class ThemeConfig implements WebMvcConfigurer {

/**

* 配置主题资源文件: theme. 表示主题资源配置文件: classpath/theme 目录下

*

* bean名称固定:themeSource

* org.springframework.web.context.support.GenericWebApplicationContext#onRefresh()

* org.springframework.ui.context.support.UiApplicationContextUtils#initThemeSource

*

* @return

*/

@Bean("themeSource")

public ResourceBundleThemeSource resourceBundleThemeSource(){

ResourceBundleThemeSource resourceBundleThemeSource = new ResourceBundleThemeSource();

resourceBundleThemeSource.setBasenamePrefix("theme.");

return resourceBundleThemeSource;

}

/**

* 主题解析器

* FixedThemeResolver: 固定主题名,不能变更

* SessionThemeResolver:主题信息保存Session

* CookieThemeResolver: 主题信息保存Cookie

*

* @return

*/

@Bean

public ThemeResolver themeResolver(){

return new SessionThemeResolver();

}

/**

* 主题变更拦截器,设置请求对应主题

* @return

*/

@Bean

public ThemeChangeInterceptor themeChangeInterceptor(){

return new ThemeChangeInterceptor();

}

/**

* 注入拦截器

* @param registry

*/

@Override

public void addInterceptors(InterceptorRegistry registry){

registry.addInterceptor(themeChangeInterceptor());

}

}

主题资源文件:

## 简单指定主题样式文件访问路径

blue.properties:

theme=/theme/blue/css/theme.css

red.proeprties:

theme=/theme/red/css/theme.css

主题样式文件:指定主题不同样式

theme.css(blue):

div{

background-color: blue

}

theme.css(red):

div{

background-color: red

}

主题JSP样例页面:

<%@ page language="java" contentType="text/html;charset=utf-8" pageEncoding="utf-8" %>

<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>

<html>

<head>

<title>spring theme</title>

<link rel="stylesheet" type="text/css" href="<spring:theme code="theme"/>"/>

</head>

<body>

<div id="divTheme">

<h1><spring:message code="page.description"/></h1>

</div>

<a href="${pageContext.request.contextPath}/theme?themeName=blue"> blue</a>

<a href="${pageContext.request.contextPath}/theme?themeName=red"> red</a>

</body>

</html>

主题控制器:

/**

* 主题控制器

*/

@Controller

@RequestMapping("/theme")

@Slf4j

public class ThemeController {

@Autowired

private ThemeResolver themeResolver;

@GetMapping

public String theme(HttpServletRequest request, HttpServletResponse response, String themeName) {

//设置默认主题

if(themeName == null){

themeName = "red";

themeResolver.setThemeName(request, response, themeName);

}

log.info("current theme change to {}", themeName);

return "theme";

}

}

项目结构图:注意静态资源文件存放目录

项目效果图:


2. 工作原理

2.1 请求属性绑定主题解析器、主题配置资源

源码:org.springframework.web.servlet.DispatcherServlet.doService

## 这里我们配置SessionThemeResolver, Session存储主题信息,默认FixedThemeResolver不支持自定义主题

request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);

## 设置主题配置资源:ResourceBundleThemeSource baseName=theme.

request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());

2.2 请求主题解析

源码:org.springframework.web.servlet.theme.ThemeChangeInterceptor.preHandle

// 默认从请求参数theme获取主题名,可通过ThemeChangeInterceptor 配置paramName修改默认参数名

String newTheme = request.getParameter(this.paramName);

if (newTheme != null) {

ThemeResolver themeResolver = RequestContextUtils.getThemeResolver(request);

if (themeResolver == null) {

throw new IllegalStateException("No ThemeResolver found: not in a DispatcherServlet request?");

}

// 设置当前请求主题名

themeResolver.setThemeName(request, response, newTheme);

}

// Proceed in any case.

return true;

2.3 设置当前请求主题名

源码:org.springframework.web.servlet.theme.SessionThemeResolver.resolveThemeName

@Override

public String resolveThemeName(HttpServletRequest request) {

// 将新主题名存储在Session

String themeName = (String) WebUtils.getSessionAttribute(request, THEME_SESSION_ATTRIBUTE_NAME);

// A specific theme indicated, or do we need to fallback to the default?

return (themeName != null ? themeName : getDefaultThemeName());

}

2.4 spring:theme 标签解析

实体类:ThemeTag

分析:ThemeTag继承MessageTag,只是修改自身的主题配置资源路径,DispatcherServlet提前存储在请求属性中

public class ThemeTag extends MessageTag {

/**

* Use the theme MessageSource for theme message resolution.

*/

@Override

protected MessageSource getMessageSource() {

// 获取主题资源:本质从Request属性获取,底层逻辑:ResourceBundleThemeSource.getTheme

return getRequestContext().getTheme().getMessageSource();

}

/**

* Return exception message that indicates the current theme.

*/

@Override

protected String getNoSuchMessageExceptionDescription(NoSuchMessageException ex) {

return "Theme "" + getRequestContext().getTheme().getName() + "": " + ex.getMessage();

}

}

2.4.1 主题资源获取

org.springframework.ui.context.support.ResourceBundleThemeSource.getTheme

@Override

public Theme getTheme(String themeName) {

if (themeName == null) {

return null;

}

Theme theme = this.themeCache.get(themeName);

if (theme == null) {

synchronized (this.themeCache) {

theme = this.themeCache.get(themeName);

if (theme == null) {

// 提前配置ResourceBundleThemeSource basenamePrefix=theme

// 若主题名称为red: basename = theme.red,资源文件为classpath/theme/red*.properties

String basename = this.basenamePrefix + themeName;

MessageSource messageSource = createMessageSource(basename);

theme = new SimpleTheme(themeName, messageSource);

initParent(theme);

this.themeCache.put(themeName, theme);

if (logger.isDebugEnabled()) {

logger.debug("Theme created: name "" + themeName + "", basename [" + basename + "]");

}

}

}

}

return theme;

}

2.4.2 标签数据解析展示

因ThemeTag是MessageTag子类,只是修改配置数据源,详细解析可以参考博客LocaleResolver、MessageSources实现国际化显示源码分析

解析后前端源码:

红色主题:

<html>

<head>

<title>spring theme</title>

<link rel="stylesheet" type="text/css" href="/theme/red/css/theme.css"/>

</head>

<body>

<div id="divTheme">

<h1>页面语言</h1>

</div>

<a href="/theme?themeName=blue"> blue</a>

<a href="/theme?themeName=red"> red</a>

</body>

</html>

蓝色主题:

<html>

<head>

<title>spring theme</title>

<link rel="stylesheet" type="text/css" href="/theme/blue/css/theme.css"/>

</head>

<body>

<div id="divTheme">

<h1>页面语言</h1>

</div>

<a href="/theme?themeName=blue"> blue</a>

<a href="/theme?themeName=red"> red</a>

</body>

</html>

以上是 【Spring】ThemeResolver主题解析器源码分析 的全部内容, 来源链接: utcz.com/z/517695.html

回到顶部