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