1. Обзор
При разработке веб-приложения ключевым компонентом является его внешний вид или тема
. Это влияет на удобство использования и доступность нашего приложения и может еще больше укрепить бренд нашей компании.
В этом руководстве мы рассмотрим шаги, необходимые для настройки тем в приложении Spring MVC .
2. Варианты использования
Проще говоря, темы — это набор статических ресурсов, обычно таблиц стилей и изображений, которые влияют на визуальный стиль нашего веб-приложения.
Мы можем использовать темы для:
- Установите общий внешний вид с
фиксированной темой
- Настройте бренд с помощью
фирменной темы
— это обычное дело в приложении SAAS, где каждый клиент хочет иметь свой внешний вид. - Решите проблемы доступности с помощью
темы удобства использования
— например, нам может понадобиться темная или высококонтрастная тема.
3. Зависимости Maven
Итак, обо всем по порядку, давайте добавим зависимости Maven, которые мы будем использовать в первой части этого руководства.
Нам понадобятся зависимости 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>
А поскольку в нашем примере мы собираемся использовать JSP, нам понадобятся сервлеты Java , 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. Настройка весенней темы
4.1. Свойства темы
Теперь давайте настроим светлую и темную темы для нашего приложения.
Для темной темы создадим dark.properties
:
styleSheet=themes/black.css
background=black
И для светлой темы light.properties
:
styleSheet=themes/white.css
background=white
Из приведенных выше свойств мы замечаем, что одно относится к файлу CSS, а другое — к стилю CSS. Через мгновение мы увидим, как они проявляются в нашем представлении.
4.2. обработчик ресурсов
Читая свойства выше, файлы black.css
и white.css
должны быть помещены в каталог с именем /themes
.
И мы должны настроить ResourceHandler
, чтобы Spring MVC мог правильно находить файлы по запросу:
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/themes/**").addResourceLocations("classpath:/themes/");
}
4.3. ThemeSource
Мы можем управлять этими специфическими для темы файлами . файлы свойств как
ResourceBundle
s через ResourceBundleThemeSource
:
@Bean
public ResourceBundleThemeSource resourceBundleThemeSource() {
return new ResourceBundleThemeSource();
}
4.4. ThemeResolver
s
Затем нам нужен ThemeResolver
для разрешения правильной темы для приложения. В зависимости от наших потребностей в дизайне мы можем выбирать между существующими реализациями или создавать свои собственные.
В нашем примере давайте настроим CookieThemeResolver.
Как видно из названия, это разрешает информацию о теме из файла cookie браузера или возвращается к значению по умолчанию, если эта информация недоступна:
@Bean
public ThemeResolver themeResolver() {
CookieThemeResolver themeResolver = new CookieThemeResolver();
themeResolver.setDefaultThemeName("light");
return themeResolver;
}
Другие варианты ThemeResolver,
поставляемые с фреймворком:
FixedThemeResolver
: используется при наличии фиксированной темы для приложения.SessionThemeResolver
: используется, чтобы позволить пользователю переключать темы для активного сеанса.
4.5. Вид
Чтобы применить тему к нашему представлению, мы должны настроить механизм запроса пакетов ресурсов.
Мы сохраним область действия только для JSP, хотя аналогичный механизм поиска можно настроить и для альтернативных механизмов рендеринга представлений.
Для JSP мы можем импортировать библиотеку тегов, которая сделает всю работу за нас:
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
И тогда мы можем обратиться к любому свойству, указав соответствующее имя свойства:
<link rel="stylesheet" href="<spring:theme code='styleSheet'/>"/>
Или же:
<body bgcolor="<spring:theme code='background'/>">
Итак, давайте теперь добавим в наше приложение одно представление с именем 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>
На самом деле, наше приложение будет работать в этот момент, всегда выбирая нашу светлую тему.
Давайте посмотрим, как мы можем позволить пользователю изменить свою тему.
4.6. ThemeChangeInterceptor
Задача ThemeChangeInterceptor
— понять запрос на изменение темы.
Давайте теперь добавим ThemeChangeInterceptor
и настроим его для поиска параметра запроса темы :
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(themeChangeInterceptor());
}
@Bean
public ThemeChangeInterceptor themeChangeInterceptor() {
ThemeChangeInterceptor interceptor = new ThemeChangeInterceptor();
interceptor.setParamName("theme");
return interceptor;
}
5. Дальнейшие зависимости
Далее давайте реализуем наш собственный ThemeResolver
, который сохраняет предпочтения пользователя в базе данных.
Для этого нам понадобится 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>
И 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. Пользовательский ThemeResolver
Давайте теперь углубимся в ThemeResolver
и реализуем один из наших собственных. Этот пользовательский ThemeResolver
сохранит настройки темы пользователя в базе данных.
Для этого давайте сначала добавим объект UserPreference
:
@Entity
@Table(name = "preferences")
public class UserPreference {
@Id
private String username;
private String theme;
}
Далее мы создадим UserPreferenceThemeResolver
, который должен реализовать интерфейс ThemeResolver
. Его основные обязанности заключаются в разрешении и сохранении информации о теме.
Давайте сначала обратимся к разрешению имени, реализуя 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();
}
И теперь мы можем написать нашу реализацию для сохранения темы в 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);
}
}
И, наконец, давайте теперь изменим ThemeResolver
в нашем приложении:
@Bean
public ThemeResolver themeResolver() {
return new UserPreferenceThemeResolver();
}
Теперь настройки темы пользователя сохраняются в базе данных, а не в виде файла cookie.
Альтернативным способом сохранения пользовательских настроек мог быть контроллер Spring MVC и отдельный API.
7. Заключение
В этой статье мы узнали, как настроить темы Spring MVC.
Мы также можем найти полный код на GitHub .