mirror of
https://gitee.com/liweiyi/ChestnutCMS.git
synced 2025-12-07 08:58:23 +08:00
删除多余文件
This commit is contained in:
parent
c772790270
commit
3e029c380e
@ -1,107 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2022-2024 兮玥(190785909@qq.com)
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package com.chestnut.contentcore.config;
|
|
||||||
|
|
||||||
import com.chestnut.contentcore.config.properties.CMSPublishProperties;
|
|
||||||
import com.chestnut.contentcore.publish.IPublishTask;
|
|
||||||
import com.chestnut.contentcore.publish.PublishTaskReceiver;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.data.redis.connection.stream.Consumer;
|
|
||||||
import org.springframework.data.redis.connection.stream.MapRecord;
|
|
||||||
import org.springframework.data.redis.connection.stream.ReadOffset;
|
|
||||||
import org.springframework.data.redis.connection.stream.StreamOffset;
|
|
||||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
|
||||||
import org.springframework.data.redis.stream.StreamMessageListenerContainer;
|
|
||||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
|
||||||
|
|
||||||
import java.time.Duration;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 内容发布配置
|
|
||||||
*
|
|
||||||
* @author 兮玥
|
|
||||||
* @email 190785909@qq.com
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
@Configuration
|
|
||||||
@EnableConfigurationProperties(CMSPublishProperties.class)
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class CMSPublishConfig {
|
|
||||||
|
|
||||||
private final CMSPublishProperties properties;
|
|
||||||
|
|
||||||
private final StringRedisTemplate redisTemplate;
|
|
||||||
|
|
||||||
private final Map<String, IPublishTask<?>> publishTaskMap;
|
|
||||||
|
|
||||||
public static final String PublishStreamName = "ChestnutCMSPublishStream";
|
|
||||||
|
|
||||||
public static final String PublishConsumerGroup = "ChestnutCMSPublishConsumerGroup";
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public StreamMessageListenerContainer<String, MapRecord<String, String, String>> streamMessageListenerContainer() {
|
|
||||||
// 启动清理消息队列数据
|
|
||||||
if (properties.isClearOnStart()) {
|
|
||||||
redisTemplate.delete(PublishStreamName);
|
|
||||||
}
|
|
||||||
// 监听容器配置
|
|
||||||
StreamMessageListenerContainer.StreamMessageListenerContainerOptions<String, MapRecord<String, String, String>> streamMessageListenerContainerOptions = StreamMessageListenerContainer.StreamMessageListenerContainerOptions
|
|
||||||
.builder()
|
|
||||||
.batchSize(10) // 一次拉取消息数量
|
|
||||||
.pollTimeout(Duration.ofSeconds(2)) // 拉取消息超时时间
|
|
||||||
.executor(cmsPublishThreadPoolTaskExecutor())
|
|
||||||
.build();
|
|
||||||
// 创建监听容器
|
|
||||||
StreamMessageListenerContainer<String, MapRecord<String, String, String>> container = StreamMessageListenerContainer
|
|
||||||
.create(redisTemplate.getRequiredConnectionFactory(), streamMessageListenerContainerOptions);
|
|
||||||
//创建消费者组
|
|
||||||
try {
|
|
||||||
redisTemplate.opsForStream().createGroup(PublishStreamName, PublishConsumerGroup);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.info("消费者组:{} 已存在", PublishConsumerGroup);
|
|
||||||
}
|
|
||||||
// 添加消费者
|
|
||||||
for (int i = 0; i < properties.getConsumerCount(); i++) {
|
|
||||||
Consumer consumer = Consumer.from(PublishConsumerGroup, "cms-publish-consumer-" + i);
|
|
||||||
PublishTaskReceiver publishTaskReceiver = new PublishTaskReceiver(publishTaskMap, redisTemplate);
|
|
||||||
publishTaskReceiver.setConsumer(consumer);
|
|
||||||
container.receive(consumer, StreamOffset.create(PublishStreamName, ReadOffset.lastConsumed()), publishTaskReceiver);
|
|
||||||
}
|
|
||||||
container.start();
|
|
||||||
return container;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
ThreadPoolTaskExecutor cmsPublishThreadPoolTaskExecutor() {
|
|
||||||
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
|
|
||||||
executor.setThreadNamePrefix(properties.getPool().getThreadNamePrefix());
|
|
||||||
executor.setCorePoolSize(properties.getPool().getCoreSize());
|
|
||||||
executor.setQueueCapacity(properties.getPool().getQueueCapacity());
|
|
||||||
executor.setMaxPoolSize(properties.getPool().getMaxSize());
|
|
||||||
executor.setKeepAliveSeconds((int) properties.getPool().getKeepAlive().getSeconds());
|
|
||||||
executor.setAllowCoreThreadTimeOut(this.properties.getPool().isAllowCoreThreadTimeout());
|
|
||||||
executor.setWaitForTasksToCompleteOnShutdown(properties.getShutdown().isAwaitTermination());
|
|
||||||
executor.setAwaitTerminationSeconds((int) properties.getShutdown().getAwaitTerminationPeriod().toSeconds());
|
|
||||||
log.info("Cms publish task executor initialize: {}", executor.getThreadNamePrefix());
|
|
||||||
executor.initialize();
|
|
||||||
return executor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,22 +0,0 @@
|
|||||||
package com.chestnut.contentcore.listener.event;
|
|
||||||
|
|
||||||
import com.chestnut.contentcore.domain.CmsSite;
|
|
||||||
import jodd.io.ZipBuilder;
|
|
||||||
import lombok.Getter;
|
|
||||||
import org.springframework.context.ApplicationEvent;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
public class SiteThemeExportEvent extends ApplicationEvent {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private CmsSite site;
|
|
||||||
|
|
||||||
private ZipBuilder zipBuilder;
|
|
||||||
|
|
||||||
public SiteThemeExportEvent(Object source, CmsSite site, ZipBuilder zipBuilder) {
|
|
||||||
super(source);
|
|
||||||
this.site = site;
|
|
||||||
this.zipBuilder = zipBuilder;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,25 +0,0 @@
|
|||||||
package com.chestnut.contentcore.listener.event;
|
|
||||||
|
|
||||||
import com.chestnut.common.security.domain.LoginUser;
|
|
||||||
import com.chestnut.contentcore.domain.CmsSite;
|
|
||||||
import lombok.Getter;
|
|
||||||
import org.springframework.context.ApplicationEvent;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
public class SiteThemeImportEvent extends ApplicationEvent {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private CmsSite site;
|
|
||||||
|
|
||||||
private String destDir;
|
|
||||||
|
|
||||||
private LoginUser operator;
|
|
||||||
|
|
||||||
public SiteThemeImportEvent(Object source, CmsSite site, String destDir, LoginUser operator) {
|
|
||||||
super(source);
|
|
||||||
this.site = site;
|
|
||||||
this.destDir = destDir;
|
|
||||||
this.operator = operator;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,202 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2022-2024 兮玥(190785909@qq.com)
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package com.chestnut.contentcore.publish;
|
|
||||||
|
|
||||||
import com.chestnut.common.async.AsyncTaskManager;
|
|
||||||
import com.chestnut.common.staticize.StaticizeService;
|
|
||||||
import com.chestnut.common.staticize.core.TemplateContext;
|
|
||||||
import com.chestnut.common.utils.IdUtils;
|
|
||||||
import com.chestnut.common.utils.StringUtils;
|
|
||||||
import com.chestnut.common.utils.file.FileExUtils;
|
|
||||||
import com.chestnut.contentcore.config.CMSPublishConfig;
|
|
||||||
import com.chestnut.contentcore.core.impl.CatalogType_Link;
|
|
||||||
import com.chestnut.contentcore.core.impl.PublishPipeProp_DefaultListTemplate;
|
|
||||||
import com.chestnut.contentcore.core.impl.PublishPipeProp_IndexTemplate;
|
|
||||||
import com.chestnut.contentcore.core.impl.PublishPipeProp_ListTemplate;
|
|
||||||
import com.chestnut.contentcore.domain.CmsCatalog;
|
|
||||||
import com.chestnut.contentcore.domain.CmsPublishPipe;
|
|
||||||
import com.chestnut.contentcore.domain.CmsSite;
|
|
||||||
import com.chestnut.contentcore.properties.MaxPageOnContentPublishProperty;
|
|
||||||
import com.chestnut.contentcore.service.ICatalogService;
|
|
||||||
import com.chestnut.contentcore.service.IPublishPipeService;
|
|
||||||
import com.chestnut.contentcore.service.ISiteService;
|
|
||||||
import com.chestnut.contentcore.service.ITemplateService;
|
|
||||||
import com.chestnut.contentcore.template.ITemplateType;
|
|
||||||
import com.chestnut.contentcore.template.impl.CatalogTemplateType;
|
|
||||||
import com.chestnut.contentcore.util.SiteUtils;
|
|
||||||
import com.chestnut.contentcore.util.TemplateUtils;
|
|
||||||
import freemarker.template.TemplateException;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.apache.commons.collections4.MapUtils;
|
|
||||||
import org.springframework.data.redis.connection.stream.MapRecord;
|
|
||||||
import org.springframework.data.redis.connection.stream.RecordId;
|
|
||||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.time.Instant;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 栏目发布任务
|
|
||||||
*
|
|
||||||
* @author 兮玥
|
|
||||||
* @email 190785909@qq.com
|
|
||||||
*/
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
@Component(IPublishTask.BeanPrefix + CatalogPublishTask.Type)
|
|
||||||
public class CatalogPublishTask implements IPublishTask<CmsCatalog> {
|
|
||||||
|
|
||||||
public final static String Type = "catalog";
|
|
||||||
|
|
||||||
private final ISiteService siteService;
|
|
||||||
|
|
||||||
private final ICatalogService catalogService;
|
|
||||||
|
|
||||||
private final IPublishPipeService publishPipeService;
|
|
||||||
|
|
||||||
private final ITemplateService templateService;
|
|
||||||
|
|
||||||
private final StaticizeService staticizeService;
|
|
||||||
|
|
||||||
private final StringRedisTemplate redisTemplate;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getType() {
|
|
||||||
return Type;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void publish(CmsCatalog catalog) {
|
|
||||||
if (!catalog.isStaticize() || !catalog.isVisible() || CatalogType_Link.ID.equals(catalog.getCatalogType())) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
String dataId = catalog.getCatalogId().toString();
|
|
||||||
MapRecord<String, String, String> record = MapRecord.create(CMSPublishConfig.PublishStreamName, Map.of(
|
|
||||||
"type", Type,
|
|
||||||
"id", dataId
|
|
||||||
));
|
|
||||||
redisTemplate.opsForStream().add(record);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void staticize(Map<String, String> dataMap) {
|
|
||||||
Long catalogId = MapUtils.getLong(dataMap, "id");
|
|
||||||
if (IdUtils.validate(catalogId)) {
|
|
||||||
CmsCatalog catalog = this.catalogService.getCatalog(catalogId);
|
|
||||||
if (Objects.nonNull(catalog)) {
|
|
||||||
this.catalogStaticize(catalog);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void catalogStaticize(CmsCatalog catalog) {
|
|
||||||
CmsSite site = this.siteService.getSite(catalog.getSiteId());
|
|
||||||
int maxPage = MaxPageOnContentPublishProperty.getValue(site.getConfigProps());
|
|
||||||
this.catalogStaticize(catalog, maxPage);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void catalogStaticize(CmsCatalog catalog, int pageMax) {
|
|
||||||
if (!catalog.isStaticize() || !catalog.isVisible() || CatalogType_Link.ID.equals(catalog.getCatalogType())) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
List<CmsPublishPipe> publishPipes = this.publishPipeService.getPublishPipes(catalog.getSiteId());
|
|
||||||
for (CmsPublishPipe pp : publishPipes) {
|
|
||||||
this.doCatalogStaticize(catalog, pp.getCode(), pageMax);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void doCatalogStaticize(CmsCatalog catalog, String publishPipeCode, int pageMax) {
|
|
||||||
CmsSite site = this.siteService.getSite(catalog.getSiteId());
|
|
||||||
if (!catalog.isStaticize()) {
|
|
||||||
logger.warn("【{}】未启用静态化的栏目跳过静态化:{}", publishPipeCode, catalog.getName());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!catalog.isVisible()) {
|
|
||||||
logger.warn("【{}】不可见状态的栏目跳过静态化:{}", publishPipeCode, catalog.getName());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (CatalogType_Link.ID.equals(catalog.getCatalogType())) {
|
|
||||||
logger.warn("【{}】链接类型栏目跳过静态化:{}", publishPipeCode, catalog.getName());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
String indexTemplate = PublishPipeProp_IndexTemplate.getValue(publishPipeCode, catalog.getPublishPipeProps());
|
|
||||||
String listTemplate = PublishPipeProp_ListTemplate.getValue(publishPipeCode, catalog.getPublishPipeProps());
|
|
||||||
if (StringUtils.isEmpty(listTemplate)) {
|
|
||||||
listTemplate = PublishPipeProp_DefaultListTemplate.getValue(publishPipeCode, site.getPublishPipeProps()); // 取站点默认模板
|
|
||||||
}
|
|
||||||
File indexTemplateFile = this.templateService.findTemplateFile(site, indexTemplate, publishPipeCode);
|
|
||||||
File listTemplateFile = this.templateService.findTemplateFile(site, listTemplate, publishPipeCode);
|
|
||||||
if (indexTemplateFile == null && listTemplateFile == null) {
|
|
||||||
logger.warn(AsyncTaskManager.addErrMessage(StringUtils.messageFormat("[{0}]栏目首页模板和列表页模板未配置或不存在:{1}",
|
|
||||||
publishPipeCode, catalog.getCatalogId() + "#" + catalog.getName())));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
String siteRoot = SiteUtils.getSiteRoot(site, publishPipeCode);
|
|
||||||
String dirPath = siteRoot + catalog.getPath();
|
|
||||||
FileExUtils.mkdirs(dirPath);
|
|
||||||
String staticSuffix = site.getStaticSuffix(publishPipeCode); // 静态化文件类型
|
|
||||||
|
|
||||||
// 发布栏目首页
|
|
||||||
long s = System.currentTimeMillis();
|
|
||||||
if (Objects.nonNull(indexTemplateFile)) {
|
|
||||||
try {
|
|
||||||
String templateKey = SiteUtils.getTemplateKey(site, publishPipeCode, indexTemplate);
|
|
||||||
TemplateContext templateContext = new TemplateContext(templateKey, false, publishPipeCode);
|
|
||||||
templateContext.setDirectory(dirPath);
|
|
||||||
templateContext.setFirstFileName("index" + StringUtils.DOT + staticSuffix);
|
|
||||||
// init template variables
|
|
||||||
TemplateUtils.initGlobalVariables(site, templateContext);
|
|
||||||
// init templateType variables
|
|
||||||
ITemplateType templateType = templateService.getTemplateType(CatalogTemplateType.TypeId);
|
|
||||||
templateType.initTemplateData(catalog.getCatalogId(), templateContext);
|
|
||||||
// staticize
|
|
||||||
this.staticizeService.process(templateContext);
|
|
||||||
logger.debug("[{}]栏目首页模板解析:{},耗时:{}ms", publishPipeCode, catalog.getCatalogId() + "#" + catalog.getName(), (System.currentTimeMillis() - s));
|
|
||||||
} catch (IOException | TemplateException e) {
|
|
||||||
logger.error(AsyncTaskManager.addErrMessage(StringUtils.messageFormat("[{0}]栏目首页解析失败:{1}",
|
|
||||||
publishPipeCode, catalog.getCatalogId() + "#" + catalog.getName())), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 发布栏目列表页
|
|
||||||
if (Objects.nonNull(listTemplateFile)) {
|
|
||||||
s = System.currentTimeMillis();
|
|
||||||
try {
|
|
||||||
String templateKey = SiteUtils.getTemplateKey(site, publishPipeCode, listTemplate);
|
|
||||||
TemplateContext templateContext = new TemplateContext(templateKey, false, publishPipeCode);
|
|
||||||
templateContext.setMaxPageNo(pageMax);
|
|
||||||
templateContext.setDirectory(dirPath);
|
|
||||||
String name = Objects.nonNull(indexTemplateFile) ? "list" : "index";
|
|
||||||
templateContext.setFirstFileName(name + StringUtils.DOT + staticSuffix);
|
|
||||||
templateContext.setOtherFileName(
|
|
||||||
name + "_" + TemplateContext.PlaceHolder_PageNo + StringUtils.DOT + staticSuffix);
|
|
||||||
// init template variables
|
|
||||||
TemplateUtils.initGlobalVariables(site, templateContext);
|
|
||||||
// init templateType variables
|
|
||||||
ITemplateType templateType = templateService.getTemplateType(CatalogTemplateType.TypeId);
|
|
||||||
templateType.initTemplateData(catalog.getCatalogId(), templateContext);
|
|
||||||
// staticize
|
|
||||||
this.staticizeService.process(templateContext);
|
|
||||||
logger.debug("[{}]栏目列表模板解析:{},耗时:{}ms", publishPipeCode, catalog.getCatalogId() + "#" + catalog.getName(), (System.currentTimeMillis() - s));
|
|
||||||
} catch (Exception e1) {
|
|
||||||
logger.error(AsyncTaskManager.addErrMessage(StringUtils.messageFormat("[{0}]栏目列表页解析失败:{1}",
|
|
||||||
publishPipeCode, catalog.getCatalogId() + "#" + catalog.getName())), e1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,39 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2022-2024 兮玥(190785909@qq.com)
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package com.chestnut.contentcore.publish;
|
|
||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* CmsStaticizeService
|
|
||||||
*
|
|
||||||
* @author 兮玥
|
|
||||||
* @email 190785909@qq.com
|
|
||||||
*/
|
|
||||||
@Service
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class CmsStaticizeService {
|
|
||||||
|
|
||||||
private final Map<String, IStaticizeType> staticizeTypeMap;
|
|
||||||
|
|
||||||
public IStaticizeType getStaticizeType(String type) {
|
|
||||||
return staticizeTypeMap.get(IStaticizeType.BEAN_PREFIX + type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -1,262 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2022-2024 兮玥(190785909@qq.com)
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package com.chestnut.contentcore.publish;
|
|
||||||
|
|
||||||
import com.chestnut.common.async.AsyncTaskManager;
|
|
||||||
import com.chestnut.common.staticize.StaticizeService;
|
|
||||||
import com.chestnut.common.staticize.core.TemplateContext;
|
|
||||||
import com.chestnut.common.utils.IdUtils;
|
|
||||||
import com.chestnut.common.utils.StringUtils;
|
|
||||||
import com.chestnut.contentcore.config.CMSPublishConfig;
|
|
||||||
import com.chestnut.contentcore.core.IPublishPipeProp;
|
|
||||||
import com.chestnut.contentcore.core.impl.PublishPipeProp_ContentTemplate;
|
|
||||||
import com.chestnut.contentcore.domain.CmsCatalog;
|
|
||||||
import com.chestnut.contentcore.domain.CmsContent;
|
|
||||||
import com.chestnut.contentcore.domain.CmsPublishPipe;
|
|
||||||
import com.chestnut.contentcore.domain.CmsSite;
|
|
||||||
import com.chestnut.contentcore.service.*;
|
|
||||||
import com.chestnut.contentcore.template.ITemplateType;
|
|
||||||
import com.chestnut.contentcore.template.impl.ContentTemplateType;
|
|
||||||
import com.chestnut.contentcore.util.ContentUtils;
|
|
||||||
import com.chestnut.contentcore.util.SiteUtils;
|
|
||||||
import com.chestnut.contentcore.util.TemplateUtils;
|
|
||||||
import freemarker.template.TemplateException;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.apache.commons.collections4.MapUtils;
|
|
||||||
import org.springframework.data.redis.connection.stream.MapRecord;
|
|
||||||
import org.springframework.data.redis.connection.stream.RecordId;
|
|
||||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.time.Instant;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 内容发布任务
|
|
||||||
*
|
|
||||||
* @author 兮玥
|
|
||||||
* @email 190785909@qq.com
|
|
||||||
*/
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
@Component(IPublishTask.BeanPrefix + ContentPublishTask.Type)
|
|
||||||
public class ContentPublishTask implements IPublishTask<CmsContent> {
|
|
||||||
|
|
||||||
public final static String Type = "content";
|
|
||||||
|
|
||||||
private final ISiteService siteService;
|
|
||||||
|
|
||||||
private final ICatalogService catalogService;
|
|
||||||
|
|
||||||
private final IContentService contentService;
|
|
||||||
|
|
||||||
private final IPublishPipeService publishPipeService;
|
|
||||||
|
|
||||||
private final ITemplateService templateService;
|
|
||||||
|
|
||||||
private final StaticizeService staticizeService;
|
|
||||||
|
|
||||||
private final StringRedisTemplate redisTemplate;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getType() {
|
|
||||||
return Type;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void publish(CmsContent content) {
|
|
||||||
CmsCatalog catalog = catalogService.getCatalog(content.getCatalogId());
|
|
||||||
if (!catalog.isStaticize() || content.isLinkContent()) {
|
|
||||||
return; // 不静态化直接跳过,标题内容不需要静态化
|
|
||||||
}
|
|
||||||
CmsSite site = siteService.getSite(content.getSiteId());
|
|
||||||
List<CmsPublishPipe> publishPipes = publishPipeService.getPublishPipes(content.getSiteId());
|
|
||||||
// 判断内容是否有设置模板
|
|
||||||
boolean hasTemplate = false;
|
|
||||||
for (CmsPublishPipe pp : publishPipes) {
|
|
||||||
final String detailTemplate = getDetailTemplate(site, catalog, content, pp.getCode());
|
|
||||||
File templateFile = this.templateService.findTemplateFile(site, detailTemplate, pp.getCode());
|
|
||||||
if (Objects.nonNull(templateFile)) {
|
|
||||||
hasTemplate = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!hasTemplate) {
|
|
||||||
return; // 没有可用模板不需要静态化
|
|
||||||
}
|
|
||||||
// 加入消息队列
|
|
||||||
String dataId = content.getContentId().toString();
|
|
||||||
MapRecord<String, String, String> record = MapRecord.create(CMSPublishConfig.PublishStreamName, Map.of(
|
|
||||||
"type", Type,
|
|
||||||
"id", dataId
|
|
||||||
));
|
|
||||||
redisTemplate.opsForStream().add(record);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void staticize(Map<String, String> dataMap) {
|
|
||||||
Long contentId = MapUtils.getLong(dataMap, "id");
|
|
||||||
if (IdUtils.validate(contentId)) {
|
|
||||||
CmsContent content = this.contentService.getById(contentId);
|
|
||||||
if (Objects.nonNull(content)) {
|
|
||||||
this.contentStaticize(content);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void contentStaticize(CmsContent cmsContent) {
|
|
||||||
List<CmsPublishPipe> publishPipes = publishPipeService.getPublishPipes(cmsContent.getSiteId());
|
|
||||||
// 发布内容
|
|
||||||
for (CmsPublishPipe pp : publishPipes) {
|
|
||||||
doContentStaticize(cmsContent, pp.getCode());
|
|
||||||
// 内容扩展模板静态化
|
|
||||||
doContentExStaticize(cmsContent, pp.getCode());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void doContentStaticize(CmsContent content, String publishPipeCode) {
|
|
||||||
CmsSite site = this.siteService.getSite(content.getSiteId());
|
|
||||||
CmsCatalog catalog = this.catalogService.getCatalog(content.getCatalogId());
|
|
||||||
if (!catalog.isStaticize()) {
|
|
||||||
logger.warn("[ {} ]栏目设置不静态化[ {}#{} ]:{}", publishPipeCode, site.getName(),
|
|
||||||
catalog.getName(), content.getTitle());
|
|
||||||
return; // 不静态化直接跳过
|
|
||||||
}
|
|
||||||
if (content.isLinkContent()) {
|
|
||||||
logger.warn("[ {} ]标题内容不需要静态化[ {}#{} ]:{}", publishPipeCode, site.getName(),
|
|
||||||
catalog.getName(), content.getTitle());
|
|
||||||
return; // 标题内容不需要静态化
|
|
||||||
}
|
|
||||||
final String detailTemplate = getDetailTemplate(site, catalog, content, publishPipeCode);
|
|
||||||
File templateFile = this.templateService.findTemplateFile(site, detailTemplate, publishPipeCode);
|
|
||||||
if (templateFile == null) {
|
|
||||||
logger.warn(AsyncTaskManager.addErrMessage(
|
|
||||||
StringUtils.messageFormat("[ {0} ]内容模板未设置或文件不存在[ {1}#{2} ]:{3}",
|
|
||||||
publishPipeCode, site.getName(), catalog.getName(), content.getTitle())));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
long s = System.currentTimeMillis();
|
|
||||||
// 自定义模板上下文
|
|
||||||
String templateKey = SiteUtils.getTemplateKey(site, publishPipeCode, detailTemplate);
|
|
||||||
TemplateContext templateContext = new TemplateContext(templateKey, false, publishPipeCode);
|
|
||||||
// init template datamode
|
|
||||||
TemplateUtils.initGlobalVariables(site, templateContext);
|
|
||||||
// init templateType data to datamode
|
|
||||||
ITemplateType templateType = this.templateService.getTemplateType(ContentTemplateType.TypeId);
|
|
||||||
templateType.initTemplateData(content.getContentId(), templateContext);
|
|
||||||
// 静态化文件地址
|
|
||||||
this.setContentStaticPath(site, catalog, content, templateContext);
|
|
||||||
// 静态化
|
|
||||||
this.staticizeService.process(templateContext);
|
|
||||||
logger.debug("[ {} ]内容详情页模板解析[ {}#{} ]:{},耗时:{}ms", publishPipeCode, site.getName(),
|
|
||||||
catalog.getName(), content.getTitle(), (System.currentTimeMillis() - s));
|
|
||||||
} catch (TemplateException | IOException e) {
|
|
||||||
logger.error(AsyncTaskManager.addErrMessage(StringUtils.messageFormat("[{0}]内容详情页解析失败:[{1}]{2}",
|
|
||||||
publishPipeCode, catalog.getName(), content.getTitle())), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setContentStaticPath(CmsSite site, CmsCatalog catalog, CmsContent content, TemplateContext context) {
|
|
||||||
String siteRoot = SiteUtils.getSiteRoot(site, context.getPublishPipeCode());
|
|
||||||
if (StringUtils.isNotBlank(content.getStaticPath())) {
|
|
||||||
String dir = "";
|
|
||||||
String filename = content.getStaticPath();
|
|
||||||
if (filename.indexOf("/") > 0) {
|
|
||||||
dir = filename.substring(0, filename.lastIndexOf("/") + 1);
|
|
||||||
filename = filename.substring(filename.lastIndexOf("/") + 1);
|
|
||||||
}
|
|
||||||
context.setDirectory(siteRoot + dir);
|
|
||||||
context.setFirstFileName(filename);
|
|
||||||
String name = filename.substring(0, filename.lastIndexOf("."));
|
|
||||||
String suffix = filename.substring(filename.lastIndexOf("."));
|
|
||||||
context.setOtherFileName(name + "_" + TemplateContext.PlaceHolder_PageNo + suffix);
|
|
||||||
} else {
|
|
||||||
context.setDirectory(siteRoot + catalog.getPath());
|
|
||||||
String suffix = site.getStaticSuffix(context.getPublishPipeCode());
|
|
||||||
context.setFirstFileName(content.getContentId() + StringUtils.DOT + suffix);
|
|
||||||
context.setOtherFileName(
|
|
||||||
content.getContentId() + "_" + TemplateContext.PlaceHolder_PageNo + StringUtils.DOT + suffix);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void doContentExStaticize(CmsContent content, String publishPipeCode) {
|
|
||||||
CmsSite site = this.siteService.getSite(content.getSiteId());
|
|
||||||
CmsCatalog catalog = this.catalogService.getCatalog(content.getCatalogId());
|
|
||||||
if (!catalog.isStaticize()) {
|
|
||||||
logger.warn("[{}]栏目设置不静态化[{}#{}]:{}", publishPipeCode, site.getName(), catalog.getName(), content.getTitle());
|
|
||||||
return; // 不静态化直接跳过
|
|
||||||
}
|
|
||||||
if (content.isLinkContent()) {
|
|
||||||
logger.warn("[{}]标题内容不需要静态化[ {}#{} ]:{}", publishPipeCode, site.getName(), catalog.getName(), content.getTitle());
|
|
||||||
return; // 标题内容不需要静态化
|
|
||||||
}
|
|
||||||
String exTemplate = ContentUtils.getContentExTemplate(content, catalog, publishPipeCode);
|
|
||||||
if (StringUtils.isEmpty(exTemplate)) {
|
|
||||||
return; // 未设置扩展模板直接跳过
|
|
||||||
}
|
|
||||||
File templateFile = this.templateService.findTemplateFile(site, exTemplate, publishPipeCode);
|
|
||||||
if (templateFile == null) {
|
|
||||||
logger.warn("[{}]内容扩展模板未设置或文件不存在[ {}#{} ]:{}", publishPipeCode, site.getName(), catalog.getName(), content.getTitle());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
long s = System.currentTimeMillis();
|
|
||||||
// 自定义模板上下文
|
|
||||||
String templateKey = SiteUtils.getTemplateKey(site, publishPipeCode, exTemplate);
|
|
||||||
TemplateContext templateContext = new TemplateContext(templateKey, false, publishPipeCode);
|
|
||||||
// init template datamode
|
|
||||||
TemplateUtils.initGlobalVariables(site, templateContext);
|
|
||||||
// init templateType data to datamode
|
|
||||||
ITemplateType templateType = this.templateService.getTemplateType(ContentTemplateType.TypeId);
|
|
||||||
templateType.initTemplateData(content.getContentId(), templateContext);
|
|
||||||
// 静态化文件地址
|
|
||||||
String siteRoot = SiteUtils.getSiteRoot(site, publishPipeCode);
|
|
||||||
templateContext.setDirectory(siteRoot + catalog.getPath());
|
|
||||||
String fileName = ContentUtils.getContextExFileName(content.getContentId(), site.getStaticSuffix(publishPipeCode));
|
|
||||||
templateContext.setFirstFileName(fileName);
|
|
||||||
// 静态化
|
|
||||||
this.staticizeService.process(templateContext);
|
|
||||||
logger.debug("[{}]内容扩展模板解析[ {}#{} ]:{},耗时:{}ms", publishPipeCode, site.getName(),
|
|
||||||
catalog.getName(), content.getTitle(), (System.currentTimeMillis() - s));
|
|
||||||
} catch (TemplateException | IOException e) {
|
|
||||||
logger.error(AsyncTaskManager.addErrMessage(StringUtils.messageFormat("[{0}] 内容扩展模板解析失败 [{1}#{2}]:{3}",
|
|
||||||
publishPipeCode, site.getName(), catalog.getName(), content.getTitle())), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getDetailTemplate(CmsSite site, CmsCatalog catalog, CmsContent content, String publishPipeCode) {
|
|
||||||
String detailTemplate = PublishPipeProp_ContentTemplate.getValue(publishPipeCode,
|
|
||||||
content.getPublishPipeProps());
|
|
||||||
if (StringUtils.isEmpty(detailTemplate)) {
|
|
||||||
// 无内容独立模板取栏目配置
|
|
||||||
detailTemplate = this.publishPipeService.getPublishPipePropValue(
|
|
||||||
IPublishPipeProp.DetailTemplatePropPrefix + content.getContentType(), publishPipeCode,
|
|
||||||
catalog.getPublishPipeProps());
|
|
||||||
if (StringUtils.isEmpty(detailTemplate)) {
|
|
||||||
// 无栏目配置去站点默认模板配置
|
|
||||||
detailTemplate = this.publishPipeService.getPublishPipePropValue(
|
|
||||||
IPublishPipeProp.DefaultDetailTemplatePropPrefix + content.getContentType(), publishPipeCode,
|
|
||||||
site.getPublishPipeProps());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return detailTemplate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,48 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2022-2024 兮玥(190785909@qq.com)
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package com.chestnut.contentcore.publish;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* IPublishStrategy
|
|
||||||
*
|
|
||||||
* @author 兮玥
|
|
||||||
* @email 190785909@qq.com
|
|
||||||
*/
|
|
||||||
public interface IPublishStrategy {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 发布策略ID
|
|
||||||
*/
|
|
||||||
String getId();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建发布任务
|
|
||||||
*
|
|
||||||
* @param dataType 数据类型
|
|
||||||
* @param dataId 数据ID
|
|
||||||
*/
|
|
||||||
void publish(String dataType, String dataId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取待处理发布任务数量
|
|
||||||
*/
|
|
||||||
long getTaskCount();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 清空所有待处理发布任务
|
|
||||||
*/
|
|
||||||
void cleanTasks();
|
|
||||||
}
|
|
||||||
@ -1,46 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2022-2024 兮玥(190785909@qq.com)
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package com.chestnut.contentcore.publish;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <TODO description class purpose>
|
|
||||||
*
|
|
||||||
* @author 兮玥
|
|
||||||
* @email 190785909@qq.com
|
|
||||||
*/
|
|
||||||
public interface IPublishTask<T> {
|
|
||||||
|
|
||||||
Logger logger = LoggerFactory.getLogger("publish");
|
|
||||||
|
|
||||||
String BeanPrefix = "PublishTask_";
|
|
||||||
|
|
||||||
String getType();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建发布任务
|
|
||||||
*/
|
|
||||||
void publish(T data);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 静态化
|
|
||||||
*/
|
|
||||||
void staticize(Map<String, String> dataMap);
|
|
||||||
}
|
|
||||||
@ -1,30 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2022-2024 兮玥(190785909@qq.com)
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package com.chestnut.contentcore.publish;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
public interface IStaticizeType {
|
|
||||||
|
|
||||||
Logger logger = LoggerFactory.getLogger("publish");
|
|
||||||
|
|
||||||
String BEAN_PREFIX = "CmsStaticizeType";
|
|
||||||
|
|
||||||
String getType();
|
|
||||||
|
|
||||||
void staticize(String dataId);
|
|
||||||
}
|
|
||||||
@ -1,73 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2022-2024 兮玥(190785909@qq.com)
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package com.chestnut.contentcore.publish;
|
|
||||||
|
|
||||||
import com.chestnut.contentcore.config.CMSPublishConfig;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.Setter;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.apache.commons.collections4.MapUtils;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.data.redis.connection.stream.Consumer;
|
|
||||||
import org.springframework.data.redis.connection.stream.MapRecord;
|
|
||||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
|
||||||
import org.springframework.data.redis.stream.StreamListener;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 发布任务消费监听
|
|
||||||
*
|
|
||||||
* @author 兮玥
|
|
||||||
* @email 190785909@qq.com
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class PublishTaskReceiver implements StreamListener<String, MapRecord<String, String, String>> {
|
|
||||||
|
|
||||||
private final static Logger logger = LoggerFactory.getLogger("publish");
|
|
||||||
|
|
||||||
private final Map<String, IPublishTask<?>> publishTaskMap;
|
|
||||||
|
|
||||||
private final StringRedisTemplate redisTemplate;
|
|
||||||
|
|
||||||
@Setter
|
|
||||||
@Getter
|
|
||||||
private Consumer consumer;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onMessage(MapRecord<String, String, String> message) {
|
|
||||||
String stream = message.getStream();
|
|
||||||
if (Objects.nonNull(stream)) {
|
|
||||||
try {
|
|
||||||
Map<String, String> map = message.getValue();
|
|
||||||
String type = MapUtils.getString(map, "type");
|
|
||||||
IPublishTask<?> publishTask = publishTaskMap.get(IPublishTask.BeanPrefix + type);
|
|
||||||
if (Objects.nonNull(publishTask)) {
|
|
||||||
publishTask.staticize(map);
|
|
||||||
}
|
|
||||||
} catch(Exception e) {
|
|
||||||
logger.error("Publish err.", e);
|
|
||||||
} finally {
|
|
||||||
redisTemplate.opsForStream().acknowledge(stream, CMSPublishConfig.PublishConsumerGroup, message.getId().getValue());
|
|
||||||
redisTemplate.opsForStream().delete(stream, message.getId().getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,129 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2022-2024 兮玥(190785909@qq.com)
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package com.chestnut.contentcore.publish;
|
|
||||||
|
|
||||||
import com.chestnut.common.async.AsyncTaskManager;
|
|
||||||
import com.chestnut.common.staticize.StaticizeService;
|
|
||||||
import com.chestnut.common.staticize.core.TemplateContext;
|
|
||||||
import com.chestnut.common.utils.IdUtils;
|
|
||||||
import com.chestnut.common.utils.JacksonUtils;
|
|
||||||
import com.chestnut.common.utils.StringUtils;
|
|
||||||
import com.chestnut.contentcore.config.CMSPublishConfig;
|
|
||||||
import com.chestnut.contentcore.domain.CmsSite;
|
|
||||||
import com.chestnut.contentcore.service.IPublishPipeService;
|
|
||||||
import com.chestnut.contentcore.service.ISiteService;
|
|
||||||
import com.chestnut.contentcore.service.ITemplateService;
|
|
||||||
import com.chestnut.contentcore.template.ITemplateType;
|
|
||||||
import com.chestnut.contentcore.template.impl.SiteTemplateType;
|
|
||||||
import com.chestnut.contentcore.util.SiteUtils;
|
|
||||||
import com.chestnut.contentcore.util.TemplateUtils;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.apache.commons.collections4.MapUtils;
|
|
||||||
import org.springframework.data.redis.connection.stream.MapRecord;
|
|
||||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 站点发布任务
|
|
||||||
*
|
|
||||||
* @author 兮玥
|
|
||||||
* @email 190785909@qq.com
|
|
||||||
*/
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
@Component(IPublishTask.BeanPrefix + SitePublishTask.Type)
|
|
||||||
public class SitePublishTask implements IPublishTask<CmsSite> {
|
|
||||||
|
|
||||||
public final static String Type = "site";
|
|
||||||
|
|
||||||
private final ISiteService siteService;
|
|
||||||
|
|
||||||
private final IPublishPipeService publishPipeService;
|
|
||||||
|
|
||||||
private final ITemplateService templateService;
|
|
||||||
|
|
||||||
private final StaticizeService staticizeService;
|
|
||||||
|
|
||||||
private final StringRedisTemplate redisTemplate;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getType() {
|
|
||||||
return Type;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void publish(CmsSite site) {
|
|
||||||
String dataId = site.getSiteId().toString();
|
|
||||||
MapRecord<String, String, String> record = MapRecord.create(CMSPublishConfig.PublishStreamName, Map.of(
|
|
||||||
"type", Type,
|
|
||||||
"id", dataId
|
|
||||||
));
|
|
||||||
redisTemplate.opsForStream().add(record);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void staticize(Map<String, String> dataMap) {
|
|
||||||
logger.info("开始发布:" + JacksonUtils.to(dataMap));
|
|
||||||
Long siteId = MapUtils.getLong(dataMap, "id");
|
|
||||||
if (IdUtils.validate(siteId)) {
|
|
||||||
CmsSite site = this.siteService.getSite(siteId);
|
|
||||||
if (Objects.nonNull(site)) {
|
|
||||||
this.siteStaticize(site);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
logger.info("结束发布:" + JacksonUtils.to(dataMap));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void siteStaticize(CmsSite site) {
|
|
||||||
this.publishPipeService.getPublishPipes(site.getSiteId())
|
|
||||||
.forEach(pp -> doSiteStaticize(site, pp.getCode()));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void doSiteStaticize(CmsSite site, String publishPipeCode) {
|
|
||||||
try {
|
|
||||||
AsyncTaskManager
|
|
||||||
.setTaskMessage(StringUtils.messageFormat("[{0}]正在发布站点首页:{1}", publishPipeCode, site.getName()));
|
|
||||||
|
|
||||||
String indexTemplate = site.getIndexTemplate(publishPipeCode);
|
|
||||||
File templateFile = this.templateService.findTemplateFile(site, indexTemplate, publishPipeCode);
|
|
||||||
if (Objects.isNull(templateFile)) {
|
|
||||||
logger.warn(AsyncTaskManager.addErrMessage(StringUtils.messageFormat("[{0}]站点首页模板未配置或不存在:{1}",
|
|
||||||
publishPipeCode, site.getSiteId() + "#" + site.getName())));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 模板ID = 通道:站点目录:模板文件名
|
|
||||||
String templateKey = SiteUtils.getTemplateKey(site, publishPipeCode, indexTemplate);
|
|
||||||
TemplateContext context = new TemplateContext(templateKey, false, publishPipeCode);
|
|
||||||
// init template datamode
|
|
||||||
TemplateUtils.initGlobalVariables(site, context);
|
|
||||||
// init templateType data to datamode
|
|
||||||
ITemplateType templateType = templateService.getTemplateType(SiteTemplateType.TypeId);
|
|
||||||
templateType.initTemplateData(site.getSiteId(), context);
|
|
||||||
|
|
||||||
long s = System.currentTimeMillis();
|
|
||||||
context.setDirectory(SiteUtils.getSiteRoot(site, publishPipeCode));
|
|
||||||
context.setFirstFileName("index" + StringUtils.DOT + site.getStaticSuffix(publishPipeCode));
|
|
||||||
this.staticizeService.process(context);
|
|
||||||
logger.debug("[{}]首页模板解析:{},耗时:{}ms", publishPipeCode, site.getName(), (System.currentTimeMillis() - s));
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.error(AsyncTaskManager.addErrMessage(StringUtils.messageFormat("[{0}][{1}]站点首页解析失败:{2}",
|
|
||||||
publishPipeCode, site.getName(), e.getMessage())), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,182 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2022-2024 兮玥(190785909@qq.com)
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package com.chestnut.contentcore.publish.staticize;
|
|
||||||
|
|
||||||
import com.chestnut.common.async.AsyncTaskManager;
|
|
||||||
import com.chestnut.common.staticize.StaticizeService;
|
|
||||||
import com.chestnut.common.staticize.core.TemplateContext;
|
|
||||||
import com.chestnut.common.utils.IdUtils;
|
|
||||||
import com.chestnut.common.utils.StringUtils;
|
|
||||||
import com.chestnut.common.utils.file.FileExUtils;
|
|
||||||
import com.chestnut.contentcore.core.impl.CatalogType_Link;
|
|
||||||
import com.chestnut.contentcore.core.impl.PublishPipeProp_DefaultListTemplate;
|
|
||||||
import com.chestnut.contentcore.core.impl.PublishPipeProp_IndexTemplate;
|
|
||||||
import com.chestnut.contentcore.core.impl.PublishPipeProp_ListTemplate;
|
|
||||||
import com.chestnut.contentcore.domain.CmsCatalog;
|
|
||||||
import com.chestnut.contentcore.domain.CmsPublishPipe;
|
|
||||||
import com.chestnut.contentcore.domain.CmsSite;
|
|
||||||
import com.chestnut.contentcore.properties.MaxPageOnContentPublishProperty;
|
|
||||||
import com.chestnut.contentcore.publish.IStaticizeType;
|
|
||||||
import com.chestnut.contentcore.service.ICatalogService;
|
|
||||||
import com.chestnut.contentcore.service.IPublishPipeService;
|
|
||||||
import com.chestnut.contentcore.service.ISiteService;
|
|
||||||
import com.chestnut.contentcore.service.ITemplateService;
|
|
||||||
import com.chestnut.contentcore.template.ITemplateType;
|
|
||||||
import com.chestnut.contentcore.template.impl.CatalogTemplateType;
|
|
||||||
import com.chestnut.contentcore.util.SiteUtils;
|
|
||||||
import com.chestnut.contentcore.util.TemplateUtils;
|
|
||||||
import freemarker.template.TemplateException;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* CatalogStaticizeType
|
|
||||||
*
|
|
||||||
* @author 兮玥
|
|
||||||
* @email 190785909@qq.com
|
|
||||||
*/
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
@Component(IStaticizeType.BEAN_PREFIX + CatalogStaticizeType.TYPE)
|
|
||||||
public class CatalogStaticizeType implements IStaticizeType {
|
|
||||||
|
|
||||||
public static final String TYPE = "catalog";
|
|
||||||
|
|
||||||
private final ISiteService siteService;
|
|
||||||
|
|
||||||
private final ICatalogService catalogService;
|
|
||||||
|
|
||||||
private final IPublishPipeService publishPipeService;
|
|
||||||
|
|
||||||
private final ITemplateService templateService;
|
|
||||||
|
|
||||||
private final StaticizeService staticizeService;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getType() {
|
|
||||||
return TYPE;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void staticize(String dataId) {
|
|
||||||
Long catalogId = Long.valueOf(dataId);
|
|
||||||
if (IdUtils.validate(catalogId)) {
|
|
||||||
CmsCatalog catalog = this.catalogService.getCatalog(catalogId);
|
|
||||||
if (Objects.nonNull(catalog)) {
|
|
||||||
this.catalogStaticize(catalog);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void catalogStaticize(CmsCatalog catalog) {
|
|
||||||
CmsSite site = this.siteService.getSite(catalog.getSiteId());
|
|
||||||
int maxPage = MaxPageOnContentPublishProperty.getValue(site.getConfigProps());
|
|
||||||
this.catalogStaticize(catalog, maxPage);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void catalogStaticize(CmsCatalog catalog, int pageMax) {
|
|
||||||
if (!catalog.isStaticize() || !catalog.isVisible() || CatalogType_Link.ID.equals(catalog.getCatalogType())) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
List<CmsPublishPipe> publishPipes = this.publishPipeService.getPublishPipes(catalog.getSiteId());
|
|
||||||
for (CmsPublishPipe pp : publishPipes) {
|
|
||||||
this.doCatalogStaticize(catalog, pp.getCode(), pageMax);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void doCatalogStaticize(CmsCatalog catalog, String publishPipeCode, int pageMax) {
|
|
||||||
CmsSite site = this.siteService.getSite(catalog.getSiteId());
|
|
||||||
if (!catalog.isStaticize()) {
|
|
||||||
logger.warn("【{}】未启用静态化的栏目跳过静态化:{}", publishPipeCode, catalog.getName());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!catalog.isVisible()) {
|
|
||||||
logger.warn("【{}】不可见状态的栏目跳过静态化:{}", publishPipeCode, catalog.getName());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (CatalogType_Link.ID.equals(catalog.getCatalogType())) {
|
|
||||||
logger.warn("【{}】链接类型栏目跳过静态化:{}", publishPipeCode, catalog.getName());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
String indexTemplate = PublishPipeProp_IndexTemplate.getValue(publishPipeCode, catalog.getPublishPipeProps());
|
|
||||||
String listTemplate = PublishPipeProp_ListTemplate.getValue(publishPipeCode, catalog.getPublishPipeProps());
|
|
||||||
if (StringUtils.isEmpty(listTemplate)) {
|
|
||||||
listTemplate = PublishPipeProp_DefaultListTemplate.getValue(publishPipeCode, site.getPublishPipeProps()); // 取站点默认模板
|
|
||||||
}
|
|
||||||
File indexTemplateFile = this.templateService.findTemplateFile(site, indexTemplate, publishPipeCode);
|
|
||||||
File listTemplateFile = this.templateService.findTemplateFile(site, listTemplate, publishPipeCode);
|
|
||||||
if (indexTemplateFile == null && listTemplateFile == null) {
|
|
||||||
logger.warn(AsyncTaskManager.addErrMessage(StringUtils.messageFormat("[{0}]栏目首页模板和列表页模板未配置或不存在:{1}",
|
|
||||||
publishPipeCode, catalog.getCatalogId() + "#" + catalog.getName())));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
String siteRoot = SiteUtils.getSiteRoot(site, publishPipeCode);
|
|
||||||
String dirPath = siteRoot + catalog.getPath();
|
|
||||||
FileExUtils.mkdirs(dirPath);
|
|
||||||
String staticSuffix = site.getStaticSuffix(publishPipeCode); // 静态化文件类型
|
|
||||||
|
|
||||||
// 发布栏目首页
|
|
||||||
long s = System.currentTimeMillis();
|
|
||||||
if (Objects.nonNull(indexTemplateFile)) {
|
|
||||||
try {
|
|
||||||
String templateKey = SiteUtils.getTemplateKey(site, publishPipeCode, indexTemplate);
|
|
||||||
TemplateContext templateContext = new TemplateContext(templateKey, false, publishPipeCode);
|
|
||||||
templateContext.setDirectory(dirPath);
|
|
||||||
templateContext.setFirstFileName("index" + StringUtils.DOT + staticSuffix);
|
|
||||||
// init template variables
|
|
||||||
TemplateUtils.initGlobalVariables(site, templateContext);
|
|
||||||
// init templateType variables
|
|
||||||
ITemplateType templateType = templateService.getTemplateType(CatalogTemplateType.TypeId);
|
|
||||||
templateType.initTemplateData(catalog.getCatalogId(), templateContext);
|
|
||||||
// staticize
|
|
||||||
this.staticizeService.process(templateContext);
|
|
||||||
logger.debug("[{}]栏目首页模板解析:{},耗时:{}ms", publishPipeCode, catalog.getCatalogId() + "#" + catalog.getName(), (System.currentTimeMillis() - s));
|
|
||||||
} catch (IOException | TemplateException e) {
|
|
||||||
logger.error(AsyncTaskManager.addErrMessage(StringUtils.messageFormat("[{0}]栏目首页解析失败:{1}",
|
|
||||||
publishPipeCode, catalog.getCatalogId() + "#" + catalog.getName())), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 发布栏目列表页
|
|
||||||
if (Objects.nonNull(listTemplateFile)) {
|
|
||||||
s = System.currentTimeMillis();
|
|
||||||
try {
|
|
||||||
String templateKey = SiteUtils.getTemplateKey(site, publishPipeCode, listTemplate);
|
|
||||||
TemplateContext templateContext = new TemplateContext(templateKey, false, publishPipeCode);
|
|
||||||
templateContext.setMaxPageNo(pageMax);
|
|
||||||
templateContext.setDirectory(dirPath);
|
|
||||||
String name = Objects.nonNull(indexTemplateFile) ? "list" : "index";
|
|
||||||
templateContext.setFirstFileName(name + StringUtils.DOT + staticSuffix);
|
|
||||||
templateContext.setOtherFileName(
|
|
||||||
name + "_" + TemplateContext.PlaceHolder_PageNo + StringUtils.DOT + staticSuffix);
|
|
||||||
// init template variables
|
|
||||||
TemplateUtils.initGlobalVariables(site, templateContext);
|
|
||||||
// init templateType variables
|
|
||||||
ITemplateType templateType = templateService.getTemplateType(CatalogTemplateType.TypeId);
|
|
||||||
templateType.initTemplateData(catalog.getCatalogId(), templateContext);
|
|
||||||
// staticize
|
|
||||||
this.staticizeService.process(templateContext);
|
|
||||||
logger.debug("[{}]栏目列表模板解析:{},耗时:{}ms", publishPipeCode, catalog.getCatalogId() + "#" + catalog.getName(), (System.currentTimeMillis() - s));
|
|
||||||
} catch (Exception e1) {
|
|
||||||
logger.error(AsyncTaskManager.addErrMessage(StringUtils.messageFormat("[{0}]栏目列表页解析失败:{1}",
|
|
||||||
publishPipeCode, catalog.getCatalogId() + "#" + catalog.getName())), e1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,223 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2022-2024 兮玥(190785909@qq.com)
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package com.chestnut.contentcore.publish.staticize;
|
|
||||||
|
|
||||||
import com.chestnut.common.async.AsyncTaskManager;
|
|
||||||
import com.chestnut.common.staticize.StaticizeService;
|
|
||||||
import com.chestnut.common.staticize.core.TemplateContext;
|
|
||||||
import com.chestnut.common.utils.IdUtils;
|
|
||||||
import com.chestnut.common.utils.StringUtils;
|
|
||||||
import com.chestnut.contentcore.core.IPublishPipeProp;
|
|
||||||
import com.chestnut.contentcore.core.impl.PublishPipeProp_ContentTemplate;
|
|
||||||
import com.chestnut.contentcore.domain.CmsCatalog;
|
|
||||||
import com.chestnut.contentcore.domain.CmsContent;
|
|
||||||
import com.chestnut.contentcore.domain.CmsPublishPipe;
|
|
||||||
import com.chestnut.contentcore.domain.CmsSite;
|
|
||||||
import com.chestnut.contentcore.publish.IStaticizeType;
|
|
||||||
import com.chestnut.contentcore.service.*;
|
|
||||||
import com.chestnut.contentcore.template.ITemplateType;
|
|
||||||
import com.chestnut.contentcore.template.impl.ContentTemplateType;
|
|
||||||
import com.chestnut.contentcore.util.ContentUtils;
|
|
||||||
import com.chestnut.contentcore.util.SiteUtils;
|
|
||||||
import com.chestnut.contentcore.util.TemplateUtils;
|
|
||||||
import freemarker.template.TemplateException;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ContentStaticizeType
|
|
||||||
*
|
|
||||||
* @author 兮玥
|
|
||||||
* @email 190785909@qq.com
|
|
||||||
*/
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
@Component(IStaticizeType.BEAN_PREFIX + ContentStaticizeType.TYPE)
|
|
||||||
public class ContentStaticizeType implements IStaticizeType {
|
|
||||||
|
|
||||||
public static final String TYPE = "content";
|
|
||||||
|
|
||||||
private final ISiteService siteService;
|
|
||||||
|
|
||||||
private final ICatalogService catalogService;
|
|
||||||
|
|
||||||
private final IContentService contentService;
|
|
||||||
|
|
||||||
private final IPublishPipeService publishPipeService;
|
|
||||||
|
|
||||||
private final ITemplateService templateService;
|
|
||||||
|
|
||||||
private final StaticizeService staticizeService;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getType() {
|
|
||||||
return TYPE;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void staticize(String dataId) {
|
|
||||||
Long contentId = Long.valueOf(dataId);
|
|
||||||
if (IdUtils.validate(contentId)) {
|
|
||||||
CmsContent content = this.contentService.dao().getById(contentId);
|
|
||||||
if (Objects.nonNull(content)) {
|
|
||||||
this.contentStaticize(content);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void contentStaticize(CmsContent cmsContent) {
|
|
||||||
List<CmsPublishPipe> publishPipes = publishPipeService.getPublishPipes(cmsContent.getSiteId());
|
|
||||||
// 发布内容
|
|
||||||
for (CmsPublishPipe pp : publishPipes) {
|
|
||||||
doContentStaticize(cmsContent, pp.getCode());
|
|
||||||
// 内容扩展模板静态化
|
|
||||||
doContentExStaticize(cmsContent, pp.getCode());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void doContentStaticize(CmsContent content, String publishPipeCode) {
|
|
||||||
CmsSite site = this.siteService.getSite(content.getSiteId());
|
|
||||||
CmsCatalog catalog = this.catalogService.getCatalog(content.getCatalogId());
|
|
||||||
if (!catalog.isStaticize()) {
|
|
||||||
logger.warn("[ {} ]栏目设置不静态化[ {}#{} ]:{}", publishPipeCode, site.getName(),
|
|
||||||
catalog.getName(), content.getTitle());
|
|
||||||
return; // 不静态化直接跳过
|
|
||||||
}
|
|
||||||
if (content.isLinkContent()) {
|
|
||||||
logger.warn("[ {} ]标题内容不需要静态化[ {}#{} ]:{}", publishPipeCode, site.getName(),
|
|
||||||
catalog.getName(), content.getTitle());
|
|
||||||
return; // 标题内容不需要静态化
|
|
||||||
}
|
|
||||||
final String detailTemplate = getDetailTemplate(site, catalog, content, publishPipeCode);
|
|
||||||
File templateFile = this.templateService.findTemplateFile(site, detailTemplate, publishPipeCode);
|
|
||||||
if (templateFile == null) {
|
|
||||||
logger.warn(AsyncTaskManager.addErrMessage(
|
|
||||||
StringUtils.messageFormat("[ {0} ]内容模板未设置或文件不存在[ {1}#{2} ]:{3}",
|
|
||||||
publishPipeCode, site.getName(), catalog.getName(), content.getTitle())));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
long s = System.currentTimeMillis();
|
|
||||||
// 自定义模板上下文
|
|
||||||
String templateKey = SiteUtils.getTemplateKey(site, publishPipeCode, detailTemplate);
|
|
||||||
TemplateContext templateContext = new TemplateContext(templateKey, false, publishPipeCode);
|
|
||||||
// init template datamode
|
|
||||||
TemplateUtils.initGlobalVariables(site, templateContext);
|
|
||||||
// init templateType data to datamode
|
|
||||||
ITemplateType templateType = this.templateService.getTemplateType(ContentTemplateType.TypeId);
|
|
||||||
templateType.initTemplateData(content.getContentId(), templateContext);
|
|
||||||
// 静态化文件地址
|
|
||||||
this.setContentStaticPath(site, catalog, content, templateContext);
|
|
||||||
// 静态化
|
|
||||||
this.staticizeService.process(templateContext);
|
|
||||||
logger.debug("[ {} ]内容详情页模板解析[ {}#{} ]:{},耗时:{}ms", publishPipeCode, site.getName(),
|
|
||||||
catalog.getName(), content.getTitle(), (System.currentTimeMillis() - s));
|
|
||||||
} catch (TemplateException | IOException e) {
|
|
||||||
logger.error(AsyncTaskManager.addErrMessage(StringUtils.messageFormat("[{0}]内容详情页解析失败:[{1}]{2}",
|
|
||||||
publishPipeCode, catalog.getName(), content.getTitle())), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setContentStaticPath(CmsSite site, CmsCatalog catalog, CmsContent content, TemplateContext context) {
|
|
||||||
String siteRoot = SiteUtils.getSiteRoot(site, context.getPublishPipeCode());
|
|
||||||
if (StringUtils.isNotBlank(content.getStaticPath())) {
|
|
||||||
String dir = "";
|
|
||||||
String filename = content.getStaticPath();
|
|
||||||
if (filename.indexOf("/") > 0) {
|
|
||||||
dir = filename.substring(0, filename.lastIndexOf("/") + 1);
|
|
||||||
filename = filename.substring(filename.lastIndexOf("/") + 1);
|
|
||||||
}
|
|
||||||
context.setDirectory(siteRoot + dir);
|
|
||||||
context.setFirstFileName(filename);
|
|
||||||
String name = filename.substring(0, filename.lastIndexOf("."));
|
|
||||||
String suffix = filename.substring(filename.lastIndexOf("."));
|
|
||||||
context.setOtherFileName(name + "_" + TemplateContext.PlaceHolder_PageNo + suffix);
|
|
||||||
} else {
|
|
||||||
context.setDirectory(siteRoot + catalog.getPath());
|
|
||||||
String suffix = site.getStaticSuffix(context.getPublishPipeCode());
|
|
||||||
context.setFirstFileName(content.getContentId() + StringUtils.DOT + suffix);
|
|
||||||
context.setOtherFileName(
|
|
||||||
content.getContentId() + "_" + TemplateContext.PlaceHolder_PageNo + StringUtils.DOT + suffix);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void doContentExStaticize(CmsContent content, String publishPipeCode) {
|
|
||||||
CmsSite site = this.siteService.getSite(content.getSiteId());
|
|
||||||
CmsCatalog catalog = this.catalogService.getCatalog(content.getCatalogId());
|
|
||||||
if (!catalog.isStaticize()) {
|
|
||||||
logger.warn("[{}]栏目设置不静态化[{}#{}]:{}", publishPipeCode, site.getName(), catalog.getName(), content.getTitle());
|
|
||||||
return; // 不静态化直接跳过
|
|
||||||
}
|
|
||||||
if (content.isLinkContent()) {
|
|
||||||
logger.warn("[{}]标题内容不需要静态化[ {}#{} ]:{}", publishPipeCode, site.getName(), catalog.getName(), content.getTitle());
|
|
||||||
return; // 标题内容不需要静态化
|
|
||||||
}
|
|
||||||
String exTemplate = ContentUtils.getContentExTemplate(content, catalog, publishPipeCode);
|
|
||||||
if (StringUtils.isEmpty(exTemplate)) {
|
|
||||||
return; // 未设置扩展模板直接跳过
|
|
||||||
}
|
|
||||||
File templateFile = this.templateService.findTemplateFile(site, exTemplate, publishPipeCode);
|
|
||||||
if (templateFile == null) {
|
|
||||||
logger.warn("[{}]内容扩展模板未设置或文件不存在[ {}#{} ]:{}", publishPipeCode, site.getName(), catalog.getName(), content.getTitle());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
long s = System.currentTimeMillis();
|
|
||||||
// 自定义模板上下文
|
|
||||||
String templateKey = SiteUtils.getTemplateKey(site, publishPipeCode, exTemplate);
|
|
||||||
TemplateContext templateContext = new TemplateContext(templateKey, false, publishPipeCode);
|
|
||||||
// init template datamode
|
|
||||||
TemplateUtils.initGlobalVariables(site, templateContext);
|
|
||||||
// init templateType data to datamode
|
|
||||||
ITemplateType templateType = this.templateService.getTemplateType(ContentTemplateType.TypeId);
|
|
||||||
templateType.initTemplateData(content.getContentId(), templateContext);
|
|
||||||
// 静态化文件地址
|
|
||||||
String siteRoot = SiteUtils.getSiteRoot(site, publishPipeCode);
|
|
||||||
templateContext.setDirectory(siteRoot + catalog.getPath());
|
|
||||||
String fileName = ContentUtils.getContextExFileName(content.getContentId(), site.getStaticSuffix(publishPipeCode));
|
|
||||||
templateContext.setFirstFileName(fileName);
|
|
||||||
// 静态化
|
|
||||||
this.staticizeService.process(templateContext);
|
|
||||||
logger.debug("[{}]内容扩展模板解析[ {}#{} ]:{},耗时:{}ms", publishPipeCode, site.getName(),
|
|
||||||
catalog.getName(), content.getTitle(), (System.currentTimeMillis() - s));
|
|
||||||
} catch (TemplateException | IOException e) {
|
|
||||||
logger.error(AsyncTaskManager.addErrMessage(StringUtils.messageFormat("[{0}] 内容扩展模板解析失败 [{1}#{2}]:{3}",
|
|
||||||
publishPipeCode, site.getName(), catalog.getName(), content.getTitle())), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getDetailTemplate(CmsSite site, CmsCatalog catalog, CmsContent content, String publishPipeCode) {
|
|
||||||
String detailTemplate = PublishPipeProp_ContentTemplate.getValue(publishPipeCode,
|
|
||||||
content.getPublishPipeProps());
|
|
||||||
if (StringUtils.isEmpty(detailTemplate)) {
|
|
||||||
// 无内容独立模板取栏目配置
|
|
||||||
detailTemplate = this.publishPipeService.getPublishPipePropValue(
|
|
||||||
IPublishPipeProp.DetailTemplatePropPrefix + content.getContentType(), publishPipeCode,
|
|
||||||
catalog.getPublishPipeProps());
|
|
||||||
if (StringUtils.isEmpty(detailTemplate)) {
|
|
||||||
// 无栏目配置去站点默认模板配置
|
|
||||||
detailTemplate = this.publishPipeService.getPublishPipePropValue(
|
|
||||||
IPublishPipeProp.DefaultDetailTemplatePropPrefix + content.getContentType(), publishPipeCode,
|
|
||||||
site.getPublishPipeProps());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return detailTemplate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,110 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2022-2024 兮玥(190785909@qq.com)
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package com.chestnut.contentcore.publish.staticize;
|
|
||||||
|
|
||||||
import com.chestnut.common.async.AsyncTaskManager;
|
|
||||||
import com.chestnut.common.staticize.StaticizeService;
|
|
||||||
import com.chestnut.common.staticize.core.TemplateContext;
|
|
||||||
import com.chestnut.common.utils.IdUtils;
|
|
||||||
import com.chestnut.common.utils.StringUtils;
|
|
||||||
import com.chestnut.contentcore.domain.CmsSite;
|
|
||||||
import com.chestnut.contentcore.publish.IStaticizeType;
|
|
||||||
import com.chestnut.contentcore.service.IPublishPipeService;
|
|
||||||
import com.chestnut.contentcore.service.ISiteService;
|
|
||||||
import com.chestnut.contentcore.service.ITemplateService;
|
|
||||||
import com.chestnut.contentcore.template.ITemplateType;
|
|
||||||
import com.chestnut.contentcore.template.impl.SiteTemplateType;
|
|
||||||
import com.chestnut.contentcore.util.SiteUtils;
|
|
||||||
import com.chestnut.contentcore.util.TemplateUtils;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SiteStaticizeType
|
|
||||||
*
|
|
||||||
* @author 兮玥
|
|
||||||
* @email 190785909@qq.com
|
|
||||||
*/
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
@Component(IStaticizeType.BEAN_PREFIX + SiteStaticizeType.TYPE)
|
|
||||||
public class SiteStaticizeType implements IStaticizeType {
|
|
||||||
|
|
||||||
public static final String TYPE = "site";
|
|
||||||
|
|
||||||
private final ISiteService siteService;
|
|
||||||
|
|
||||||
private final IPublishPipeService publishPipeService;
|
|
||||||
|
|
||||||
private final ITemplateService templateService;
|
|
||||||
|
|
||||||
private final StaticizeService staticizeService;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getType() {
|
|
||||||
return TYPE;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void staticize(String dataId) {
|
|
||||||
Long siteId = Long.valueOf(dataId);
|
|
||||||
if (IdUtils.validate(siteId)) {
|
|
||||||
CmsSite site = this.siteService.getSite(siteId);
|
|
||||||
if (Objects.nonNull(site)) {
|
|
||||||
this.siteStaticize(site);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void siteStaticize(CmsSite site) {
|
|
||||||
this.publishPipeService.getPublishPipes(site.getSiteId())
|
|
||||||
.forEach(pp -> doSiteStaticize(site, pp.getCode()));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void doSiteStaticize(CmsSite site, String publishPipeCode) {
|
|
||||||
try {
|
|
||||||
AsyncTaskManager
|
|
||||||
.setTaskMessage(StringUtils.messageFormat("[{0}]正在发布站点首页:{1}", publishPipeCode, site.getName()));
|
|
||||||
|
|
||||||
String indexTemplate = site.getIndexTemplate(publishPipeCode);
|
|
||||||
File templateFile = this.templateService.findTemplateFile(site, indexTemplate, publishPipeCode);
|
|
||||||
if (Objects.isNull(templateFile)) {
|
|
||||||
logger.warn(AsyncTaskManager.addErrMessage(StringUtils.messageFormat("[{0}]站点首页模板未配置或不存在:{1}",
|
|
||||||
publishPipeCode, site.getSiteId() + "#" + site.getName())));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 模板ID = 通道:站点目录:模板文件名
|
|
||||||
String templateKey = SiteUtils.getTemplateKey(site, publishPipeCode, indexTemplate);
|
|
||||||
TemplateContext context = new TemplateContext(templateKey, false, publishPipeCode);
|
|
||||||
// init template datamode
|
|
||||||
TemplateUtils.initGlobalVariables(site, context);
|
|
||||||
// init templateType data to datamode
|
|
||||||
ITemplateType templateType = templateService.getTemplateType(SiteTemplateType.TypeId);
|
|
||||||
templateType.initTemplateData(site.getSiteId(), context);
|
|
||||||
|
|
||||||
long s = System.currentTimeMillis();
|
|
||||||
context.setDirectory(SiteUtils.getSiteRoot(site, publishPipeCode));
|
|
||||||
context.setFirstFileName("index" + StringUtils.DOT + site.getStaticSuffix(publishPipeCode));
|
|
||||||
this.staticizeService.process(context);
|
|
||||||
logger.debug("[{}]首页模板解析:{},耗时:{}ms", publishPipeCode, site.getName(), (System.currentTimeMillis() - s));
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.error(AsyncTaskManager.addErrMessage(StringUtils.messageFormat("[{0}][{1}]站点首页解析失败:{2}",
|
|
||||||
publishPipeCode, site.getName(), e.getMessage())), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,80 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2022-2024 兮玥(190785909@qq.com)
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package com.chestnut.contentcore.publish.strategies;
|
|
||||||
|
|
||||||
import com.chestnut.contentcore.publish.CmsStaticizeService;
|
|
||||||
import com.chestnut.contentcore.publish.IStaticizeType;
|
|
||||||
import com.chestnut.contentcore.publish.strategies.RedisStreamPublishStrategy;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.Setter;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.apache.commons.collections4.MapUtils;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.data.redis.connection.stream.Consumer;
|
|
||||||
import org.springframework.data.redis.connection.stream.MapRecord;
|
|
||||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
|
||||||
import org.springframework.data.redis.stream.StreamListener;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 发布任务消费监听
|
|
||||||
*
|
|
||||||
* @author 兮玥
|
|
||||||
* @email 190785909@qq.com
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class PublishTaskReceiver implements StreamListener<String, MapRecord<String, String, String>> {
|
|
||||||
|
|
||||||
private final static Logger logger = LoggerFactory.getLogger("publish");
|
|
||||||
|
|
||||||
private final CmsStaticizeService cmsStaticizeService;
|
|
||||||
|
|
||||||
private final StringRedisTemplate redisTemplate;
|
|
||||||
|
|
||||||
@Setter
|
|
||||||
@Getter
|
|
||||||
private Consumer consumer;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onMessage(MapRecord<String, String, String> message) {
|
|
||||||
String stream = message.getStream();
|
|
||||||
if (Objects.nonNull(stream)) {
|
|
||||||
try {
|
|
||||||
Map<String, String> map = message.getValue();
|
|
||||||
String type = MapUtils.getString(map, "type");
|
|
||||||
|
|
||||||
IStaticizeType staticizeType = cmsStaticizeService.getStaticizeType(type);
|
|
||||||
if (Objects.nonNull(staticizeType)) {
|
|
||||||
staticizeType.staticize(map.get("id"));
|
|
||||||
}
|
|
||||||
} catch(Exception e) {
|
|
||||||
logger.error("Publish err.", e);
|
|
||||||
} finally {
|
|
||||||
redisTemplate.opsForStream().acknowledge(
|
|
||||||
stream,
|
|
||||||
RedisStreamPublishStrategy.PublishConsumerGroup,
|
|
||||||
message.getId().getValue()
|
|
||||||
);
|
|
||||||
redisTemplate.opsForStream().delete(stream, message.getId().getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,114 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2022-2024 兮玥(190785909@qq.com)
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package com.chestnut.contentcore.publish.strategies;
|
|
||||||
|
|
||||||
import com.chestnut.common.async.AsyncTask;
|
|
||||||
import com.chestnut.contentcore.config.properties.CMSPublishProperties;
|
|
||||||
import com.chestnut.contentcore.publish.CmsStaticizeService;
|
|
||||||
import com.chestnut.contentcore.publish.IPublishStrategy;
|
|
||||||
import com.chestnut.contentcore.publish.IStaticizeType;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.boot.CommandLineRunner;
|
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
|
||||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
|
||||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
|
|
||||||
import org.springframework.scheduling.support.PeriodicTrigger;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import java.time.Duration;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 发布策略:Redis Set
|
|
||||||
*
|
|
||||||
* @author 兮玥
|
|
||||||
* @email 190785909@qq.com
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
@ConditionalOnProperty(prefix = CMSPublishProperties.PREFIX, name = "strategy", havingValue = RedisSetPublishStrategy.ID)
|
|
||||||
public class RedisSetPublishStrategy implements IPublishStrategy, CommandLineRunner {
|
|
||||||
|
|
||||||
public static final String ID = "RedisSet";
|
|
||||||
|
|
||||||
static final String CACHE_NAME = "cms:publish:list";
|
|
||||||
|
|
||||||
private final StringRedisTemplate redisTemplate;
|
|
||||||
|
|
||||||
private final CMSPublishProperties properties;
|
|
||||||
|
|
||||||
private final CmsStaticizeService cmsStaticizeService;
|
|
||||||
|
|
||||||
private final ThreadPoolTaskScheduler threadPoolTaskScheduler;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getId() {
|
|
||||||
return ID;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void publish(String dataType, String dataId) {
|
|
||||||
redisTemplate.opsForSet().add(CACHE_NAME, dataType+"-"+dataId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getTaskCount() {
|
|
||||||
Long size = redisTemplate.opsForSet().size(CACHE_NAME);
|
|
||||||
return Objects.requireNonNullElse(size, 0L);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void cleanTasks() {
|
|
||||||
redisTemplate.opsForSet().remove(CACHE_NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run(String... args) throws Exception {
|
|
||||||
for (int i = 1; i <= properties.getConsumerCount(); i++) {
|
|
||||||
// 创建一个3秒间隔执行的定时任务
|
|
||||||
PeriodicTrigger periodicTrigger = new PeriodicTrigger(Duration.ofSeconds(3L));
|
|
||||||
periodicTrigger.setFixedRate(false);
|
|
||||||
|
|
||||||
AsyncTask task = new AsyncTask() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run0() {
|
|
||||||
String data = null;
|
|
||||||
do {
|
|
||||||
try {
|
|
||||||
data = redisTemplate.opsForSet().pop(CACHE_NAME);
|
|
||||||
if (Objects.nonNull(data)) {
|
|
||||||
String[] split = data.split("-");
|
|
||||||
String dataType = split[0];
|
|
||||||
String dataId = split[1];
|
|
||||||
|
|
||||||
IStaticizeType staticizeType = cmsStaticizeService.getStaticizeType(dataType);
|
|
||||||
if (Objects.nonNull(staticizeType)) {
|
|
||||||
staticizeType.staticize(dataId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
IStaticizeType.logger.error("静态化失败", e);
|
|
||||||
}
|
|
||||||
} while(Objects.nonNull(data));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
task.setTaskId("cms-publish-" + i);
|
|
||||||
task.setType("CMS-PUBLISH");
|
|
||||||
threadPoolTaskScheduler.schedule(task, periodicTrigger);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,135 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2022-2024 兮玥(190785909@qq.com)
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package com.chestnut.contentcore.publish.strategies;
|
|
||||||
|
|
||||||
import com.chestnut.contentcore.config.properties.CMSPublishProperties;
|
|
||||||
import com.chestnut.contentcore.publish.CmsStaticizeService;
|
|
||||||
import com.chestnut.contentcore.publish.IPublishStrategy;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.data.redis.connection.stream.*;
|
|
||||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
|
||||||
import org.springframework.data.redis.stream.StreamMessageListenerContainer;
|
|
||||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import java.time.Duration;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 发布策略:Redis Stream
|
|
||||||
*
|
|
||||||
* @author 兮玥
|
|
||||||
* @email 190785909@qq.com
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
@Component
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
@ConditionalOnProperty(prefix = CMSPublishProperties.PREFIX, name = "strategy", havingValue = RedisStreamPublishStrategy.ID)
|
|
||||||
public class RedisStreamPublishStrategy implements IPublishStrategy {
|
|
||||||
|
|
||||||
public static final String ID = "RedisStream";
|
|
||||||
|
|
||||||
public static final String PublishStreamName = "ChestnutCMSPublishStream";
|
|
||||||
|
|
||||||
public static final String PublishConsumerGroup = "ChestnutCMSPublishConsumerGroup";
|
|
||||||
|
|
||||||
private final CMSPublishProperties properties;
|
|
||||||
|
|
||||||
private final StringRedisTemplate redisTemplate;
|
|
||||||
|
|
||||||
private final CmsStaticizeService cmsStaticizeService;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getId() {
|
|
||||||
return ID;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void publish(String dataType, String dataId) {
|
|
||||||
MapRecord<String, String, String> record = MapRecord.create(PublishStreamName, Map.of(
|
|
||||||
"type", dataType,
|
|
||||||
"id", dataId
|
|
||||||
));
|
|
||||||
redisTemplate.opsForStream().add(record);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getTaskCount() {
|
|
||||||
StreamInfo.XInfoStream info = redisTemplate.opsForStream().info(PublishStreamName);
|
|
||||||
return info.streamLength();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void cleanTasks() {
|
|
||||||
try {
|
|
||||||
redisTemplate.delete(PublishStreamName);
|
|
||||||
redisTemplate.opsForStream().createGroup(PublishStreamName, PublishConsumerGroup);
|
|
||||||
} catch (Exception ignored) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public StreamMessageListenerContainer<String, MapRecord<String, String, String>> streamMessageListenerContainer() {
|
|
||||||
// 启动清理消息队列数据
|
|
||||||
if (properties.isClearOnStart()) {
|
|
||||||
redisTemplate.delete(PublishStreamName);
|
|
||||||
}
|
|
||||||
// 监听容器配置
|
|
||||||
StreamMessageListenerContainer.StreamMessageListenerContainerOptions<String, MapRecord<String, String, String>> streamMessageListenerContainerOptions = StreamMessageListenerContainer.StreamMessageListenerContainerOptions
|
|
||||||
.builder()
|
|
||||||
.batchSize(10) // 一次拉取消息数量
|
|
||||||
.pollTimeout(Duration.ofSeconds(2)) // 拉取消息超时时间
|
|
||||||
.executor(cmsPublishThreadPoolTaskExecutor())
|
|
||||||
.build();
|
|
||||||
// 创建监听容器
|
|
||||||
StreamMessageListenerContainer<String, MapRecord<String, String, String>> container = StreamMessageListenerContainer
|
|
||||||
.create(redisTemplate.getRequiredConnectionFactory(), streamMessageListenerContainerOptions);
|
|
||||||
//创建消费者组
|
|
||||||
try {
|
|
||||||
redisTemplate.opsForStream().createGroup(PublishStreamName, PublishConsumerGroup);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.info("消费者组:{} 已存在", PublishConsumerGroup);
|
|
||||||
}
|
|
||||||
// 添加消费者
|
|
||||||
for (int i = 0; i < properties.getConsumerCount(); i++) {
|
|
||||||
Consumer consumer = Consumer.from(PublishConsumerGroup, "cms-publish-consumer-" + i);
|
|
||||||
PublishTaskReceiver publishTaskReceiver = new PublishTaskReceiver(cmsStaticizeService, redisTemplate);
|
|
||||||
publishTaskReceiver.setConsumer(consumer);
|
|
||||||
container.receive(consumer, StreamOffset.create(PublishStreamName, ReadOffset.lastConsumed()), publishTaskReceiver);
|
|
||||||
}
|
|
||||||
container.start();
|
|
||||||
return container;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
ThreadPoolTaskExecutor cmsPublishThreadPoolTaskExecutor() {
|
|
||||||
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
|
|
||||||
executor.setThreadNamePrefix(properties.getPool().getThreadNamePrefix());
|
|
||||||
executor.setCorePoolSize(properties.getPool().getCoreSize());
|
|
||||||
executor.setQueueCapacity(properties.getPool().getQueueCapacity());
|
|
||||||
executor.setMaxPoolSize(properties.getPool().getMaxSize());
|
|
||||||
executor.setKeepAliveSeconds((int) properties.getPool().getKeepAlive().getSeconds());
|
|
||||||
executor.setAllowCoreThreadTimeOut(this.properties.getPool().isAllowCoreThreadTimeout());
|
|
||||||
executor.setWaitForTasksToCompleteOnShutdown(properties.getShutdown().isAwaitTermination());
|
|
||||||
executor.setAwaitTerminationSeconds((int) properties.getShutdown().getAwaitTerminationPeriod().toSeconds());
|
|
||||||
log.info("Cms publish task executor initialize: {}", executor.getThreadNamePrefix());
|
|
||||||
executor.initialize();
|
|
||||||
return executor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,90 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2022-2024 兮玥(190785909@qq.com)
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package com.chestnut.contentcore.publish.strategies;
|
|
||||||
|
|
||||||
import com.chestnut.contentcore.config.properties.CMSPublishProperties;
|
|
||||||
import com.chestnut.contentcore.publish.CmsStaticizeService;
|
|
||||||
import com.chestnut.contentcore.publish.IPublishStrategy;
|
|
||||||
import com.chestnut.contentcore.publish.IStaticizeType;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.boot.CommandLineRunner;
|
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
|
||||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.concurrent.ThreadPoolExecutor;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 发布策略:ThreadPool
|
|
||||||
*
|
|
||||||
* @author 兮玥
|
|
||||||
* @email 190785909@qq.com
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
@ConditionalOnProperty(prefix = CMSPublishProperties.PREFIX, name = "strategy", havingValue = ThreadPoolPublishStrategy.ID)
|
|
||||||
public class ThreadPoolPublishStrategy implements IPublishStrategy, CommandLineRunner {
|
|
||||||
|
|
||||||
public static final String ID = "ThreadPool";
|
|
||||||
|
|
||||||
private final CMSPublishProperties properties;
|
|
||||||
|
|
||||||
private final CmsStaticizeService cmsStaticizeService;
|
|
||||||
|
|
||||||
private ThreadPoolTaskExecutor threadPoolTaskExecutor;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getId() {
|
|
||||||
return ID;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void publish(String dataType, String dataId) {
|
|
||||||
IStaticizeType staticizeType = cmsStaticizeService.getStaticizeType(dataType);
|
|
||||||
if (Objects.nonNull(staticizeType)) {
|
|
||||||
threadPoolTaskExecutor.execute(() -> staticizeType.staticize(dataId));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getTaskCount() {
|
|
||||||
// 返回线程池队列信息
|
|
||||||
return threadPoolTaskExecutor.getQueueSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void cleanTasks() {
|
|
||||||
// 清空线程池队列
|
|
||||||
threadPoolTaskExecutor.getThreadPoolExecutor().getQueue().clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run(String... args) throws Exception {
|
|
||||||
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
|
|
||||||
executor.setThreadNamePrefix(properties.getPool().getThreadNamePrefix());
|
|
||||||
executor.setCorePoolSize(properties.getPool().getCoreSize());
|
|
||||||
executor.setQueueCapacity(properties.getPool().getQueueCapacity());
|
|
||||||
executor.setMaxPoolSize(properties.getPool().getMaxSize());
|
|
||||||
executor.setKeepAliveSeconds((int) properties.getPool().getKeepAlive().getSeconds());
|
|
||||||
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); // 默认池满使用调用线程执行
|
|
||||||
executor.setAllowCoreThreadTimeOut(this.properties.getPool().isAllowCoreThreadTimeout());
|
|
||||||
executor.setWaitForTasksToCompleteOnShutdown(properties.getShutdown().isAwaitTermination());
|
|
||||||
executor.setAwaitTerminationSeconds((int) properties.getShutdown().getAwaitTerminationPeriod().toSeconds());
|
|
||||||
executor.initialize();
|
|
||||||
this.threadPoolTaskExecutor = executor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,38 +0,0 @@
|
|||||||
package com.chestnut.exmodel.domain.dto;
|
|
||||||
|
|
||||||
import com.chestnut.exmodel.CmsExtendMetaModelType;
|
|
||||||
import com.chestnut.xmodel.domain.XModelField;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
public class XModelFieldDataDTO {
|
|
||||||
|
|
||||||
private String label;
|
|
||||||
|
|
||||||
private String fieldName;
|
|
||||||
|
|
||||||
private String controlType;
|
|
||||||
|
|
||||||
private List<Map<String, Object>> validations;
|
|
||||||
|
|
||||||
private List<Map<String, String>> options;
|
|
||||||
|
|
||||||
private Object value;
|
|
||||||
|
|
||||||
private String valueSrc;
|
|
||||||
|
|
||||||
public static XModelFieldDataDTO newInstance(XModelField field, String value) {
|
|
||||||
XModelFieldDataDTO dto = new XModelFieldDataDTO();
|
|
||||||
dto.setLabel(field.getName());
|
|
||||||
dto.setFieldName(CmsExtendMetaModelType.DATA_FIELD_PREFIX + field.getCode());
|
|
||||||
dto.setControlType(field.getControlType());
|
|
||||||
dto.setValidations(field.getValidations());
|
|
||||||
dto.setValue(value);
|
|
||||||
return dto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,14 +0,0 @@
|
|||||||
package com.chestnut.cms.stat.core;
|
|
||||||
|
|
||||||
import com.chestnut.cms.stat.domain.CmsSiteVisitLog;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <TODO description class purpose>
|
|
||||||
*
|
|
||||||
* @author 兮玥
|
|
||||||
* @email 190785909@qq.com
|
|
||||||
*/
|
|
||||||
public interface CmsStat {
|
|
||||||
|
|
||||||
void deal(CmsSiteVisitLog log);
|
|
||||||
}
|
|
||||||
@ -1,25 +0,0 @@
|
|||||||
package com.chestnut.cms.stat.core.impl;
|
|
||||||
|
|
||||||
import com.chestnut.cms.stat.core.CmsStat;
|
|
||||||
import com.chestnut.cms.stat.domain.CmsSiteVisitLog;
|
|
||||||
import com.chestnut.contentcore.service.impl.ContentDynamicDataService;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 内容动态浏览量统计
|
|
||||||
*
|
|
||||||
* @author 兮玥
|
|
||||||
* @email 190785909@qq.com
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class CmsContentViewStat implements CmsStat {
|
|
||||||
|
|
||||||
private final ContentDynamicDataService contentDynamicDataService;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void deal(final CmsSiteVisitLog log) {
|
|
||||||
this.contentDynamicDataService.increaseViewCount(log.getContentId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,32 +0,0 @@
|
|||||||
package com.chestnut.common.async;
|
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
|
|
||||||
import org.apache.commons.lang3.ArrayUtils;
|
|
||||||
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
|
|
||||||
|
|
||||||
import com.chestnut.common.async.enums.TaskStatus;
|
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 异步任务异常处理器
|
|
||||||
*
|
|
||||||
* @author 兮玥
|
|
||||||
* @email 190785909@qq.com
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
public class AsyncTaskExceptionHandler implements AsyncUncaughtExceptionHandler {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void handleUncaughtException(Throwable ex, Method method, Object... params) {
|
|
||||||
if (ArrayUtils.isNotEmpty(params) && params[0] instanceof AsyncTask task) {
|
|
||||||
task.setStatus(TaskStatus.FAILED);
|
|
||||||
task.setEndTime(LocalDateTime.now());
|
|
||||||
task.addErrorMessage(ex.getMessage());
|
|
||||||
AsyncTaskManager.setTaskMessage("Async task failed:" + ex.getMessage());
|
|
||||||
log.error("Async task failed:{}", ex.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,21 +0,0 @@
|
|||||||
package com.chestnut.stat;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 统计类型
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* 每一个统计类型对应一种统计数据的存储及展示,前端根据统计类型进行分类展示
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @author 兮玥
|
|
||||||
* @email 190785909@qq.com
|
|
||||||
*/
|
|
||||||
public interface IStatType {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 统计菜单树
|
|
||||||
*/
|
|
||||||
public List<StatMenu> getStatMenus();
|
|
||||||
}
|
|
||||||
@ -1,86 +0,0 @@
|
|||||||
package com.chestnut.stat;
|
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
|
|
||||||
import com.chestnut.common.utils.IP2RegionUtils;
|
|
||||||
import com.chestnut.common.utils.ServletUtils;
|
|
||||||
import com.chestnut.common.utils.StringUtils;
|
|
||||||
|
|
||||||
import eu.bitwalker.useragentutils.UserAgent;
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
public class RequestEvent {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 请求域
|
|
||||||
*/
|
|
||||||
private String host;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* IP地址
|
|
||||||
*/
|
|
||||||
private String ip;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* IP所属地区
|
|
||||||
*/
|
|
||||||
private String address;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 来源地址
|
|
||||||
*/
|
|
||||||
private String referer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 浏览器类型
|
|
||||||
*/
|
|
||||||
private String browser;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* UserAgent
|
|
||||||
*/
|
|
||||||
private String userAgent;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 操作系统
|
|
||||||
*/
|
|
||||||
private String os;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设备类型
|
|
||||||
*/
|
|
||||||
private String deviceType;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 语言
|
|
||||||
*/
|
|
||||||
private String locale;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 事件发生时间
|
|
||||||
*/
|
|
||||||
private LocalDateTime evtTime;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 提取request请求信息到RequestEvent
|
|
||||||
*
|
|
||||||
* @param request
|
|
||||||
*/
|
|
||||||
public void fill(HttpServletRequest request) {
|
|
||||||
this.setHost(request.getRemoteHost());
|
|
||||||
this.setIp(ServletUtils.getIpAddr(request));
|
|
||||||
this.setAddress(IP2RegionUtils.ip2Region(this.getIp()));
|
|
||||||
this.setReferer(ServletUtils.getReferer(request));
|
|
||||||
this.setLocale(StringUtils.substringBefore(ServletUtils.getAcceptLanaguage(request), ","));
|
|
||||||
|
|
||||||
this.setUserAgent(ServletUtils.getUserAgent(request));
|
|
||||||
UserAgent ua = ServletUtils.parseUserAgent(request);
|
|
||||||
this.setBrowser(ua.getBrowser().getName());
|
|
||||||
this.setOs(ua.getOperatingSystem().getName());
|
|
||||||
this.setDeviceType(ua.getOperatingSystem().getDeviceType().getName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,11 +0,0 @@
|
|||||||
package com.chestnut.stat;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 统计菜单
|
|
||||||
*
|
|
||||||
* @author 兮玥
|
|
||||||
* @email 190785909@qq.com
|
|
||||||
*/
|
|
||||||
public record StatMenu(String menuId, String parentId, String name, int sort) {
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,42 +0,0 @@
|
|||||||
package com.chestnut.system.intercepter;
|
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
import org.springframework.http.HttpMethod;
|
|
||||||
import org.springframework.web.method.HandlerMethod;
|
|
||||||
import org.springframework.web.servlet.HandlerInterceptor;
|
|
||||||
|
|
||||||
import com.chestnut.common.security.SecurityUtils;
|
|
||||||
import com.chestnut.common.security.exception.SecurityErrorCode;
|
|
||||||
import com.chestnut.system.annotation.IgnoreDemoMode;
|
|
||||||
import com.chestnut.system.security.StpAdminUtil;
|
|
||||||
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 演示模式拦截器
|
|
||||||
*/
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class DemoModeIntercepter implements HandlerInterceptor {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
|
|
||||||
throws Exception {
|
|
||||||
String method = request.getMethod();
|
|
||||||
if (StpAdminUtil.isLogin() && SecurityUtils.isSuperAdmin(StpAdminUtil.getLoginIdAsLong())) {
|
|
||||||
return true; // 超级管理员允许操作
|
|
||||||
}
|
|
||||||
// 非Get且无忽略演示模式注解则抛出异常
|
|
||||||
if (HttpMethod.POST.matches(method) || HttpMethod.PUT.matches(method) || HttpMethod.DELETE.matches(method)) {
|
|
||||||
if (handler instanceof HandlerMethod handlerMethod) {
|
|
||||||
IgnoreDemoMode ignoreDemoMode = handlerMethod.getMethodAnnotation(IgnoreDemoMode.class);
|
|
||||||
if (Objects.isNull(ignoreDemoMode)) {
|
|
||||||
throw SecurityErrorCode.DEMO_EXCEPTION.exception();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,67 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2022-2024 兮玥(190785909@qq.com)
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package com.chestnut.system.mapper;
|
|
||||||
|
|
||||||
import org.apache.ibatis.annotations.Param;
|
|
||||||
import org.apache.ibatis.annotations.Select;
|
|
||||||
import org.apache.ibatis.annotations.Update;
|
|
||||||
|
|
||||||
public interface DataBaseMapper {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 表字段是否存在
|
|
||||||
*
|
|
||||||
* @param tableName
|
|
||||||
* @param columnName
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@Select("select count(*) from information_schema.columns where table_name = #{tableName} and column_name = #{columnName}")
|
|
||||||
public Integer isTableColumnExists(@Param("tableName") String tableName, @Param("columnName") String columnName);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 添加表字段
|
|
||||||
*
|
|
||||||
* @param tableName 表明
|
|
||||||
* @param columnName 字段名
|
|
||||||
* @param columnType 字段类型
|
|
||||||
*/
|
|
||||||
@Update("alter table #{tableName} add column #{columnName} #{columnType}")
|
|
||||||
public void addTableColumn(@Param("tableName") String tableName, @Param("columnName") String columnName,
|
|
||||||
@Param("columnType") String columnType);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 重命名表
|
|
||||||
*
|
|
||||||
* @param oldName
|
|
||||||
* @param newName
|
|
||||||
*/
|
|
||||||
@Update("alter table #{oldTableName} rename #{newTableName}")
|
|
||||||
public void renameTable(String oldTableName, String newTableName);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 清空表数据,自增清零
|
|
||||||
*
|
|
||||||
* @param tableName
|
|
||||||
*/
|
|
||||||
@Update("truncate table ${tableName}")
|
|
||||||
public void truncateTable(@Param("tableName") String tableName);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 当前数据库名
|
|
||||||
*/
|
|
||||||
@Select("select database()")
|
|
||||||
public void getDatabaseName();
|
|
||||||
}
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 62 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 54 KiB |
Loading…
x
Reference in New Issue
Block a user