1. Overview
1.概述
When designing a web application, its look-and-feel, or theme, is a key component. It impacts our application’s usability and accessibility and can further establish our company’s brand.
当设计一个网络应用时,它的外观和感觉,或主题,是一个关键的组成部分。它影响着我们应用程序的可用性和可访问性,并能进一步建立我们公司的品牌。
In this tutorial, we’ll go through the steps required to configure themes in a Spring MVC application.
在本教程中,我们将通过在一个Spring MVC应用程序中配置主题所需的步骤。
2. Use Cases
2.使用案例
Simply put, themes are a set of static resources, typically stylesheets and images, that impact the visual style of our web application.
简单地说,主题是一组静态资源,通常是样式表和图片,影响我们的网络应用的视觉风格。
We can use themes to:
我们可以利用主题来。
- Establish a common look-and-feel with a fixed theme
- Customize for a brand with a branding theme – this is common in a SAAS application where each client wants a different look-and-feel
- Address accessibility concerns with a usability theme – for example, we might want a dark or a high-contrast theme
3. Maven Dependencies
3.Maven的依赖性
So, first things first, let’s add the Maven dependencies we’ll be using for the first part of this tutorial.
所以,首先,让我们添加本教程第一部分要用到的Maven依赖项。
We’ll need the Spring WebMVC and Spring Context dependencies:
我们将需要Spring WebMVC和Spring Context的依赖。
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.1.RELEASE</version>
</dependency>
And since we’re going to use JSP in our example, we’ll need Java Servlets, JSP, and JSTL:
而且,由于我们将在我们的例子中使用JSP,我们将需要Java Servlets,JSP,以及JSTL。
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.3</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
4. Configuring Spring Theme
4.配置Spring主题
4.1. Theme Properties
4.1.主题属性
Now, let’s configure light and dark themes for our application.
现在,让我们为我们的应用程序配置光明和黑暗主题。
For the dark theme, let’s create dark.properties:
对于黑暗主题,让我们创建dark.properties。
styleSheet=themes/black.css
background=black
And for the light theme, light.properties:
而对于灯光主题,light.properties。
styleSheet=themes/white.css
background=white
From the properties above, we notice that one refers to a CSS file and another refers to a CSS style. We’ll see in a moment how these are manifest in our view.
从上面的属性中,我们注意到一个是指一个CSS文件,另一个是指一个CSS样式。我们一会儿就会看到这些在我们的视图中是如何体现的。
4.2. ResourceHandler
4.2.ResourceHandler
Reading the properties above, the files black.css and white.css must be placed in the directory named /themes.
阅读上述属性,文件black.css和white.css必须放在名为/themes的目录中。
And, we must configure a ResourceHandler to enable Spring MVC to correctly locate the files when requested:
而且,我们必须配置一个ResourceHandler,以使Spring MVC能够在请求时正确定位文件。
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/themes/**").addResourceLocations("classpath:/themes/");
}
4.3. ThemeSource
4.3.ThemeSource
We can manage these theme-specific .properties files as ResourceBundles via ResourceBundleThemeSource:
我们可以通过ResourceBundleThemeSource将这些特定主题的.properties文件作为ResourceBundles进行管理。
@Bean
public ResourceBundleThemeSource resourceBundleThemeSource() {
return new ResourceBundleThemeSource();
}
4.4. ThemeResolvers
4.4.ThemeResolvers
Next, we need a ThemeResolver to resolve the correct theme for the application. Depending on our design needs, we can choose between existing implementations or create our own.
接下来,我们需要一个ThemeResolver来解决应用程序的正确主题。根据我们的设计需求,我们可以选择现有的实现或创建自己的实现。
For our example, let’s configure the CookieThemeResolver. As the name depicts, this resolves the theme information from a browser cookie or falls back to the default if that information isn’t available:
对于我们的例子,让我们来配置CookieThemeResolver。正如其名称所描述的那样,它从浏览器的cookie中解析主题信息,如果该信息不可用,则退回到默认值。
@Bean
public ThemeResolver themeResolver() {
CookieThemeResolver themeResolver = new CookieThemeResolver();
themeResolver.setDefaultThemeName("light");
return themeResolver;
}
The other variants of ThemeResolver shipped with the framework are:
与框架一起运送的ThemeResolver的其他变体是。
- FixedThemeResolver: Used when there is a fixed theme for an application
- SessionThemeResolver: Used to allow the user to switch themes for the active session
4.5. View
4.5. 查看
In order to apply the theme to our view, we must configure a mechanism to query the resource bundles.
为了将主题应用于我们的视图,我们必须配置一个机制来查询资源包。
We’ll keep the scope to JSP only, though a similar lookup mechanism could be configured for alternate view rendering engines as well.
我们将只保留JSP的范围,尽管类似的查找机制也可以配置给其他的视图渲染引擎。
For JSPs, we can import a tag library that does the job for us:
对于JSP,我们可以导入一个标签库,为我们做这个工作。
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
And then we can refer to any property specifying the appropriate property name:
然后,我们可以引用任何属性,指定适当的属性名称。
<link rel="stylesheet" href="<spring:theme code='styleSheet'/>"/>
Or:
或者。
<body bgcolor="<spring:theme code='background'/>">
So, let’s now add a single view called index.jsp into our application and place it in the WEB-INF/ directory:
所以,现在让我们在我们的应用程序中添加一个名为index.jsp的单一视图,并将其放在WEB-INF/目录下。
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="stylesheet" href="<spring:theme code='styleSheet'/>"/>
<title>Themed Application</title>
</head>
<body>
<header>
<h1>Themed Application</h1>
<hr />
</header>
<section>
<h2>Spring MVC Theme Demo</h2>
<form action="<c:url value='/'/>" method="POST" name="themeChangeForm" id="themeChangeForm">
<div>
<h4>
Change Theme
</h4>
</div>
<select id="theme" name="theme" onChange="submitForm()">
<option value="">Reset</option>
<option value="light">Light</option>
<option value="dark">Dark</option>
</select>
</form>
</section>
<script type="text/javascript">
function submitForm() {
document.themeChangeForm.submit();
}
</script>
</body>
</html>
Actually, our application would work at this point, always choosing our light theme.
实际上,我们的应用程序将在这一点上工作,总是选择我们的浅色主题。
Let’s see how we can allow the user to change their theme.
让我们看看我们如何允许用户改变他们的主题。
4.6. ThemeChangeInterceptor
4.6.ThemeChangeInterceptor
The job of the ThemeChangeInterceptor is to understand the theme change request.
ThemeChangeInterceptor的工作是理解主题变更请求。
Let’s now add a ThemeChangeInterceptor and configure it to look for a theme request parameter:
现在让我们添加一个ThemeChangeInterceptor,并将其配置为寻找Theme请求参数。
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(themeChangeInterceptor());
}
@Bean
public ThemeChangeInterceptor themeChangeInterceptor() {
ThemeChangeInterceptor interceptor = new ThemeChangeInterceptor();
interceptor.setParamName("theme");
return interceptor;
}
5. Further Dependencies
5.进一步的依赖性
Next, let’s implement our own ThemeResolver that stores the user’s preference to a database.
接下来,让我们实现我们自己的ThemeResolver,将用户的偏好存储到数据库。
To achieve this, we’ll need Spring Security for identifying the user:
为了实现这一点,我们需要Spring Security来识别用户。
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>5.2.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>5.2.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
<version>5.2.1.RELEASE</version>
</dependency>
And Spring Data, Hibernate, and HSQLDB for storing the user’s preference:
而Spring Data、Hibernate,和HSQLDB用于存储用户的偏好。
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>2.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.4.9.Final</version>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>2.5.0</version>
</dependency>
6. Custom ThemeResolver
6.自定义ThemeResolver
Let’s now dive more into ThemeResolver and implement one of our own. This custom ThemeResolver will save the user’s theme preference to a database.
现在让我们更深入地了解ThemeResolver,并实现我们自己的一个。这个自定义的ThemeResolver将把用户的主题偏好保存到数据库中。
To achieve this, let’s first add a UserPreference entity:
为了实现这一点,首先让我们添加一个UserPreference实体。
@Entity
@Table(name = "preferences")
public class UserPreference {
@Id
private String username;
private String theme;
}
Next, we’ll create UserPreferenceThemeResolver, which must implement the ThemeResolver interface. Its key responsibilities are to resolve and save theme information.
接下来,我们将创建UserPreferenceThemeResolver,它必须实现ThemeResolver接口。它的主要职责是解析和保存主题信息。
Let’s first address resolving the name by implementing UserPreferenceThemeResolver#resolveThemeName:
让我们首先通过实现UserPreferenceThemeResolver#resolveThemeName来解决名称的解析。
@Override
public String resolveThemeName(HttpServletRequest request) {
String themeName = findThemeFromRequest(request)
.orElse(findUserPreferredTheme().orElse(getDefaultThemeName()));
request.setAttribute(THEME_REQUEST_ATTRIBUTE_NAME, themeName);
return themeName;
}
private Optional<String> findUserPreferredTheme() {
Authentication authentication = SecurityContextHolder.getContext()
.getAuthentication();
UserPreference userPreference = getUserPreference(authentication).orElse(new UserPreference());
return Optional.ofNullable(userPreference.getTheme());
}
private Optional<String> findThemeFromRequest(HttpServletRequest request) {
return Optional.ofNullable((String) request.getAttribute(THEME_REQUEST_ATTRIBUTE_NAME));
}
private Optional<UserPreference> getUserPreference(Authentication authentication) {
return isAuthenticated(authentication) ?
userPreferenceRepository.findById(((User) authentication.getPrincipal()).getUsername()) :
Optional.empty();
}
And now we can write our implementation for saving the theme in UserPreferenceThemeResolver#setThemeName:
现在我们可以在UserPreferenceThemeResolver#setThemeName中编写保存主题的实现。
@Override
public void setThemeName(HttpServletRequest request, HttpServletResponse response, String theme) {
Authentication authentication = SecurityContextHolder.getContext()
.getAuthentication();
if (isAuthenticated(authentication)) {
request.setAttribute(THEME_REQUEST_ATTRIBUTE_NAME, theme);
UserPreference userPreference = getUserPreference(authentication).orElse(new UserPreference());
userPreference.setUsername(((User) authentication.getPrincipal()).getUsername());
userPreference.setTheme(StringUtils.hasText(theme) ? theme : null);
userPreferenceRepository.save(userPreference);
}
}
And finally, let’s now change out the ThemeResolver in our app:
最后,让我们现在改变我们的应用程序中的ThemeResolver。
@Bean
public ThemeResolver themeResolver() {
return new UserPreferenceThemeResolver();
}
Now, the user’s theme preference is saved in the database instead of as a cookie.
现在,用户的主题偏好被保存在数据库中,而不是作为一个cookie。
An alternative way of saving the user’s preference could’ve been through a Spring MVC Controller and a separate API.
另一种保存用户偏好的方式可能是通过Spring MVC控制器和一个单独的API。
7. Conclusion
7.结语
In this article, we learned the steps to configure Spring MVC themes.
在这篇文章中,我们学习了配置Spring MVC主题的步骤。
We can also find the complete code over on GitHub.
我们还可以在GitHub上找到完整的代码,。