mirror of https://github.com/halo-dev/halo
Add option cache feature
parent
6e8ef4b35a
commit
cea6a55963
|
@ -38,21 +38,17 @@ public class FreemarkerConfigAwareListener {
|
|||
|
||||
private final ThemeSettingService themeSettingService;
|
||||
|
||||
private final OptionService optionsService;
|
||||
|
||||
private final UserService userService;
|
||||
|
||||
public FreemarkerConfigAwareListener(OptionService optionService,
|
||||
Configuration configuration,
|
||||
ThemeService themeService,
|
||||
ThemeSettingService themeSettingService,
|
||||
OptionService optionsService,
|
||||
UserService userService) {
|
||||
this.optionService = optionService;
|
||||
this.configuration = configuration;
|
||||
this.themeService = themeService;
|
||||
this.themeSettingService = themeSettingService;
|
||||
this.optionsService = optionsService;
|
||||
this.userService = userService;
|
||||
}
|
||||
|
||||
|
@ -97,13 +93,11 @@ public class FreemarkerConfigAwareListener {
|
|||
}
|
||||
|
||||
private void loadOptionsConfig() throws TemplateModelException {
|
||||
Map<String, Object> options = optionService.listOptions();
|
||||
configuration.setSharedVariable("options", options);
|
||||
configuration.setSharedVariable("options", optionService.listOptions());
|
||||
}
|
||||
|
||||
private void loadThemeConfig() throws TemplateModelException {
|
||||
ThemeProperty activatedTheme = themeService.getActivatedTheme();
|
||||
configuration.setSharedVariable("theme", activatedTheme);
|
||||
configuration.setSharedVariable("theme", themeService.getActivatedTheme());
|
||||
configuration.setSharedVariable("settings", themeSettingService.listAsMapBy(themeService.getActivatedThemeId()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
package run.halo.app.event.options;
|
||||
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Component;
|
||||
import run.halo.app.cache.StringCacheStore;
|
||||
import run.halo.app.service.OptionService;
|
||||
|
||||
/**
|
||||
* Option updated listener.
|
||||
*
|
||||
* @author johnniang
|
||||
* @date 19-4-29
|
||||
*/
|
||||
@Component
|
||||
public class OptionUpdatedListener implements ApplicationListener<OptionUpdatedEvent> {
|
||||
|
||||
private final StringCacheStore cacheStore;
|
||||
|
||||
public OptionUpdatedListener(StringCacheStore cacheStore) {
|
||||
this.cacheStore = cacheStore;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Async
|
||||
public void onApplicationEvent(OptionUpdatedEvent event) {
|
||||
cacheStore.delete(OptionService.OPTIONS_KEY);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package run.halo.app.event.theme;
|
||||
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
|
||||
/**
|
||||
* Theme updated event.
|
||||
*
|
||||
* @author johnniang
|
||||
* @date 19-4-29
|
||||
*/
|
||||
public class ThemeUpdatedEvent extends ApplicationEvent {
|
||||
|
||||
/**
|
||||
* Create a new ApplicationEvent.
|
||||
*
|
||||
* @param source the object on which the event initially occurred (never {@code null})
|
||||
*/
|
||||
public ThemeUpdatedEvent(Object source) {
|
||||
super(source);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package run.halo.app.event.theme;
|
||||
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Component;
|
||||
import run.halo.app.cache.StringCacheStore;
|
||||
import run.halo.app.service.ThemeService;
|
||||
|
||||
/**
|
||||
* Theme updated listener.
|
||||
*
|
||||
* @author johnniang
|
||||
* @date 19-4-29
|
||||
*/
|
||||
@Component
|
||||
public class ThemeUpdatedListener implements ApplicationListener<ThemeUpdatedEvent> {
|
||||
|
||||
private final StringCacheStore cacheStore;
|
||||
|
||||
public ThemeUpdatedListener(StringCacheStore cacheStore) {
|
||||
this.cacheStore = cacheStore;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Async
|
||||
public void onApplicationEvent(ThemeUpdatedEvent event) {
|
||||
cacheStore.delete(ThemeService.THEMES_CACHE_KEY);
|
||||
}
|
||||
}
|
|
@ -30,14 +30,7 @@ public interface OptionService extends CrudService<Option, Integer> {
|
|||
|
||||
int DEFAULT_RSS_PAGE_SIZE = 20;
|
||||
|
||||
/**
|
||||
* Save one option
|
||||
*
|
||||
* @param key key must not be blank
|
||||
* @param value value
|
||||
*/
|
||||
@Transactional
|
||||
void save(@NonNull String key, String value);
|
||||
String OPTIONS_KEY = "options";
|
||||
|
||||
/**
|
||||
* Save multiple options
|
||||
|
|
|
@ -19,7 +19,6 @@ import run.halo.app.model.params.OptionParam;
|
|||
import run.halo.app.model.properties.*;
|
||||
import run.halo.app.repository.OptionRepository;
|
||||
import run.halo.app.service.OptionService;
|
||||
import run.halo.app.service.ThemeService;
|
||||
import run.halo.app.service.base.AbstractCrudService;
|
||||
import run.halo.app.utils.HaloUtils;
|
||||
import run.halo.app.utils.ServiceUtils;
|
||||
|
@ -60,8 +59,7 @@ public class OptionServiceImpl extends AbstractCrudService<Option, Integer> impl
|
|||
propertyEnumMap = Collections.unmodifiableMap(PropertyEnum.getValuePropertyEnumMap());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(String key, String value) {
|
||||
private void save(String key, String value) {
|
||||
Assert.hasText(key, "Option key must not be blank");
|
||||
|
||||
if (StringUtils.isBlank(value)) {
|
||||
|
@ -90,8 +88,6 @@ public class OptionServiceImpl extends AbstractCrudService<Option, Integer> impl
|
|||
Option savedOption = optionRepository.save(option);
|
||||
|
||||
log.debug("Saved option: [{}]", savedOption);
|
||||
|
||||
cacheStore.delete(ThemeService.THEMES_CACHE_KEY);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -103,7 +99,7 @@ public class OptionServiceImpl extends AbstractCrudService<Option, Integer> impl
|
|||
// TODO Optimize the queries
|
||||
options.forEach(this::save);
|
||||
|
||||
publishEvent();
|
||||
publishOptionUpdatedEvent();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -115,7 +111,7 @@ public class OptionServiceImpl extends AbstractCrudService<Option, Integer> impl
|
|||
// TODO Optimize the query
|
||||
optionParams.forEach(optionParam -> save(optionParam.getKey(), optionParam.getValue()));
|
||||
|
||||
publishEvent();
|
||||
publishOptionUpdatedEvent();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -124,7 +120,7 @@ public class OptionServiceImpl extends AbstractCrudService<Option, Integer> impl
|
|||
|
||||
save(property.getValue(), value);
|
||||
|
||||
publishEvent();
|
||||
publishOptionUpdatedEvent();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -135,44 +131,51 @@ public class OptionServiceImpl extends AbstractCrudService<Option, Integer> impl
|
|||
|
||||
properties.forEach((property, value) -> save(property.getValue(), value));
|
||||
|
||||
publishEvent();
|
||||
publishOptionUpdatedEvent();
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Map<String, Object> listOptions() {
|
||||
List<Option> options = listAll();
|
||||
// Get options from cache
|
||||
return cacheStore.getAny(OPTIONS_KEY, Map.class).orElseGet(() -> {
|
||||
List<Option> options = listAll();
|
||||
|
||||
Set<String> keys = ServiceUtils.fetchProperty(options, Option::getKey);
|
||||
Set<String> keys = ServiceUtils.fetchProperty(options, Option::getKey);
|
||||
|
||||
Map<String, Object> userDefinedOptionMap = ServiceUtils.convertToMap(options, Option::getKey, option -> {
|
||||
String key = option.getKey();
|
||||
Map<String, Object> userDefinedOptionMap = ServiceUtils.convertToMap(options, Option::getKey, option -> {
|
||||
String key = option.getKey();
|
||||
|
||||
PropertyEnum propertyEnum = propertyEnumMap.get(key);
|
||||
PropertyEnum propertyEnum = propertyEnumMap.get(key);
|
||||
|
||||
if (propertyEnum == null) {
|
||||
return option.getValue();
|
||||
}
|
||||
if (propertyEnum == null) {
|
||||
return option.getValue();
|
||||
}
|
||||
|
||||
return PropertyEnum.convertTo(option.getValue(), propertyEnum);
|
||||
return PropertyEnum.convertTo(option.getValue(), propertyEnum);
|
||||
});
|
||||
|
||||
Map<String, Object> result = new HashMap<>(userDefinedOptionMap);
|
||||
|
||||
// Add default property
|
||||
propertyEnumMap.keySet()
|
||||
.stream()
|
||||
.filter(key -> !keys.contains(key))
|
||||
.forEach(key -> {
|
||||
PropertyEnum propertyEnum = propertyEnumMap.get(key);
|
||||
|
||||
if (StringUtils.isBlank(propertyEnum.defaultValue())) {
|
||||
return;
|
||||
}
|
||||
|
||||
result.put(key, PropertyEnum.convertTo(propertyEnum.defaultValue(), propertyEnum));
|
||||
});
|
||||
|
||||
// Cache the result
|
||||
cacheStore.putAny(OPTIONS_KEY, result);
|
||||
|
||||
return result;
|
||||
});
|
||||
|
||||
Map<String, Object> result = new HashMap<>(userDefinedOptionMap);
|
||||
|
||||
// Add default property
|
||||
propertyEnumMap.keySet()
|
||||
.stream()
|
||||
.filter(key -> !keys.contains(key))
|
||||
.forEach(key -> {
|
||||
PropertyEnum propertyEnum = propertyEnumMap.get(key);
|
||||
|
||||
if (StringUtils.isBlank(propertyEnum.defaultValue())) {
|
||||
return;
|
||||
}
|
||||
|
||||
result.put(key, PropertyEnum.convertTo(propertyEnum.defaultValue(), propertyEnum));
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -357,7 +360,7 @@ public class OptionServiceImpl extends AbstractCrudService<Option, Integer> impl
|
|||
return blogUrl;
|
||||
}
|
||||
|
||||
private void publishEvent() {
|
||||
private void publishOptionUpdatedEvent() {
|
||||
eventPublisher.publishEvent(new OptionUpdatedEvent(this));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ import org.springframework.web.multipart.MultipartFile;
|
|||
import run.halo.app.cache.StringCacheStore;
|
||||
import run.halo.app.config.properties.HaloProperties;
|
||||
import run.halo.app.event.theme.ThemeActivatedEvent;
|
||||
import run.halo.app.event.theme.ThemeUpdatedEvent;
|
||||
import run.halo.app.exception.*;
|
||||
import run.halo.app.handler.theme.config.ThemeConfigResolver;
|
||||
import run.halo.app.handler.theme.config.ThemePropertyResolver;
|
||||
|
@ -237,7 +238,7 @@ public class ThemeServiceImpl implements ThemeService {
|
|||
FileUtil.del(Paths.get(themeProperty.getThemePath()));
|
||||
|
||||
// Delete theme cache
|
||||
clearThemeCache();
|
||||
eventPublisher.publishEvent(new ThemeUpdatedEvent(this));
|
||||
} catch (Exception e) {
|
||||
throw new ServiceException("Failed to delete theme folder", e).setErrorData(themeId);
|
||||
}
|
||||
|
@ -329,7 +330,7 @@ public class ThemeServiceImpl implements ThemeService {
|
|||
setActivatedTheme(themeProperty);
|
||||
|
||||
// Clear the cache
|
||||
clearThemeCache();
|
||||
eventPublisher.publishEvent(new ThemeUpdatedEvent(this));
|
||||
|
||||
// Publish a theme activated event
|
||||
eventPublisher.publishEvent(new ThemeActivatedEvent(this));
|
||||
|
@ -402,7 +403,7 @@ public class ThemeServiceImpl implements ThemeService {
|
|||
ThemeProperty property = getProperty(targetThemePath);
|
||||
|
||||
// Clear theme cache
|
||||
clearThemeCache();
|
||||
this.eventPublisher.publishEvent(new ThemeUpdatedEvent(this));
|
||||
|
||||
// Delete cache
|
||||
return property;
|
||||
|
@ -496,13 +497,6 @@ public class ThemeServiceImpl implements ThemeService {
|
|||
return Files.createTempDirectory("halo");
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears theme cache.
|
||||
*/
|
||||
private void clearThemeCache() {
|
||||
cacheStore.delete(THEMES_CACHE_KEY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets activated theme.
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue