diff --git a/Jenkinsfile b/Jenkinsfile index c8e18251..3fb8f75a 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -121,20 +121,17 @@ pipeline { dir('./ChestnutCMS') { withCredentials([usernamePassword(credentialsId: 'ALIYUN-DOCKER-REGISTRY-LWY', passwordVariable: 'DOCKERPWD', usernameVariable: 'DOCKERUSER')]) { sh ''' - cp -f bin/docker-deploy.sh ${APP_PATH} - + cp -f bin/docker-deploy.sh ${APP_PATH}/docker-deploy.sh + cp -f docker/docker-compose_${DEPLOY_ENV}.yml ${APP_PATH}/docker-compose.yml + cd ${APP_PATH} - cp -f ../bin/docker-deploy.sh docker-deploy.sh - sed -i "s/{{DOCKERUSER}}/${DOCKERUSER}/g" docker-deploy.sh sed -i "s/{{DOCKERPWD}}/${DOCKERPWD}/g" docker-deploy.sh sed -i "s/{{DOCKER_HUB_URL}}/${DOCKER_HUB_URL}/g" docker-deploy.sh sed -i "s/{{IMAGE_REPOSITORY}}/${DOCKER_HUB_WORKSPACE}\\/${APP_NAME}/g" docker-deploy.sh sed -i "s/{{IMAGE_TAG}}/${IMAGE_TAG}/g" docker-deploy.sh - - cp -f docker/docker-compose_${DEPLOY_ENV}.yml docker-compose.yml - + sed -i "s/{{DOCKER_IMAGE}}/${DOCKER_HUB_URL}\\/${DOCKER_HUB_WORKSPACE}\\/${APP_NAME}:${IMAGE_TAG}/g" docker-compose.yml ''' sshPublisher(publishers: [sshPublisherDesc(configName: 'GameCluster', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: ''' @@ -203,7 +200,6 @@ pipeline { usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: true)]) sh 'rm -f ui.zip' } - } } } diff --git a/README.md b/README.md index a631abdd..3f6a0893 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# ChestnutCMS v1.5.7 +# ChestnutCMS v1.5.8 ### 系统简介 diff --git a/chestnut-admin/pom.xml b/chestnut-admin/pom.xml index be056458..2afdcd2f 100644 --- a/chestnut-admin/pom.xml +++ b/chestnut-admin/pom.xml @@ -3,7 +3,7 @@ chestnut com.chestnut - 1.5.7 + 1.5.8 4.0.0 jar diff --git a/chestnut-admin/src/main/resources/application-dev.yml b/chestnut-admin/src/main/resources/application-dev.yml index 61647c3e..6da0a7a0 100644 --- a/chestnut-admin/src/main/resources/application-dev.yml +++ b/chestnut-admin/src/main/resources/application-dev.yml @@ -5,7 +5,7 @@ chestnut: # 代号 alias: ChestnutCMS # 版本 - version: 1.5.7 + version: 1.5.8 # 版权年份 copyrightYear: 2022-2025 system: @@ -15,6 +15,8 @@ chestnut: uploadPath: 'E:/dev/workspace_chestnut/uploadPath' member: uploadPath: 'E:/dev/workspace_chestnut/_xy_member/' + image: + type: 'JDK' cms: publish: strategy: ThreadPool @@ -24,7 +26,7 @@ chestnut: # 开发环境配置 server: - # 服务器的HTTP端口,默认为8080 + # 服务器的HTTP端口,默认为9080 port: 9080 # 开启优雅停机 shutdown: graceful diff --git a/chestnut-admin/src/main/resources/application-prod.yml b/chestnut-admin/src/main/resources/application-prod.yml index cf05a101..50af0c03 100644 --- a/chestnut-admin/src/main/resources/application-prod.yml +++ b/chestnut-admin/src/main/resources/application-prod.yml @@ -5,7 +5,7 @@ chestnut: # 代号 alias: ChestnutCMS # 版本 - version: 1.5.7 + version: 1.5.8 # 版权年份 copyrightYear: 2022-2025 system: @@ -15,6 +15,8 @@ chestnut: uploadPath: /home/app/uploadPath freemarker: templateLoaderPath: /home/app/statics + image: + type: 'JDK' cms: resourceRoot: /home/app/wwwroot_release publish: diff --git a/chestnut-admin/src/main/resources/application-test.yml b/chestnut-admin/src/main/resources/application-test.yml index 88bf7f93..7312687c 100644 --- a/chestnut-admin/src/main/resources/application-test.yml +++ b/chestnut-admin/src/main/resources/application-test.yml @@ -5,7 +5,7 @@ chestnut: # 代号 alias: ChestnutCMS # 版本 - version: 1.5.7 + version: 1.5.8 # 版权年份 copyrightYear: 2022-2025 system: @@ -13,12 +13,17 @@ chestnut: demoMode: true # 文件路径 示例( Windows配置D:/chestnut/uploadPath,Linux配置 /home/app/uploadPath) uploadPath: /home/app/uploadPath - # 验证码类型 math 数组计算 char 字符验证 - captchaType: math freemarker: templateLoaderPath: /home/app/statics + image: + type: 'JDK' cms: resourceRoot: /home/app/wwwroot_release + publish: + strategy: ThreadPool + pool: + threadNamePrefix: "CMS-PUBLISH-" + queueCapacity: 10000 # 开发环境配置 server: diff --git a/chestnut-cms/chestnut-cms-advertisement/pom.xml b/chestnut-cms/chestnut-cms-advertisement/pom.xml index ad5766ba..50f8f229 100644 --- a/chestnut-cms/chestnut-cms-advertisement/pom.xml +++ b/chestnut-cms/chestnut-cms-advertisement/pom.xml @@ -7,7 +7,7 @@ com.chestnut chestnut-cms - 1.5.7 + 1.5.8 chestnut-cms-advertisement diff --git a/chestnut-cms/chestnut-cms-advertisement/src/main/java/com/chestnut/advertisement/listener/AdvertisementListener.java b/chestnut-cms/chestnut-cms-advertisement/src/main/java/com/chestnut/advertisement/listener/AdvertisementListener.java index d688fbfe..1aaa8815 100644 --- a/chestnut-cms/chestnut-cms-advertisement/src/main/java/com/chestnut/advertisement/listener/AdvertisementListener.java +++ b/chestnut-cms/chestnut-cms-advertisement/src/main/java/com/chestnut/advertisement/listener/AdvertisementListener.java @@ -16,6 +16,7 @@ package com.chestnut.advertisement.listener; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.chestnut.advertisement.domain.CmsAdvertisement; import com.chestnut.advertisement.service.IAdvertisementService; import com.chestnut.common.async.AsyncTaskManager; @@ -26,6 +27,8 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; +import java.util.List; + @Slf4j @Component @RequiredArgsConstructor @@ -41,10 +44,21 @@ public class AdvertisementListener { try { long total = this.advertisementService .count(new LambdaQueryWrapper().eq(CmsAdvertisement::getSiteId, site.getSiteId())); + long lastId = 0; for (long i = 0; i * pageSize < total; i++) { AsyncTaskManager.setTaskProgressInfo((int) (i * pageSize * 100 / total), "正在删除广告数据:" + (i * pageSize) + "/" + total); - this.advertisementService.remove(new LambdaQueryWrapper() - .eq(CmsAdvertisement::getSiteId, site.getSiteId()).last("limit " + pageSize)); + Page advertisements = this.advertisementService.lambdaQuery() + .select(CmsAdvertisement::getAdvertisementId) + .eq(CmsAdvertisement::getSiteId, site.getSiteId()) + .gt(CmsAdvertisement::getAdvertisementId, lastId) + .orderByAsc(CmsAdvertisement::getAdvertisementId) + .page(Page.of(1, pageSize, false)); + if (!advertisements.getRecords().isEmpty()) { + List advertisementIds = advertisements.getRecords().stream() + .map(CmsAdvertisement::getAdvertisementId).toList(); + this.advertisementService.removeBatchByIds(advertisementIds); + lastId = advertisementIds.get(advertisementIds.size() - 1); + } } } catch (Exception e) { AsyncTaskManager.addErrMessage("删除广告数据错误:" + e.getMessage()); diff --git a/chestnut-cms/chestnut-cms-advertisement/src/main/resources/i18n/messages_zh_TW.properties b/chestnut-cms/chestnut-cms-advertisement/src/main/resources/i18n/messages_zh_TW.properties index 405aaf24..ec8f0444 100644 --- a/chestnut-cms/chestnut-cms-advertisement/src/main/resources/i18n/messages_zh_TW.properties +++ b/chestnut-cms/chestnut-cms-advertisement/src/main/resources/i18n/messages_zh_TW.properties @@ -8,9 +8,9 @@ ADVERTISEMENT.TYPE.image=圖片 FREEMARKER.TAG.cms_advertisement.NAME=廣告列表標籤 FREEMARKER.TAG.cms_advertisement.DESC=獲取廣告數據列表,內嵌`<#list DataList as ad>${ad.name}`遍曆數據 FREEMARKER.TAG.cms_advertisement.code=廣告位編碼 -FREEMARKER.TAG.cms_advertisement.type=廣告鏈接類型 -FREEMARKER.TAG.cms_advertisement.type.None=原始鏈接 -FREEMARKER.TAG.cms_advertisement.type.Stat=統計鏈接 +FREEMARKER.TAG.cms_advertisement.type=廣告連結類型 +FREEMARKER.TAG.cms_advertisement.type.None=原始連結 +FREEMARKER.TAG.cms_advertisement.type.Stat=統計連結 # 統計菜單 STAT.MENU.CmsAdv=廣告數據統計 @@ -23,7 +23,7 @@ SCHEDULED_TASK.AdvertisementStatJob=廣告統計任務 SCHEDULED_TASK.AdvertisementPublishJob=廣告定時發布下線任務 MONITORED.CACHE.AD_ID2NAME=廣告名稱 -MONITORED.CACHE.AD_ID2URL=廣告跳轉鏈接 +MONITORED.CACHE.AD_ID2URL=廣告跳轉連結 CMS.AD.ID=廣告ID CMS.AD.SPACE_ID=所屬廣告版位(頁面部件)ID @@ -34,7 +34,7 @@ CMS.AD.KEYWORDS=關鍵詞 CMS.AD.STATE=狀態 CMS.AD.ONLINE_DATE=上線時間 CMS.AD.OFFLINE_DATE=下線時間 -CMS.AD.REDIRECT_URL=原始跳轉鏈接 -CMS.AD.LINK=實際跳轉鏈接(可設置為中轉地址) -CMS.AD.RESOURCE_PATH=廣告素材资源路徑 -CMS.AD.RESOURCE_SRC=廣告素材訪問鏈接 +CMS.AD.REDIRECT_URL=原始跳轉連結 +CMS.AD.LINK=實際跳轉連結(可設置為中轉地址) +CMS.AD.RESOURCE_PATH=廣告素材資源路徑 +CMS.AD.RESOURCE_SRC=廣告素材訪問地址 diff --git a/chestnut-cms/chestnut-cms-article/pom.xml b/chestnut-cms/chestnut-cms-article/pom.xml index 34dd1d61..c8195829 100644 --- a/chestnut-cms/chestnut-cms-article/pom.xml +++ b/chestnut-cms/chestnut-cms-article/pom.xml @@ -7,7 +7,7 @@ com.chestnut chestnut-cms - 1.5.7 + 1.5.8 chestnut-cms-article diff --git a/chestnut-cms/chestnut-cms-article/src/main/java/com/chestnut/article/controller/front/ArticleApiController.java b/chestnut-cms/chestnut-cms-article/src/main/java/com/chestnut/article/controller/front/ArticleApiController.java index 24015a4d..b5091320 100644 --- a/chestnut-cms/chestnut-cms-article/src/main/java/com/chestnut/article/controller/front/ArticleApiController.java +++ b/chestnut-cms/chestnut-cms-article/src/main/java/com/chestnut/article/controller/front/ArticleApiController.java @@ -1,139 +1,139 @@ -/* - * Copyright 2022-2025 兮玥(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.article.controller.front; - -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.chestnut.article.domain.CmsArticleDetail; -import com.chestnut.article.domain.vo.ArticleApiVO; -import com.chestnut.article.service.IArticleService; -import com.chestnut.common.domain.R; -import com.chestnut.common.security.web.BaseRestController; -import com.chestnut.common.utils.IdUtils; -import com.chestnut.common.utils.StringUtils; -import com.chestnut.contentcore.domain.CmsCatalog; -import com.chestnut.contentcore.domain.CmsContent; -import com.chestnut.contentcore.fixed.dict.ContentAttribute; -import com.chestnut.contentcore.fixed.dict.ContentStatus; -import com.chestnut.contentcore.service.ICatalogService; -import com.chestnut.contentcore.service.IContentService; -import com.chestnut.contentcore.template.tag.CmsCatalogTag; -import com.chestnut.contentcore.template.tag.CmsContentTag; -import com.chestnut.contentcore.util.CatalogUtils; -import com.chestnut.contentcore.util.InternalUrlUtils; -import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -import java.util.*; -import java.util.stream.Collectors; - -/** - * 内容数据API接口 - * - * @author 兮玥 - * @email 190785909@qq.com - */ -@RestController -@RequiredArgsConstructor -@RequestMapping("/api/cms/article") -public class ArticleApiController extends BaseRestController { - - private final ICatalogService catalogService; - - private final IContentService contentService; - - private final IArticleService articleService; - - @GetMapping("/list") - public R> getContentList( - @RequestParam("sid") Long siteId, - @RequestParam(value = "cid", required = false, defaultValue = "0") Long catalogId, - @RequestParam(value = "lv", required = false, defaultValue = "Root") String level, - @RequestParam(value = "attrs", required = false) String hasAttributes, - @RequestParam(value = "no_attrs", required = false) String noAttributes, - @RequestParam(value = "st", required = false, defaultValue = "Recent") String sortType, - @RequestParam(value = "ps", required = false, defaultValue = "16") Integer pageSize, - @RequestParam(value = "pn", required = false, defaultValue = "1") Long pageNumber, - @RequestParam(value = "pp") String publishPipeCode, - @RequestParam(value = "preview", required = false, defaultValue = "false") Boolean preview, - @RequestParam(value = "text", required = false, defaultValue = "false") Boolean text - ) { - if (!CmsCatalogTag.CatalogTagLevel.isRoot(level) && !IdUtils.validate(catalogId)) { - return R.fail("The parameter cid is required where lv is `Root`."); - } - LambdaQueryWrapper q = new LambdaQueryWrapper<>(); - q.eq(CmsContent::getSiteId, siteId).eq(CmsContent::getStatus, ContentStatus.PUBLISHED); - if (!CmsCatalogTag.CatalogTagLevel.isRoot(level)) { - CmsCatalog catalog = this.catalogService.getCatalog(catalogId); - if (Objects.isNull(catalog)) { - return R.fail("Catalog not found: " + catalogId); - } - if (CmsCatalogTag.CatalogTagLevel.isCurrent(level)) { - q.eq(CmsContent::getCatalogId, catalog.getCatalogId()); - } else if (CmsCatalogTag.CatalogTagLevel.isChild(level)) { - q.likeRight(CmsContent::getCatalogAncestors, catalog.getAncestors() + CatalogUtils.ANCESTORS_SPLITER); - } else if (CmsCatalogTag.CatalogTagLevel.isCurrentAndChild(level)) { - q.likeRight(CmsContent::getCatalogAncestors, catalog.getAncestors()); - } - } - if (StringUtils.isNotEmpty(hasAttributes)) { - int attrTotal = ContentAttribute.convertInt(hasAttributes.split(",")); - q.apply(attrTotal > 0, "attributes&{0}={1}", attrTotal, attrTotal); - } - if (StringUtils.isNotEmpty(noAttributes)) { - String[] contentAttrs = noAttributes.split(","); - int attrTotal = ContentAttribute.convertInt(contentAttrs); - for (String attr : contentAttrs) { - int bit = ContentAttribute.bit(attr); - q.apply(bit > 0, "attributes&{0}<>{1}", attrTotal, bit); - } - } - if (CmsContentTag.SortTagAttr.isRecent(sortType)) { - q.orderByDesc(CmsContent::getPublishDate); - } else { - q.orderByDesc(Arrays.asList(CmsContent::getTopFlag, CmsContent::getSortFlag)); - } - - Page pageResult = this.contentService.dao().page(new Page<>(pageNumber, pageSize, false), q); - if (pageResult.getRecords().isEmpty()) { - return R.ok(List.of()); - } - List contentIds = pageResult.getRecords().stream().map(CmsContent::getContentId).toList(); - Map articleDetails = new HashMap<>(); - if (text) { - articleDetails.putAll(this.articleService.dao().listByIds(contentIds) - .stream().collect(Collectors.toMap(CmsArticleDetail::getContentId, c -> c))); - } - - List list = new ArrayList<>(); - pageResult.getRecords().forEach(c -> { - ArticleApiVO vo = ArticleApiVO.newInstance(c, null); - CmsCatalog catalog = this.catalogService.getCatalog(c.getCatalogId()); - vo.setCatalogName(catalog.getName()); - vo.setCatalogLink(catalogService.getCatalogLink(catalog, 1, publishPipeCode, preview)); - vo.setLink(this.contentService.getContentLink(c, 1, publishPipeCode, preview)); - vo.setLogoSrc(InternalUrlUtils.getActualUrl(c.getLogo(), publishPipeCode, preview)); - if (text && articleDetails.containsKey(c.getContentId())) { - vo.setContentHtml(articleDetails.get(c.getContentId()).getContentHtml()); - } - list.add(vo); - }); - return R.ok(list); - } -} +/* + * Copyright 2022-2025 兮玥(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.article.controller.front; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.chestnut.article.domain.CmsArticleDetail; +import com.chestnut.article.domain.vo.ArticleApiVO; +import com.chestnut.article.service.IArticleService; +import com.chestnut.common.domain.R; +import com.chestnut.common.security.web.BaseRestController; +import com.chestnut.common.utils.IdUtils; +import com.chestnut.common.utils.StringUtils; +import com.chestnut.contentcore.domain.CmsCatalog; +import com.chestnut.contentcore.domain.CmsContent; +import com.chestnut.contentcore.fixed.dict.ContentAttribute; +import com.chestnut.contentcore.fixed.dict.ContentStatus; +import com.chestnut.contentcore.service.ICatalogService; +import com.chestnut.contentcore.service.IContentService; +import com.chestnut.contentcore.template.tag.CmsCatalogTag; +import com.chestnut.contentcore.template.tag.CmsContentTag; +import com.chestnut.contentcore.util.CatalogUtils; +import com.chestnut.contentcore.util.InternalUrlUtils; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 内容数据API接口 + * + * @author 兮玥 + * @email 190785909@qq.com + */ +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/cms/article") +public class ArticleApiController extends BaseRestController { + + private final ICatalogService catalogService; + + private final IContentService contentService; + + private final IArticleService articleService; + + @GetMapping("/list") + public R> getContentList( + @RequestParam("sid") Long siteId, + @RequestParam(value = "cid", required = false, defaultValue = "0") Long catalogId, + @RequestParam(value = "lv", required = false, defaultValue = "Root") String level, + @RequestParam(value = "attrs", required = false) String hasAttributes, + @RequestParam(value = "no_attrs", required = false) String noAttributes, + @RequestParam(value = "st", required = false, defaultValue = "Recent") String sortType, + @RequestParam(value = "ps", required = false, defaultValue = "16") Integer pageSize, + @RequestParam(value = "pn", required = false, defaultValue = "1") Long pageNumber, + @RequestParam(value = "pp") String publishPipeCode, + @RequestParam(value = "preview", required = false, defaultValue = "false") Boolean preview, + @RequestParam(value = "text", required = false, defaultValue = "false") Boolean text + ) { + if (!CmsCatalogTag.CatalogTagLevel.isRoot(level) && !IdUtils.validate(catalogId)) { + return R.fail("The parameter cid is required where lv is `Root`."); + } + LambdaQueryWrapper q = new LambdaQueryWrapper<>(); + q.eq(CmsContent::getSiteId, siteId).eq(CmsContent::getStatus, ContentStatus.PUBLISHED); + if (!CmsCatalogTag.CatalogTagLevel.isRoot(level)) { + CmsCatalog catalog = this.catalogService.getCatalog(catalogId); + if (Objects.isNull(catalog)) { + return R.fail("Catalog not found: " + catalogId); + } + if (CmsCatalogTag.CatalogTagLevel.isCurrent(level)) { + q.eq(CmsContent::getCatalogId, catalog.getCatalogId()); + } else if (CmsCatalogTag.CatalogTagLevel.isChild(level)) { + q.likeRight(CmsContent::getCatalogAncestors, catalog.getAncestors() + CatalogUtils.ANCESTORS_SPLITER); + } else if (CmsCatalogTag.CatalogTagLevel.isCurrentAndChild(level)) { + q.likeRight(CmsContent::getCatalogAncestors, catalog.getAncestors()); + } + } + if (StringUtils.isNotEmpty(hasAttributes)) { + int attrTotal = ContentAttribute.convertInt(hasAttributes.split(",")); + q.apply(attrTotal > 0, "attributes&{0}={1}", attrTotal, attrTotal); + } + if (StringUtils.isNotEmpty(noAttributes)) { + String[] contentAttrs = noAttributes.split(","); + int attrTotal = ContentAttribute.convertInt(contentAttrs); + for (String attr : contentAttrs) { + int bit = ContentAttribute.bit(attr); + q.apply(bit > 0, "attributes&{0}<>{1}", attrTotal, bit); + } + } + if (CmsContentTag.SortTagAttr.isRecent(sortType)) { + q.orderByDesc(CmsContent::getPublishDate); + } else { + q.orderByDesc(Arrays.asList(CmsContent::getTopFlag, CmsContent::getSortFlag)); + } + + Page pageResult = this.contentService.dao().page(new Page<>(pageNumber, pageSize, false), q); + if (pageResult.getRecords().isEmpty()) { + return R.ok(List.of()); + } + List contentIds = pageResult.getRecords().stream().map(CmsContent::getContentId).toList(); + Map articleDetails = new HashMap<>(); + if (text) { + articleDetails.putAll(this.articleService.dao().listByIds(contentIds) + .stream().collect(Collectors.toMap(CmsArticleDetail::getContentId, c -> c))); + } + + List list = new ArrayList<>(); + pageResult.getRecords().forEach(c -> { + ArticleApiVO vo = ArticleApiVO.newInstance(c, null); + CmsCatalog catalog = this.catalogService.getCatalog(c.getCatalogId()); + vo.setCatalogName(catalog.getName()); + vo.setCatalogLink(catalogService.getCatalogLink(catalog, 1, publishPipeCode, preview)); + vo.setLink(this.contentService.getContentLink(c, 1, publishPipeCode, preview)); + vo.setLogoSrc(InternalUrlUtils.getActualUrl(c.getLogo(), publishPipeCode, preview)); + if (text && articleDetails.containsKey(c.getContentId())) { + vo.setContentHtml(articleDetails.get(c.getContentId()).getContentHtml()); + } + list.add(vo); + }); + return R.ok(list); + } +} diff --git a/chestnut-cms/chestnut-cms-article/src/main/resources/i18n/messages_zh_TW.properties b/chestnut-cms/chestnut-cms-article/src/main/resources/i18n/messages_zh_TW.properties index 3aa5ab62..a64e96de 100644 --- a/chestnut-cms/chestnut-cms-article/src/main/resources/i18n/messages_zh_TW.properties +++ b/chestnut-cms/chestnut-cms-article/src/main/resources/i18n/messages_zh_TW.properties @@ -10,6 +10,7 @@ FREEMARKER.FUNC.dealArticleBody.DESC=文章正文處理函數,主要用來處 FREEMARKER.FUNC.dealArticleBody.Arg1.Name=文章正文內容 FREEMARKER.FUNC.dealArticleBody.Arg2.Name=文章正文格式 +# 固定字典項 ArticleBodyFormat.RichText=富文本 CMS.ARTICLE.FORMAT=文章正文格式 diff --git a/chestnut-cms/chestnut-cms-block/pom.xml b/chestnut-cms/chestnut-cms-block/pom.xml index 7ea55f72..cbedcbfa 100644 --- a/chestnut-cms/chestnut-cms-block/pom.xml +++ b/chestnut-cms/chestnut-cms-block/pom.xml @@ -7,7 +7,7 @@ com.chestnut chestnut-cms - 1.5.7 + 1.5.8 chestnut-cms-block diff --git a/chestnut-cms/chestnut-cms-comment/pom.xml b/chestnut-cms/chestnut-cms-comment/pom.xml index d2f2826a..5fd29423 100644 --- a/chestnut-cms/chestnut-cms-comment/pom.xml +++ b/chestnut-cms/chestnut-cms-comment/pom.xml @@ -6,7 +6,7 @@ com.chestnut chestnut-cms - 1.5.7 + 1.5.8 chestnut-cms-comment diff --git a/chestnut-cms/chestnut-cms-comment/src/main/resources/i18n/messages_zh_TW.properties b/chestnut-cms/chestnut-cms-comment/src/main/resources/i18n/messages_zh_TW.properties index 869d5129..44e96c65 100644 --- a/chestnut-cms/chestnut-cms-comment/src/main/resources/i18n/messages_zh_TW.properties +++ b/chestnut-cms/chestnut-cms-comment/src/main/resources/i18n/messages_zh_TW.properties @@ -7,19 +7,19 @@ FREEMARKER.TAG.cms_comment.type=來源類型 CMS.COMMENT.ID=評論ID CMS.COMMENT.UID=評論用戶ID CMS.COMMENT.PARENT_ID=父級評論ID -CMS.COMMENT.REPLY_UID=回復的用戶ID -CMS.COMMENT.REPLY_COUNT=回復數 +CMS.COMMENT.REPLY_UID=回複的用戶ID +CMS.COMMENT.REPLY_COUNT=回複數 CMS.COMMENT.SOURCE_TYPE=來源分類 CMS.COMMENT.SOURCE_ID=來源唯一標識 CMS.COMMENT.SOURCE_TITLE=來源標題 CMS.COMMENT.SOURCE_URL=來源URL CMS.COMMENT.CONTENT=評論內容 -CMS.COMMENT.LIKE_COUNT=點讚數 +CMS.COMMENT.LIKE_COUNT=點贊數 CMS.COMMENT.AUDIT_STATUS=評論審核狀態 CMS.COMMENT.COMMENT_TIME=評論提交時間 CMS.COMMENT.DEL_FLAG=刪除標識 -CMS.COMMENT.IP=用戶ID +CMS.COMMENT.IP=用戶IP CMS.COMMENT.REGION=用戶歸屬地 CMS.COMMENT.CLIENT_TYPE=客戶端類型 CMS.COMMENT.USER_AGENT=UserAgent -CMS.COMMENT.REPLY_LIST=回復列表 +CMS.COMMENT.REPLY_LIST=回複列表 diff --git a/chestnut-cms/chestnut-cms-contentcore/pom.xml b/chestnut-cms/chestnut-cms-contentcore/pom.xml index ab2b2387..59ceb4a6 100644 --- a/chestnut-cms/chestnut-cms-contentcore/pom.xml +++ b/chestnut-cms/chestnut-cms-contentcore/pom.xml @@ -7,7 +7,7 @@ com.chestnut chestnut-cms - 1.5.7 + 1.5.8 chestnut-cms-contentcore diff --git a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/cache/CatalogMonitoredCache.java b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/cache/CatalogMonitoredCache.java index 4c694e60..b613c343 100644 --- a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/cache/CatalogMonitoredCache.java +++ b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/cache/CatalogMonitoredCache.java @@ -84,8 +84,8 @@ public class CatalogMonitoredCache implements IMonitoredCache { return redisCache.getCacheObject(cacheKeyByAlias(siteId, alias), CmsCatalog.class, supplier); } - public void clear(CmsCatalog catalog) { - this.redisCache.deleteObject(cacheKeyById(catalog.getCatalogId())); - this.redisCache.deleteObject(cacheKeyByAlias(catalog.getSiteId(), catalog.getAlias())); + public void clear(Long siteId, Long catalogId, String catalogAlias) { + this.redisCache.deleteObject(cacheKeyById(catalogId)); + this.redisCache.deleteObject(cacheKeyByAlias(siteId, catalogAlias)); } } diff --git a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/controller/CatalogController.java b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/controller/CatalogController.java index 5409b05e..1b8375ad 100644 --- a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/controller/CatalogController.java +++ b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/controller/CatalogController.java @@ -28,6 +28,7 @@ import com.chestnut.common.log.annotation.Log; import com.chestnut.common.log.enums.BusinessType; import com.chestnut.common.security.anno.Priv; import com.chestnut.common.security.domain.LoginUser; +import com.chestnut.common.security.domain.Operator; import com.chestnut.common.security.web.BaseRestController; import com.chestnut.common.utils.*; import com.chestnut.contentcore.core.ICatalogType; @@ -270,7 +271,7 @@ public class CatalogController extends BaseRestController { throw ContentCoreErrorCode.CATALOG_CANNOT_PUBLISH.exception(); } AsyncTask task = this.publishService.publishCatalog(catalog, dto.getPublishChild(), dto.getPublishDetail(), - dto.getPublishStatus(), StpAdminUtil.getLoginUser()); + dto.getPublishStatus(), Operator.of(StpAdminUtil.getLoginUser())); return R.ok(task.getTaskId()); } diff --git a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/controller/ContentController.java b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/controller/ContentController.java index b738fb04..6f5d1228 100644 --- a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/controller/ContentController.java +++ b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/controller/ContentController.java @@ -25,6 +25,7 @@ import com.chestnut.common.log.annotation.Log; import com.chestnut.common.log.enums.BusinessType; import com.chestnut.common.security.anno.Priv; import com.chestnut.common.security.domain.LoginUser; +import com.chestnut.common.security.domain.Operator; import com.chestnut.common.security.web.BaseRestController; import com.chestnut.common.security.web.PageRequest; import com.chestnut.common.utils.IdUtils; @@ -171,12 +172,11 @@ public class ContentController extends BaseRestController { @PostMapping public R addContent(@RequestParam("contentType") String contentType, HttpServletRequest request) throws IOException { + LoginUser loginUser = StpAdminUtil.getLoginUser(); IContentType ct = ContentCoreUtils.getContentType(contentType); - IContent content = ct.readFrom(request.getInputStream()); - content.setOperator(StpAdminUtil.getLoginUser()); - PermissionUtils.checkPermission(CatalogPrivItem.AddContent.getPermissionKey(content.getCatalogId()), - content.getOperator()); + PermissionUtils.checkPermission(CatalogPrivItem.AddContent.getPermissionKey(content.getCatalogId()), loginUser); + content.setOperator(Operator.of(loginUser)); AsyncTask task = this.contentService.addContent(content); return R.ok(Map.of("taskId", task.getTaskId())); @@ -187,12 +187,13 @@ public class ContentController extends BaseRestController { @PutMapping public R saveContent(@RequestParam("contentType") String contentType, HttpServletRequest request) throws IOException { + LoginUser loginUser = StpAdminUtil.getLoginUser(); IContentType ct = ContentCoreUtils.getContentType(contentType); IContent content = ct.readFrom(request.getInputStream()); - content.setOperator(StpAdminUtil.getLoginUser()); + content.setOperator(Operator.of(loginUser)); PermissionUtils.checkPermission(CatalogPrivItem.EditContent.getPermissionKey(content.getCatalogId()), - content.getOperator()); + StpAdminUtil.getLoginUser()); AsyncTask task = this.contentService.saveContent(content); return R.ok(Map.of("taskId", task.getTaskId())); diff --git a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/controller/CoreController.java b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/controller/CoreController.java index 4b03a832..ff732e5d 100644 --- a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/controller/CoreController.java +++ b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/controller/CoreController.java @@ -89,13 +89,13 @@ public class CoreController extends BaseRestController { IInternalDataType internalDataType = ContentCoreUtils.getInternalDataType(dataType); Assert.notNull(internalDataType, () -> ContentCoreErrorCode.UNSUPPORTED_INTERNAL_DATA_TYPE.exception(dataType)); + IInternalDataType.RequestData data = new IInternalDataType.RequestData(dataId, pageIndex, publishPipe, + true, ServletUtils.getParamMap(ServletUtils.getRequest())); try { - IInternalDataType.RequestData data = new IInternalDataType.RequestData(dataId, pageIndex, publishPipe, - true, ServletUtils.getParamMap(ServletUtils.getRequest())); - String pageData = internalDataType.getPageData(data); - response.getWriter().write(pageData); + internalDataType.processPageData(data, response.getWriter()); } catch (Exception e) { - response.getWriter().write(e.getMessage()); + // Ignore + e.printStackTrace(response.getWriter()); } } diff --git a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/controller/ResourceController.java b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/controller/ResourceController.java index e17fcf14..93509872 100644 --- a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/controller/ResourceController.java +++ b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/controller/ResourceController.java @@ -32,6 +32,7 @@ import com.chestnut.common.utils.ServletUtils; import com.chestnut.common.utils.StringUtils; import com.chestnut.contentcore.core.IResourceType; import com.chestnut.contentcore.core.impl.InternalDataType_Resource; +import com.chestnut.contentcore.core.impl.ResourceType_Image; import com.chestnut.contentcore.domain.CmsResource; import com.chestnut.contentcore.domain.CmsSite; import com.chestnut.contentcore.domain.dto.ResourceUploadDTO; @@ -118,7 +119,11 @@ public class ResourceController extends BaseRestController { if (r.getPath().startsWith("http://") || r.getPath().startsWith("https://")) { r.setSrc(r.getPath()); } else { - resourceService.dealDefaultThumbnail(site, r.getInternalUrl(), r::setSrc); + if (ResourceType_Image.isImage(r.getResourceType())) { + resourceService.dealDefaultThumbnail(site, r.getInternalUrl(), r::setSrc); + } else { + r.setSrc(InternalUrlUtils.getActualPreviewUrl(r.getInternalUrl())); + } } }); } @@ -192,7 +197,7 @@ public class ResourceController extends BaseRestController { return R.ok(resource); } - @GetMapping("/downlad/{resourceId}") + @GetMapping("/download/{resourceId}") public void downloadResourceFile(@PathVariable @LongId Long resourceId, HttpServletResponse response) { CmsResource resource = this.resourceService.getById(resourceId); Assert.notNull(resource, () -> CommonErrorCode.DATA_NOT_FOUND_BY_ID.exception("resourceId", resourceId)); diff --git a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/controller/SiteController.java b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/controller/SiteController.java index 9ded1867..53f34ac0 100644 --- a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/controller/SiteController.java +++ b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/controller/SiteController.java @@ -26,6 +26,7 @@ import com.chestnut.common.log.annotation.Log; import com.chestnut.common.log.enums.BusinessType; import com.chestnut.common.security.anno.Priv; import com.chestnut.common.security.domain.LoginUser; +import com.chestnut.common.security.domain.Operator; import com.chestnut.common.security.web.BaseRestController; import com.chestnut.common.security.web.PageRequest; import com.chestnut.common.utils.Assert; @@ -257,7 +258,7 @@ public class SiteController extends BaseRestController { Assert.notNull(site, () -> CommonErrorCode.DATA_NOT_FOUND_BY_ID.exception("siteId", dto.getSiteId())); if (!dto.isPublishIndex()) { - AsyncTask task = publishService.publishAll(site, dto.getContentStatus(), StpAdminUtil.getLoginUser()); + AsyncTask task = publishService.publishAll(site, dto.getContentStatus(), Operator.of(StpAdminUtil.getLoginUser())); return R.ok(task.getTaskId()); } publishService.publishSiteIndex(site); diff --git a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/controller/TemplateController.java b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/controller/TemplateController.java index 99a24cf2..946ba025 100644 --- a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/controller/TemplateController.java +++ b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/controller/TemplateController.java @@ -29,6 +29,7 @@ import com.chestnut.common.security.web.PageRequest; import com.chestnut.common.staticize.StaticizeService; import com.chestnut.common.utils.*; import com.chestnut.common.utils.file.FileExUtils; +import com.chestnut.common.validation.RegexConsts; import com.chestnut.contentcore.domain.CmsSite; import com.chestnut.contentcore.domain.CmsTemplate; import com.chestnut.contentcore.domain.dto.TemplateAddDTO; @@ -182,7 +183,7 @@ public class TemplateController extends BaseRestController { fileName = FileExUtils.normalizePath(fileName); String[] split = fileName.substring(0, fileName.indexOf(suffix)).split("/"); for (String item : split) { - if (StringUtils.isEmpty(item) || !Pattern.matches("^[a-zA-Z0-9_]+$", item)) { + if (StringUtils.isEmpty(item) || !Pattern.matches(RegexConsts.REGEX_CODE, item)) { return false; } } diff --git a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/core/AbstractContent.java b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/core/AbstractContent.java index 584269e1..ab637c41 100644 --- a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/core/AbstractContent.java +++ b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/core/AbstractContent.java @@ -16,8 +16,9 @@ package com.chestnut.contentcore.core; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.chestnut.common.exception.CommonErrorCode; -import com.chestnut.common.security.domain.LoginUser; +import com.chestnut.common.security.domain.Operator; import com.chestnut.common.utils.*; import com.chestnut.contentcore.domain.CmsCatalog; import com.chestnut.contentcore.domain.CmsContent; @@ -30,7 +31,6 @@ import com.chestnut.contentcore.listener.event.AfterContentSaveEvent; import com.chestnut.contentcore.listener.event.BeforeContentSaveEvent; import com.chestnut.contentcore.listener.event.OnContentCopyEvent; import com.chestnut.contentcore.listener.event.OnContentMoveEvent; -import com.chestnut.contentcore.perms.CatalogPermissionType; import com.chestnut.contentcore.properties.PublishedContentEditProperty; import com.chestnut.contentcore.service.ICatalogService; import com.chestnut.contentcore.service.IContentService; @@ -40,7 +40,6 @@ import com.chestnut.contentcore.util.ContentCoreUtils; import com.chestnut.contentcore.util.ContentLogUtils; import com.chestnut.contentcore.util.InternalUrlUtils; import com.chestnut.system.fixed.dict.YesOrNo; -import com.chestnut.system.permission.PermissionUtils; import lombok.Setter; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.MapUtils; @@ -73,7 +72,7 @@ public abstract class AbstractContent implements IContent { @Setter private Map params; - private LoginUser operator; + private Operator operator; @Override public CmsSite getSite() { @@ -122,12 +121,12 @@ public abstract class AbstractContent implements IContent { } @Override - public LoginUser getOperator() { + public Operator getOperator() { return this.operator; } @Override - public void setOperator(LoginUser operator) { + public void setOperator(Operator operator) { this.operator = operator; } @@ -274,9 +273,6 @@ public abstract class AbstractContent implements IContent { this.getContentEntity().getTitle())) { throw ContentCoreErrorCode.TITLE_REPLEAT.exception(); } - // 校验权限 - PermissionUtils.checkPermission(CatalogPermissionType.CatalogPrivItem.AddContent.getPermissionKey(toCatalog.getCatalogId()), this.getOperator()); - CmsContent newContent = new CmsContent(); BeanUtils.copyProperties(this.getContentEntity(), newContent, "contentId", "template", "staticPath", "topFlag", "topDate", "isLock", "lockUser"); @@ -316,8 +312,6 @@ public abstract class AbstractContent implements IContent { this.getContentEntity().getTitle())) { throw ContentCoreErrorCode.TITLE_REPLEAT.exception(); } - // 校验权限 - PermissionUtils.checkPermission(CatalogPermissionType.CatalogPrivItem.AddContent.getPermissionKey(toCatalog.getCatalogId()), this.getOperator()); CmsCatalog fromCatalog = this.getCatalogService().getCatalog(content.getCatalogId()); // 重置内容信息 @@ -377,12 +371,12 @@ public abstract class AbstractContent implements IContent { } LambdaQueryWrapper q = new LambdaQueryWrapper() .eq(CmsContent::getCatalogId, next.getCatalogId()).gt(CmsContent::getSortFlag, next.getSortFlag()) - .orderByAsc(CmsContent::getSortFlag).last("limit 1"); - CmsContent prev = this.getContentService().dao().getOne(q); - if (prev == null) { + .orderByAsc(CmsContent::getSortFlag); + Page prev = this.getContentService().dao().page(Page.of(1, 1, false), q); + if (prev.getRecords().isEmpty()) { this.content.setSortFlag(SortUtils.getDefaultSortValue()); } else { - this.content.setSortFlag((next.getSortFlag() + prev.getSortFlag()) / 2); + this.content.setSortFlag((next.getSortFlag() + prev.getRecords().get(0).getSortFlag()) / 2); } this.getContentEntity().updateBy(this.getOperatorUName()); this.getContentService().dao().updateById(content); diff --git a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/core/IContent.java b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/core/IContent.java index b40fbb69..1d45a82e 100644 --- a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/core/IContent.java +++ b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/core/IContent.java @@ -15,7 +15,7 @@ */ package com.chestnut.contentcore.core; -import com.chestnut.common.security.domain.LoginUser; +import com.chestnut.common.security.domain.Operator; import com.chestnut.contentcore.domain.CmsCatalog; import com.chestnut.contentcore.domain.CmsContent; import com.chestnut.contentcore.domain.CmsSite; @@ -95,7 +95,7 @@ public interface IContent { /** * 获取操作人信息 */ - LoginUser getOperator(); + Operator getOperator(); /** * 获取操作人用户名 @@ -111,7 +111,7 @@ public interface IContent { /** * 设置操作人信息 */ - void setOperator(LoginUser operator); + void setOperator(Operator operator); /** * 复制内容到指定栏目 diff --git a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/core/IInternalDataType.java b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/core/IInternalDataType.java index bd4ea8fd..ecaf1e0e 100644 --- a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/core/IInternalDataType.java +++ b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/core/IInternalDataType.java @@ -22,6 +22,7 @@ import lombok.Getter; import lombok.Setter; import java.io.IOException; +import java.io.Writer; import java.util.Map; /** @@ -93,6 +94,8 @@ public interface IInternalDataType { return StringUtils.EMPTY; } + default void processPageData(RequestData requestData, Writer writer) throws TemplateException, IOException {} + /** * 访问链接 * diff --git a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/core/impl/InternalDataType_Catalog.java b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/core/impl/InternalDataType_Catalog.java index 6105970e..59df9c8d 100644 --- a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/core/impl/InternalDataType_Catalog.java +++ b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/core/impl/InternalDataType_Catalog.java @@ -26,6 +26,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; import java.io.IOException; +import java.io.Writer; import java.util.Objects; /** @@ -56,6 +57,14 @@ public class InternalDataType_Catalog implements IInternalDataType { return this.publishService.getCatalogPageData(catalog, requestData, listFlag); } + @Override + public void processPageData(RequestData requestData, Writer writer) throws TemplateException, IOException { + CmsCatalog catalog = catalogService.getCatalog(requestData.getDataId()); + boolean listFlag = YesOrNo.isYes(requestData.getParams().get("list")); + this.publishService.processCatalogPage(catalog, requestData, listFlag, writer); + + } + @Override public String getLink(InternalURL internalUrl, int pageIndex, String publishPipeCode, boolean isPreview) { CmsCatalog catalog = catalogService.getCatalog(internalUrl.getId()); diff --git a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/core/impl/InternalDataType_Content.java b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/core/impl/InternalDataType_Content.java index 61d13b3d..61754c8d 100644 --- a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/core/impl/InternalDataType_Content.java +++ b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/core/impl/InternalDataType_Content.java @@ -27,6 +27,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; import java.io.IOException; +import java.io.Writer; import java.util.Objects; /** @@ -58,6 +59,14 @@ public class InternalDataType_Content implements IInternalDataType { return this.publishService.getContentPageData(content, requestData); } + @Override + public void processPageData(RequestData requestData, Writer writer) throws TemplateException, IOException { + CmsContent content = contentService.dao().getById(requestData.getDataId()); + Assert.notNull(content, () -> CommonErrorCode.DATA_NOT_FOUND_BY_ID.exception("contentId", requestData.getDataId())); + + this.publishService.processContentPage(content, requestData, writer); + } + @Override public String getLink(InternalURL internalUrl, int pageIndex, String publishPipeCode, boolean isPreview) { CmsContent content = contentService.dao().getById(internalUrl.getId()); diff --git a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/core/impl/InternalDataType_PageWidget.java b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/core/impl/InternalDataType_PageWidget.java index cac5258f..3f5dfabd 100644 --- a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/core/impl/InternalDataType_PageWidget.java +++ b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/core/impl/InternalDataType_PageWidget.java @@ -26,6 +26,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; import java.io.IOException; +import java.io.Writer; /** * 内部数据类型:页面组件 @@ -53,6 +54,14 @@ public class InternalDataType_PageWidget implements IInternalDataType { CmsPageWidget pageWidget = pageWidgetService.getById(data.getDataId()); Assert.notNull(pageWidget, () -> CommonErrorCode.DATA_NOT_FOUND_BY_ID.exception("pageWidgetId", data.getDataId())); - return this.publishService.getPageWidgetPageData(pageWidget, data.getPublishPipeCode(), data.isPreview()); + return this.publishService.getPageWidgetPageData(pageWidget, data); + } + + @Override + public void processPageData(RequestData data, Writer writer) throws TemplateException, IOException { + CmsPageWidget pageWidget = pageWidgetService.getById(data.getDataId()); + Assert.notNull(pageWidget, () -> CommonErrorCode.DATA_NOT_FOUND_BY_ID.exception("pageWidgetId", data.getDataId())); + + this.publishService.processPageWidget(pageWidget, data, writer); } } diff --git a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/core/impl/InternalDataType_Site.java b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/core/impl/InternalDataType_Site.java index 2963481f..0debcfbd 100644 --- a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/core/impl/InternalDataType_Site.java +++ b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/core/impl/InternalDataType_Site.java @@ -26,6 +26,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; import java.io.IOException; +import java.io.Writer; /** * 内部数据类型:站点 @@ -54,6 +55,12 @@ public class InternalDataType_Site implements IInternalDataType { return this.publishService.getSitePageData(site, requestData); } + @Override + public void processPageData(RequestData requestData, Writer writer) throws TemplateException, IOException { + CmsSite site = siteService.getSite(requestData.getDataId()); + this.publishService.processSitePage(site, requestData, writer); + } + @Override public String getLink(InternalURL internalUrl, int pageIndex, String publishPipeCode, boolean isPreview) { CmsSite site = siteService.getSite(internalUrl.getId()); diff --git a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/core/impl/PublishPipeProp_RelativePrefix.java b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/core/impl/PublishPipeProp_RelativePrefix.java index bc8ec641..e8b7292d 100644 --- a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/core/impl/PublishPipeProp_RelativePrefix.java +++ b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/core/impl/PublishPipeProp_RelativePrefix.java @@ -15,6 +15,7 @@ */ package com.chestnut.contentcore.core.impl; +import com.chestnut.common.utils.StringUtils; import com.chestnut.contentcore.core.IPublishPipeProp; import org.apache.commons.collections4.MapUtils; import org.springframework.stereotype.Component; @@ -59,7 +60,10 @@ public class PublishPipeProp_RelativePrefix implements IPublishPipeProp { public static String getValue(String publishPipeCode, Map> publishPipeProps) { if (Objects.nonNull(publishPipeProps)) { - return MapUtils.getString(publishPipeProps.get(publishPipeCode), KEY); + String v = MapUtils.getString(publishPipeProps.get(publishPipeCode), KEY); + if (StringUtils.isNotBlank(v)) { + return v; + } } return DEFAULT_VALUE; } diff --git a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/dao/CmsContentDAO.java b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/dao/CmsContentDAO.java index b2cc3b5e..447694fd 100644 --- a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/dao/CmsContentDAO.java +++ b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/dao/CmsContentDAO.java @@ -65,7 +65,8 @@ public class CmsContentDAO extends BackupServiceImpl q = new LambdaQueryWrapper() .select(StringUtils.isNotEmpty(columns), columns) - .eq(CmsContent::getSiteId, siteId); + .eq(CmsContent::getSiteId, siteId) + .orderByAsc(CmsContent::getContentId); return this.page(page, q); } @@ -83,7 +84,8 @@ public class CmsContentDAO extends BackupServiceImpl() .select(StringUtils.isNotEmpty(columns), columns) - .eq(BCmsContent::getSiteId, siteId)); + .eq(BCmsContent::getSiteId, siteId) + .orderByAsc(BCmsContent::getBackupId)); } public void removeBackupBatchByIds(List backupIds) { diff --git a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/domain/CmsPublishPipe.java b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/domain/CmsPublishPipe.java index c5207e4a..86da1937 100644 --- a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/domain/CmsPublishPipe.java +++ b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/domain/CmsPublishPipe.java @@ -19,8 +19,8 @@ import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.chestnut.common.db.domain.BaseEntity; +import com.chestnut.common.validation.RegexConsts; import com.chestnut.system.fixed.dict.EnableOrDisable; - import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.Pattern; @@ -64,7 +64,7 @@ public class CmsPublishPipe extends BaseEntity { /** * 编码 */ - @Pattern(regexp = "[A-Za-z0-9_]+") + @Pattern(regexp = RegexConsts.REGEX_CODE) private String code; /** diff --git a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/domain/CmsSiteProperty.java b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/domain/CmsSiteProperty.java index c6802277..7ecb029c 100644 --- a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/domain/CmsSiteProperty.java +++ b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/domain/CmsSiteProperty.java @@ -20,6 +20,7 @@ import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.chestnut.common.annotation.XComment; import com.chestnut.common.db.domain.BaseEntity; +import com.chestnut.common.validation.RegexConsts; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.Pattern; import lombok.Getter; @@ -55,7 +56,7 @@ public class CmsSiteProperty extends BaseEntity { private String propName; @XComment("属性编码") - @Pattern(regexp = "[A-Za-z0-9_]+", message = "{VALIDATOR.CMS.SITE_PROPERTY.REGEXP_ERR}") + @Pattern(regexp = RegexConsts.REGEX_CODE) private String propCode; @XComment("属性值") diff --git a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/domain/dto/CatalogAddDTO.java b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/domain/dto/CatalogAddDTO.java index 81575bfa..dd884a96 100644 --- a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/domain/dto/CatalogAddDTO.java +++ b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/domain/dto/CatalogAddDTO.java @@ -16,7 +16,7 @@ package com.chestnut.contentcore.domain.dto; import com.chestnut.common.security.domain.BaseDTO; - +import com.chestnut.common.validation.RegexConsts; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.Pattern; import lombok.Getter; @@ -46,14 +46,14 @@ public class CatalogAddDTO extends BaseDTO { * 栏目别名 */ @NotBlank - @Pattern(regexp = "^[A-Za-z0-9_]+$", message = "栏目别名只能使用大小写字母、数字、下划线组合") + @Pattern(regexp = RegexConsts.REGEX_CODE) private String alias; /** * 栏目目录 */ @NotBlank - @Pattern(regexp = "^[A-Za-z0-9_\\/]+$", message = "栏目路径只能使用大小写字母、数字、下划线组合") + @Pattern(regexp = RegexConsts.REGEX_PATH) private String path; /** diff --git a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/domain/dto/CatalogUpdateDTO.java b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/domain/dto/CatalogUpdateDTO.java index 75555305..9454b572 100644 --- a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/domain/dto/CatalogUpdateDTO.java +++ b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/domain/dto/CatalogUpdateDTO.java @@ -16,6 +16,7 @@ package com.chestnut.contentcore.domain.dto; import com.chestnut.common.security.domain.BaseDTO; +import com.chestnut.common.validation.RegexConsts; import com.chestnut.contentcore.domain.pojo.PublishPipeProps; import com.chestnut.system.fixed.dict.YesOrNo; import com.chestnut.system.validator.Dict; @@ -54,14 +55,14 @@ public class CatalogUpdateDTO extends BaseDTO { * 栏目别名 */ @NotBlank - @Pattern(regexp = "^[A-Za-z0-9_]+$", message = "栏目别名只能使用大小写字母、数字、下划线组合") + @Pattern(regexp = RegexConsts.REGEX_CODE, message = "栏目别名只能使用大小写字母、数字、下划线组合") private String alias; /** * 栏目目录 */ @NotBlank - @Pattern(regexp = "^[A-Za-z0-9_\\/]+$", message = "栏目路径只能使用大小写字母、数字、下划线组合") + @Pattern(regexp = RegexConsts.REGEX_PATH, message = "栏目路径只能使用大小写字母、数字、下划线组合") private String path; /* diff --git a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/enums/ContentTips.java b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/enums/ContentTips.java index e41d6a0e..ed657c6e 100644 --- a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/enums/ContentTips.java +++ b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/enums/ContentTips.java @@ -1,3 +1,18 @@ +/* + * Copyright 2022-2025 兮玥(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.enums; import com.chestnut.common.i18n.I18nUtils; diff --git a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/listener/ContentCoreListener.java b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/listener/ContentCoreListener.java index 7f266e0d..1c30ba0b 100644 --- a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/listener/ContentCoreListener.java +++ b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/listener/ContentCoreListener.java @@ -60,8 +60,6 @@ public class ContentCoreListener { private final IPublishService publishService; - private final AsyncTaskManager asyncTaskManager; - @EventListener public void beforeSiteDelete(BeforeSiteDeleteEvent event) { CmsSite site = event.getSite(); @@ -74,27 +72,37 @@ public class ContentCoreListener { // 删除内容数据 try { long total = this.contentService.dao().countBySiteId(site.getSiteId()); + long lastId = 0; for (long i = 0; i * pageSize < total; i++) { AsyncTaskManager.setTaskProgressInfo((int) (i * pageSize * 100 / total), "正在删除内容数据:" + (i * pageSize) + "/" + total); - List contentIds = this.contentService.dao() - .pageBySiteId( - new Page<>(0, pageSize, false), - site.getSiteId(), - List.of(CmsContent::getContentId) - ).getRecords().stream().map(CmsContent::getContentId).toList(); - this.contentService.dao().removeBatchByIds(contentIds); + Page page = this.contentService.dao().lambdaQuery() + .select(CmsContent::getContentId) + .eq(CmsContent::getSiteId, site.getSiteId()) + .gt(CmsContent::getContentId, lastId) + .orderByAsc(CmsContent::getContentId) + .page(Page.of(0, pageSize, false)); + if (!page.getRecords().isEmpty()) { + List contentIds = page.getRecords().stream().map(CmsContent::getContentId).toList(); + this.contentService.dao().removeBatchByIds(contentIds); + lastId = contentIds.get(contentIds.size() - 1); + } } // 删除备份内容数据 total = this.contentService.dao().countBackupBySiteId(site.getSiteId()); + lastId = 0; for (long i = 0; i * pageSize < total; i++) { AsyncTaskManager.setTaskProgressInfo((int) (i * pageSize * 100 / total), "正在删除内容备份数据:" + (i * pageSize) + "/" + total); - List backupIds = this.contentService.dao() - .pageBackupBySiteId( - new Page<>(0, pageSize, false), - site.getSiteId(), - List.of(BCmsContent::getContentId) - ).getRecords().stream().map(BCmsContent::getBackupId).toList(); - this.contentService.dao().removeBackupBatchByIds(backupIds); + Page page = this.contentService.dao().getBackupMapper() + .selectPage(Page.of(0, pageSize, false), new LambdaQueryWrapper() + .select(BCmsContent::getBackupId) + .eq(BCmsContent::getSiteId, site.getSiteId()) + .gt(BCmsContent::getBackupId, lastId) + .orderByAsc(BCmsContent::getBackupId)); + if (!page.getRecords().isEmpty()) { + List backupIds = page.getRecords().stream().map(BCmsContent::getBackupId).toList(); + this.contentService.dao().removeBackupBatchByIds(backupIds); + lastId = backupIds.get(backupIds.size() - 1); + } } } catch (Exception e) { AsyncTaskManager.addErrMessage("删除内容错误:" + e.getMessage()); @@ -104,10 +112,20 @@ public class ContentCoreListener { try { long total = this.resourceService .count(new LambdaQueryWrapper().eq(CmsResource::getSiteId, site.getSiteId())); + long lastId = 0; for (long i = 0; i * pageSize < total; i++) { AsyncTaskManager.setTaskProgressInfo((int) (i * pageSize * 100 / total), "正在删除资源数据:" + (i * pageSize) + "/" + total); - this.resourceService.remove(new LambdaQueryWrapper() - .eq(CmsResource::getSiteId, site.getSiteId()).last("limit " + pageSize)); + Page resources = this.resourceService.lambdaQuery() + .select(CmsResource::getResourceId) + .eq(CmsResource::getSiteId, site.getSiteId()) + .gt(CmsResource::getResourceId, lastId) + .orderByAsc(CmsResource::getResourceId) + .page(Page.of(0, pageSize, false)); + if (!resources.getRecords().isEmpty()) { + List resourceIds = resources.getRecords().stream().map(CmsResource::getResourceId).toList(); + this.resourceService.removeBatchByIds(resourceIds); + lastId = resourceIds.get(resourceIds.size() - 1); + } } } catch (Exception e) { AsyncTaskManager.addErrMessage("删除资源数据错误:" + e.getMessage()); @@ -117,10 +135,20 @@ public class ContentCoreListener { try { long total = this.catalogService .count(new LambdaQueryWrapper().eq(CmsCatalog::getSiteId, site.getSiteId())); + long lastId = 0; for (long i = 0; i * pageSize < total; i++) { AsyncTaskManager.setTaskProgressInfo((int) (i * pageSize * 100 / total), "正在删除栏目数据:" + (i * pageSize) + "/" + total); - this.catalogService.remove(new LambdaQueryWrapper() - .eq(CmsCatalog::getSiteId, site.getSiteId()).last("limit " + pageSize)); + Page catalogs = this.catalogService.lambdaQuery() + .select(CmsCatalog::getCatalogId) + .eq(CmsCatalog::getSiteId, site.getSiteId()) + .gt(CmsCatalog::getCatalogId, lastId) + .orderByAsc(CmsCatalog::getCatalogId) + .page(Page.of(0, pageSize, false)); + if (!catalogs.getRecords().isEmpty()) { + List catalogIds = catalogs.getRecords().stream().map(CmsCatalog::getCatalogId).toList(); + this.catalogService.removeBatchByIds(catalogIds); + lastId = catalogIds.get(catalogIds.size() - 1); + } } } catch (Exception e) { AsyncTaskManager.addErrMessage("删除栏目数据错误:" + e.getMessage()); @@ -130,10 +158,20 @@ public class ContentCoreListener { try { long total = this.sitePropertyService .count(new LambdaQueryWrapper().eq(CmsSiteProperty::getSiteId, site.getSiteId())); + long lastId = 0; for (long i = 0; i * pageSize < total; i++) { AsyncTaskManager.setTaskProgressInfo((int) (i * pageSize * 100 / total), "正在删除站点扩展属性数据:" + (i * pageSize) + "/" + total); - this.sitePropertyService.remove(new LambdaQueryWrapper() - .eq(CmsSiteProperty::getSiteId, site.getSiteId()).last("limit " + pageSize)); + Page siteProperties = this.sitePropertyService.lambdaQuery() + .select(CmsSiteProperty::getPropertyId) + .eq(CmsSiteProperty::getSiteId, site.getSiteId()) + .gt(CmsSiteProperty::getPropertyId, lastId) + .orderByAsc(CmsSiteProperty::getPropertyId) + .page(Page.of(0, pageSize, false)); + if (!siteProperties.getRecords().isEmpty()) { + List ids = siteProperties.getRecords().stream().map(CmsSiteProperty::getPropertyId).toList(); + this.sitePropertyService.removeBatchByIds(ids); + lastId = ids.get(ids.size() - 1); + } } } catch (Exception e) { AsyncTaskManager.addErrMessage("删除站点扩展属性错误:" + e.getMessage()); @@ -143,10 +181,20 @@ public class ContentCoreListener { try { long total = this.templateService .count(new LambdaQueryWrapper().eq(CmsTemplate::getSiteId, site.getSiteId())); + long lastId = 0; for (long i = 0; i * pageSize < total; i++) { AsyncTaskManager.setTaskProgressInfo((int) (i * pageSize * 100 / total), "正在删除模板数据:" + (i * pageSize) + "/" + total); - this.templateService.remove(new LambdaQueryWrapper() - .eq(CmsTemplate::getSiteId, site.getSiteId()).last("limit " + pageSize)); + Page templates = this.templateService.lambdaQuery() + .select(CmsTemplate::getTemplateId) + .eq(CmsTemplate::getSiteId, site.getSiteId()) + .gt(CmsTemplate::getTemplateId, lastId) + .orderByAsc(CmsTemplate::getTemplateId) + .page(Page.of(0, pageSize, false)); + if (!templates.getRecords().isEmpty()) { + List ids = templates.getRecords().stream().map(CmsTemplate::getTemplateId).toList(); + this.templateService.removeBatchByIds(ids); + lastId = ids.get(ids.size() - 1); + } } } catch (Exception e) { AsyncTaskManager.addErrMessage("删除模板数据错误:" + e.getMessage()); @@ -156,10 +204,21 @@ public class ContentCoreListener { try { long total = this.contentRelaService .count(new LambdaQueryWrapper().eq(CmsContentRela::getSiteId, site.getSiteId())); + long lastId = 0; for (long i = 0; i * pageSize < total; i++) { - AsyncTaskManager.setTaskProgressInfo((int) (i * pageSize * 100 / total), "正在内容关联表数据:" + (i * pageSize) + "/" + total); - this.contentRelaService.remove(new LambdaQueryWrapper() - .eq(CmsContentRela::getSiteId, site.getSiteId()).last("limit " + pageSize)); + AsyncTaskManager.setTaskProgressInfo((int) (i * pageSize * 100 / total), + "正在内容关联表数据:" + (i * pageSize) + "/" + total); + Page templates = this.contentRelaService.lambdaQuery() + .select(CmsContentRela::getRelaContentId) + .eq(CmsContentRela::getSiteId, site.getSiteId()) + .gt(CmsContentRela::getRelaContentId, lastId) + .orderByAsc(CmsContentRela::getRelaContentId) + .page(Page.of(0, pageSize, false)); + if (!templates.getRecords().isEmpty()) { + List ids = templates.getRecords().stream().map(CmsContentRela::getRelaContentId).toList(); + this.contentRelaService.removeBatchByIds(ids); + lastId = ids.get(ids.size() - 1); + } } } catch (Exception e) { AsyncTaskManager.addErrMessage("删除内容关联表数据错误:" + e.getMessage()); diff --git a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/service/IPublishService.java b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/service/IPublishService.java index 233c04bd..081b685d 100644 --- a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/service/IPublishService.java +++ b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/service/IPublishService.java @@ -17,6 +17,7 @@ package com.chestnut.contentcore.service; import com.chestnut.common.async.AsyncTask; import com.chestnut.common.security.domain.LoginUser; +import com.chestnut.common.security.domain.Operator; import com.chestnut.contentcore.core.IContent; import com.chestnut.contentcore.core.IInternalDataType; import com.chestnut.contentcore.core.IPageWidget; @@ -27,6 +28,7 @@ import com.chestnut.contentcore.domain.CmsSite; import freemarker.template.TemplateException; import java.io.IOException; +import java.io.Writer; import java.util.List; public interface IPublishService { @@ -50,7 +52,7 @@ public interface IPublishService { * @param contentStatus 内容状态 * @return 结果 */ - AsyncTask publishAll(CmsSite site, final String contentStatus, final LoginUser operator); + AsyncTask publishAll(CmsSite site, final String contentStatus, final Operator operator); /** * 站点首页页面内容 @@ -64,6 +66,8 @@ public interface IPublishService { String getSitePageData(CmsSite site, IInternalDataType.RequestData requestData) throws IOException, TemplateException; + void processSitePage(CmsSite site, IInternalDataType.RequestData requestData, Writer writer) throws TemplateException, IOException; + /** * 获取栏目模板页面内容 * @@ -77,6 +81,9 @@ public interface IPublishService { String getCatalogPageData(CmsCatalog catalog, IInternalDataType.RequestData requestData, boolean listFlag) throws IOException, TemplateException; + void processCatalogPage(CmsCatalog catalog, IInternalDataType.RequestData requestData, boolean listFlag, Writer writer) + throws IOException, TemplateException; + /** * 发布栏目,异步任务 * @@ -87,7 +94,7 @@ public interface IPublishService { * @return 结果 */ AsyncTask publishCatalog(CmsCatalog catalog, boolean publishChild, boolean publishDetail, - String publishStatus, final LoginUser operator); + String publishStatus, final Operator operator); /** * 获取内容模板页面结果 @@ -108,6 +115,9 @@ public interface IPublishService { */ void asyncStaticizeContent(IContent content); + String processContentPage(CmsContent content, IInternalDataType.RequestData requestData, Writer writer) + throws IOException, TemplateException; + /** * 发布内容 * @@ -116,7 +126,7 @@ public interface IPublishService { */ AsyncTask publishContents(List contents, LoginUser operator); - void publishContent(CmsContent content, LoginUser operator); + void publishContent(CmsContent content, Operator operator); /** * 获取内容扩展模板解析内容 @@ -135,13 +145,15 @@ public interface IPublishService { * 获取页面部件模板解析内容 * * @param pageWidget 页面部件 - * @param publishPipeCode 发布通道编码 - * @param isPreview 是否预览 + * @param data 请求数据 * @return 结果 * @throws IOException e1 * @throws TemplateException e2 */ - String getPageWidgetPageData(CmsPageWidget pageWidget, String publishPipeCode, boolean isPreview) throws IOException, TemplateException; + String getPageWidgetPageData(CmsPageWidget pageWidget, IInternalDataType.RequestData data) throws IOException, TemplateException; + + void processPageWidget(CmsPageWidget pageWidget, IInternalDataType.RequestData data, Writer writer) + throws IOException, TemplateException; /** * 页面部件静态化 diff --git a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/service/impl/CatalogServiceImpl.java b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/service/impl/CatalogServiceImpl.java index 9a0ec4b3..73ffb202 100644 --- a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/service/impl/CatalogServiceImpl.java +++ b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/service/impl/CatalogServiceImpl.java @@ -277,6 +277,7 @@ public class CatalogServiceImpl extends ServiceImpl> publishPipeProps = dto.getPublishPipeDatas().stream() @@ -285,7 +286,7 @@ public class CatalogServiceImpl extends ServiceImpl params) { + public void deleteContent(CmsContent cmsContent, LoginUser loginUser, Map params) { boolean canDelete = ContentStatus.isDraft(cmsContent.getStatus()) || ContentStatus.isOffline(cmsContent.getStatus()); Assert.isTrue(canDelete, ContentCoreErrorCode.DEL_CONTENT_ERR::exception); IContentType contentType = ContentCoreUtils.getContentType(cmsContent.getContentType()); IContent content = contentType.loadContent(cmsContent); - content.setOperator(operator); + content.setOperator(Operator.of(loginUser)); content.setParams(params); transactionTemplate.executeWithoutResult(transactionStatus -> deleteContent0(content)); SpringUtils.publishEvent(new AfterContentDeleteEvent(this, content)); - } - - private void deleteContent0(IContent content) { - content.delete(); // 删除映射内容 List mappingList = this.dao().lambdaQuery() .eq(CmsContent::getCopyType, ContentCopyType.Mapping) @@ -126,15 +124,21 @@ public class ContentServiceImpl implements IContentService { for (CmsContent mappingContent : mappingList) { log.debug("CC.Content[{}].delete: mapping content delete", content.getContentEntity().getContentId()); try { - deleteContent(mappingContent, content.getOperator(), Map.of( - IContent.PARAM_IS_DELETE_BY_CATALOG, content.getParams().get(IContent.PARAM_IS_DELETE_BY_CATALOG) - )); + IContentType mappingContentType = ContentCoreUtils.getContentType(cmsContent.getContentType()); + IContent mappingIContent = mappingContentType.loadContent(cmsContent); + mappingIContent.setOperator(Operator.of(loginUser)); + mappingIContent.setParams(params); + transactionTemplate.executeWithoutResult(transactionStatus -> deleteContent0(mappingIContent)); + SpringUtils.publishEvent(new AfterContentDeleteEvent(this, mappingIContent)); } catch (Exception e) { AsyncTaskManager.setTaskTenPercentProgressInfo(ContentTips.DELETING_MAPPING_CONTENT.locale( mappingContent.getTitle(), mappingContent.getContentId())); } } - // 删除相关内容 + } + + private void deleteContent0(IContent content) { + content.delete(); contentRelaService.onContentDelete(content.getContentEntity().getContentId()); // TODO 删除内容历史版本? } @@ -170,13 +174,13 @@ public class ContentServiceImpl implements IContentService { } @Override - public void deleteContentsByCatalog(CmsCatalog catalog, boolean includeChild, LoginUser operator) { + public void deleteContentsByCatalog(CmsCatalog catalog, boolean includeChild, LoginUser loginUser) { long pageSize = 100; long total = this.dao().lambdaQuery() .eq(!includeChild, CmsContent::getCatalogId, catalog.getCatalogId()) .likeRight(includeChild, CmsContent::getCatalogAncestors, catalog.getAncestors()) .count(); - + Operator operator = Operator.of(loginUser); for (int i = 0; i * pageSize < total; i++) { AsyncTaskManager.setTaskProgressInfo((int) (i * pageSize / total), "正在栏目删除内容:" + (i * pageSize) + " / " + total); @@ -307,6 +311,8 @@ public class ContentServiceImpl implements IContentService { CmsContent cmsContent = dao().getById(contentId); if (Objects.nonNull(cmsContent)) { for (CmsCatalog catalog : catalogs) { + // 校验权限 + PermissionUtils.checkPermission(CatalogPermissionType.CatalogPrivItem.AddContent.getPermissionKey(catalog.getCatalogId()), dto.getOperator()); CmsContent copyContent = copy0(cmsContent, catalog, dto.getCopyType(), dto.getOperator()); SpringUtils.publishEvent(new AfterContentCopyEvent(this, cmsContent, copyContent)); } @@ -321,12 +327,12 @@ public class ContentServiceImpl implements IContentService { } - private CmsContent copy0(CmsContent cmsContent, CmsCatalog toCatalog, Integer copyType, LoginUser operator) { + private CmsContent copy0(CmsContent cmsContent, CmsCatalog toCatalog, Integer copyType, LoginUser loginUser) { AsyncTaskManager.setTaskTenPercentProgressInfo(ContentTips.COPYING_CONTENT.locale(AsyncTaskManager.getLocale(), cmsContent.getTitle(), toCatalog.getName())); IContentType ct = ContentCoreUtils.getContentType(cmsContent.getContentType()); IContent content = ct.loadContent(cmsContent); - content.setOperator(operator); + content.setOperator(Operator.of(loginUser)); return transactionTemplate.execute(transactionStatus -> content.copyTo(toCatalog, copyType)); } @@ -357,7 +363,9 @@ public class ContentServiceImpl implements IContentService { } @Override - public void moveContent(CmsContent cmsContent, CmsCatalog toCatalog, LoginUser operator) { + public void moveContent(CmsContent cmsContent, CmsCatalog toCatalog, LoginUser loginUser) { + // 校验权限 + PermissionUtils.checkPermission(CatalogPermissionType.CatalogPrivItem.AddContent.getPermissionKey(toCatalog.getCatalogId()), loginUser); if (cmsContent.getCatalogId().equals(toCatalog.getCatalogId())) { log.warn("Cannot move content to source catalog!"); return; @@ -366,7 +374,7 @@ public class ContentServiceImpl implements IContentService { cmsContent.getTitle(), toCatalog.getName())); IContentType ct = ContentCoreUtils.getContentType(cmsContent.getContentType()); IContent content = ct.loadContent(cmsContent); - content.setOperator(operator); + content.setOperator(Operator.of(loginUser)); transactionTemplate.executeWithoutResult(transactionStatus -> content.moveTo(toCatalog)); } @@ -376,7 +384,7 @@ public class ContentServiceImpl implements IContentService { for (CmsContent c : contents) { IContentType ct = ContentCoreUtils.getContentType(c.getContentType()); IContent content = ct.loadContent(c); - content.setOperator(dto.getOperator()); + content.setOperator(Operator.of(dto.getOperator())); transactionTemplate.executeWithoutResult(transactionStatus -> content.setTop(dto.getTopEndTime())); SpringUtils.publishEvent(new AfterContentTopSetEvent(this, content)); } @@ -391,7 +399,7 @@ public class ContentServiceImpl implements IContentService { for (CmsContent c : contents) { IContentType ct = ContentCoreUtils.getContentType(c.getContentType()); IContent content = ct.loadContent(c); - content.setOperator(operator); + content.setOperator(Operator.of(operator)); transactionTemplate.executeWithoutResult(transactionStatus -> content.cancelTop()); SpringUtils.publishEvent(new AfterContentTopCancelEvent(this, content)); } @@ -420,11 +428,11 @@ public class ContentServiceImpl implements IContentService { offline0(cmsContent, operator, LocaleContextHolder.getLocale()); } - private void offline0(CmsContent cmsContent, LoginUser operator, Locale locale) { + private void offline0(CmsContent cmsContent, LoginUser loginUser, Locale locale) { AsyncTaskManager.setTaskTenPercentProgressInfo(ContentTips.OFFLINE_CONTENT.locale(locale, cmsContent.getTitle())); IContentType ct = ContentCoreUtils.getContentType(cmsContent.getContentType()); IContent content = ct.loadContent(cmsContent); - content.setOperator(operator); + content.setOperator(Operator.of(loginUser)); transactionTemplate.executeWithoutResult(transactionStatus -> content.offline()); // 映射关联内容同步下线 if (!cmsContent.isLinkContent() && !ContentCopyType.isMapping(cmsContent.getCopyType())) { @@ -435,7 +443,7 @@ public class ContentServiceImpl implements IContentService { for (CmsContent c : mappingList) { log.debug("CC.Content[{}].offline: mapping content offline", cmsContent.getContentId()); AsyncTaskManager.setTaskTenPercentProgressInfo(ContentTips.OFFLINE_MAPPING_CONTENT.locale(locale, c.getTitle())); - offline0(c, operator, locale); + offline0(c, loginUser, locale); } } SpringUtils.publishEvent(new AfterContentOfflineEvent(this, content)); @@ -447,7 +455,7 @@ public class ContentServiceImpl implements IContentService { CmsContent c = this.dao().getById(dto.getContentId()); IContentType ct = ContentCoreUtils.getContentType(c.getContentType()); IContent content = ct.loadContent(c); - content.setOperator(dto.getOperator()); + content.setOperator(Operator.of(dto.getOperator())); content.sort(dto.getTargetContentId()); } @@ -460,10 +468,10 @@ public class ContentServiceImpl implements IContentService { } @Override - public void toPublish(CmsContent cmsContent, LoginUser operator) { + public void toPublish(CmsContent cmsContent, LoginUser loginUser) { IContentType ct = ContentCoreUtils.getContentType(cmsContent.getContentType()); IContent content = ct.loadContent(cmsContent); - content.setOperator(operator); + content.setOperator(Operator.of(loginUser)); transactionTemplate.executeWithoutResult(transactionStatus -> content.toPublish()); SpringUtils.publishEvent(new AfterContentToPublishEvent(this, content)); } diff --git a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/service/impl/PageWidgetServiceImpl.java b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/service/impl/PageWidgetServiceImpl.java index 27677c94..ff7eaca6 100644 --- a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/service/impl/PageWidgetServiceImpl.java +++ b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/service/impl/PageWidgetServiceImpl.java @@ -15,12 +15,12 @@ */ package com.chestnut.contentcore.service.impl; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.chestnut.common.async.AsyncTaskManager; import com.chestnut.common.exception.CommonErrorCode; import com.chestnut.common.security.domain.LoginUser; import com.chestnut.common.utils.Assert; +import com.chestnut.common.utils.IdUtils; import com.chestnut.contentcore.cache.PageWidgetMonitoredCache; import com.chestnut.contentcore.core.IPageWidget; import com.chestnut.contentcore.core.IPageWidgetType; @@ -76,11 +76,10 @@ public class PageWidgetServiceImpl extends ServiceImpl q = new LambdaQueryWrapper().eq(CmsPageWidget::getCode, code) + return this.lambdaQuery().eq(CmsPageWidget::getCode, code) .eq(CmsPageWidget::getSiteId, siteId) - .ne(pageWidgetId != null && pageWidgetId > 0, CmsPageWidget::getPageWidgetId, pageWidgetId) - .last("limit 1"); - return this.count(q) == 0; + .ne(IdUtils.validate(pageWidgetId), CmsPageWidget::getPageWidgetId, pageWidgetId) + .count() == 0; } @Override diff --git a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/service/impl/PublishServiceImpl.java b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/service/impl/PublishServiceImpl.java index 73f5ef1e..9754a148 100644 --- a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/service/impl/PublishServiceImpl.java +++ b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/service/impl/PublishServiceImpl.java @@ -20,6 +20,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.chestnut.common.async.AsyncTask; import com.chestnut.common.async.AsyncTaskManager; import com.chestnut.common.security.domain.LoginUser; +import com.chestnut.common.security.domain.Operator; import com.chestnut.common.staticize.StaticizeService; import com.chestnut.common.staticize.core.TemplateContext; import com.chestnut.common.utils.Assert; @@ -61,6 +62,7 @@ import org.springframework.transaction.support.TransactionTemplate; import java.io.File; import java.io.IOException; import java.io.StringWriter; +import java.io.Writer; import java.util.*; @Service @@ -92,6 +94,14 @@ public class PublishServiceImpl implements IPublishService, ApplicationContextAw @Override public String getSitePageData(CmsSite site, IInternalDataType.RequestData requestData) throws IOException, TemplateException { + try (StringWriter writer = new StringWriter()) { + processSitePage(site, requestData, writer); + return writer.toString(); + } + } + + @Override + public void processSitePage(CmsSite site, IInternalDataType.RequestData requestData, Writer writer) throws TemplateException, IOException { String indexTemplate = site.getIndexTemplate(requestData.getPublishPipeCode()); File templateFile = this.templateService.findTemplateFile(site, indexTemplate, requestData.getPublishPipeCode()); if (Objects.isNull(templateFile)) { @@ -108,9 +118,8 @@ public class PublishServiceImpl implements IPublishService, ApplicationContextAw templateType.initTemplateData(site.getSiteId(), context); long s = System.currentTimeMillis(); - try (StringWriter writer = new StringWriter()) { + try { this.staticizeService.process(context, writer); - return writer.toString(); } finally { logger.debug("[{}]Parse index template: {}\t, cost: {}ms", requestData.getPublishPipeCode(), site.getName(), System.currentTimeMillis() - s); } @@ -126,7 +135,7 @@ public class PublishServiceImpl implements IPublishService, ApplicationContextAw } @Override - public AsyncTask publishAll(CmsSite site, final String contentStatus, final LoginUser operator) { + public AsyncTask publishAll(CmsSite site, final String contentStatus, final Operator operator) { AsyncTask asyncTask = new AsyncTask() { @Override @@ -162,7 +171,7 @@ public class PublishServiceImpl implements IPublishService, ApplicationContextAw content.setContentEntity(xContent); content.setOperator(operator); Boolean published = transactionTemplate.execute(callback -> content.publish()); - if (published) { + if (Boolean.TRUE.equals(published)) { applicationContext.publishEvent(new AfterContentPublishEvent(contentType, content)); } this.checkInterrupt(); @@ -200,6 +209,15 @@ public class PublishServiceImpl implements IPublishService, ApplicationContextAw @Override public String getCatalogPageData(CmsCatalog catalog, IInternalDataType.RequestData requestData, boolean listFlag) throws IOException, TemplateException { + try (StringWriter writer = new StringWriter()) { + this.processCatalogPage(catalog, requestData, listFlag, writer); + return writer.toString(); + } + } + + @Override + public void processCatalogPage(CmsCatalog catalog, IInternalDataType.RequestData requestData, boolean listFlag, Writer writer) + throws IOException, TemplateException { if (CatalogType_Link.ID.equals(catalog.getCatalogType())) { throw new RuntimeException("链接类型栏目无独立页面:" + catalog.getName()); } @@ -240,9 +258,8 @@ public class PublishServiceImpl implements IPublishService, ApplicationContextAw templateContext.setFirstFileName(catalogLink); templateContext.setOtherFileName(TemplateUtils.appendPageIndexParam(catalogLink, TemplateContext.PlaceHolder_PageNo)); } - try (StringWriter writer = new StringWriter()) { + try { this.staticizeService.process(templateContext, writer); - return writer.toString(); } finally { logger.debug("[{}]栏目页模板解析:{},耗时:{}ms", requestData.getPublishPipeCode(), catalog.getName(), (System.currentTimeMillis() - s)); @@ -251,7 +268,7 @@ public class PublishServiceImpl implements IPublishService, ApplicationContextAw @Override public AsyncTask publishCatalog(CmsCatalog catalog, boolean publishChild, boolean publishDetail, - final String publishStatus, final LoginUser operator) { + final String publishStatus, final Operator operator) { List publishPipes = publishPipeService.getPublishPipes(catalog.getSiteId()); Assert.isTrue(!publishPipes.isEmpty(), ContentCoreErrorCode.NO_PUBLISHPIPE::exception); @@ -296,7 +313,7 @@ public class PublishServiceImpl implements IPublishService, ApplicationContextAw content.setContentEntity(xContent); content.setOperator(operator); Boolean published = transactionTemplate.execute(callback -> content.publish()); - if (published) { + if (Boolean.TRUE.equals(published)) { applicationContext.publishEvent(new AfterContentPublishEvent(contentType, content)); } this.checkInterrupt(); @@ -386,23 +403,64 @@ public class PublishServiceImpl implements IPublishService, ApplicationContextAw templateContext.setFirstFileName(contentLink); templateContext.setOtherFileName(TemplateUtils.appendPageIndexParam(contentLink, TemplateContext.PlaceHolder_PageNo)); // staticize - this.staticizeService.process(templateContext, writer); + this.processContentPage(content, requestData, writer); logger.debug("[{}][{}]内容模板解析:{},耗时:{}", requestData.getPublishPipeCode(), contentType.getId(), content.getTitle(), System.currentTimeMillis() - s); return writer.toString(); } } + @Override + public String processContentPage(CmsContent content, IInternalDataType.RequestData requestData, Writer writer) + throws IOException, TemplateException { + CmsSite site = this.siteService.getById(content.getSiteId()); + CmsCatalog catalog = this.catalogService.getCatalog(content.getCatalogId()); + if (content.isLinkContent()) { + throw new RuntimeException("标题内容:" + content.getTitle() + ",跳转链接:" + content.getRedirectUrl()); + } + // 查找模板 + final String detailTemplate = getDetailTemplate(site, catalog, content, requestData.getPublishPipeCode()); + File templateFile = this.templateService.findTemplateFile(site, detailTemplate, requestData.getPublishPipeCode()); + Assert.notNull(templateFile, + () -> ContentCoreErrorCode.TEMPLATE_EMPTY.exception(requestData.getPublishPipeCode(), detailTemplate)); + + IContentType contentType = ContentCoreUtils.getContentType(content.getContentType()); + long s = System.currentTimeMillis(); + // 生成静态页面 + try { + // 模板ID = 通道:站点目录:模板文件名 + String templateKey = SiteUtils.getTemplateKey(site, requestData.getPublishPipeCode(), detailTemplate); + TemplateContext templateContext = new TemplateContext(templateKey, requestData.isPreview(), requestData.getPublishPipeCode()); + templateContext.setPageIndex(requestData.getPageIndex()); + templateContext.getVariables().put(TemplateUtils.TemplateVariable_Request, Objects.requireNonNullElse(requestData.getParams(), Map.of())); + // 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 contentLink = this.contentService.getContentLink(content, 1, requestData.getPublishPipeCode(), requestData.isPreview()); + templateContext.setFirstFileName(contentLink); + templateContext.setOtherFileName(TemplateUtils.appendPageIndexParam(contentLink, TemplateContext.PlaceHolder_PageNo)); + // staticize + this.staticizeService.process(templateContext, writer); + return writer.toString(); + } finally { + logger.debug("[{}][{}]内容模板解析:{},耗时:{}", requestData.getPublishPipeCode(), contentType.getId(), content.getTitle(), + System.currentTimeMillis() - s); + } + } + /** * 内容发布 */ @Override - public AsyncTask publishContents(List contents, LoginUser operator) { + public AsyncTask publishContents(List contents, LoginUser loginUser) { Locale locale = LocaleContextHolder.getLocale(); AsyncTask task = new AsyncTask() { @Override public void run0() { - publishContents0(contents, operator, locale); + publishContents0(contents, Operator.of(loginUser), locale); } }; task.setType("PublishContents"); @@ -411,11 +469,11 @@ public class PublishServiceImpl implements IPublishService, ApplicationContextAw } @Override - public void publishContent(CmsContent content, LoginUser operator) { + public void publishContent(CmsContent content, Operator operator) { publishContents0(List.of(content), operator, null); } - private void publishContents0(List contents, LoginUser operator, Locale locale) { + private void publishContents0(List contents, Operator operator, Locale locale) { if (contents.isEmpty()) { return; } @@ -427,7 +485,7 @@ public class PublishServiceImpl implements IPublishService, ApplicationContextAw IContent content = contentType.loadContent(cmsContent); content.setOperator(operator); Boolean published = transactionTemplate.execute(callback -> content.publish()); - if (published) { + if (Boolean.TRUE.equals(published)) { applicationContext.publishEvent(new AfterContentPublishEvent(contentType, content)); } catalogIds.add(cmsContent.getCatalogId()); @@ -517,20 +575,29 @@ public class PublishServiceImpl implements IPublishService, ApplicationContextAw } @Override - public String getPageWidgetPageData(CmsPageWidget pageWidget, String publishPipeCode, boolean isPreview) + public String getPageWidgetPageData(CmsPageWidget pageWidget, IInternalDataType.RequestData data) + throws IOException, TemplateException { + try (StringWriter writer = new StringWriter()) { + processPageWidget(pageWidget, data, writer); + return writer.toString(); + } + } + + @Override + public void processPageWidget(CmsPageWidget pageWidget, IInternalDataType.RequestData data, Writer writer) throws IOException, TemplateException { CmsSite site = this.siteService.getById(pageWidget.getSiteId()); - String template = MapUtils.getString(pageWidget.getTemplates(), publishPipeCode, ""); + String template = MapUtils.getString(pageWidget.getTemplates(), data.getPublishPipeCode(), ""); File templateFile = this.templateService.findTemplateFile(site, template, - publishPipeCode); + data.getPublishPipeCode()); Assert.notNull(templateFile, () -> ContentCoreErrorCode.TEMPLATE_EMPTY.exception(template)); // 生成静态页面 - try (StringWriter writer = new StringWriter()) { - long s = System.currentTimeMillis(); + long s = System.currentTimeMillis(); + try { // 模板ID = 通道:站点目录:模板文件名 - String templateKey = SiteUtils.getTemplateKey(site, publishPipeCode, template); - TemplateContext templateContext = new TemplateContext(templateKey, isPreview, publishPipeCode); + String templateKey = SiteUtils.getTemplateKey(site, data.getPublishPipeCode(), template); + TemplateContext templateContext = new TemplateContext(templateKey, data.isPreview(), data.getPublishPipeCode()); // init template global variables TemplateUtils.initGlobalVariables(site, templateContext); templateContext.getVariables().put(TemplateUtils.TemplateVariable_PageWidget, pageWidget); @@ -539,9 +606,9 @@ public class PublishServiceImpl implements IPublishService, ApplicationContextAw templateType.initTemplateData(site.getSiteId(), templateContext); // staticize this.staticizeService.process(templateContext, writer); - logger.debug("[{}]页面部件【{}#{}】模板解析耗时:{}ms", publishPipeCode, pageWidget.getName(), + } finally { + logger.debug("[{}]页面部件【{}#{}】模板解析耗时:{}ms", data.getPublishPipeCode(), pageWidget.getName(), pageWidget.getCode(), System.currentTimeMillis() - s); - return writer.toString(); } } diff --git a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/template/exception/CatalogNotFoundException.java b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/template/exception/CatalogNotFoundException.java index 455c7d34..7c27c264 100644 --- a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/template/exception/CatalogNotFoundException.java +++ b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/template/exception/CatalogNotFoundException.java @@ -15,8 +15,7 @@ */ package com.chestnut.contentcore.template.exception; -import com.chestnut.common.utils.StringUtils; - +import com.chestnut.common.i18n.I18nUtils; import freemarker.core.Environment; import freemarker.template.TemplateException; @@ -24,7 +23,7 @@ public class CatalogNotFoundException extends TemplateException { private static final long serialVersionUID = 1L; - public CatalogNotFoundException(String tag, long catalogId, String alias, Environment env) { - super(StringUtils.messageFormat("<@{0}>[id: {1}, alias: {2}]", tag, catalogId, alias), env); + public CatalogNotFoundException(long catalogId, String alias, Environment env) { + super(I18nUtils.parse("FREEMARKER.ERR.CatalogNotFound", env.getLocale(), catalogId, alias), env); } } diff --git a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/template/tag/CmsCatalogTag.java b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/template/tag/CmsCatalogTag.java index 1b12818e..8185f7cb 100644 --- a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/template/tag/CmsCatalogTag.java +++ b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/template/tag/CmsCatalogTag.java @@ -85,7 +85,7 @@ public class CmsCatalogTag extends AbstractListTag { } String level = MapUtils.getString(attrs, ATTR_LEVEL); if (!CatalogTagLevel.isRoot(level) && Objects.isNull(catalog)) { - throw new CatalogNotFoundException(getTagName(), catalogId, alias, env); + throw new CatalogNotFoundException(catalogId, alias, env); } String condition = MapUtils.getString(attrs, TagAttr.AttrName_Condition); diff --git a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/template/tag/CmsContentClosestTag.java b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/template/tag/CmsContentClosestTag.java index a4fea036..b96730a8 100644 --- a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/template/tag/CmsContentClosestTag.java +++ b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/template/tag/CmsContentClosestTag.java @@ -25,10 +25,16 @@ import com.chestnut.common.staticize.tag.TagAttr; import com.chestnut.common.staticize.tag.TagAttrOption; import com.chestnut.common.utils.Assert; import com.chestnut.common.utils.StringUtils; +import com.chestnut.contentcore.domain.CmsCatalog; import com.chestnut.contentcore.domain.CmsContent; import com.chestnut.contentcore.domain.vo.TagContentVO; +import com.chestnut.contentcore.fixed.dict.ContentAttribute; import com.chestnut.contentcore.fixed.dict.ContentStatus; +import com.chestnut.contentcore.service.ICatalogService; import com.chestnut.contentcore.service.IContentService; +import com.chestnut.contentcore.template.exception.CatalogNotFoundException; +import com.chestnut.contentcore.util.CatalogUtils; +import com.chestnut.contentcore.util.TemplateUtils; import freemarker.core.Environment; import freemarker.template.TemplateException; import lombok.RequiredArgsConstructor; @@ -37,6 +43,7 @@ import org.springframework.stereotype.Component; import java.util.List; import java.util.Map; +import java.util.Objects; @Component @RequiredArgsConstructor @@ -47,35 +54,82 @@ public class CmsContentClosestTag extends AbstractListTag { public final static String DESC = "{FREEMARKER.TAG." + TAG_NAME + ".DESC}"; public final static String ATTR_USAGE_CONTENT_ID = "{FREEMARKER.TAG." + TAG_NAME + ".contentId}"; public final static String ATTR_USAGE_TYPE = "{FREEMARKER.TAG." + TAG_NAME + ".type}"; - public final static String ATTR_USAGE_SORT = "{FREEMARKER.TAG." + TAG_NAME + ".sort}"; public final static String ATTR_OPTION_TYPE_PREV = "{FREEMARKER.TAG." + TAG_NAME + ".type.Prev}"; public final static String ATTR_OPTION_TYPE_NEXT = "{FREEMARKER.TAG." + TAG_NAME + ".type.Next}"; final static String ATTR_CONTENT_ID = "contentid"; - - final static String ATTR_SORT = "sort"; - final static String ATTR_TYPE = "type"; + public final static String ATTR_CATALOG_ID = "catalogid"; + public final static String ATTR_CATALOG_ALIAS = "catalogalias"; + public final static String ATTR_LEVEL = "level"; + public final static String ATTR_SORT = "sort"; + public final static String ATTR_HAS_ATTRIBUTE = "hasattribute"; + public final static String ATTR_NO_ATTRIBUTE = "noattribute"; + public final static String ATTR_STATUS = "status"; + public final static String ATTR_TOP_FLAG = "topflag"; + + private final ICatalogService catalogService; private final IContentService contentService; @Override public TagPageData prepareData(Environment env, Map attrs, boolean page, int size, int pageIndex) throws TemplateException { boolean isNext = TypeTagAttr.isNext(attrs.get(ATTR_TYPE)); - String sort = attrs.get(ATTR_SORT); Long contentId = MapUtils.getLong(attrs, ATTR_CONTENT_ID); CmsContent content = this.contentService.dao().getById(contentId); Assert.notNull(content, () -> new TemplateException(StringUtils.messageFormat("Tag attr[contentid={0}] data not found.", contentId), env)); - LambdaQueryWrapper q = new LambdaQueryWrapper() - .eq(CmsContent::getCatalogId, content.getCatalogId()) - .eq(CmsContent::getStatus, ContentStatus.PUBLISHED); - if (CmsContentTag.SortTagAttr.isRecent(sort)) { + CmsCatalog catalog = null; + long catalogId = MapUtils.getLongValue(attrs, ATTR_CATALOG_ID); + if (catalogId > 0) { + catalog = this.catalogService.getCatalog(catalogId); + } + long siteId = TemplateUtils.evalSiteId(env); + String alias = MapUtils.getString(attrs, ATTR_CATALOG_ALIAS); + if (Objects.isNull(catalog) && StringUtils.isNotEmpty(alias)) { + catalog = this.catalogService.getCatalogByAlias(siteId, alias); + } + String level = MapUtils.getString(attrs, ATTR_LEVEL); + if (!CmsContentTag.LevelTagAttr.isRoot(level) && Objects.isNull(catalog)) { + throw new CatalogNotFoundException(catalogId, alias, env); + } + String condition = MapUtils.getString(attrs, TagAttr.AttrName_Condition); + String status = MapUtils.getString(attrs, ATTR_STATUS, ContentStatus.PUBLISHED); + + LambdaQueryWrapper q = new LambdaQueryWrapper<>(); + q.eq(CmsContent::getSiteId, siteId).eq(!"-1".equals(status), CmsContent::getStatus, status); + if (Objects.nonNull(catalog)) { + if (CmsContentTag.LevelTagAttr.isCurrent(level)) { + q.eq(CmsContent::getCatalogId, catalog.getCatalogId()); + } else if (CmsContentTag.LevelTagAttr.isChild(level)) { + q.likeRight(CmsContent::getCatalogAncestors, catalog.getAncestors() + CatalogUtils.ANCESTORS_SPLITER); + } else if (CmsContentTag.LevelTagAttr.isCurrentAndChild(level)) { + q.likeRight(CmsContent::getCatalogAncestors, catalog.getAncestors()); + } + } + String hasAttribute = MapUtils.getString(attrs, ATTR_HAS_ATTRIBUTE); + if (StringUtils.isNotEmpty(hasAttribute)) { + int attrTotal = ContentAttribute.convertInt(hasAttribute.split(",")); + q.apply(attrTotal > 0, "attributes&{0}={1}", attrTotal, attrTotal); + } + String noAttribute = MapUtils.getString(attrs, ATTR_NO_ATTRIBUTE); + if (StringUtils.isNotEmpty(noAttribute)) { + String[] contentAttrs = noAttribute.split(","); + int attrTotal = ContentAttribute.convertInt(contentAttrs); + for (String attr : contentAttrs) { + int bit = ContentAttribute.bit(attr); + q.apply(bit > 0, "attributes&{0}<>{1}", attrTotal, bit); + } + } + q.apply(StringUtils.isNotEmpty(condition), condition); + String sortType = MapUtils.getString(attrs, ATTR_SORT); + q.orderByDesc(MapUtils.getBooleanValue(attrs, ATTR_TOP_FLAG, true), CmsContent::getTopFlag); + if (CmsContentTag.SortTagAttr.isRecent(sortType)) { q.gt(isNext, CmsContent::getPublishDate, content.getPublishDate()); q.lt(!isNext, CmsContent::getPublishDate, content.getPublishDate()); q.orderBy(true, isNext, CmsContent::getPublishDate); - } else if(CmsContentTag.SortTagAttr.isViews(sort)) { + } else if(CmsContentTag.SortTagAttr.isViews(sortType)) { q.gt(isNext, CmsContent::getViewCount, content.getViewCount()); q.lt(!isNext, CmsContent::getViewCount, content.getViewCount()); q.orderBy(true, isNext, CmsContent::getViewCount); @@ -120,11 +174,18 @@ public class CmsContentClosestTag extends AbstractListTag { @Override public List getTagAttrs() { - return List.of( - new TagAttr(ATTR_CONTENT_ID, true, TagAttrDataType.INTEGER, ATTR_USAGE_CONTENT_ID), - new TagAttr(ATTR_TYPE, true, TagAttrDataType.STRING, ATTR_USAGE_TYPE, TypeTagAttr.toTagAttrOptions(), TypeTagAttr.Prev.name()), - new TagAttr(ATTR_SORT, false, TagAttrDataType.STRING, ATTR_USAGE_SORT, CmsContentTag.SortTagAttr.toTagAttrOptions(), CmsContentTag.SortTagAttr.Default.name()) - ); + List tagAttrs = super.getTagAttrs(); + tagAttrs.add(new TagAttr(ATTR_CONTENT_ID, true, TagAttrDataType.INTEGER, ATTR_USAGE_CONTENT_ID)); + tagAttrs.add(new TagAttr(ATTR_TYPE, true, TagAttrDataType.STRING, ATTR_USAGE_TYPE, TypeTagAttr.toTagAttrOptions(), TypeTagAttr.Prev.name())); + tagAttrs.add(new TagAttr(ATTR_CATALOG_ID, false, TagAttrDataType.INTEGER, CmsContentTag.ATTR_USAGE_CATALOG_ID)); + tagAttrs.add(new TagAttr(ATTR_CATALOG_ALIAS, false, TagAttrDataType.STRING, CmsContentTag.ATTR_USAGE_CATALOG_ALIAS)); + tagAttrs.add(new TagAttr(ATTR_LEVEL, false, TagAttrDataType.STRING, CmsContentTag.ATTR_USAGE_LEVEL, CmsContentTag.LevelTagAttr.toTagAttrOptions(), CmsContentTag.LevelTagAttr.Current.name())); + tagAttrs.add(new TagAttr(ATTR_SORT, false, TagAttrDataType.STRING, CmsContentTag.ATTR_USAGE_SORT, CmsContentTag.SortTagAttr.toTagAttrOptions(), CmsContentTag.SortTagAttr.Default.name())); + tagAttrs.add(new TagAttr(ATTR_HAS_ATTRIBUTE, false, TagAttrDataType.STRING, CmsContentTag.ATTR_USAGE_HAS_ATTRIBUTE)); + tagAttrs.add(new TagAttr(ATTR_NO_ATTRIBUTE, false, TagAttrDataType.STRING, CmsContentTag.ATTR_USAGE_NO_ATTRIBUTE)); + tagAttrs.add(new TagAttr(ATTR_STATUS, false, TagAttrDataType.STRING, CmsContentTag.ATTR_USAGE_STATUS)); + tagAttrs.add(new TagAttr(ATTR_TOP_FLAG, false, TagAttrDataType.BOOLEAN, CmsContentTag.ATTR_USAGE_TOP_FLAG, Boolean.TRUE.toString())); + return tagAttrs; } enum TypeTagAttr { diff --git a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/template/tag/CmsContentTag.java b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/template/tag/CmsContentTag.java index bdbed5ee..07434d75 100644 --- a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/template/tag/CmsContentTag.java +++ b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/template/tag/CmsContentTag.java @@ -109,7 +109,7 @@ public class CmsContentTag extends AbstractListTag { } String level = MapUtils.getString(attrs, ATTR_LEVEL); if (!LevelTagAttr.isRoot(level) && Objects.isNull(catalog)) { - throw new CatalogNotFoundException(getTagName(), catalogId, alias, env); + throw new CatalogNotFoundException(catalogId, alias, env); } String condition = MapUtils.getString(attrs, TagAttr.AttrName_Condition); String status = MapUtils.getString(attrs, ATTR_STATUS, ContentStatus.PUBLISHED); diff --git a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/template/tag/CmsIncludeTag.java b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/template/tag/CmsIncludeTag.java index 1c3688f4..58cafba9 100644 --- a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/template/tag/CmsIncludeTag.java +++ b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/template/tag/CmsIncludeTag.java @@ -23,7 +23,10 @@ import com.chestnut.common.staticize.tag.AbstractTag; import com.chestnut.common.staticize.tag.TagAttr; import com.chestnut.common.utils.Assert; import com.chestnut.common.utils.StringUtils; +import com.chestnut.contentcore.core.impl.PublishPipeProp_PrefixMode; +import com.chestnut.contentcore.core.impl.PublishPipeProp_RelativePrefix; import com.chestnut.contentcore.domain.CmsSite; +import com.chestnut.contentcore.enums.SitePrefixMode; import com.chestnut.contentcore.properties.EnableSSIProperty; import com.chestnut.contentcore.service.ISiteService; import com.chestnut.contentcore.service.ITemplateService; @@ -160,7 +163,7 @@ public class CmsIncludeTag extends AbstractTag { } } if (ssi) { - String prefix = SiteUtils.getPublishPipePrefix(site, context.getPublishPipeCode(), context.isPreview()); + String prefix = getIncludePathPrefix(context.getPublishPipeCode(), site); env.getOut().write(StringUtils.messageFormat(SSI_INCLUDE_TAG, prefix + staticFilePath)); } else { env.getOut().write(staticContent); @@ -169,6 +172,18 @@ public class CmsIncludeTag extends AbstractTag { return null; } + public static String getIncludePathPrefix(String publishPipeCode, CmsSite site) { + String prefix = null; + String prefixMode = PublishPipeProp_PrefixMode.getValue(publishPipeCode, site.getPublishPipeProps()); + if (SitePrefixMode.isRelative(prefixMode)) { + prefix = PublishPipeProp_RelativePrefix.getValue(publishPipeCode, site.getPublishPipeProps()); + } + if (StringUtils.isEmpty(prefix)) { + prefix = "/"; + } + return prefix; + } + private Map mergeRequestVariable(Environment env, Map params) throws TemplateModelException { TemplateModel variable = env.getVariable(TemplateUtils.TemplateVariable_Request); if (Objects.nonNull(variable)) { diff --git a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/template/tag/CmsPageWidgetTag.java b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/template/tag/CmsPageWidgetTag.java index 3fc628b4..f096b107 100644 --- a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/template/tag/CmsPageWidgetTag.java +++ b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/template/tag/CmsPageWidgetTag.java @@ -124,19 +124,19 @@ public class CmsPageWidgetTag extends AbstractTag { String siteRoot = SiteUtils.getSiteRoot(site, context.getPublishPipeCode()); String staticFileName = PageWidgetUtils.getStaticFileName(pw, site.getStaticSuffix(context.getPublishPipeCode())); String staticFilePath = pw.getPath() + staticFileName; - if (ssi) { - // 读取页面部件静态化内容 - String staticContent = templateService.getTemplateStaticContentCache(templateKey); - if (Objects.isNull(staticContent) || !new File(siteRoot + staticFilePath).exists()) { - staticContent = this.processTemplate(env, pw, templateKey); + + String staticContent = templateService.getTemplateStaticContentCache(templateKey); + if (Objects.isNull(staticContent) || !new File(siteRoot + staticFilePath).exists()) { + staticContent = this.processTemplate(env, pw, templateKey); + this.templateService.setTemplateStaticContentCache(templateKey, staticContent); + if (ssi) { FileUtils.writeStringToFile(new File(siteRoot + staticFilePath), staticContent, StandardCharsets.UTF_8); - this.templateService.setTemplateStaticContentCache(templateKey, staticContent); } - String prefix = SiteUtils.getPublishPipePrefix(site, context.getPublishPipeCode(), context.isPreview()); + } + if (ssi) { + String prefix = CmsIncludeTag.getIncludePathPrefix(context.getPublishPipeCode(), site); env.getOut().write(StringUtils.messageFormat(CmsIncludeTag.SSI_INCLUDE_TAG, prefix + staticFilePath)); } else { - // 非ssi模式无法使用缓存 - String staticContent = this.processTemplate(env, pw, templateKey); env.getOut().write(staticContent); } } diff --git a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/util/CatalogUtils.java b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/util/CatalogUtils.java index 77554b50..8565d5c7 100644 --- a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/util/CatalogUtils.java +++ b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/util/CatalogUtils.java @@ -88,7 +88,7 @@ public class CatalogUtils { publishPipeCode, pageIndex); return BackendContext.getValue() + catalogPath; } - String prefix = SiteUtils.getPublishPipePrefix(site, publishPipeCode, isPreview); + String prefix = SiteUtils.getPublishPipePrefix(site, publishPipeCode, false); if (catalog.isStaticize()) { return prefix + catalog.getPath(); } else { diff --git a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/util/ContentLogUtils.java b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/util/ContentLogUtils.java index 0aa7abbc..495d2f88 100644 --- a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/util/ContentLogUtils.java +++ b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/util/ContentLogUtils.java @@ -16,7 +16,7 @@ package com.chestnut.contentcore.util; import com.chestnut.common.async.AsyncTaskManager; -import com.chestnut.common.security.domain.LoginUser; +import com.chestnut.common.security.domain.Operator; import com.chestnut.common.utils.IdUtils; import com.chestnut.common.utils.SpringUtils; import com.chestnut.contentcore.domain.CmsContent; @@ -39,7 +39,7 @@ public class ContentLogUtils { private static final AsyncTaskManager asyncTaskManager = SpringUtils.getBean(AsyncTaskManager.class); - public static void addLog(String opType, CmsContent content, LoginUser operator) { + public static void addLog(String opType, CmsContent content, Operator operator) { addLog(opType, content, null, operator.getUserType(), operator.getUsername()); } diff --git a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/util/SiteUtils.java b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/util/SiteUtils.java index 4df6d3d9..dcced234 100644 --- a/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/util/SiteUtils.java +++ b/chestnut-cms/chestnut-cms-contentcore/src/main/java/com/chestnut/contentcore/util/SiteUtils.java @@ -21,6 +21,7 @@ import com.chestnut.contentcore.config.CMSConfig; import com.chestnut.contentcore.core.IInternalDataType; import com.chestnut.contentcore.core.impl.InternalDataType_Site; import com.chestnut.contentcore.core.impl.PublishPipeProp_PrefixMode; +import com.chestnut.contentcore.core.impl.PublishPipeProp_RelativePrefix; import com.chestnut.contentcore.domain.CmsSite; import com.chestnut.contentcore.enums.SitePrefixMode; import com.chestnut.system.fixed.config.BackendContext; @@ -48,7 +49,7 @@ public class SiteUtils { } String pathMode = PublishPipeProp_PrefixMode.getValue(publishPipeCode, site.getPublishPipeProps()); if (SitePrefixMode.isRelative(pathMode)) { - return "/"; + return PublishPipeProp_RelativePrefix.getValue(publishPipeCode, site.getPublishPipeProps()); } return site.getUrl(publishPipeCode); } @@ -81,7 +82,7 @@ public class SiteUtils { } /** - * 获取站点资源文件访问链接前缀 + * 获取站点资源文件访问链接前缀,非预览模式为设置资源域名则使用指定发布通道域名 * * @param site 站点 * @param publishPipeCode 发布通道编码 diff --git a/chestnut-cms/chestnut-cms-contentcore/src/main/resources/i18n/messages.properties b/chestnut-cms/chestnut-cms-contentcore/src/main/resources/i18n/messages.properties index ecabcdad..c1bb0dd9 100644 --- a/chestnut-cms/chestnut-cms-contentcore/src/main/resources/i18n/messages.properties +++ b/chestnut-cms/chestnut-cms-contentcore/src/main/resources/i18n/messages.properties @@ -149,7 +149,6 @@ FREEMARKER.TAG.cms_content_closest.contentId=內容ID FREEMARKER.TAG.cms_content_closest.type=类型 FREEMARKER.TAG.cms_content_closest.type.Prev=上一篇 FREEMARKER.TAG.cms_content_closest.type.Next=下一篇 -FREEMARKER.TAG.cms_content_closest.sort=排序值 FREEMARKER.TAG.cms_content_rela.NAME=相关内容标签 FREEMARKER.TAG.cms_content_rela.DESC=相关内容标签,内嵌`<#list DataList as content>${content.name}`遍历数据 FREEMARKER.TAG.cms_content_rela.contentId=内容ID @@ -195,6 +194,8 @@ FREEMARKER.FUNC.fileExtractor.DESC=提取html文本中的文件资源链接 FREEMARKER.FUNC.fileExtractor.Arg1.Name=Html文本内容 FREEMARKER.FUNC.fileExtractor.Arg2.Name=文件类型/后缀 +FREEMARKER.ERR.CatalogNotFound=栏目数据不存在:[栏目ID: {0}], [栏目别名: {1}] + # 校验规则 VALIDATOR.CMS.SITE.PUBLISH_PIPE_PROPS_EMPTY=发布通道配置不能为空 VALIDATOR.CMS.SITE_PROPERTY.REGEXP_ERR=属性编码只能使用大小写字母、数字和下划线 diff --git a/chestnut-cms/chestnut-cms-contentcore/src/main/resources/i18n/messages_en.properties b/chestnut-cms/chestnut-cms-contentcore/src/main/resources/i18n/messages_en.properties index d49065c0..a3a7e611 100644 --- a/chestnut-cms/chestnut-cms-contentcore/src/main/resources/i18n/messages_en.properties +++ b/chestnut-cms/chestnut-cms-contentcore/src/main/resources/i18n/messages_en.properties @@ -149,7 +149,6 @@ FREEMARKER.TAG.cms_content_closest.contentId=Target content id FREEMARKER.TAG.cms_content_closest.type=Type FREEMARKER.TAG.cms_content_closest.type.Prev=Prev FREEMARKER.TAG.cms_content_closest.type.Next=Next -FREEMARKER.TAG.cms_content_closest.sort=Sort Value FREEMARKER.TAG.cms_content_rela.NAME=Related content tag FREEMARKER.TAG.cms_content_rela.DESC=Fetch related contents by contentId, use `<#list>` in tag like `<#list DataList as content>${content.title}` to walk through the list of contents. FREEMARKER.TAG.cms_content_rela.contentId=Target content id @@ -195,6 +194,8 @@ FREEMARKER.FUNC.fileExtractor.DESC=Get file link list from html text. FREEMARKER.FUNC.fileExtractor.Arg1.Name=Html text FREEMARKER.FUNC.fileExtractor.Arg2.Name=File type or suffix +FREEMARKER.ERR.CatalogNotFound=Missing catalog: [id: {0}], [alias: {1}] + # 校验规则 VALIDATOR.CMS.SITE.PUBLISH_PIPE_PROPS_EMPTY=The site publish pipe props cannot be empty. VALIDATOR.CMS.SITE_PROPERTY.REGEXP_ERR=The code can only use uppercase/lowercase letters, numbers and underscores. diff --git a/chestnut-cms/chestnut-cms-contentcore/src/main/resources/i18n/messages_zh_TW.properties b/chestnut-cms/chestnut-cms-contentcore/src/main/resources/i18n/messages_zh_TW.properties index 84f407bc..17c0acb0 100644 --- a/chestnut-cms/chestnut-cms-contentcore/src/main/resources/i18n/messages_zh_TW.properties +++ b/chestnut-cms/chestnut-cms-contentcore/src/main/resources/i18n/messages_zh_TW.properties @@ -1,338 +1,339 @@ -# 資源類型 -CMS.CONTENTCORE.RESOURCE_TYPE.image=圖片 -CMS.CONTENTCORE.RESOURCE_TYPE.audio=音頻 -CMS.CONTENTCORE.RESOURCE_TYPE.video=視頻 -CMS.CONTENTCORE.RESOURCE_TYPE.file=檔案 - -# 欄目類型 -CMS.CONTENTCORE.CATALOG_TYPE.common=普通欄目 -CMS.CONTENTCORE.CATALOG_TYPE.link=連結欄目 - -# 字典數據 -DICT.CMSPageWidgetStatus=內容狀態 -DICT.CMSPageWidgetStatus.0=初稿 -DICT.CMSPageWidgetStatus.30=已發布 -DICT.CMSPageWidgetStatus.40=已下線 -DICT.CMSPageWidgetStatus.60=重新編輯 -DICT.CMSContentStatus=內容狀態 -DICT.CMSContentStatus.0=初稿 -DICT.CMSContentStatus.20=待發布 -DICT.CMSContentStatus.30=已發布 -DICT.CMSContentStatus.40=已下線 -DICT.CMSContentStatus.60=重新編輯 -DICT.CMSContentAttribute=內容屬性 -DICT.CMSContentAttribute.image=圖片 -DICT.CMSContentAttribute.video=視頻 -DICT.CMSContentAttribute.attach=附件 -DICT.CMSContentAttribute.hot=熱點 -DICT.CMSContentAttribute.recommend=推薦 -DICT.CMSStaticSuffix=靜態檔案類型 -DICT.CMSStaticSuffix.shtml=shtml -DICT.CMSStaticSuffix.html=html -DICT.CMSStaticSuffix.xml=xml -DICT.CMSStaticSuffix.json=json -DICT.CMSContentOpType=內容操作類型 -DICT.CMSContentOpType.ADD=新增 -DICT.CMSContentOpType.UPDATE=修改 -DICT.CMSContentOpType.DELETE=刪除 -DICT.CMSContentOpType.LOCK=鎖定 -DICT.CMSContentOpType.UNLOCK=解鎖 -DICT.CMSContentOpType.TO_PUBLISH=待發佈 -DICT.CMSContentOpType.PUBLISH=發佈 -DICT.CMSContentOpType.OFFLINE=下線 -DICT.CMSContentOpType.SORT=排序 -DICT.CMSContentOpType.TOP=置頂 -DICT.CMSContentOpType.CANCEL_TOP=取消置頂 - -# 固定配置參數 -CONFIG.CMSBackendContext=後台訪問地址 -CONFIG.CMSModuleEnable=是否開啟CMS功能 -CONFIG.CMSTemplateSuffix=模板尾碼名 -CONFIG.AllowUploadFileType=CMS檔案上傳類型限制 -CONFIG.SiteApiUrl=站點API地址 -CONFIG.ResourceUploadAcceptSize=素材庫資源上傳大小限制 - -# 錯誤資訊 -ERRCODE.CMS.CONTENTCORE.NO_SITE=無站點數據,請先去站點管理菜單創建站點 -ERRCODE.CMS.CONTENTCORE.UNSUPPORTED_PAGE_WIDGET_TYPE=未知頁面部件類型:{0} -ERRCODE.CMS.CONTENTCORE.TEMPLATE_EMPTY=模板未配置或模板檔案不存在 -ERRCODE.CMS.CONTENTCORE.TEMPLATE_FILE_NOT_FOUND=模板檔案“{0}”不存在 -ERRCODE.CMS.CONTENTCORE.INVALID_TEMPLATE_NAME=模板檔案名只能使用大小寫字母和下劃線,且必須以`{0}`結尾 -ERRCODE.CMS.CONTENTCORE.UNSUPPORTED_CONTENT_TYPE=未知內容類型:{0} -ERRCODE.CMS.CONTENTCORE.UNSUPPORTED_CATALOG_TYPE=未知欄目類型:{0} -ERRCODE.CMS.CONTENTCORE.UNSUPPORTED_INTERNAL_DATA_TYPE=未知內部數據類型:{0} -ERRCODE.CMS.CONTENTCORE.UNSUPPORTED_RESOURCE_TYPE=未知資源類型:{0} -ERRCODE.CMS.CONTENTCORE.UNSUPPORTED_DYNAMIC_PAGE_TYPE=未知動態模板類型:{0} -ERRCODE.CMS.CONTENTCORE.UNSUPPORTED_CONTENT_PATH_RULE=未知內容詳情頁路徑規則:{0} -ERRCODE.CMS.CONTENTCORE.DEL_CHILD_FIRST=請先刪除子欄目 -ERRCODE.CMS.CONTENTCORE.CONFLICT_CATALOG=欄目名稱/別名/目錄重複 -ERRCODE.CMS.CONTENTCORE.CATALOG_MAX_TREE_LEVEL=欄目層級超出上限 -ERRCODE.CMS.CONTENTCORE.CATALOG_MOVE_TO_SELF_OR_CHILD=欄目不能轉移到自身或子欄目 -ERRCODE.CMS.CONTENTCORE.INVALID_PROPERTY=擴展屬性[{0}={1}]校驗失敗 -ERRCODE.CMS.CONTENTCORE.EXISTS_SITE_PATH=站點目錄衝突 -ERRCODE.CMS.CONTENTCORE.CONTENT_LOCKED=內容已被"{0}"鎖定 -ERRCODE.CMS.CONTENTCORE.TITLE_REPLEAT=標題重複 -ERRCODE.CMS.CONTENTCORE.CANNOT_EDIT_PUBLISHED_CONTENT=已發布內容不允許編輯,請先下線內容! -ERRCODE.CMS.CONTENTCORE.NO_PUBLISHPIPE=無可用發布通道 -ERRCODE.CMS.CONTENTCORE.CATALOG_CANNOT_PUBLISH=欄目發布失敗:欄目不可見/不可靜態化/標題欄目。 -ERRCODE.CMS.CONTENTCORE.SITE_FILE_OP_ERR=不能操作非當前站點檔案 -ERRCODE.CMS.CONTENTCORE.TEMPLATE_PATH_EXISTS=模板檔案已存在或路徑被佔用 -ERRCODE.CMS.CONTENTCORE.NOT_ALLOW_FILE_TYPE=禁止上傳的檔案類型:{0} -ERRCODE.CMS.CONTENTCORE.NOT_EDITABLE_FILE=指定檔案不支援線上編輯 -ERRCODE.CMS.CONTENTCORE.FILE_NOT_EXIST=檔案不存在 -ERRCODE.CMS.CONTENTCORE.FILE_ALREADY_EXISTS=檔案已存在 -ERRCODE.CMS.CONTENTCORE.CATALOG_SORT_VALUE_ZERO=欄目排序值不能為0 -ERRCODE.CMS.CONTENTCORE.SITE_EXPORT_TASK_EXISTS=站點導出任務正在進行中 -ERRCODE.CMS.CONTENTCORE.DEL_CONTENT_ERR=只能刪除初稿和已下線內容 -ERRCODE.CMS.CONTENTCORE.RESOURCE_ACCEPT_SIZE_LIMIT=上傳文件大小超過限制 -ERRCODE.CMS.CONTENTCORE.UNSUPPORTED_RESOURCE_STORAGE=資源存儲方式與當前站點配置不一致 -ERRCODE.CMS.CONTENTCORE.MERGE_CATALOG_IS_EMPTY=被合並欄目不存在 -ERRCODE.CMS.CONTENTCORE.MERGE_CATALOG_NOT_LEAF=被合並欄目不能包含子欄目 -ERRCODE.CMS.CONTENTCORE.DENY_LINK_TO_LINK_INTERNAL_DATA=不能链接到链接内容或栏目 - -# freemarker模板標籤 -FREEMARKER.TAG.cms_site.NAME=站點列表標籤 -FREEMARKER.TAG.cms_site.DESC=獲取站點數據列表,內嵌`<#list DataList as site>${catalog.site}`遍曆數據 -FREEMARKER.TAG.cms_site.id=站點ID -FREEMARKER.TAG.cms_site.level=數據獲取範圍,值為`Root`時忽略屬性`id` -FREEMARKER.TAG.cms_site.level.Root=所有站點 -FREEMARKER.TAG.cms_site.level.Current=同級站點 -FREEMARKER.TAG.cms_site.level.Child=子站點 -FREEMARKER.TAG.cms_catalog.NAME=欄目列表標籤 -FREEMARKER.TAG.cms_catalog.DESC=獲取欄目數據列表,內嵌`<#list DataList as catalog>${catalog.name}`遍曆數據 -FREEMARKER.TAG.cms_catalog.id=欄目ID -FREEMARKER.TAG.cms_catalog.alias=欄目別名 -FREEMARKER.TAG.cms_catalog.level=數據獲取範圍,值為`Root`時忽略屬性`id`、`alias` -FREEMARKER.TAG.cms_catalog.level.Root=所有欄目 -FREEMARKER.TAG.cms_catalog.level.Current=同級欄目 -FREEMARKER.TAG.cms_catalog.level.Child=子欄目 -FREEMARKER.TAG.cms_catalog.level.CurrentAndChild=當前欄目及子欄目 -FREEMARKER.TAG.cms_catalog.level.Self=當前欄目 -FREEMARKER.TAG.cms_content.NAME=內容列表標籤 -FREEMARKER.TAG.cms_content.DESC=獲取內容數據列表,內嵌`<#list DataList as content>${content.name}`遍曆數據 -FREEMARKER.TAG.cms_content.catalogId=欄目ID -FREEMARKER.TAG.cms_content.catalogAlias=欄目別名 -FREEMARKER.TAG.cms_content.level=數據獲取範圍,值為`Root`時忽略屬性`catalogid`、`catalogalias` -FREEMARKER.TAG.cms_content.level.Root=所有欄目 -FREEMARKER.TAG.cms_content.level.Current=當前欄目 -FREEMARKER.TAG.cms_content.level.Child=子欄目 -FREEMARKER.TAG.cms_content.level.CurrentAndChild=當前欄目及子欄目 -FREEMARKER.TAG.cms_content.sort=排序方式 -FREEMARKER.TAG.cms_content.sort.Recent=發佈時間降序 -FREEMARKER.TAG.cms_content.sort.Views=瀏覽量降序 -FREEMARKER.TAG.cms_content.sort.Default=排序字段降序(默認) -FREEMARKER.TAG.cms_content.hasattribute=包含內容屬性,多個屬性英文逗號分隔 -FREEMARKER.TAG.cms_content.noattribute=不包含內容屬性,多個屬性英文逗號分隔 -FREEMARKER.TAG.cms_content.status=狀態,'-1'表示不限制狀態 -FREEMARKER.TAG.cms_content.status.defaultValue=30: 已發佈 -FREEMARKER.TAG.cms_content.topflag=是否允許指定 -FREEMARKER.TAG.cms_site_property.NAME=站點自定義屬性標籤 -FREEMARKER.TAG.cms_site_property.DESC=獲取站點自定義屬性數據列表,內嵌`<#list DataList as prop>${prop.propName}`遍曆數據 -FREEMARKER.TAG.cms_site_property.siteid=站點ID,默認從模板變量中獲取`${Site.siteId}` -FREEMARKER.TAG.cms_site_property.code=屬性編碼 -FREEMARKER.TAG.cms_include.NAME=模板引用標籤 -FREEMARKER.TAG.cms_include.DESC=引用其他模板內容,支援ssi引用標籤 -FREEMARKER.TAG.cms_include.file=引用模板文件路徑(相對模板目錄template/) -FREEMARKER.TAG.cms_include.ssi=是否啟用SSI -FREEMARKER.TAG.cms_include.virtual=是否啟用Virtual模式 -FREEMARKER.TAG.cms_include.cache=是否啟用緩存 -FREEMARKER.TAG.cms_pagewidget.NAME=頁面部件引用標籤 -FREEMARKER.TAG.cms_pagewidget.DESC=引用頁面部件內容,支援ssi引用標籤 -FREEMARKER.TAG.cms_pagewidget.code=頁面部件編碼 -FREEMARKER.TAG.cms_pagewidget.ssi=是否啟用SSI -FREEMARKER.TAG.cms_pagewidget_data.NAME=頁面部件數據標籤 -FREEMARKER.TAG.cms_pagewidget_data.DESC=頁面部件數據標籤,標籤體內可使用`${Data.name}`獲取數據 -FREEMARKER.TAG.cms_pagewidget_data.code=頁面部件編碼 -FREEMARKER.TAG.cms_content_closest.NAME=內容前後篇標籤 -FREEMARKER.TAG.cms_content_closest.DESC=內容前後篇標籤,僅支援指定內容當前欄目列表,標籤體內可使用`${Data.title}`獲取數據 -FREEMARKER.TAG.cms_content_closest.contentId=內容ID -FREEMARKER.TAG.cms_content_closest.type=類型 -FREEMARKER.TAG.cms_content_closest.type.Prev=上一篇 -FREEMARKER.TAG.cms_content_closest.type.Next=下一篇 -FREEMARKER.TAG.cms_content_closest.sort=排序方式 -FREEMARKER.TAG.cms_content_rela.NAME=相關內容標籤 -FREEMARKER.TAG.cms_content_rela.DESC=相關內容標籤,內嵌`<#list DataList as content>${content.name}`遍曆數據 -FREEMARKER.TAG.cms_content_rela.contentId=內容ID - -# freemarker模板函數 -FREEMARKER.FUNC.htmlInternalUrl.DESC=將html文本中的內部連結地址“iurl://”解析為正常http(s)訪問地址,例如:`${htmlInternalUrl(ArticleContent)}` -FREEMARKER.FUNC.htmlInternalUrl.Arg1.Name=Html文本內容 -FREEMARKER.FUNC.imageSize.DESC=獲得圖片縮放圖函數,不在的縮略圖會自動建立,例如:`${imageSize(content.logo, 300, 300)}` -FREEMARKER.FUNC.imageSize.Arg1.Name=圖片資源內部路徑(iurl://) -FREEMARKER.FUNC.imageSize.Arg1.Desc=僅支持處理內部資源圖片(iurl://) -FREEMARKER.FUNC.imageSize.Arg2.Name=寬度 -FREEMARKER.FUNC.imageSize.Arg3.Name=高度 -FREEMARKER.FUNC.internalUrl.DESC=將內部連結“iurl://”解析為正常http(s)訪問地址,例如:`${internalUrl(content.redirectUrl)}` -FREEMARKER.FUNC.internalUrl.Arg1.Name=內部鏈接(iurl://) -FREEMARKER.FUNC.siteUrl.DESC=獲取站點指定發布通道訪問連結,例如:`${siteUrl(Site.siteId, 'h5')}` -FREEMARKER.FUNC.siteUrl.Arg1.Name=站點ID -FREEMARKER.FUNC.siteUrl.Arg2.Name=發佈通道編碼 -FREEMARKER.FUNC.catalogUrl.DESC=獲取欄目指定發布通道訪問連結,例如:`${catalogUrl(Catalog.catalogId, 'h5')}` -FREEMARKER.FUNC.catalogUrl.Arg1.Name=欄目ID -FREEMARKER.FUNC.catalogUrl.Arg2.Name=發佈通道編碼 -FREEMARKER.FUNC.contentUrl.DESC=獲取內容指定發布通道訪問連結,例如:`${contentUrl(Content.contentId, 'h5')}` -FREEMARKER.FUNC.contentUrl.Arg1.Name=內容ID -FREEMARKER.FUNC.contentUrl.Arg2.Name=發佈通道編碼 -FREEMARKER.FUNC.dynamicPageLink.DESC=動態頁面連結獲取函數,例如:`${dynamicPageLink('Search')}` -FREEMARKER.FUNC.dynamicPageLink.Arg1.Name=動態頁面類型 -FREEMARKER.FUNC.dynamicPageLink.Arg2.Name=忽略`sid/pp`參數 -FREEMARKER.FUNC.dict.DESC=獲取字典數據列表,例如:`${dict('YesOrNo', 'Y')}` -FREEMARKER.FUNC.dict.Arg1.Name=字典類型 -FREEMARKER.FUNC.dict.Arg2.Name=字典數據值 -FREEMARKER.FUNC.dict.Arg3.Name=國際化標識 -FREEMARKER.FUNC.sysConfig.DESC=獲取系統參數配置值,例如:`${sysConfig('SiteApiUrl')}` -FREEMARKER.FUNC.sysConfig.Arg1.Name=系統參數鍵名 -FREEMARKER.FUNC.listHtmlInternalUrl.DESC=獲取html文本中的iurl列表,例如:`${listHtmlInternalUrl(ArticleContent)}` -FREEMARKER.FUNC.listHtmlInternalUrl.Arg1.Name=Html文本內容 -FREEMARKER.FUNC.contentPageLink.DESC=獲取內容分頁鏈接,例如:`${contentPageLink(content.link, 2)}` -FREEMARKER.FUNC.contentPageLink.Arg1.Name=內容鏈接 -FREEMARKER.FUNC.contentPageLink.Arg2.Name=頁碼 -FREEMARKER.FUNC.videoPlayer.DESC=將html文本中的視頻資源連結替換為