对于指提供个别字段的 config 的更新;对于前端 pageQuery title 因为缓存缘故,当 siteConfig...
等与标题有关的配置修改后,查询结果不变更的问题;mermaid 本地渲染配置文件路径 bug
This commit is contained in:
@@ -1,7 +1,9 @@
|
|||||||
package me.qwq.doghouse.controller.admin;
|
package me.qwq.doghouse.controller.admin;
|
||||||
|
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
|
||||||
|
import jakarta.validation.UnexpectedTypeException;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import me.qwq.doghouse.annotation.ConfigInfo;
|
import me.qwq.doghouse.annotation.ConfigInfo;
|
||||||
import me.qwq.doghouse.controller.common.BaseController;
|
import me.qwq.doghouse.controller.common.BaseController;
|
||||||
@@ -10,10 +12,20 @@ import me.qwq.doghouse.interfaces.IConfig;
|
|||||||
import me.qwq.doghouse.pojo.dto.R;
|
import me.qwq.doghouse.pojo.dto.R;
|
||||||
import me.qwq.doghouse.service.ConfigService;
|
import me.qwq.doghouse.service.ConfigService;
|
||||||
|
|
||||||
import org.reflections.Reflections;
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.ArrayUtils;
|
||||||
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.core.MethodParameter;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.validation.BeanPropertyBindingResult;
|
||||||
|
import org.springframework.validation.Validator;
|
||||||
|
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import org.springframework.validation.BindingResult;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -26,10 +38,10 @@ import org.springframework.web.bind.annotation.*;
|
|||||||
public class ConfigController extends BaseController {
|
public class ConfigController extends BaseController {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
ConfigService configService;
|
Validator validator;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
Reflections reflections;
|
ConfigService configService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 前端设置页面接口,其设置项必须实现 ConfigInterface 接口,且 resources/templates/admin/config 下有对应的 html 模板,例:
|
* 前端设置页面接口,其设置项必须实现 ConfigInterface 接口,且 resources/templates/admin/config 下有对应的 html 模板,例:
|
||||||
@@ -57,20 +69,52 @@ public class ConfigController extends BaseController {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 保存配置项统一接口
|
* 保存配置项统一接口
|
||||||
|
* <p>
|
||||||
|
* 注意该接口和系统初始化配置接口不一样,虽然从 json 中恢复配置,
|
||||||
|
* 但只会替换 json 中指明的字段的值, 其他值不会进行置换
|
||||||
|
* </p>
|
||||||
|
* @param configField 注解 @ConfigInfo 的 field
|
||||||
|
* @param config 配置 json
|
||||||
*/
|
*/
|
||||||
@PostMapping({"/{configField}", "/{configField}/", "/{configField}/index"})
|
@PostMapping({"/{configField}", "/{configField}/", "/{configField}/index"})
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
public <T extends IConfig<T>> R<?> saveConfig(@PathVariable String configField, @RequestBody JSONObject config) {
|
public <T extends IConfig<T>> R<?> saveConfig(@PathVariable String configField, @RequestBody JsonNode config) throws Exception {
|
||||||
|
|
||||||
Class<T> clazz = configService.getConfigClassByField(configField);
|
Class<T> clazz = configService.getConfigClassByField(configField);
|
||||||
if (clazz == null) {
|
if (clazz == null) {
|
||||||
throw new PageNotFoundException();
|
throw new PageNotFoundException();
|
||||||
}
|
}
|
||||||
|
|
||||||
return R.judge(
|
return R.judgeThrow(() -> {
|
||||||
configService.saveOrUpdate((T)config.to(clazz)),
|
// 找出其中有的字段
|
||||||
"保存失败");
|
Set<String> jsonFields = new HashSet<>();
|
||||||
|
config.fieldNames().forEachRemaining(jsonFields::add);
|
||||||
|
|
||||||
|
T newConfig = (T)new ObjectMapper().treeToValue(config, clazz);
|
||||||
|
T oldConfig = configService.getConfig(clazz);
|
||||||
|
// 把除了本次更新以外的字段复制过去
|
||||||
|
BeanUtils.copyProperties(oldConfig, newConfig, ArrayUtils.toStringArray(jsonFields.toArray()));
|
||||||
|
|
||||||
|
Method method = this.getClass().getMethod("saveConfig", String.class, JsonNode.class);
|
||||||
|
MethodParameter methodParameter = new MethodParameter(method, 1);
|
||||||
|
|
||||||
|
if (validator.supports(clazz)) {
|
||||||
|
try {
|
||||||
|
BindingResult bindingResult = new BeanPropertyBindingResult(newConfig, clazz.getSimpleName());
|
||||||
|
validator.validate(newConfig, bindingResult);
|
||||||
|
|
||||||
|
if (bindingResult.hasErrors()) {
|
||||||
|
throw new MethodArgumentNotValidException(methodParameter, bindingResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (UnexpectedTypeException e) {
|
||||||
|
// 对指定类型未找到 validator,忽略之
|
||||||
|
log.debug("Cannot find a validator for {}", clazz.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return newConfig.saveOrUpdate();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,8 +74,9 @@ public class MailConfig implements Serializable, IConfig<MailConfig> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void afterSaving() {
|
public MailConfig afterSaving() {
|
||||||
SpringContextHolder.getBean(MailService.class).resetTaskDelay();
|
SpringContextHolder.getBean(MailService.class).resetTaskDelay();
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ public class MarkdownConfig implements Serializable, IConfig<MarkdownConfig> {
|
|||||||
|
|
||||||
private String mermaidConfig = DEFAULT_MERMAID_CONFIG;
|
private String mermaidConfig = DEFAULT_MERMAID_CONFIG;
|
||||||
|
|
||||||
public void afterSaving() {
|
public MarkdownConfig afterSaving() {
|
||||||
if (StringUtils.isNotBlank(mermaidConfig)) {
|
if (StringUtils.isNotBlank(mermaidConfig)) {
|
||||||
try {
|
try {
|
||||||
JSONObject jo = JSONObject.parse(mermaidConfig);
|
JSONObject jo = JSONObject.parse(mermaidConfig);
|
||||||
@@ -33,6 +33,7 @@ public class MarkdownConfig implements Serializable, IConfig<MarkdownConfig> {
|
|||||||
log.warn("Save mermaid self-defined css failed", e);
|
log.warn("Save mermaid self-defined css failed", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -121,8 +121,9 @@ public class NetworkConfig implements Serializable, IConfig<NetworkConfig> {
|
|||||||
return trustedCidrBlockList;
|
return trustedCidrBlockList;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void afterSaving() {
|
public NetworkConfig afterSaving() {
|
||||||
trustedIpList = null;
|
trustedIpList = null;
|
||||||
trustedCidrBlockList = null;
|
trustedCidrBlockList = null;
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,11 +65,12 @@ public class PageConfig implements Serializable, IConfig<PageConfig>, IPostTypeC
|
|||||||
private Boolean imageCompress = false;
|
private Boolean imageCompress = false;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void afterSaving() {
|
public PageConfig afterSaving() {
|
||||||
// 缓存驱逐:GET_JUMP_TO_URL
|
// 缓存驱逐:GET_JUMP_TO_URL
|
||||||
// 因为具体是哪一页是和每页评论数有关的,每页评论数又在 SiteConfig 里定义
|
// 因为具体是哪一页是和每页评论数有关的,每页评论数又在 SiteConfig 里定义
|
||||||
// 一旦更改,那么评论对应页的缓存得驱逐
|
// 一旦更改,那么评论对应页的缓存得驱逐
|
||||||
((CacheManager)SpringContextHolder.getBean("cacheManager")).getCache(CacheConstants.Comments.GET_JUMP_TO_URL).clear();
|
((CacheManager)SpringContextHolder.getBean("cacheManager")).getCache(CacheConstants.Comments.GET_JUMP_TO_URL).clear();
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PostTypeEnum getPostType() {
|
public PostTypeEnum getPostType() {
|
||||||
|
|||||||
@@ -103,11 +103,12 @@ public class SiteConfig implements Serializable, IConfig<SiteConfig>, IPostTypeC
|
|||||||
private Boolean imageCompress = false;
|
private Boolean imageCompress = false;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void afterSaving() {
|
public SiteConfig afterSaving() {
|
||||||
// 缓存驱逐:GET_JUMP_TO_URL
|
// 缓存驱逐:GET_JUMP_TO_URL
|
||||||
// 因为具体是哪一页是和每页评论数有关的,每页评论数又在 SiteConfig 里定义
|
// 因为具体是哪一页是和每页评论数有关的,每页评论数又在 SiteConfig 里定义
|
||||||
// 一旦更改,那么评论对应页的缓存得驱逐
|
// 一旦更改,那么评论对应页的缓存得驱逐
|
||||||
((CacheManager)SpringContextHolder.getBean("cacheManager")).getCache(CacheConstants.Comments.GET_JUMP_TO_URL).clear();
|
((CacheManager)SpringContextHolder.getBean("cacheManager")).getCache(CacheConstants.Comments.GET_JUMP_TO_URL).clear();
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PostTypeEnum getPostType() {
|
public PostTypeEnum getPostType() {
|
||||||
|
|||||||
@@ -153,7 +153,7 @@ public class MermaidNodeRenderer implements NodeRenderer {
|
|||||||
|
|
||||||
if (theme.isInternal()) {
|
if (theme.isInternal()) {
|
||||||
// 内部文件要释放到临时目录使用
|
// 内部文件要释放到临时目录使用
|
||||||
Resource configResource = RESOURCE_LOADER.getResource(theme.getTemplateString("conf/mermaid/config.json"));
|
Resource configResource = RESOURCE_LOADER.getResource("classpath:templates/" + theme.getTemplateString("conf/mermaid/config.json"));
|
||||||
if (configResource.exists()) {
|
if (configResource.exists()) {
|
||||||
configPath = tmpPath.resolve("config.json");
|
configPath = tmpPath.resolve("config.json");
|
||||||
try (InputStream in = configResource.getInputStream()) {
|
try (InputStream in = configResource.getInputStream()) {
|
||||||
@@ -169,10 +169,12 @@ public class MermaidNodeRenderer implements NodeRenderer {
|
|||||||
configPath = Paths.get(themeService.getCurrentTheme().getDirectory(), "conf/mermaid/config.json");
|
configPath = Paths.get(themeService.getCurrentTheme().getDirectory(), "conf/mermaid/config.json");
|
||||||
}
|
}
|
||||||
|
|
||||||
File configFile = configPath.toFile();
|
if (configPath != null) {
|
||||||
if (configFile.exists()) {
|
File configFile = configPath.toFile();
|
||||||
cmd.add("-c");
|
if (configFile.exists()) {
|
||||||
cmd.add(configPath.toString());
|
cmd.add("-c");
|
||||||
|
cmd.add(configPath.toString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -18,8 +18,13 @@ public interface IConfig<T extends IConfig<T>> {
|
|||||||
return SpringContextHolder.getBean(ConfigService.class).saveOrUpdate((T)this);
|
return SpringContextHolder.getBean(ConfigService.class).saveOrUpdate((T)this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public default void afterSaving() {}
|
@SuppressWarnings("unchecked")
|
||||||
|
public default T afterSaving() {
|
||||||
public default void beforeSaving() {}
|
return (T) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public default T beforeSaving() {
|
||||||
|
return (T) this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -510,6 +510,9 @@ public abstract class AbstractPostService<S extends AbstractPostService<S, C>, C
|
|||||||
@UpdatePosts(postViews = true, commentsCount = true)
|
@UpdatePosts(postViews = true, commentsCount = true)
|
||||||
public <R> PageQuery<R> conditionPage(PageQuery<R> pageQueryCondition) {
|
public <R> PageQuery<R> conditionPage(PageQuery<R> pageQueryCondition) {
|
||||||
PageQuery<R> result = proxy().cacheableConditionPage(pageQueryCondition, isLogin());
|
PageQuery<R> result = proxy().cacheableConditionPage(pageQueryCondition, isLogin());
|
||||||
|
// result 可能是缓存的,title 又可能是和 siteConfig... 有关的
|
||||||
|
// 获取到结果以后要把与查询无关的内容更新上去
|
||||||
|
result.setTitle(pageQueryCondition.getTitle());
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user