mirror of
https://gitee.com/liweiyi/ChestnutCMS.git
synced 2025-12-06 16:38:24 +08:00
版本更新到 1.4.2
This commit is contained in:
parent
85cab07588
commit
01adc9f252
@ -1,4 +1,4 @@
|
|||||||
# ChestnutCMS v1.4.1
|
# ChestnutCMS v1.4.2
|
||||||
|
|
||||||
### 系统简介
|
### 系统简介
|
||||||
|
|
||||||
@ -20,6 +20,8 @@ ChestnutCMS是前后端分离的企业级内容管理系统。项目基于[RuoYi
|
|||||||
|
|
||||||
游戏站演示地址:PC端:<http://game.1000mz.com> 移动端:<http://mgame.1000mz.com>
|
游戏站演示地址:PC端:<http://game.1000mz.com> 移动端:<http://mgame.1000mz.com>
|
||||||
|
|
||||||
|
影视站演示地址:PC端:<http://movie.1000mz.com> 移动端:<http://movie.1000mz.com>
|
||||||
|
|
||||||
### 开发环境
|
### 开发环境
|
||||||
- OpenJDK 17
|
- OpenJDK 17
|
||||||
- Maven 3.8+
|
- Maven 3.8+
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>chestnut</artifactId>
|
<artifactId>chestnut</artifactId>
|
||||||
<groupId>com.chestnut</groupId>
|
<groupId>com.chestnut</groupId>
|
||||||
<version>1.4.1</version>
|
<version>1.4.2</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|||||||
@ -5,7 +5,7 @@ chestnut:
|
|||||||
# 代号
|
# 代号
|
||||||
alias: ChestnutCMS
|
alias: ChestnutCMS
|
||||||
# 版本
|
# 版本
|
||||||
version: 1.4.1
|
version: 1.4.2
|
||||||
# 版权年份
|
# 版权年份
|
||||||
copyrightYear: 2022-2024
|
copyrightYear: 2022-2024
|
||||||
system:
|
system:
|
||||||
|
|||||||
@ -5,7 +5,7 @@ chestnut:
|
|||||||
# 代号
|
# 代号
|
||||||
alias: ChestnutCMS
|
alias: ChestnutCMS
|
||||||
# 版本
|
# 版本
|
||||||
version: 1.4.1
|
version: 1.4.2
|
||||||
# 版权年份
|
# 版权年份
|
||||||
copyrightYear: 2022-2024
|
copyrightYear: 2022-2024
|
||||||
system:
|
system:
|
||||||
|
|||||||
@ -5,7 +5,7 @@ chestnut:
|
|||||||
# 代号
|
# 代号
|
||||||
alias: ChestnutCMS
|
alias: ChestnutCMS
|
||||||
# 版本
|
# 版本
|
||||||
version: 1.4.1
|
version: 1.4.2
|
||||||
# 版权年份
|
# 版权年份
|
||||||
copyrightYear: 2022-2024
|
copyrightYear: 2022-2024
|
||||||
system:
|
system:
|
||||||
|
|||||||
@ -1,3 +1,22 @@
|
|||||||
|
CREATE TABLE `cms_site_visit_log` (
|
||||||
|
`log_id` bigint NOT NULL,
|
||||||
|
`site_id` bigint NOT NULL,
|
||||||
|
`catalog_id` bigint DEFAULT NULL,
|
||||||
|
`content_id` bigint DEFAULT NULL,
|
||||||
|
`host` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL,
|
||||||
|
`uri` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL,
|
||||||
|
`ip` varchar(100) COLLATE utf8mb4_general_ci DEFAULT NULL,
|
||||||
|
`address` varchar(100) COLLATE utf8mb4_general_ci DEFAULT NULL,
|
||||||
|
`referer` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL,
|
||||||
|
`browser` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL,
|
||||||
|
`user_agent` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
|
||||||
|
`os` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL,
|
||||||
|
`device_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
|
||||||
|
`locale` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL,
|
||||||
|
`evt_time` datetime NOT NULL,
|
||||||
|
PRIMARY KEY (`log_id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||||
|
|
||||||
CREATE TABLE `cms_dynamic_page` (
|
CREATE TABLE `cms_dynamic_page` (
|
||||||
`page_id` bigint NOT NULL COMMENT 'ID',
|
`page_id` bigint NOT NULL COMMENT 'ID',
|
||||||
`site_id` bigint NOT NULL COMMENT '站点ID',
|
`site_id` bigint NOT NULL COMMENT '站点ID',
|
||||||
|
|||||||
@ -0,0 +1,30 @@
|
|||||||
|
CREATE TABLE `search_word` (
|
||||||
|
`word_id` bigint NOT NULL COMMENT '主键ID',
|
||||||
|
`word` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '搜索词',
|
||||||
|
`search_total` bigint NOT NULL COMMENT '历史累计搜索次数',
|
||||||
|
`top_flag` bigint NOT NULL COMMENT '置顶标识',
|
||||||
|
`top_date` datetime DEFAULT NULL COMMENT '置顶结束时间',
|
||||||
|
`source` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '来源标识',
|
||||||
|
`create_by` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '创建人',
|
||||||
|
`create_time` datetime NOT NULL COMMENT '创建时间',
|
||||||
|
`update_by` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '最后修改人',
|
||||||
|
`update_time` datetime DEFAULT NULL COMMENT '最后修改时间',
|
||||||
|
`remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '备注',
|
||||||
|
PRIMARY KEY (`word_id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||||
|
|
||||||
|
CREATE TABLE `search_word_hour_stat` (
|
||||||
|
`stat_id` bigint NOT NULL AUTO_INCREMENT,
|
||||||
|
`hour` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
||||||
|
`word_id` bigint NOT NULL,
|
||||||
|
`word` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
||||||
|
`search_count` bigint NOT NULL,
|
||||||
|
PRIMARY KEY (`stat_id`)
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||||
|
# 菜单名称路由调整
|
||||||
|
UPDATE sys_menu SET component = 'search/wordTab', path = 'searchWord' where menu_id = 2053;
|
||||||
|
|
||||||
|
ALTER TABLE cms_content ADD COLUMN prop1 VARCHAR(100);
|
||||||
|
ALTER TABLE cms_content ADD COLUMN prop2 VARCHAR(100);
|
||||||
|
ALTER TABLE cms_content ADD COLUMN prop3 VARCHAR(255);
|
||||||
|
ALTER TABLE cms_content ADD COLUMN prop4 VARCHAR(255);
|
||||||
@ -7,7 +7,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.chestnut</groupId>
|
<groupId>com.chestnut</groupId>
|
||||||
<artifactId>chestnut-cms</artifactId>
|
<artifactId>chestnut-cms</artifactId>
|
||||||
<version>1.4.1</version>
|
<version>1.4.2</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>chestnut-cms-advertisement</artifactId>
|
<artifactId>chestnut-cms-advertisement</artifactId>
|
||||||
|
|||||||
@ -77,8 +77,17 @@ public class AdLogController extends BaseRestController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/chart")
|
@GetMapping("/chart")
|
||||||
public R<?> getLineChartStatDatas(@RequestParam @Min(1) Long advertisementId, @RequestParam Date beginTime, @RequestParam Date endTime) {
|
public R<?> getLineChartStatDatas(
|
||||||
List<CmsAdHourStat> list = this.advHourStatMapper.selectHourStat(advertisementId, FORMAT.format(beginTime), FORMAT.format(endTime));
|
@RequestParam @Min(1) Long advertisementId,
|
||||||
|
@RequestParam Date beginTime,
|
||||||
|
@RequestParam Date endTime
|
||||||
|
) {
|
||||||
|
LambdaQueryWrapper<CmsAdHourStat> q = new LambdaQueryWrapper<CmsAdHourStat>()
|
||||||
|
.eq(CmsAdHourStat::getAdvertisementId, advertisementId)
|
||||||
|
.gt(Objects.nonNull(beginTime), CmsAdHourStat::getHour, beginTime)
|
||||||
|
.gt(Objects.nonNull(endTime), CmsAdHourStat::getHour, endTime)
|
||||||
|
.orderByAsc(CmsAdHourStat::getHour);
|
||||||
|
List<CmsAdHourStat> list = this.advHourStatMapper.selectList(q);
|
||||||
if (!list.isEmpty()) {
|
if (!list.isEmpty()) {
|
||||||
Map<String, String> map = this.advService.getAdvertisementMap();
|
Map<String, String> map = this.advService.getAdvertisementMap();
|
||||||
list.forEach(l -> l.setAdName(map.get(l.getAdvertisementId().toString())));
|
list.forEach(l -> l.setAdName(map.get(l.getAdvertisementId().toString())));
|
||||||
|
|||||||
@ -25,18 +25,6 @@ import com.chestnut.advertisement.domain.CmsAdHourStat;
|
|||||||
|
|
||||||
public interface CmsAdHourStatMapper extends BaseMapper<CmsAdHourStat> {
|
public interface CmsAdHourStatMapper extends BaseMapper<CmsAdHourStat> {
|
||||||
|
|
||||||
@Select("""
|
|
||||||
<script>
|
|
||||||
SELECT * FROM `cms_ad_hour_stat`
|
|
||||||
WHERE advertisement_id = #{advertisementId}
|
|
||||||
<if test='begin != null'> and hour >= #{begin} </if>
|
|
||||||
<if test='end != null'> and hour <= #{end} </if>
|
|
||||||
ORDER BY hour ASC
|
|
||||||
</script>
|
|
||||||
""")
|
|
||||||
public List<CmsAdHourStat> selectHourStat(@Param("advertisementId") Long advertisementId,
|
|
||||||
@Param("begin") String begin, @Param("end") String end);
|
|
||||||
|
|
||||||
@Select("""
|
@Select("""
|
||||||
<script>
|
<script>
|
||||||
SELECT advertisement_id, sum(click) click, sum(view) view FROM `cms_ad_hour_stat`
|
SELECT advertisement_id, sum(click) click, sum(view) view FROM `cms_ad_hour_stat`
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.chestnut</groupId>
|
<groupId>com.chestnut</groupId>
|
||||||
<artifactId>chestnut-cms</artifactId>
|
<artifactId>chestnut-cms</artifactId>
|
||||||
<version>1.4.1</version>
|
<version>1.4.2</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>chestnut-cms-article</artifactId>
|
<artifactId>chestnut-cms-article</artifactId>
|
||||||
|
|||||||
@ -16,7 +16,6 @@
|
|||||||
package com.chestnut.article.template.func;
|
package com.chestnut.article.template.func;
|
||||||
|
|
||||||
import com.chestnut.article.ArticleUtils;
|
import com.chestnut.article.ArticleUtils;
|
||||||
import com.chestnut.article.service.IArticleService;
|
|
||||||
import com.chestnut.common.staticize.FreeMarkerUtils;
|
import com.chestnut.common.staticize.FreeMarkerUtils;
|
||||||
import com.chestnut.common.staticize.core.TemplateContext;
|
import com.chestnut.common.staticize.core.TemplateContext;
|
||||||
import com.chestnut.common.staticize.func.AbstractFunc;
|
import com.chestnut.common.staticize.func.AbstractFunc;
|
||||||
@ -41,8 +40,6 @@ public class dealArticleBodyFunction extends AbstractFunc {
|
|||||||
|
|
||||||
private static final String DESC = "{FREEMARKER.FUNC.DESC." + FUNC_NAME + "}";
|
private static final String DESC = "{FREEMARKER.FUNC.DESC." + FUNC_NAME + "}";
|
||||||
|
|
||||||
private final IArticleService articleService;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getFuncName() {
|
public String getFuncName() {
|
||||||
return FUNC_NAME;
|
return FUNC_NAME;
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.chestnut</groupId>
|
<groupId>com.chestnut</groupId>
|
||||||
<artifactId>chestnut-cms</artifactId>
|
<artifactId>chestnut-cms</artifactId>
|
||||||
<version>1.4.1</version>
|
<version>1.4.2</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>chestnut-cms-block</artifactId>
|
<artifactId>chestnut-cms-block</artifactId>
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.chestnut</groupId>
|
<groupId>com.chestnut</groupId>
|
||||||
<artifactId>chestnut-cms</artifactId>
|
<artifactId>chestnut-cms</artifactId>
|
||||||
<version>1.4.1</version>
|
<version>1.4.2</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>chestnut-cms-comment</artifactId>
|
<artifactId>chestnut-cms-comment</artifactId>
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.chestnut</groupId>
|
<groupId>com.chestnut</groupId>
|
||||||
<artifactId>chestnut-cms</artifactId>
|
<artifactId>chestnut-cms</artifactId>
|
||||||
<version>1.4.1</version>
|
<version>1.4.2</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>chestnut-cms-contentcore</artifactId>
|
<artifactId>chestnut-cms-contentcore</artifactId>
|
||||||
|
|||||||
@ -16,6 +16,7 @@
|
|||||||
package com.chestnut.contentcore.controller;
|
package com.chestnut.contentcore.controller;
|
||||||
|
|
||||||
import com.chestnut.common.domain.R;
|
import com.chestnut.common.domain.R;
|
||||||
|
import com.chestnut.common.i18n.I18nUtils;
|
||||||
import com.chestnut.common.security.anno.Priv;
|
import com.chestnut.common.security.anno.Priv;
|
||||||
import com.chestnut.common.security.web.BaseRestController;
|
import com.chestnut.common.security.web.BaseRestController;
|
||||||
import com.chestnut.common.staticize.StaticizeService;
|
import com.chestnut.common.staticize.StaticizeService;
|
||||||
@ -24,6 +25,7 @@ import com.chestnut.common.utils.Assert;
|
|||||||
import com.chestnut.common.utils.ServletUtils;
|
import com.chestnut.common.utils.ServletUtils;
|
||||||
import com.chestnut.contentcore.core.IInternalDataType;
|
import com.chestnut.contentcore.core.IInternalDataType;
|
||||||
import com.chestnut.contentcore.domain.CmsSite;
|
import com.chestnut.contentcore.domain.CmsSite;
|
||||||
|
import com.chestnut.contentcore.domain.vo.DynamicPageTypeVO;
|
||||||
import com.chestnut.contentcore.exception.ContentCoreErrorCode;
|
import com.chestnut.contentcore.exception.ContentCoreErrorCode;
|
||||||
import com.chestnut.contentcore.service.ISiteService;
|
import com.chestnut.contentcore.service.ISiteService;
|
||||||
import com.chestnut.contentcore.service.ITemplateService;
|
import com.chestnut.contentcore.service.ITemplateService;
|
||||||
@ -44,6 +46,7 @@ import org.springframework.web.bind.annotation.RestController;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
@ -154,6 +157,11 @@ public class CoreController extends BaseRestController {
|
|||||||
@Priv(type = AdminUserType.TYPE)
|
@Priv(type = AdminUserType.TYPE)
|
||||||
@GetMapping("/cms/dynamicPageTypes")
|
@GetMapping("/cms/dynamicPageTypes")
|
||||||
public R<?> getDynamicPageTypes() {
|
public R<?> getDynamicPageTypes() {
|
||||||
return R.ok(ContentCoreUtils.getDynamicPageTypes());
|
List<DynamicPageTypeVO> list = ContentCoreUtils.getDynamicPageTypes().stream()
|
||||||
|
.map(DynamicPageTypeVO::newInstance).toList();
|
||||||
|
list.forEach( vo ->
|
||||||
|
vo.setName(I18nUtils.get(vo.getName()))
|
||||||
|
);
|
||||||
|
return R.ok(list);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -100,6 +100,7 @@ public class TemplateController extends BaseRestController {
|
|||||||
.filesize(t.getFilesize())
|
.filesize(t.getFilesize())
|
||||||
.filesizeName(FileUtils.byteCountToDisplaySize(t.getFilesize()))
|
.filesizeName(FileUtils.byteCountToDisplaySize(t.getFilesize()))
|
||||||
.modifyTime(DateUtils.epochMilliToLocalDateTime(t.getModifyTime()))
|
.modifyTime(DateUtils.epochMilliToLocalDateTime(t.getModifyTime()))
|
||||||
|
.remark(t.getRemark())
|
||||||
.build()).toList();
|
.build()).toList();
|
||||||
return this.bindDataTable(list, (int) page.getTotal());
|
return this.bindDataTable(list, (int) page.getTotal());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -97,9 +97,9 @@ public class SiteExportContext implements ISiteThemeContext {
|
|||||||
* @param dest 目标路径,项目资源根目录(resourceRoot)
|
* @param dest 目标路径,项目资源根目录(resourceRoot)
|
||||||
*/
|
*/
|
||||||
public void saveFile(File source, String dest) {
|
public void saveFile(File source, String dest) {
|
||||||
|
dest = ExportDir + SiteDirPath + dest;
|
||||||
File destFile = new File(SiteUtils.getSiteResourceRoot(site) + dest);
|
File destFile = new File(SiteUtils.getSiteResourceRoot(site) + dest);
|
||||||
try {
|
try {
|
||||||
dest = ExportDir + SiteDirPath + dest;
|
|
||||||
if (source.isDirectory()) {
|
if (source.isDirectory()) {
|
||||||
FileUtils.copyDirectory(source, destFile);
|
FileUtils.copyDirectory(source, destFile);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -288,6 +288,26 @@ public class CmsContent extends BaseEntityWithLogicDelete {
|
|||||||
*/
|
*/
|
||||||
@TableField(typeHandler = JacksonTypeHandler.class)
|
@TableField(typeHandler = JacksonTypeHandler.class)
|
||||||
private Map<String, Object> configProps;
|
private Map<String, Object> configProps;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 备用字段1
|
||||||
|
*/
|
||||||
|
private String prop1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 备用字段2
|
||||||
|
*/
|
||||||
|
private String prop2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 备用字段3
|
||||||
|
*/
|
||||||
|
private String prop3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 备用字段4
|
||||||
|
*/
|
||||||
|
private String prop4;
|
||||||
|
|
||||||
public boolean isLock() {
|
public boolean isLock() {
|
||||||
return YesOrNo.isYes(this.isLock);
|
return YesOrNo.isYes(this.isLock);
|
||||||
|
|||||||
@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2022-2024 兮玥(190785909@qq.com)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.chestnut.contentcore.domain.vo;
|
||||||
|
|
||||||
|
import com.chestnut.contentcore.core.IDynamicPageType;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class DynamicPageTypeVO {
|
||||||
|
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private String desc;
|
||||||
|
|
||||||
|
private String requestPath;
|
||||||
|
|
||||||
|
private String publishPipeKey;
|
||||||
|
|
||||||
|
private List<IDynamicPageType.RequestArg> requestArgs;
|
||||||
|
|
||||||
|
public static DynamicPageTypeVO newInstance(IDynamicPageType dynamicPageType) {
|
||||||
|
DynamicPageTypeVO vo = new DynamicPageTypeVO();
|
||||||
|
vo.setType(dynamicPageType.getType());
|
||||||
|
vo.setName(dynamicPageType.getName());
|
||||||
|
vo.setDesc(dynamicPageType.getDesc());
|
||||||
|
vo.setRequestPath(dynamicPageType.getRequestPath());
|
||||||
|
vo.setPublishPipeKey(dynamicPageType.getPublishPipeKey());
|
||||||
|
vo.setRequestArgs(dynamicPageType.getRequestArgs());
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -54,4 +54,6 @@ public class TemplateListVO {
|
|||||||
* 模板文件最后变更时间
|
* 模板文件最后变更时间
|
||||||
*/
|
*/
|
||||||
private LocalDateTime modifyTime;
|
private LocalDateTime modifyTime;
|
||||||
|
|
||||||
|
private String remark;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -36,12 +36,12 @@ public interface ISiteService extends IService<CmsSite> {
|
|||||||
* @param siteId
|
* @param siteId
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public boolean checkSiteUnique(String siteName, String sitePath, Long siteId);
|
boolean checkSiteUnique(String siteName, String sitePath, Long siteId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取当前站点,保存在token中
|
* 获取当前站点,保存在token中
|
||||||
*/
|
*/
|
||||||
public CmsSite getCurrentSite(HttpServletRequest request);
|
CmsSite getCurrentSite(HttpServletRequest request);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取站点数据
|
* 获取站点数据
|
||||||
@ -49,7 +49,7 @@ public interface ISiteService extends IService<CmsSite> {
|
|||||||
* @param siteId
|
* @param siteId
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public CmsSite getSite(Long siteId);
|
CmsSite getSite(Long siteId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 新增站点数据
|
* 新增站点数据
|
||||||
@ -58,7 +58,7 @@ public interface ISiteService extends IService<CmsSite> {
|
|||||||
* @return
|
* @return
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public CmsSite addSite(SiteDTO dto) throws IOException;
|
CmsSite addSite(SiteDTO dto) throws IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 修改站点数据
|
* 修改站点数据
|
||||||
@ -67,7 +67,7 @@ public interface ISiteService extends IService<CmsSite> {
|
|||||||
* @return
|
* @return
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public CmsSite saveSite(SiteDTO site) throws IOException;
|
CmsSite saveSite(SiteDTO site) throws IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除站点数据
|
* 删除站点数据
|
||||||
@ -76,7 +76,7 @@ public interface ISiteService extends IService<CmsSite> {
|
|||||||
* @return
|
* @return
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public void deleteSite(Long siteId) throws IOException;
|
void deleteSite(Long siteId) throws IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 保存站点默认模板配置
|
* 保存站点默认模板配置
|
||||||
@ -84,7 +84,7 @@ public interface ISiteService extends IService<CmsSite> {
|
|||||||
* @param dto
|
* @param dto
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public void saveSiteDefaultTemplate(SiteDefaultTemplateDTO dto);
|
void saveSiteDefaultTemplate(SiteDefaultTemplateDTO dto);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 清理站点缓存数据
|
* 清理站点缓存数据
|
||||||
|
|||||||
@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2022-2024 兮玥(190785909@qq.com)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.chestnut.contentcore.template.func;
|
||||||
|
|
||||||
|
import com.chestnut.common.staticize.FreeMarkerUtils;
|
||||||
|
import com.chestnut.common.staticize.core.TemplateContext;
|
||||||
|
import com.chestnut.common.staticize.func.AbstractFunc;
|
||||||
|
import com.chestnut.common.utils.StringUtils;
|
||||||
|
import com.chestnut.contentcore.service.ICatalogService;
|
||||||
|
import freemarker.core.Environment;
|
||||||
|
import freemarker.template.SimpleNumber;
|
||||||
|
import freemarker.template.TemplateModelException;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Freemarker模板自定义函数:获取内容分页链接
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class ContentPageLinkFunction extends AbstractFunc {
|
||||||
|
|
||||||
|
private static final String FUNC_NAME = "contentPageLink";
|
||||||
|
|
||||||
|
private static final String DESC = "{FREEMARKER.FUNC.DESC." + FUNC_NAME + "}";
|
||||||
|
|
||||||
|
private final ICatalogService catalogService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getFuncName() {
|
||||||
|
return FUNC_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDesc() {
|
||||||
|
return DESC;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object exec0(Object... args) throws TemplateModelException {
|
||||||
|
if (args.length == 0) {
|
||||||
|
return StringUtils.EMPTY;
|
||||||
|
}
|
||||||
|
String link = args[0].toString();
|
||||||
|
if (args.length == 1) {
|
||||||
|
return link;
|
||||||
|
}
|
||||||
|
int pageNumber = ((SimpleNumber) args[1]).getAsNumber().intValue();
|
||||||
|
if(pageNumber <= 1) {
|
||||||
|
return link;
|
||||||
|
}
|
||||||
|
TemplateContext context = FreeMarkerUtils.getTemplateContext(Environment.getCurrentEnvironment());
|
||||||
|
if (context.isPreview()) {
|
||||||
|
link += "&pi=" + pageNumber;
|
||||||
|
} else {
|
||||||
|
int dotIndex = link.lastIndexOf(StringUtils.DOT);
|
||||||
|
link = link.substring(0, dotIndex) + "_" + pageNumber + link.substring(dotIndex);
|
||||||
|
}
|
||||||
|
return link;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<FuncArg> getFuncArgs() {
|
||||||
|
return List.of(new FuncArg("内容链接", FuncArgType.String, true, null),
|
||||||
|
new FuncArg("页码", FuncArgType.Int, true, null));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -16,6 +16,7 @@
|
|||||||
package com.chestnut.contentcore.template.func;
|
package com.chestnut.contentcore.template.func;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@ -58,6 +59,9 @@ public class InternalUrlFunction extends AbstractFunc {
|
|||||||
}
|
}
|
||||||
TemplateContext context = FreeMarkerUtils.getTemplateContext(Environment.getCurrentEnvironment());
|
TemplateContext context = FreeMarkerUtils.getTemplateContext(Environment.getCurrentEnvironment());
|
||||||
SimpleScalar simpleScalar = (SimpleScalar) args[0];
|
SimpleScalar simpleScalar = (SimpleScalar) args[0];
|
||||||
|
if (Objects.isNull(simpleScalar)) {
|
||||||
|
return StringUtils.EMPTY;
|
||||||
|
}
|
||||||
return InternalUrlUtils.getActualUrl(simpleScalar.getAsString(), context.getPublishPipeCode(), context.isPreview());
|
return InternalUrlUtils.getActualUrl(simpleScalar.getAsString(), context.getPublishPipeCode(), context.isPreview());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -129,7 +129,7 @@ public class CmsContentTag extends AbstractListTag {
|
|||||||
|
|
||||||
TemplateContext context = FreeMarkerUtils.getTemplateContext(env);
|
TemplateContext context = FreeMarkerUtils.getTemplateContext(env);
|
||||||
Page<CmsContent> pageResult = this.contentService.page(new Page<>(pageIndex, size, page), q);
|
Page<CmsContent> pageResult = this.contentService.page(new Page<>(pageIndex, size, page), q);
|
||||||
if (pageIndex > 1 & pageResult.getRecords().size() == 0) {
|
if (pageIndex > 1 & pageResult.getRecords().isEmpty()) {
|
||||||
throw new TemplateException("内容列表页码超出上限:" + pageIndex, env);
|
throw new TemplateException("内容列表页码超出上限:" + pageIndex, env);
|
||||||
}
|
}
|
||||||
List<ContentDTO> list = new ArrayList<>();
|
List<ContentDTO> list = new ArrayList<>();
|
||||||
|
|||||||
@ -73,7 +73,7 @@ public class CmsSitePropertyTag extends AbstractListTag {
|
|||||||
.eq(StringUtils.isNotEmpty(code), CmsSiteProperty::getPropCode, code);
|
.eq(StringUtils.isNotEmpty(code), CmsSiteProperty::getPropCode, code);
|
||||||
q.apply(StringUtils.isNotEmpty(condition), condition);
|
q.apply(StringUtils.isNotEmpty(condition), condition);
|
||||||
Page<CmsSiteProperty> pageResult = this.sitePropertyService.page(new Page<>(pageIndex, size, page), q);
|
Page<CmsSiteProperty> pageResult = this.sitePropertyService.page(new Page<>(pageIndex, size, page), q);
|
||||||
if (pageIndex > 1 & pageResult.getRecords().size() == 0) {
|
if (pageIndex > 1 & pageResult.getRecords().isEmpty()) {
|
||||||
throw new TemplateException("站点自定义属性数据列表页码超出上限:" + pageIndex, env);
|
throw new TemplateException("站点自定义属性数据列表页码超出上限:" + pageIndex, env);
|
||||||
}
|
}
|
||||||
return TagPageData.of(pageResult.getRecords(), pageResult.getTotal());
|
return TagPageData.of(pageResult.getRecords(), pageResult.getTotal());
|
||||||
|
|||||||
@ -106,6 +106,7 @@ FREEMARKER.FUNC.DESC.dynamicPageLink=动态页面链接获取函数,例如:$
|
|||||||
FREEMARKER.FUNC.DESC.dict=获取字典数据列表,例如:${dict('YesOrNo', 'Y')}
|
FREEMARKER.FUNC.DESC.dict=获取字典数据列表,例如:${dict('YesOrNo', 'Y')}
|
||||||
FREEMARKER.FUNC.DESC.sysConfig=获取系统参数配置值,例如:${sysConfig('SiteApiUrl')}
|
FREEMARKER.FUNC.DESC.sysConfig=获取系统参数配置值,例如:${sysConfig('SiteApiUrl')}
|
||||||
FREEMARKER.FUNC.DESC.listHtmlInternalUrl=获取html文本中的iurl列表,例如:${listHtmlInternalUrl(ArticleContent)}
|
FREEMARKER.FUNC.DESC.listHtmlInternalUrl=获取html文本中的iurl列表,例如:${listHtmlInternalUrl(ArticleContent)}
|
||||||
|
FREEMARKER.FUNC.DESC.contentPageLink=获取内容分页链接,例如:${contentPageLink(content.link, 2)}
|
||||||
FREEMARKER.FUNC.DESC.videoPlayer=将html文本中的视频资源链接替换为<video>视频播放器
|
FREEMARKER.FUNC.DESC.videoPlayer=将html文本中的视频资源链接替换为<video>视频播放器
|
||||||
FREEMARKER.FUNC.videoPlayer.Arg1.Name=Html文本内容
|
FREEMARKER.FUNC.videoPlayer.Arg1.Name=Html文本内容
|
||||||
FREEMARKER.FUNC.videoPlayer.Arg2.Name=视频宽度
|
FREEMARKER.FUNC.videoPlayer.Arg2.Name=视频宽度
|
||||||
|
|||||||
@ -106,6 +106,7 @@ FREEMARKER.FUNC.DESC.dynamicPageLink=Use ${dynamicPageLink('Search')} in templat
|
|||||||
FREEMARKER.FUNC.DESC.dict=Use ${dict(content.linkFlag, 'YesOrNo')} in template to get the dict data label.
|
FREEMARKER.FUNC.DESC.dict=Use ${dict(content.linkFlag, 'YesOrNo')} in template to get the dict data label.
|
||||||
FREEMARKER.FUNC.DESC.sysConfig=Use ${sysConfig('SiteApiUrl')} in template to get the system config value.
|
FREEMARKER.FUNC.DESC.sysConfig=Use ${sysConfig('SiteApiUrl')} in template to get the system config value.
|
||||||
FREEMARKER.FUNC.DESC.listHtmlInternalUrl=Use ${listHtmlInternalUrl(ArticleContent)} in template to get the iurl list.
|
FREEMARKER.FUNC.DESC.listHtmlInternalUrl=Use ${listHtmlInternalUrl(ArticleContent)} in template to get the iurl list.
|
||||||
|
FREEMARKER.FUNC.DESC.contentPageLink=Use ${contentPageLink(content.link, 2)} in template to get the content page link.
|
||||||
FREEMARKER.FUNC.DESC.videoPlayer=Replace html video resource link tag to video tag.
|
FREEMARKER.FUNC.DESC.videoPlayer=Replace html video resource link tag to video tag.
|
||||||
FREEMARKER.FUNC.videoPlayer.Arg1.Name=Html content
|
FREEMARKER.FUNC.videoPlayer.Arg1.Name=Html content
|
||||||
FREEMARKER.FUNC.videoPlayer.Arg2.Name=Width
|
FREEMARKER.FUNC.videoPlayer.Arg2.Name=Width
|
||||||
|
|||||||
@ -106,6 +106,7 @@ FREEMARKER.FUNC.DESC.dynamicPageLink=動態頁面連結獲取函數,例如:$
|
|||||||
FREEMARKER.FUNC.DESC.dict=獲取字典數據列表,例如:${dict('YesOrNo', 'Y')}
|
FREEMARKER.FUNC.DESC.dict=獲取字典數據列表,例如:${dict('YesOrNo', 'Y')}
|
||||||
FREEMARKER.FUNC.DESC.sysConfig=獲取系統參數配置值,例如:${sysConfig('SiteApiUrl')}
|
FREEMARKER.FUNC.DESC.sysConfig=獲取系統參數配置值,例如:${sysConfig('SiteApiUrl')}
|
||||||
FREEMARKER.FUNC.DESC.listHtmlInternalUrl=獲取html文本中的iurl列表,例如:${listHtmlInternalUrl(ArticleContent)}
|
FREEMARKER.FUNC.DESC.listHtmlInternalUrl=獲取html文本中的iurl列表,例如:${listHtmlInternalUrl(ArticleContent)}
|
||||||
|
FREEMARKER.FUNC.DESC.contentPageLink=獲取內容分頁鏈接,例如:${contentPageLink(content.link, 2)}
|
||||||
FREEMARKER.FUNC.DESC.videoPlayer=將html文本中的視頻資源連結替換為<video>視頻播放器
|
FREEMARKER.FUNC.DESC.videoPlayer=將html文本中的視頻資源連結替換為<video>視頻播放器
|
||||||
FREEMARKER.FUNC.videoPlayer.Arg1.Name=Html文本內容
|
FREEMARKER.FUNC.videoPlayer.Arg1.Name=Html文本內容
|
||||||
FREEMARKER.FUNC.videoPlayer.Arg2.Name=視頻寬度
|
FREEMARKER.FUNC.videoPlayer.Arg2.Name=視頻寬度
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.chestnut</groupId>
|
<groupId>com.chestnut</groupId>
|
||||||
<artifactId>chestnut-cms</artifactId>
|
<artifactId>chestnut-cms</artifactId>
|
||||||
<version>1.4.1</version>
|
<version>1.4.2</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>chestnut-cms-customform</artifactId>
|
<artifactId>chestnut-cms-customform</artifactId>
|
||||||
|
|||||||
@ -0,0 +1,216 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2022-2024 兮玥(190785909@qq.com)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.chestnut.customform;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.chestnut.common.async.AsyncTaskManager;
|
||||||
|
import com.chestnut.common.utils.IdUtils;
|
||||||
|
import com.chestnut.common.utils.JacksonUtils;
|
||||||
|
import com.chestnut.common.utils.StringUtils;
|
||||||
|
import com.chestnut.contentcore.core.ICoreDataHandler;
|
||||||
|
import com.chestnut.contentcore.core.SiteExportContext;
|
||||||
|
import com.chestnut.contentcore.core.SiteImportContext;
|
||||||
|
import com.chestnut.contentcore.util.InternalUrlUtils;
|
||||||
|
import com.chestnut.customform.domain.CmsCustomForm;
|
||||||
|
import com.chestnut.customform.domain.CmsCustomFormData;
|
||||||
|
import com.chestnut.customform.mapper.CustomFormDataMapper;
|
||||||
|
import com.chestnut.customform.service.ICustomFormService;
|
||||||
|
import com.chestnut.exmodel.MetaControlType_CmsImage;
|
||||||
|
import com.chestnut.exmodel.MetaControlType_UEditor;
|
||||||
|
import com.chestnut.xmodel.core.MetaModel;
|
||||||
|
import com.chestnut.xmodel.domain.XModel;
|
||||||
|
import com.chestnut.xmodel.domain.XModelField;
|
||||||
|
import com.chestnut.xmodel.service.IModelFieldService;
|
||||||
|
import com.chestnut.xmodel.service.IModelService;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义表单内容核心数据处理器
|
||||||
|
*
|
||||||
|
* @author 兮玥
|
||||||
|
* @email 190785909@qq.com
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class CustomFormCoreDataHandler implements ICoreDataHandler {
|
||||||
|
|
||||||
|
private static final String XMODEL_TABLE_SUFFIX = "_cms_custom_form";
|
||||||
|
|
||||||
|
private final ICustomFormService customFormService;
|
||||||
|
|
||||||
|
private final CustomFormDataMapper customFormDataMapper;
|
||||||
|
|
||||||
|
private final IModelService modelService;
|
||||||
|
|
||||||
|
private final IModelFieldService modelFieldService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSiteExport(SiteExportContext context) {
|
||||||
|
AsyncTaskManager.setTaskTenPercentProgressInfo("正在导出自定义表单数据");
|
||||||
|
// 自定义表单数据导出
|
||||||
|
List<CmsCustomForm> customForms = customFormService.lambdaQuery()
|
||||||
|
.eq(CmsCustomForm::getSiteId, context.getSite().getSiteId())
|
||||||
|
.list();
|
||||||
|
context.saveData(CmsCustomForm.TABLE_NAME, JacksonUtils.to(customForms));
|
||||||
|
|
||||||
|
// 自定义表单关联扩展模型
|
||||||
|
List<Long> modelIds = customForms.stream().map(CmsCustomForm::getModelId).toList();
|
||||||
|
if (modelIds.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
List<XModel> modelList = this.modelService.lambdaQuery().in(XModel::getModelId, modelIds).list();
|
||||||
|
context.saveData(XModel.TABLE_NAME + XMODEL_TABLE_SUFFIX, JacksonUtils.to(modelList));
|
||||||
|
// 扩展模型字段
|
||||||
|
List<XModelField> fieldList = this.modelFieldService.lambdaQuery()
|
||||||
|
.in(XModelField::getModelId, modelIds).list();
|
||||||
|
context.saveData(XModelField.TABLE_NAME + XMODEL_TABLE_SUFFIX, JacksonUtils.to(fieldList));
|
||||||
|
// 扩展模型数据
|
||||||
|
int pageSize = 200;
|
||||||
|
int fileIndex = 1;
|
||||||
|
for (XModel model : modelList) {
|
||||||
|
int pageIndex = 1;
|
||||||
|
while (true) {
|
||||||
|
LambdaQueryWrapper<CmsCustomFormData> q = new LambdaQueryWrapper<CmsCustomFormData>()
|
||||||
|
.eq(CmsCustomFormData::getModelId, model.getModelId());
|
||||||
|
Page<CmsCustomFormData> page = customFormDataMapper.selectPage(new Page<>(pageIndex, pageSize, false), q);
|
||||||
|
if (page.getRecords().isEmpty()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pageIndex++;
|
||||||
|
context.saveData(CmsCustomFormData.TABLE_NAME, JacksonUtils.to(page.getRecords()), fileIndex);
|
||||||
|
fileIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSiteImport(SiteImportContext context) {
|
||||||
|
// CmsCustomForm
|
||||||
|
AsyncTaskManager.setTaskTenPercentProgressInfo("正在导入自定义表单");
|
||||||
|
Map<Long, Long> customFormIdMapping = new HashMap<>();
|
||||||
|
List<File> files = context.readDataFiles(CmsCustomForm.TABLE_NAME);
|
||||||
|
files.forEach(f -> {
|
||||||
|
List<CmsCustomForm> list = JacksonUtils.fromList(f, CmsCustomForm.class);
|
||||||
|
for (CmsCustomForm data : list) {
|
||||||
|
try {
|
||||||
|
Long oldFormId = data.getFormId();
|
||||||
|
data.setFormId(IdUtils.getSnowflakeId());
|
||||||
|
data.setModelId(data.getFormId());
|
||||||
|
data.setSiteId(context.getSite().getSiteId());
|
||||||
|
data.createBy(context.getOperator());
|
||||||
|
customFormService.save(data);
|
||||||
|
customFormIdMapping.put(oldFormId, data.getFormId());
|
||||||
|
} catch (Exception e) {
|
||||||
|
AsyncTaskManager.addErrMessage("导入自定义表单失败:" + data.getName()
|
||||||
|
+ "[" + data.getModelId() + "]");
|
||||||
|
log.error("Import custom form failed: {}", data.getCode(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (files.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// XModel
|
||||||
|
AsyncTaskManager.setTaskTenPercentProgressInfo("正在导入自定义表单元数据模型");
|
||||||
|
files = context.readDataFiles(XModel.TABLE_NAME + XMODEL_TABLE_SUFFIX);
|
||||||
|
files.forEach(f -> {
|
||||||
|
List<XModel> list = JacksonUtils.fromList(f, XModel.class);
|
||||||
|
for (XModel data : list) {
|
||||||
|
try {
|
||||||
|
data.setModelId(customFormIdMapping.get(data.getModelId()));
|
||||||
|
data.setCode(data.getModelId().toString());
|
||||||
|
data.setOwnerId(context.getSite().getSiteId().toString());
|
||||||
|
data.createBy(context.getOperator());
|
||||||
|
modelService.save(data);
|
||||||
|
} catch (Exception e) {
|
||||||
|
AsyncTaskManager.addErrMessage("导入自定义表单元数据模型失败:" + data.getName()
|
||||||
|
+ "[" + data.getModelId() + "]");
|
||||||
|
log.error("Import custom form xmodel failed: {}", data.getCode(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// XModelField
|
||||||
|
AsyncTaskManager.setTaskTenPercentProgressInfo("正在导入自定义表单模型字段");
|
||||||
|
files = context.readDataFiles(XModelField.TABLE_NAME + XMODEL_TABLE_SUFFIX);
|
||||||
|
files.forEach(f -> {
|
||||||
|
List<XModelField> list = JacksonUtils.fromList(f, XModelField.class);
|
||||||
|
for (XModelField data : list) {
|
||||||
|
try {
|
||||||
|
data.setFieldId(IdUtils.getSnowflakeId());
|
||||||
|
data.setModelId(customFormIdMapping.get(data.getModelId()));
|
||||||
|
data.createBy(context.getOperator());
|
||||||
|
modelFieldService.save(data);
|
||||||
|
} catch (Exception e) {
|
||||||
|
AsyncTaskManager.addErrMessage("导入自定义表单模型字段失败:" + data.getName()
|
||||||
|
+ "[" + data.getFieldId() + "]");
|
||||||
|
log.error("Import custom form xmodel field failed: {}", data.getCode(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// CmsCustomFormData
|
||||||
|
AsyncTaskManager.setTaskTenPercentProgressInfo("正在导入自定义表单数据");
|
||||||
|
files = context.readDataFiles(CmsCustomFormData.TABLE_NAME);
|
||||||
|
files.forEach(f -> {
|
||||||
|
List<CmsCustomFormData> list = JacksonUtils.fromList(f, CmsCustomFormData.class);
|
||||||
|
for (CmsCustomFormData data : list) {
|
||||||
|
try {
|
||||||
|
data.setDataId(IdUtils.getSnowflakeId());
|
||||||
|
data.setModelId(customFormIdMapping.get(data.getModelId()));
|
||||||
|
// 处理图片和富文本内部链接
|
||||||
|
MetaModel model = modelService.getMetaModel(data.getModelId());
|
||||||
|
model.getFields().forEach(field -> {
|
||||||
|
if (MetaControlType_CmsImage.TYPE.equals(field.getControlType())) {
|
||||||
|
String fieldValue = data.getStringFieldValue(field.getFieldName());
|
||||||
|
data.setFieldValue(field.getFieldName(), context.dealInternalUrl(fieldValue));
|
||||||
|
} else if (MetaControlType_UEditor.TYPE.equals(field.getControlType())) {
|
||||||
|
String fieldValue = data.getStringFieldValue(field.getFieldName());
|
||||||
|
if (StringUtils.isNotEmpty(fieldValue)) {
|
||||||
|
// 替换正文内部资源地址
|
||||||
|
StringBuilder html = new StringBuilder();
|
||||||
|
int index = 0;
|
||||||
|
Matcher matcher = InternalUrlUtils.InternalUrlTagPattern.matcher(fieldValue);
|
||||||
|
while (matcher.find()) {
|
||||||
|
String tagStr = matcher.group();
|
||||||
|
String iurl = matcher.group(1);
|
||||||
|
String newIurl = context.dealInternalUrl(iurl);
|
||||||
|
tagStr = StringUtils.replaceEx(tagStr, iurl, newIurl);
|
||||||
|
html.append(fieldValue, index, matcher.start()).append(tagStr);
|
||||||
|
index = matcher.end();
|
||||||
|
}
|
||||||
|
html.append(fieldValue.substring(index));
|
||||||
|
data.setFieldValue(field.getFieldName(), html.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
customFormDataMapper.insert(data);
|
||||||
|
} catch (Exception e) {
|
||||||
|
AsyncTaskManager.addErrMessage("导入自定义及表单数据失败:" + data.getModelId() + "-" + data.getDataId());
|
||||||
|
log.error("Import custom form data failed: {} - {}", data.getModelId(), data.getDataId(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -51,7 +51,7 @@ public class CmsCustomForm extends BaseEntity {
|
|||||||
private Long siteId;
|
private Long siteId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 关联元数据模型ID
|
* 关联元数据模型ID(与主键form_id一致)
|
||||||
*/
|
*/
|
||||||
private Long modelId;
|
private Long modelId;
|
||||||
|
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.chestnut</groupId>
|
<groupId>com.chestnut</groupId>
|
||||||
<artifactId>chestnut-cms</artifactId>
|
<artifactId>chestnut-cms</artifactId>
|
||||||
<version>1.4.1</version>
|
<version>1.4.2</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>chestnut-cms-dynamic</artifactId>
|
<artifactId>chestnut-cms-dynamic</artifactId>
|
||||||
|
|||||||
@ -18,6 +18,7 @@ package com.chestnut.cms.dynamic.controller;
|
|||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import com.chestnut.cms.dynamic.core.IDynamicPageInitData;
|
import com.chestnut.cms.dynamic.core.IDynamicPageInitData;
|
||||||
import com.chestnut.cms.dynamic.domain.CmsDynamicPage;
|
import com.chestnut.cms.dynamic.domain.CmsDynamicPage;
|
||||||
|
import com.chestnut.cms.dynamic.domain.vo.DynamicPageInitDataTypeVO;
|
||||||
import com.chestnut.cms.dynamic.service.IDynamicPageService;
|
import com.chestnut.cms.dynamic.service.IDynamicPageService;
|
||||||
import com.chestnut.common.domain.R;
|
import com.chestnut.common.domain.R;
|
||||||
import com.chestnut.common.exception.CommonErrorCode;
|
import com.chestnut.common.exception.CommonErrorCode;
|
||||||
@ -78,7 +79,9 @@ public class DynamicPageController extends BaseRestController {
|
|||||||
|
|
||||||
@GetMapping("/init_data_types")
|
@GetMapping("/init_data_types")
|
||||||
public R<?> getInitDataTypes() {
|
public R<?> getInitDataTypes() {
|
||||||
return R.ok(initDataTypes);
|
List<DynamicPageInitDataTypeVO> list = initDataTypes.stream()
|
||||||
|
.map(DynamicPageInitDataTypeVO::newInstance).toList();
|
||||||
|
return R.ok(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/{pageId}")
|
@GetMapping("/{pageId}")
|
||||||
|
|||||||
@ -52,7 +52,7 @@ public class DynamicPageFrontController extends BaseRestController {
|
|||||||
public void handleDynamicPageRequest(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
public void handleDynamicPageRequest(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||||
Map<String, String> parameters = ServletUtils.getParameters();
|
Map<String, String> parameters = ServletUtils.getParameters();
|
||||||
String requestURI = request.getRequestURI();
|
String requestURI = request.getRequestURI();
|
||||||
System.out.println("dynamicPage: " + requestURI);
|
|
||||||
Long siteId = MapUtils.getLong(parameters, "sid", 0L);
|
Long siteId = MapUtils.getLong(parameters, "sid", 0L);
|
||||||
String publishPipeCode = parameters.get("pp");
|
String publishPipeCode = parameters.get("pp");
|
||||||
boolean preview = MapUtils.getBoolean(parameters, "preview", false);
|
boolean preview = MapUtils.getBoolean(parameters, "preview", false);
|
||||||
|
|||||||
@ -17,6 +17,8 @@ package com.chestnut.cms.dynamic.core;
|
|||||||
|
|
||||||
import com.chestnut.common.staticize.core.TemplateContext;
|
import com.chestnut.common.staticize.core.TemplateContext;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 动态页面初始化数据接口
|
* 动态页面初始化数据接口
|
||||||
*
|
*
|
||||||
@ -27,7 +29,7 @@ public interface IDynamicPageInitData {
|
|||||||
|
|
||||||
String BEAN_PREFIX = "DynamicPageInitData.";
|
String BEAN_PREFIX = "DynamicPageInitData.";
|
||||||
|
|
||||||
void initTemplateData(TemplateContext context);
|
void initTemplateData(TemplateContext context, Map<String, String> parameters);
|
||||||
|
|
||||||
String getType();
|
String getType();
|
||||||
|
|
||||||
|
|||||||
@ -22,27 +22,31 @@ import com.chestnut.member.security.StpMemberUtil;
|
|||||||
import com.chestnut.member.util.MemberUtils;
|
import com.chestnut.member.util.MemberUtils;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MemberDynamicPageInitData
|
* MemberDynamicPageInitData
|
||||||
*
|
*
|
||||||
* @author 兮玥
|
* @author 兮玥
|
||||||
* @email 190785909@qq.com
|
* @email 190785909@qq.com
|
||||||
*/
|
*/
|
||||||
@Component
|
@Component(IDynamicPageInitData.BEAN_PREFIX + MemberDynamicPageInitData.TYPE)
|
||||||
public class MemberDynamicPageInitData implements IDynamicPageInitData {
|
public class MemberDynamicPageInitData implements IDynamicPageInitData {
|
||||||
|
|
||||||
|
public static final String TYPE = "Member";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getType() {
|
public String getType() {
|
||||||
return "Member";
|
return TYPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return "登录会员";
|
return "{DYNAMIC_PAGE_INIT_DATA." + TYPE + "}";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initTemplateData(TemplateContext context) {
|
public void initTemplateData(TemplateContext context, Map<String, String> parameters) {
|
||||||
if (StpMemberUtil.isLogin()) {
|
if (StpMemberUtil.isLogin()) {
|
||||||
LoginUser loginUser = StpMemberUtil.getLoginUser();
|
LoginUser loginUser = StpMemberUtil.getLoginUser();
|
||||||
context.getVariables().put("Member", loginUser.getUser());
|
context.getVariables().put("Member", loginUser.getUser());
|
||||||
|
|||||||
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2022-2024 兮玥(190785909@qq.com)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.chestnut.cms.dynamic.core.impl;
|
||||||
|
|
||||||
|
import com.chestnut.cms.dynamic.core.IDynamicPageInitData;
|
||||||
|
import com.chestnut.common.staticize.core.TemplateContext;
|
||||||
|
import org.apache.commons.collections4.MapUtils;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PaginationDynamicPageInitData
|
||||||
|
*
|
||||||
|
* @author 兮玥
|
||||||
|
* @email 190785909@qq.com
|
||||||
|
*/
|
||||||
|
@Component(IDynamicPageInitData.BEAN_PREFIX + PaginationDynamicPageInitData.TYPE)
|
||||||
|
public class PaginationDynamicPageInitData implements IDynamicPageInitData {
|
||||||
|
|
||||||
|
public static final String TYPE = "Pagination";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getType() {
|
||||||
|
return TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "{DYNAMIC_PAGE_INIT_DATA." + TYPE + "}";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initTemplateData(TemplateContext context, Map<String, String> parameters) {
|
||||||
|
int pageIndex = MapUtils.getIntValue(parameters, "pi", 1);
|
||||||
|
context.setPageIndex(pageIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2022-2024 兮玥(190785909@qq.com)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.chestnut.cms.dynamic.domain.vo;
|
||||||
|
|
||||||
|
import com.chestnut.cms.dynamic.core.IDynamicPageInitData;
|
||||||
|
import com.chestnut.common.i18n.I18nUtils;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义动态页面初始化数据类型VO
|
||||||
|
*
|
||||||
|
* @author 兮玥
|
||||||
|
* @email 190785909@qq.com
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class DynamicPageInitDataTypeVO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 类型,唯一标识
|
||||||
|
*/
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 名称
|
||||||
|
*/
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
public static DynamicPageInitDataTypeVO newInstance(IDynamicPageInitData dynamicPageInitData) {
|
||||||
|
DynamicPageInitDataTypeVO vo = new DynamicPageInitDataTypeVO();
|
||||||
|
vo.setType(dynamicPageInitData.getType());
|
||||||
|
vo.setName(I18nUtils.get(dynamicPageInitData.getName()));
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -25,8 +25,6 @@ import java.util.Map;
|
|||||||
|
|
||||||
public interface IDynamicPageService extends IService<CmsDynamicPage> {
|
public interface IDynamicPageService extends IService<CmsDynamicPage> {
|
||||||
|
|
||||||
String getDynamicPagePath(Long siteId, String code);
|
|
||||||
|
|
||||||
void addDynamicPage(CmsDynamicPage dynamicPage);
|
void addDynamicPage(CmsDynamicPage dynamicPage);
|
||||||
|
|
||||||
void saveDynamicPage(CmsDynamicPage dynamicPage);
|
void saveDynamicPage(CmsDynamicPage dynamicPage);
|
||||||
|
|||||||
@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2022-2024 兮玥(190785909@qq.com)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.chestnut.cms.dynamic.service.impl;
|
||||||
|
|
||||||
|
import com.chestnut.cms.dynamic.core.IDynamicPageInitData;
|
||||||
|
import com.chestnut.cms.dynamic.domain.CmsDynamicPage;
|
||||||
|
import com.chestnut.common.redis.RedisCache;
|
||||||
|
import com.chestnut.contentcore.config.CMSConfig;
|
||||||
|
import com.chestnut.contentcore.core.IDynamicPageType;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class DynamicPageHelper {
|
||||||
|
|
||||||
|
private static final String CACHE_PREFIX = CMSConfig.CachePrefix + "dynamic_page:";
|
||||||
|
|
||||||
|
|
||||||
|
private final RedisCache redisCache;
|
||||||
|
|
||||||
|
private final Map<String, IDynamicPageInitData> dynamicPageInitDataMap;
|
||||||
|
|
||||||
|
private final Map<String, IDynamicPageType> dynamicPageTypeMap;
|
||||||
|
|
||||||
|
public IDynamicPageInitData getDynamicPageInitData(String type) {
|
||||||
|
return dynamicPageInitDataMap.get(IDynamicPageInitData.BEAN_PREFIX + type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDynamicPagePath(Long siteId, String code) {
|
||||||
|
IDynamicPageType dynamicPageType = this.dynamicPageTypeMap.get(IDynamicPageType.BEAN_PREFIX + code);
|
||||||
|
if (Objects.nonNull(dynamicPageType)) {
|
||||||
|
return dynamicPageType.getRequestPath();
|
||||||
|
}
|
||||||
|
CmsDynamicPage dynamicPage = getDynamicPage(siteId, code);
|
||||||
|
if (Objects.nonNull(dynamicPage)) {
|
||||||
|
return dynamicPage.getPath();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearCache(CmsDynamicPage dynamicPage) {
|
||||||
|
this.redisCache.deleteObject(CACHE_PREFIX + dynamicPage.getSiteId() + ":" + dynamicPage.getPath());
|
||||||
|
this.redisCache.deleteObject(CACHE_PREFIX + dynamicPage.getSiteId() + ":" + dynamicPage.getCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateCache(CmsDynamicPage dynamicPage) {
|
||||||
|
this.redisCache.setCacheObject(CACHE_PREFIX + dynamicPage.getSiteId() + ":" + dynamicPage.getPath(), dynamicPage);
|
||||||
|
this.redisCache.setCacheObject(CACHE_PREFIX + dynamicPage.getSiteId() + ":" + dynamicPage.getCode(), dynamicPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CmsDynamicPage getDynamicPage(Long siteId, String path) {
|
||||||
|
if (path.startsWith("/")) {
|
||||||
|
path = path.substring(1);
|
||||||
|
}
|
||||||
|
return redisCache.getCacheObject(CACHE_PREFIX + siteId + ":" + path);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -24,15 +24,12 @@ import com.chestnut.cms.dynamic.mapper.CmsDynamicPageMapper;
|
|||||||
import com.chestnut.cms.dynamic.service.IDynamicPageService;
|
import com.chestnut.cms.dynamic.service.IDynamicPageService;
|
||||||
import com.chestnut.common.exception.CommonErrorCode;
|
import com.chestnut.common.exception.CommonErrorCode;
|
||||||
import com.chestnut.common.exception.GlobalException;
|
import com.chestnut.common.exception.GlobalException;
|
||||||
import com.chestnut.common.redis.RedisCache;
|
|
||||||
import com.chestnut.common.staticize.StaticizeService;
|
import com.chestnut.common.staticize.StaticizeService;
|
||||||
import com.chestnut.common.staticize.core.TemplateContext;
|
import com.chestnut.common.staticize.core.TemplateContext;
|
||||||
import com.chestnut.common.utils.Assert;
|
import com.chestnut.common.utils.Assert;
|
||||||
import com.chestnut.common.utils.IdUtils;
|
import com.chestnut.common.utils.IdUtils;
|
||||||
import com.chestnut.common.utils.ServletUtils;
|
|
||||||
import com.chestnut.common.utils.SpringUtils;
|
import com.chestnut.common.utils.SpringUtils;
|
||||||
import com.chestnut.contentcore.config.CMSConfig;
|
import com.chestnut.contentcore.config.CMSConfig;
|
||||||
import com.chestnut.contentcore.core.IDynamicPageType;
|
|
||||||
import com.chestnut.contentcore.domain.CmsSite;
|
import com.chestnut.contentcore.domain.CmsSite;
|
||||||
import com.chestnut.contentcore.service.ISiteService;
|
import com.chestnut.contentcore.service.ISiteService;
|
||||||
import com.chestnut.contentcore.service.ITemplateService;
|
import com.chestnut.contentcore.service.ITemplateService;
|
||||||
@ -67,33 +64,17 @@ public class DynamicPageServiceImpl extends ServiceImpl<CmsDynamicPageMapper, Cm
|
|||||||
|
|
||||||
private final StaticizeService staticizeService;
|
private final StaticizeService staticizeService;
|
||||||
|
|
||||||
private final RedisCache redisCache;
|
|
||||||
|
|
||||||
private final Map<String, IDynamicPageInitData> dynamicPageInitDataMap;
|
|
||||||
|
|
||||||
private final List<RequestMappingHandlerMapping> allRequestMapping;
|
private final List<RequestMappingHandlerMapping> allRequestMapping;
|
||||||
|
|
||||||
private final DynamicPageRequestMappingHandlerMapping dynamicPageRequestMapping;
|
private final DynamicPageRequestMappingHandlerMapping dynamicPageRequestMapping;
|
||||||
|
|
||||||
private final Map<String, IDynamicPageType> dynamicPageTypeMap;
|
private final DynamicPageHelper dynamicPageHelper;
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getDynamicPagePath(Long siteId, String code) {
|
|
||||||
IDynamicPageType dynamicPageType = this.dynamicPageTypeMap.get(IDynamicPageType.BEAN_PREFIX + code);
|
|
||||||
if (Objects.nonNull(dynamicPageType)) {
|
|
||||||
return dynamicPageType.getRequestPath();
|
|
||||||
}
|
|
||||||
CmsDynamicPage dynamicPage = getDynamicPage(siteId, code);
|
|
||||||
if (Objects.nonNull(dynamicPage)) {
|
|
||||||
return dynamicPage.getPath();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addDynamicPage(CmsDynamicPage dynamicPage) {
|
public void addDynamicPage(CmsDynamicPage dynamicPage) {
|
||||||
if (!dynamicPage.getPath().startsWith("/")) {
|
if (dynamicPage.getPath().startsWith("/")) {
|
||||||
dynamicPage.setPath("/" + dynamicPage.getPath());
|
dynamicPage.setPath(dynamicPage.getPath().substring(1));
|
||||||
}
|
}
|
||||||
this.checkDynamicPage(dynamicPage);
|
this.checkDynamicPage(dynamicPage);
|
||||||
|
|
||||||
@ -102,7 +83,7 @@ public class DynamicPageServiceImpl extends ServiceImpl<CmsDynamicPageMapper, Cm
|
|||||||
|
|
||||||
this.registerDynamicPageMapping(dynamicPage);
|
this.registerDynamicPageMapping(dynamicPage);
|
||||||
|
|
||||||
this.updateCache(dynamicPage);
|
dynamicPageHelper.updateCache(dynamicPage);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -119,7 +100,7 @@ public class DynamicPageServiceImpl extends ServiceImpl<CmsDynamicPageMapper, Cm
|
|||||||
dbDynamicPage.setTemplates(dynamicPage.getTemplates());
|
dbDynamicPage.setTemplates(dynamicPage.getTemplates());
|
||||||
this.updateById(dbDynamicPage);
|
this.updateById(dbDynamicPage);
|
||||||
|
|
||||||
this.updateCache(dbDynamicPage);
|
dynamicPageHelper.updateCache(dbDynamicPage);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -129,24 +110,10 @@ public class DynamicPageServiceImpl extends ServiceImpl<CmsDynamicPageMapper, Cm
|
|||||||
|
|
||||||
dynamicPages.forEach(dynamicPage -> {
|
dynamicPages.forEach(dynamicPage -> {
|
||||||
this.unregisterDynamicPageMapping(dynamicPage);
|
this.unregisterDynamicPageMapping(dynamicPage);
|
||||||
this.clearCache(dynamicPage);
|
dynamicPageHelper.clearCache(dynamicPage);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void clearCache(CmsDynamicPage dynamicPage) {
|
|
||||||
this.redisCache.deleteObject(CACHE_PREFIX + dynamicPage.getSiteId() + ":" + dynamicPage.getPath());
|
|
||||||
this.redisCache.deleteObject(CACHE_PREFIX + dynamicPage.getSiteId() + ":" + dynamicPage.getCode());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateCache(CmsDynamicPage dynamicPage) {
|
|
||||||
this.redisCache.setCacheObject(CACHE_PREFIX + dynamicPage.getSiteId() + ":" + dynamicPage.getPath(), dynamicPage);
|
|
||||||
this.redisCache.setCacheObject(CACHE_PREFIX + dynamicPage.getSiteId() + ":" + dynamicPage.getCode(), dynamicPage);
|
|
||||||
}
|
|
||||||
|
|
||||||
private CmsDynamicPage getDynamicPage(Long siteId, String path) {
|
|
||||||
return redisCache.getCacheObject(CACHE_PREFIX + siteId + ":" + path);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkDynamicPage(CmsDynamicPage dynamicPage) {
|
private void checkDynamicPage(CmsDynamicPage dynamicPage) {
|
||||||
Long count = this.lambdaQuery()
|
Long count = this.lambdaQuery()
|
||||||
.and(wrapper -> wrapper.eq(CmsDynamicPage::getPath, dynamicPage.getPath())
|
.and(wrapper -> wrapper.eq(CmsDynamicPage::getPath, dynamicPage.getPath())
|
||||||
@ -201,7 +168,7 @@ public class DynamicPageServiceImpl extends ServiceImpl<CmsDynamicPageMapper, Cm
|
|||||||
public void run(String... args) throws Exception {
|
public void run(String... args) throws Exception {
|
||||||
// 初始化DynamicPageRequestMapping
|
// 初始化DynamicPageRequestMapping
|
||||||
this.list().forEach(dynamicPage -> {
|
this.list().forEach(dynamicPage -> {
|
||||||
this.updateCache(dynamicPage);
|
dynamicPageHelper.updateCache(dynamicPage);
|
||||||
|
|
||||||
this.registerDynamicPageMapping(dynamicPage);
|
this.registerDynamicPageMapping(dynamicPage);
|
||||||
});
|
});
|
||||||
@ -218,7 +185,7 @@ public class DynamicPageServiceImpl extends ServiceImpl<CmsDynamicPageMapper, Cm
|
|||||||
this.catchException("/", response, new RuntimeException("Site not found: " + siteId));
|
this.catchException("/", response, new RuntimeException("Site not found: " + siteId));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
CmsDynamicPage dynamicPage = this.getDynamicPage(siteId, requestURI);
|
CmsDynamicPage dynamicPage = dynamicPageHelper.getDynamicPage(siteId, requestURI);
|
||||||
String template = dynamicPage.getTemplates().get(publishPipeCode);
|
String template = dynamicPage.getTemplates().get(publishPipeCode);
|
||||||
File templateFile = this.templateService.findTemplateFile(site, template, publishPipeCode);
|
File templateFile = this.templateService.findTemplateFile(site, template, publishPipeCode);
|
||||||
if (Objects.isNull(templateFile) || !templateFile.exists()) {
|
if (Objects.isNull(templateFile) || !templateFile.exists()) {
|
||||||
@ -236,13 +203,13 @@ public class DynamicPageServiceImpl extends ServiceImpl<CmsDynamicPageMapper, Cm
|
|||||||
// init template datamode
|
// init template datamode
|
||||||
TemplateUtils.initGlobalVariables(site, templateContext);
|
TemplateUtils.initGlobalVariables(site, templateContext);
|
||||||
// init templateType data to datamode
|
// init templateType data to datamode
|
||||||
templateContext.getVariables().put("Request", ServletUtils.getParameters());
|
templateContext.getVariables().put("Request", parameters);
|
||||||
// 动态页面自定义数据
|
// 动态页面自定义数据
|
||||||
if (Objects.nonNull(dynamicPage.getInitDataTypes())) {
|
if (Objects.nonNull(dynamicPage.getInitDataTypes())) {
|
||||||
dynamicPage.getInitDataTypes().forEach(initDataType -> {
|
dynamicPage.getInitDataTypes().forEach(initDataType -> {
|
||||||
IDynamicPageInitData initData = dynamicPageInitDataMap.get(IDynamicPageInitData.BEAN_PREFIX + initDataType);
|
IDynamicPageInitData initData = dynamicPageHelper.getDynamicPageInitData(initDataType);
|
||||||
if (Objects.nonNull(initData)) {
|
if (Objects.nonNull(initData)) {
|
||||||
initData.initTemplateData(templateContext);
|
initData.initTemplateData(templateContext, parameters);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,95 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2022-2024 兮玥(190785909@qq.com)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.chestnut.cms.dynamic.template.func;
|
||||||
|
|
||||||
|
import com.chestnut.cms.dynamic.service.impl.DynamicPageHelper;
|
||||||
|
import com.chestnut.common.staticize.FreeMarkerUtils;
|
||||||
|
import com.chestnut.common.staticize.core.TemplateContext;
|
||||||
|
import com.chestnut.common.staticize.func.AbstractFunc;
|
||||||
|
import com.chestnut.common.utils.StringUtils;
|
||||||
|
import com.chestnut.contentcore.util.TemplateUtils;
|
||||||
|
import freemarker.core.Environment;
|
||||||
|
import freemarker.template.TemplateBooleanModel;
|
||||||
|
import freemarker.template.TemplateModelException;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Freemarker模板自定义函数:获取自定义动态模板链接
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class CustomDynamicPageLinkFunction extends AbstractFunc {
|
||||||
|
|
||||||
|
static final String FUNC_NAME = "customDynamicPageLink";
|
||||||
|
|
||||||
|
private static final String DESC = "{FREEMARKER.FUNC.DESC." + FUNC_NAME + "}";
|
||||||
|
|
||||||
|
private final DynamicPageHelper dynamicPageHelper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getFuncName() {
|
||||||
|
return FUNC_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDesc() {
|
||||||
|
return DESC;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object exec0(Object... args) throws TemplateModelException {
|
||||||
|
if (args.length < 1) {
|
||||||
|
return StringUtils.EMPTY;
|
||||||
|
}
|
||||||
|
String code = args[0].toString(); // 自动动态模板编码
|
||||||
|
|
||||||
|
Environment env = Environment.getCurrentEnvironment();
|
||||||
|
TemplateContext context = FreeMarkerUtils.getTemplateContext(env);
|
||||||
|
long siteId = FreeMarkerUtils.evalLongVariable(env, "Site.siteId");
|
||||||
|
String path = this.dynamicPageHelper.getDynamicPagePath(siteId, code);
|
||||||
|
if (StringUtils.isEmpty(path)) {
|
||||||
|
throw new TemplateModelException("Unknown dynamic page code: " + code);
|
||||||
|
}
|
||||||
|
if (context.isPreview()) {
|
||||||
|
path += "?preview=true";
|
||||||
|
path = TemplateUtils.appendTokenParameter(path, Environment.getCurrentEnvironment());
|
||||||
|
}
|
||||||
|
if (args.length == 2) {
|
||||||
|
String queryString = args[1].toString();
|
||||||
|
path += (path.contains("?") ? "&" : "?") + queryString;
|
||||||
|
}
|
||||||
|
boolean ignoreBaseArg = true;
|
||||||
|
if (args.length == 3) {
|
||||||
|
ignoreBaseArg = ((TemplateBooleanModel) args[2]).getAsBoolean();
|
||||||
|
}
|
||||||
|
if (context.isPreview() || !ignoreBaseArg) {
|
||||||
|
path += (path.contains("?") ? "&" : "?") + "sid=" + siteId + "&pp=" + context.getPublishPipeCode();
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<FuncArg> getFuncArgs() {
|
||||||
|
return List.of(
|
||||||
|
new FuncArg("动态页面编码", FuncArgType.String, true, null),
|
||||||
|
new FuncArg("自定义参数", FuncArgType.String, false, null),
|
||||||
|
new FuncArg("忽略sid/pp参数", FuncArgType.String, false, "默认:true")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
DYNAMIC_PAGE_INIT_DATA.Member=登录会员
|
||||||
|
DYNAMIC_PAGE_INIT_DATA.Pagination=分页参数
|
||||||
|
|
||||||
|
FREEMARKER.FUNC.DESC.customDynamicPageLink=获取自定义动态模板页面链接,例如:${customDynamicPageLink('Test','a=1&b=2',true)}
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
DYNAMIC_PAGE_INIT_DATA.Member=Member
|
||||||
|
DYNAMIC_PAGE_INIT_DATA.Pagination=Pagination
|
||||||
|
|
||||||
|
FREEMARKER.FUNC.DESC.customDynamicPageLink=Get custom dynamic page link, eg: ${customDynamicPageLink('Test','a=1&b=2',true)}
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
DYNAMIC_PAGE_INIT_DATA.Member=登錄會員
|
||||||
|
DYNAMIC_PAGE_INIT_DATA.Pagination=分頁參數
|
||||||
|
|
||||||
|
FREEMARKER.FUNC.DESC.customDynamicPageLink=獲取自定義動態模板頁面鏈接,例如:${customDynamicPageLink('Test','a=1&b=2',true)}
|
||||||
@ -7,7 +7,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.chestnut</groupId>
|
<groupId>com.chestnut</groupId>
|
||||||
<artifactId>chestnut-cms</artifactId>
|
<artifactId>chestnut-cms</artifactId>
|
||||||
<version>1.4.1</version>
|
<version>1.4.2</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>chestnut-cms-exmodel</artifactId>
|
<artifactId>chestnut-cms-exmodel</artifactId>
|
||||||
|
|||||||
@ -59,6 +59,8 @@ import java.util.regex.Matcher;
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class EXModelCoreDataHandler implements ICoreDataHandler {
|
public class EXModelCoreDataHandler implements ICoreDataHandler {
|
||||||
|
|
||||||
|
private static final String XMODEL_TABLE_SUFFIX = "_cms_exmodel";
|
||||||
|
|
||||||
private final ExtendModelMapper modelDataMapper;
|
private final ExtendModelMapper modelDataMapper;
|
||||||
|
|
||||||
private final IModelService modelService;
|
private final IModelService modelService;
|
||||||
@ -88,11 +90,11 @@ public class EXModelCoreDataHandler implements ICoreDataHandler {
|
|||||||
|
|
||||||
// 扩展模型
|
// 扩展模型
|
||||||
List<XModel> modelList = this.modelService.lambdaQuery().in(XModel::getModelId, modelIdStrings).list();
|
List<XModel> modelList = this.modelService.lambdaQuery().in(XModel::getModelId, modelIdStrings).list();
|
||||||
context.saveData(XModel.TABLE_NAME, JacksonUtils.to(modelList));
|
context.saveData(XModel.TABLE_NAME + XMODEL_TABLE_SUFFIX, JacksonUtils.to(modelList));
|
||||||
// 扩展模型字段
|
// 扩展模型字段
|
||||||
List<XModelField> fieldList = this.modelFieldService.lambdaQuery()
|
List<XModelField> fieldList = this.modelFieldService.lambdaQuery()
|
||||||
.in(XModelField::getModelId, modelIdStrings).list();
|
.in(XModelField::getModelId, modelIdStrings).list();
|
||||||
context.saveData(XModelField.TABLE_NAME, JacksonUtils.to(fieldList));
|
context.saveData(XModelField.TABLE_NAME + XMODEL_TABLE_SUFFIX, JacksonUtils.to(fieldList));
|
||||||
// 扩展模型数据
|
// 扩展模型数据
|
||||||
int pageSize = 200;
|
int pageSize = 200;
|
||||||
int fileIndex = 1;
|
int fileIndex = 1;
|
||||||
@ -117,7 +119,7 @@ public class EXModelCoreDataHandler implements ICoreDataHandler {
|
|||||||
AsyncTaskManager.setTaskTenPercentProgressInfo("正在导入扩展模型");
|
AsyncTaskManager.setTaskTenPercentProgressInfo("正在导入扩展模型");
|
||||||
// XModel
|
// XModel
|
||||||
Map<Long, Long> modelIdMapping = new HashMap<>();
|
Map<Long, Long> modelIdMapping = new HashMap<>();
|
||||||
List<File> files = context.readDataFiles(XModel.TABLE_NAME);
|
List<File> files = context.readDataFiles(XModel.TABLE_NAME + XMODEL_TABLE_SUFFIX);
|
||||||
files.forEach(f -> {
|
files.forEach(f -> {
|
||||||
List<XModel> list = JacksonUtils.fromList(f, XModel.class);
|
List<XModel> list = JacksonUtils.fromList(f, XModel.class);
|
||||||
for (XModel data : list) {
|
for (XModel data : list) {
|
||||||
@ -141,7 +143,7 @@ public class EXModelCoreDataHandler implements ICoreDataHandler {
|
|||||||
});
|
});
|
||||||
// XModelField
|
// XModelField
|
||||||
AsyncTaskManager.setTaskTenPercentProgressInfo("正在导入扩展模型字段");
|
AsyncTaskManager.setTaskTenPercentProgressInfo("正在导入扩展模型字段");
|
||||||
files = context.readDataFiles(XModelField.TABLE_NAME);
|
files = context.readDataFiles(XModelField.TABLE_NAME + XMODEL_TABLE_SUFFIX);
|
||||||
files.forEach(f -> {
|
files.forEach(f -> {
|
||||||
List<XModelField> list = JacksonUtils.fromList(f, XModelField.class);
|
List<XModelField> list = JacksonUtils.fromList(f, XModelField.class);
|
||||||
for (XModelField data : list) {
|
for (XModelField data : list) {
|
||||||
@ -198,7 +200,7 @@ public class EXModelCoreDataHandler implements ICoreDataHandler {
|
|||||||
});
|
});
|
||||||
modelDataMapper.insert(data);
|
modelDataMapper.insert(data);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
AsyncTaskManager.addErrMessage("导入扩展模型字段失败:" + data.getModelId()
|
AsyncTaskManager.addErrMessage("导入扩展模型数据失败:" + data.getModelId()
|
||||||
+ data.getDataType() + "-" + data.getDataId());
|
+ data.getDataType() + "-" + data.getDataId());
|
||||||
log.error("Import xmodel data failed: {} - {}", data.getModelId(), data.getDataId(), e);
|
log.error("Import xmodel data failed: {} - {}", data.getModelId(), data.getDataId(), e);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -52,9 +52,9 @@ public class MetaControlType_CmsImage implements IMetaControlType {
|
|||||||
String imagePath = value.toString();
|
String imagePath = value.toString();
|
||||||
if (InternalUrlUtils.isInternalUrl(imagePath)) {
|
if (InternalUrlUtils.isInternalUrl(imagePath)) {
|
||||||
String previewUrl = InternalUrlUtils.getActualPreviewUrl(imagePath);
|
String previewUrl = InternalUrlUtils.getActualPreviewUrl(imagePath);
|
||||||
fieldData.setValueSrc(previewUrl);
|
fieldData.setValueObj(previewUrl);
|
||||||
} else {
|
} else {
|
||||||
fieldData.setValueSrc(imagePath);
|
fieldData.setValueObj(imagePath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2022-2024 兮玥(190785909@qq.com)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.chestnut.exmodel;
|
||||||
|
|
||||||
|
import com.chestnut.common.utils.StringUtils;
|
||||||
|
import com.chestnut.contentcore.domain.CmsContent;
|
||||||
|
import com.chestnut.contentcore.service.IContentService;
|
||||||
|
import com.chestnut.xmodel.core.IMetaControlType;
|
||||||
|
import com.chestnut.xmodel.dto.XModelFieldDataDTO;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 元数据模型字段控件类型:内容选择
|
||||||
|
*
|
||||||
|
* @author 兮玥
|
||||||
|
* @email 190785909@qq.com
|
||||||
|
*/
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Component(IMetaControlType.BEAN_PREFIX + MetaControlType_ContentSelect.TYPE)
|
||||||
|
public class MetaControlType_ContentSelect implements IMetaControlType {
|
||||||
|
|
||||||
|
public static final String TYPE = "CMSContentSelect";
|
||||||
|
|
||||||
|
private final IContentService contentService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getType() {
|
||||||
|
return TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "{META.CONTROL_TYPE." + TYPE + "}";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void parseFieldValue(XModelFieldDataDTO fieldData) {
|
||||||
|
Object value = fieldData.getValue();
|
||||||
|
if (Objects.isNull(value) || StringUtils.isEmpty(value.toString())) {
|
||||||
|
fieldData.setValueObj(Map.of());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Optional<CmsContent> content = contentService.lambdaQuery()
|
||||||
|
.select(List.of(CmsContent::getContentId, CmsContent::getTitle))
|
||||||
|
.eq(CmsContent::getContentId, value).oneOpt();
|
||||||
|
if (content.isEmpty()) {
|
||||||
|
fieldData.setValue(StringUtils.EMPTY);
|
||||||
|
fieldData.setValueObj(Map.of());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fieldData.setValueObj(Map.of(
|
||||||
|
"contentId", content.get().getContentId(),
|
||||||
|
"title", content.get().getTitle()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -11,4 +11,5 @@ DICT.ExtendModelDataType.catalog=栏目
|
|||||||
DICT.ExtendModelDataType.content=内容
|
DICT.ExtendModelDataType.content=内容
|
||||||
|
|
||||||
META.CONTROL_TYPE.CMSImage=图片上传
|
META.CONTROL_TYPE.CMSImage=图片上传
|
||||||
META.CONTROL_TYPE.UEditor=富文本编辑器
|
META.CONTROL_TYPE.UEditor=富文本编辑器
|
||||||
|
META.CONTROL_TYPE.CMSContentSelect=内容选择
|
||||||
@ -11,4 +11,5 @@ DICT.ExtendModelDataType.catalog=Catalog
|
|||||||
DICT.ExtendModelDataType.content=Content
|
DICT.ExtendModelDataType.content=Content
|
||||||
|
|
||||||
META.CONTROL_TYPE.CMSImage=Image Upload
|
META.CONTROL_TYPE.CMSImage=Image Upload
|
||||||
META.CONTROL_TYPE.UEditor=Rich Text Editor
|
META.CONTROL_TYPE.UEditor=Rich Text Editor
|
||||||
|
META.CONTROL_TYPE.CMSContentSelect=Content Selector
|
||||||
@ -12,3 +12,4 @@ DICT.ExtendModelDataType.content=內容
|
|||||||
|
|
||||||
META.CONTROL_TYPE.CMSImage=圖片上傳
|
META.CONTROL_TYPE.CMSImage=圖片上傳
|
||||||
META.CONTROL_TYPE.UEditor=富文本編輯器
|
META.CONTROL_TYPE.UEditor=富文本編輯器
|
||||||
|
META.CONTROL_TYPE.CMSContentSelect=內容選擇
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.chestnut</groupId>
|
<groupId>com.chestnut</groupId>
|
||||||
<artifactId>chestnut-cms</artifactId>
|
<artifactId>chestnut-cms</artifactId>
|
||||||
<version>1.4.1</version>
|
<version>1.4.2</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>chestnut-cms-image</artifactId>
|
<artifactId>chestnut-cms-image</artifactId>
|
||||||
|
|||||||
@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2022-2024 兮玥(190785909@qq.com)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.chestnut.cms.image;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.chestnut.cms.image.domain.CmsImage;
|
||||||
|
import com.chestnut.cms.image.service.IImageService;
|
||||||
|
import com.chestnut.common.async.AsyncTaskManager;
|
||||||
|
import com.chestnut.common.utils.IdUtils;
|
||||||
|
import com.chestnut.common.utils.JacksonUtils;
|
||||||
|
import com.chestnut.contentcore.core.ICoreDataHandler;
|
||||||
|
import com.chestnut.contentcore.core.SiteExportContext;
|
||||||
|
import com.chestnut.contentcore.core.SiteImportContext;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图集内容扩展内容核心数据处理器
|
||||||
|
*
|
||||||
|
* @author 兮玥
|
||||||
|
* @email 190785909@qq.com
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class ImageCoreDataHandler implements ICoreDataHandler {
|
||||||
|
|
||||||
|
private final IImageService imageService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSiteExport(SiteExportContext context) {
|
||||||
|
// cms_image
|
||||||
|
AsyncTaskManager.setTaskTenPercentProgressInfo("正在导出图集内容数据");
|
||||||
|
int pageSize = 200;
|
||||||
|
long offset = 0;
|
||||||
|
int fileIndex = 1;
|
||||||
|
while (true) {
|
||||||
|
LambdaQueryWrapper<CmsImage> q = new LambdaQueryWrapper<CmsImage>()
|
||||||
|
.eq(CmsImage::getSiteId, context.getSite().getSiteId())
|
||||||
|
.gt(CmsImage::getImageId, offset)
|
||||||
|
.orderByAsc(CmsImage::getImageId);
|
||||||
|
Page<CmsImage> page = imageService.page(new Page<>(1, pageSize, false), q);
|
||||||
|
if (!page.getRecords().isEmpty()) {
|
||||||
|
context.saveData(CmsImage.TABLE_NAME, JacksonUtils.to(page.getRecords()), fileIndex);
|
||||||
|
if (page.getRecords().size() < pageSize) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
offset = page.getRecords().get(page.getRecords().size() - 1).getContentId();
|
||||||
|
fileIndex++;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSiteImport(SiteImportContext context) {
|
||||||
|
// cms_image
|
||||||
|
AsyncTaskManager.setTaskTenPercentProgressInfo("正在导入图集内容数据");
|
||||||
|
List<File> files = context.readDataFiles(CmsImage.TABLE_NAME);
|
||||||
|
files.forEach(f -> {
|
||||||
|
List<CmsImage> list = JacksonUtils.fromList(f, CmsImage.class);
|
||||||
|
for (CmsImage data : list) {
|
||||||
|
try {
|
||||||
|
data.setImageId(IdUtils.getSnowflakeId());
|
||||||
|
data.setSiteId(context.getSite().getSiteId());
|
||||||
|
data.setContentId(context.getContentIdMap().get(data.getContentId()));
|
||||||
|
data.createBy(context.getOperator());
|
||||||
|
data.setPath(context.dealInternalUrl(data.getPath()));
|
||||||
|
imageService.save(data);
|
||||||
|
} catch (Exception e) {
|
||||||
|
AsyncTaskManager.addErrMessage("导入图集内容数据失败:" + data.getTitle()
|
||||||
|
+ "[" + data.getImageId() + "]");
|
||||||
|
log.error("Import cms_image failed: {}", data.getImageId(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -7,7 +7,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.chestnut</groupId>
|
<groupId>com.chestnut</groupId>
|
||||||
<artifactId>chestnut-cms</artifactId>
|
<artifactId>chestnut-cms</artifactId>
|
||||||
<version>1.4.1</version>
|
<version>1.4.2</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>chestnut-cms-link</artifactId>
|
<artifactId>chestnut-cms-link</artifactId>
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.chestnut</groupId>
|
<groupId>com.chestnut</groupId>
|
||||||
<artifactId>chestnut-cms</artifactId>
|
<artifactId>chestnut-cms</artifactId>
|
||||||
<version>1.4.1</version>
|
<version>1.4.2</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>chestnut-cms-media</artifactId>
|
<artifactId>chestnut-cms-media</artifactId>
|
||||||
|
|||||||
@ -77,7 +77,7 @@ public class CmsVideoTag extends AbstractListTag {
|
|||||||
q.orderByAsc(CmsVideo::getSortFlag);
|
q.orderByAsc(CmsVideo::getSortFlag);
|
||||||
|
|
||||||
Page<CmsVideo> pageResult = this.videoService.page(new Page<>(pageIndex, size, page), q);
|
Page<CmsVideo> pageResult = this.videoService.page(new Page<>(pageIndex, size, page), q);
|
||||||
if (pageIndex > 1 & pageResult.getRecords().size() == 0) {
|
if (pageIndex > 1 & pageResult.getRecords().isEmpty()) {
|
||||||
throw new TemplateException("内容列表页码超出上限:" + pageIndex, env);
|
throw new TemplateException("内容列表页码超出上限:" + pageIndex, env);
|
||||||
}
|
}
|
||||||
TemplateContext context = FreeMarkerUtils.getTemplateContext(env);
|
TemplateContext context = FreeMarkerUtils.getTemplateContext(env);
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.chestnut</groupId>
|
<groupId>com.chestnut</groupId>
|
||||||
<artifactId>chestnut-cms</artifactId>
|
<artifactId>chestnut-cms</artifactId>
|
||||||
<version>1.4.1</version>
|
<version>1.4.2</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>chestnut-cms-member</artifactId>
|
<artifactId>chestnut-cms-member</artifactId>
|
||||||
|
|||||||
@ -63,7 +63,7 @@ public class AccountBindEmailDynamicPageType implements IDynamicPageType {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return "会员绑定邮箱页";
|
return "{DYNAMIC_PAGE_TYPE.NAME." + TYPE + "}";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -59,7 +59,7 @@ public class AccountCentreDynamicPageType implements IDynamicPageType {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return "个人中心页";
|
return "{DYNAMIC_PAGE_TYPE.NAME." + TYPE + "}";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -76,7 +76,7 @@ public class AccountContributeDynamicPageType implements IDynamicPageType {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return "会员投稿页";
|
return "{DYNAMIC_PAGE_TYPE.NAME." + TYPE + "}";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -47,7 +47,7 @@ public class AccountForgetPasswordDynamicPageType implements IDynamicPageType {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return "会员找回密码页";
|
return "{DYNAMIC_PAGE_TYPE.NAME." + TYPE + "}";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -47,7 +47,7 @@ public class AccountLoginDynamicPageType implements IDynamicPageType {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return "会员登录页";
|
return "{DYNAMIC_PAGE_TYPE.NAME." + TYPE + "}";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -58,12 +58,12 @@ public class AccountPasswordDynamicPageType implements IDynamicPageType {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getType() {
|
public String getType() {
|
||||||
return TYPE;
|
return "{DYNAMIC_PAGE_TYPE.NAME." + TYPE + "}";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return "会员修改密码页";
|
return "{DYNAMIC_PAGE_TYPE.NAME." + TYPE + "}";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -47,7 +47,7 @@ public class AccountRegisterDynamicPageType implements IDynamicPageType {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return "会员注册页";
|
return "{DYNAMIC_PAGE_TYPE.NAME." + TYPE + "}";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -63,7 +63,7 @@ public class AccountSettingDynamicPageType implements IDynamicPageType {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return "会员设置页";
|
return "{DYNAMIC_PAGE_TYPE.NAME." + TYPE + "}";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -9,3 +9,13 @@ FREEMARKER.TAG.DESC.cms_member_follow=获取关注/粉丝数据列表,内嵌<#
|
|||||||
|
|
||||||
# freemarker模板函数
|
# freemarker模板函数
|
||||||
FREEMARKER.FUNC.DESC.accountUrl=会员中心动态页面地址,例如:${accountUrl('comment')}
|
FREEMARKER.FUNC.DESC.accountUrl=会员中心动态页面地址,例如:${accountUrl('comment')}
|
||||||
|
|
||||||
|
# 动态模板
|
||||||
|
DYNAMIC_PAGE_TYPE.NAME.AccountBindEmail=会员绑定邮箱页
|
||||||
|
DYNAMIC_PAGE_TYPE.NAME.AccountCentre=会员个人中心页
|
||||||
|
DYNAMIC_PAGE_TYPE.NAME.AccountContribute=会员投稿页
|
||||||
|
DYNAMIC_PAGE_TYPE.NAME.AccountForgetPassword=会员找回密码页
|
||||||
|
DYNAMIC_PAGE_TYPE.NAME.AccountLogin=会员登录页
|
||||||
|
DYNAMIC_PAGE_TYPE.NAME.AccountPassword=会员修改密码页
|
||||||
|
DYNAMIC_PAGE_TYPE.NAME.AccountRegister=会员注册页
|
||||||
|
DYNAMIC_PAGE_TYPE.NAME.AccountSetting=会员设置页
|
||||||
@ -9,3 +9,13 @@ FREEMARKER.TAG.DESC.cms_member_follow=Fetch member follow/follower list, use <#l
|
|||||||
|
|
||||||
# freemarker模板函数
|
# freemarker模板函数
|
||||||
FREEMARKER.FUNC.DESC.accountUrl=Account centre page url, eg: ${accountUrl('comment')}.
|
FREEMARKER.FUNC.DESC.accountUrl=Account centre page url, eg: ${accountUrl('comment')}.
|
||||||
|
|
||||||
|
# 动态模板
|
||||||
|
DYNAMIC_PAGE_TYPE.NAME.AccountBindEmail=Account binding email page
|
||||||
|
DYNAMIC_PAGE_TYPE.NAME.AccountCentre=Account centre page
|
||||||
|
DYNAMIC_PAGE_TYPE.NAME.AccountContribute=Account contribute page
|
||||||
|
DYNAMIC_PAGE_TYPE.NAME.AccountForgetPassword=Account forget password page
|
||||||
|
DYNAMIC_PAGE_TYPE.NAME.AccountLogin=Account login page
|
||||||
|
DYNAMIC_PAGE_TYPE.NAME.AccountPassword=Account modify password page
|
||||||
|
DYNAMIC_PAGE_TYPE.NAME.AccountRegister=Account register page
|
||||||
|
DYNAMIC_PAGE_TYPE.NAME.AccountSetting=Account setting page
|
||||||
@ -9,3 +9,13 @@ FREEMARKER.TAG.DESC.cms_member_follow=獲取關注/粉絲數據列表,內嵌<#
|
|||||||
|
|
||||||
# freemarker模板函數
|
# freemarker模板函數
|
||||||
FREEMARKER.FUNC.DESC.accountUrl=會員中心動態頁面地址,例如:${accountUrl('comment')}
|
FREEMARKER.FUNC.DESC.accountUrl=會員中心動態頁面地址,例如:${accountUrl('comment')}
|
||||||
|
|
||||||
|
# 动态模板
|
||||||
|
DYNAMIC_PAGE_TYPE.NAME.AccountBindEmail=會員綁定郵箱頁
|
||||||
|
DYNAMIC_PAGE_TYPE.NAME.AccountCentre=會員個人中心頁
|
||||||
|
DYNAMIC_PAGE_TYPE.NAME.AccountContribute=會員投稿頁
|
||||||
|
DYNAMIC_PAGE_TYPE.NAME.AccountForgetPassword=會員找回密碼頁
|
||||||
|
DYNAMIC_PAGE_TYPE.NAME.AccountLogin=會員登錄頁
|
||||||
|
DYNAMIC_PAGE_TYPE.NAME.AccountPassword=會員修改密碼頁
|
||||||
|
DYNAMIC_PAGE_TYPE.NAME.AccountRegister=會員註冊頁
|
||||||
|
DYNAMIC_PAGE_TYPE.NAME.AccountSetting=會員設置頁
|
||||||
@ -7,7 +7,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.chestnut</groupId>
|
<groupId>com.chestnut</groupId>
|
||||||
<artifactId>chestnut-cms</artifactId>
|
<artifactId>chestnut-cms</artifactId>
|
||||||
<version>1.4.1</version>
|
<version>1.4.2</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>chestnut-cms-search</artifactId>
|
<artifactId>chestnut-cms-search</artifactId>
|
||||||
|
|||||||
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2022-2024 兮玥(190785909@qq.com)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.chestnut.cms.search;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CmsSearchConstants
|
||||||
|
*
|
||||||
|
* @author 兮玥
|
||||||
|
* @email 190785909@qq.com
|
||||||
|
*/
|
||||||
|
public interface CmsSearchConstants {
|
||||||
|
|
||||||
|
String SEARCH_SOURCE_PREFIX = "cms:";
|
||||||
|
|
||||||
|
static String generateSearchSource(Long siteId) {
|
||||||
|
return SEARCH_SOURCE_PREFIX + siteId;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2022-2024 兮玥(190785909@qq.com)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.chestnut.cms.search.controller;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.chestnut.cms.search.CmsSearchConstants;
|
||||||
|
import com.chestnut.common.domain.R;
|
||||||
|
import com.chestnut.common.security.anno.Priv;
|
||||||
|
import com.chestnut.common.security.web.BaseRestController;
|
||||||
|
import com.chestnut.common.security.web.PageRequest;
|
||||||
|
import com.chestnut.common.utils.ServletUtils;
|
||||||
|
import com.chestnut.common.utils.StringUtils;
|
||||||
|
import com.chestnut.contentcore.domain.CmsSite;
|
||||||
|
import com.chestnut.contentcore.service.ISiteService;
|
||||||
|
import com.chestnut.search.domain.SearchLog;
|
||||||
|
import com.chestnut.search.domain.SearchWord;
|
||||||
|
import com.chestnut.search.service.ISearchLogService;
|
||||||
|
import com.chestnut.system.security.AdminUserType;
|
||||||
|
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;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/cms/search/log")
|
||||||
|
public class CMSSearchLogController extends BaseRestController {
|
||||||
|
|
||||||
|
private final ISiteService siteService;
|
||||||
|
|
||||||
|
private final ISearchLogService searchLogService;
|
||||||
|
|
||||||
|
@Priv(type = AdminUserType.TYPE)
|
||||||
|
@GetMapping
|
||||||
|
public R<?> getPageList(@RequestParam(value = "query", required = false) String query) {
|
||||||
|
PageRequest pr = this.getPageRequest();
|
||||||
|
CmsSite site = this.siteService.getCurrentSite(ServletUtils.getRequest());
|
||||||
|
Page<SearchLog> page = this.searchLogService.lambdaQuery()
|
||||||
|
.eq(SearchLog::getSource, CmsSearchConstants.generateSearchSource(site.getSiteId()))
|
||||||
|
.like(StringUtils.isNotEmpty(query), SearchLog::getWord, query)
|
||||||
|
.orderByDesc(SearchLog::getLogId)
|
||||||
|
.page(new Page<>(pr.getPageNumber(), pr.getPageSize(), true));
|
||||||
|
return this.bindDataTable(page);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2022-2024 兮玥(190785909@qq.com)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.chestnut.cms.search.controller;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.chestnut.cms.search.CmsSearchConstants;
|
||||||
|
import com.chestnut.common.domain.R;
|
||||||
|
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.web.BaseRestController;
|
||||||
|
import com.chestnut.common.security.web.PageRequest;
|
||||||
|
import com.chestnut.common.utils.ServletUtils;
|
||||||
|
import com.chestnut.common.utils.StringUtils;
|
||||||
|
import com.chestnut.contentcore.domain.CmsSite;
|
||||||
|
import com.chestnut.contentcore.service.ISiteService;
|
||||||
|
import com.chestnut.search.domain.SearchWord;
|
||||||
|
import com.chestnut.search.service.ISearchWordService;
|
||||||
|
import com.chestnut.system.security.AdminUserType;
|
||||||
|
import com.chestnut.system.security.StpAdminUtil;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
@Priv(type = AdminUserType.TYPE)
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/cms/search/word")
|
||||||
|
public class CMSSearchWordStatController extends BaseRestController {
|
||||||
|
|
||||||
|
private final ISiteService siteService;
|
||||||
|
|
||||||
|
private final ISearchWordService searchWordStatService;
|
||||||
|
|
||||||
|
@GetMapping
|
||||||
|
public R<?> getPageList(@RequestParam(value = "query", required = false) String query) {
|
||||||
|
PageRequest pr = this.getPageRequest();
|
||||||
|
CmsSite site = this.siteService.getCurrentSite(ServletUtils.getRequest());
|
||||||
|
Page<SearchWord> page = this.searchWordStatService.lambdaQuery()
|
||||||
|
.eq(SearchWord::getSource, CmsSearchConstants.generateSearchSource(site.getSiteId()))
|
||||||
|
.like(StringUtils.isNotEmpty(query), SearchWord::getWord, query)
|
||||||
|
.orderByDesc(SearchWord::getTopFlag, SearchWord::getSearchTotal)
|
||||||
|
.page(new Page<>(pr.getPageNumber(), pr.getPageSize(), true));
|
||||||
|
return this.bindDataTable(page);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Log(title = "新增搜索词", businessType = BusinessType.INSERT)
|
||||||
|
@PostMapping
|
||||||
|
public R<?> addWord(@RequestBody SearchWord wordStat) {
|
||||||
|
CmsSite site = this.siteService.getCurrentSite(ServletUtils.getRequest());
|
||||||
|
wordStat.setSource(CmsSearchConstants.generateSearchSource(site.getSiteId()));
|
||||||
|
wordStat.createBy(StpAdminUtil.getLoginUser().getUsername());
|
||||||
|
this.searchWordStatService.addWord(wordStat);
|
||||||
|
return R.ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -19,6 +19,7 @@ import co.elastic.clients.elasticsearch.ElasticsearchClient;
|
|||||||
import co.elastic.clients.elasticsearch._types.ElasticsearchException;
|
import co.elastic.clients.elasticsearch._types.ElasticsearchException;
|
||||||
import co.elastic.clients.elasticsearch._types.SortOrder;
|
import co.elastic.clients.elasticsearch._types.SortOrder;
|
||||||
import co.elastic.clients.elasticsearch.core.SearchResponse;
|
import co.elastic.clients.elasticsearch.core.SearchResponse;
|
||||||
|
import com.chestnut.cms.search.CmsSearchConstants;
|
||||||
import com.chestnut.cms.search.es.doc.ESContent;
|
import com.chestnut.cms.search.es.doc.ESContent;
|
||||||
import com.chestnut.cms.search.vo.ESContentVO;
|
import com.chestnut.cms.search.vo.ESContentVO;
|
||||||
import com.chestnut.common.domain.R;
|
import com.chestnut.common.domain.R;
|
||||||
@ -153,7 +154,7 @@ public class SearchApiController extends BaseRestController {
|
|||||||
c.setCommentCount(cdd.getComments());
|
c.setCommentCount(cdd.getComments());
|
||||||
});
|
});
|
||||||
// 记录搜索日志
|
// 记录搜索日志
|
||||||
this.logService.addSearchLog("site:" + siteId, query, ServletUtils.getRequest());
|
this.logService.addSearchLog(CmsSearchConstants.generateSearchSource(siteId), query, ServletUtils.getRequest());
|
||||||
return this.bindDataTable(list, Objects.isNull(sr.hits().total()) ? 0 : sr.hits().total().value());
|
return this.bindDataTable(list, Objects.isNull(sr.hits().total()) ? 0 : sr.hits().total().value());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -58,7 +58,7 @@ public class SearchDynamicPageType implements IDynamicPageType {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return "搜索结果页";
|
return "{DYNAMIC_PAGE_TYPE.NAME." + TYPE + "}";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.chestnut.cms.search.properties;
|
package com.chestnut.cms.search.properties;
|
||||||
|
|
||||||
|
import com.chestnut.common.utils.StringUtils;
|
||||||
import com.chestnut.contentcore.core.IProperty;
|
import com.chestnut.contentcore.core.IProperty;
|
||||||
import com.chestnut.contentcore.util.ConfigPropertyUtils;
|
import com.chestnut.contentcore.util.ConfigPropertyUtils;
|
||||||
import com.chestnut.system.fixed.dict.YesOrNo;
|
import com.chestnut.system.fixed.dict.YesOrNo;
|
||||||
@ -29,6 +30,8 @@ import java.util.Map;
|
|||||||
public class EnableIndexProperty implements IProperty {
|
public class EnableIndexProperty implements IProperty {
|
||||||
|
|
||||||
public final static String ID = "EnableIndex";
|
public final static String ID = "EnableIndex";
|
||||||
|
|
||||||
|
private final static String DEFAULT_VALUE = YesOrNo.YES;
|
||||||
|
|
||||||
static UseType[] UseTypes = new UseType[] { UseType.Site, UseType.Catalog };
|
static UseType[] UseTypes = new UseType[] { UseType.Site, UseType.Catalog };
|
||||||
|
|
||||||
@ -49,11 +52,14 @@ public class EnableIndexProperty implements IProperty {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String defaultValue() {
|
public String defaultValue() {
|
||||||
return YesOrNo.YES;
|
return DEFAULT_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getValue(Map<String, String> firstConfigProps, Map<String, String> secondConfigProps) {
|
public static String getValue(Map<String, String> firstConfigProps, Map<String, String> secondConfigProps) {
|
||||||
String value = ConfigPropertyUtils.getStringValue(ID, firstConfigProps, secondConfigProps);
|
String value = ConfigPropertyUtils.getStringValue(ID, firstConfigProps, secondConfigProps);
|
||||||
|
if (StringUtils.isEmpty(value)) {
|
||||||
|
value = DEFAULT_VALUE;
|
||||||
|
}
|
||||||
return YesOrNo.isYes(value) ? value : YesOrNo.NO;
|
return YesOrNo.isYes(value) ? value : YesOrNo.NO;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -29,7 +29,6 @@ import com.chestnut.cms.search.properties.EnableIndexProperty;
|
|||||||
import com.chestnut.common.async.AsyncTask;
|
import com.chestnut.common.async.AsyncTask;
|
||||||
import com.chestnut.common.async.AsyncTaskManager;
|
import com.chestnut.common.async.AsyncTaskManager;
|
||||||
import com.chestnut.common.utils.Assert;
|
import com.chestnut.common.utils.Assert;
|
||||||
import com.chestnut.common.utils.DateUtils;
|
|
||||||
import com.chestnut.contentcore.core.IContent;
|
import com.chestnut.contentcore.core.IContent;
|
||||||
import com.chestnut.contentcore.core.IContentType;
|
import com.chestnut.contentcore.core.IContentType;
|
||||||
import com.chestnut.contentcore.core.impl.InternalDataType_Content;
|
import com.chestnut.contentcore.core.impl.InternalDataType_Content;
|
||||||
@ -105,7 +104,7 @@ public class ContentIndexService implements CommandLineRunner {
|
|||||||
Assert.isTrue(response.acknowledged(), () -> new RuntimeException("Create Index[cms_content] failed."));
|
Assert.isTrue(response.acknowledged(), () -> new RuntimeException("Create Index[cms_content] failed."));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void recreateIndex(CmsSite site) throws IOException {
|
public void deleteContentIndices(CmsSite site) throws IOException {
|
||||||
boolean exists = esClient.indices().exists(fn -> fn.index(ESContent.INDEX_NAME)).value();
|
boolean exists = esClient.indices().exists(fn -> fn.index(ESContent.INDEX_NAME)).value();
|
||||||
if (exists) {
|
if (exists) {
|
||||||
// 删除站点索引文档数据
|
// 删除站点索引文档数据
|
||||||
@ -119,9 +118,7 @@ public class ContentIndexService implements CommandLineRunner {
|
|||||||
.getRecords().stream().map(CmsContent::getContentId).toList();
|
.getRecords().stream().map(CmsContent::getContentId).toList();
|
||||||
deleteContentDoc(contentIds);
|
deleteContentDoc(contentIds);
|
||||||
}
|
}
|
||||||
esClient.indices().delete(fn -> fn.index(ESContent.INDEX_NAME));
|
|
||||||
}
|
}
|
||||||
this.createIndex();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -219,8 +216,8 @@ public class ContentIndexService implements CommandLineRunner {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run0() throws Exception {
|
public void run0() throws Exception {
|
||||||
// 先重建索引
|
// 先删除内容索引 TODO batchDelete
|
||||||
recreateIndex(site);
|
deleteContentIndices(site);
|
||||||
|
|
||||||
List<CmsCatalog> catalogs = catalogService.lambdaQuery()
|
List<CmsCatalog> catalogs = catalogService.lambdaQuery()
|
||||||
.eq(CmsCatalog::getSiteId, site.getSiteId()).list();
|
.eq(CmsCatalog::getSiteId, site.getSiteId()).list();
|
||||||
|
|||||||
@ -47,6 +47,7 @@ import java.util.Map;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
|
||||||
|
@Deprecated(since = "1.4.2", forRemoval = true)
|
||||||
@Component
|
@Component
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class CmsRelaContentTag extends AbstractListTag {
|
public class CmsRelaContentTag extends AbstractListTag {
|
||||||
|
|||||||
@ -17,6 +17,7 @@ package com.chestnut.cms.search.template.tag;
|
|||||||
|
|
||||||
import co.elastic.clients.elasticsearch.ElasticsearchClient;
|
import co.elastic.clients.elasticsearch.ElasticsearchClient;
|
||||||
import co.elastic.clients.elasticsearch._types.SortOrder;
|
import co.elastic.clients.elasticsearch._types.SortOrder;
|
||||||
|
import co.elastic.clients.elasticsearch._types.query_dsl.QueryBuilders;
|
||||||
import co.elastic.clients.elasticsearch.core.SearchResponse;
|
import co.elastic.clients.elasticsearch.core.SearchResponse;
|
||||||
import com.chestnut.cms.search.es.doc.ESContent;
|
import com.chestnut.cms.search.es.doc.ESContent;
|
||||||
import com.chestnut.cms.search.vo.ESContentVO;
|
import com.chestnut.cms.search.vo.ESContentVO;
|
||||||
@ -36,6 +37,7 @@ import freemarker.template.TemplateException;
|
|||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.collections4.MapUtils;
|
import org.apache.commons.collections4.MapUtils;
|
||||||
|
import org.ehcache.shadow.org.terracotta.context.query.QueryBuilder;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -64,7 +66,7 @@ public class CmsSearchContentTag extends AbstractListTag {
|
|||||||
@Override
|
@Override
|
||||||
public List<TagAttr> getTagAttrs() {
|
public List<TagAttr> getTagAttrs() {
|
||||||
List<TagAttr> tagAttrs = super.getTagAttrs();
|
List<TagAttr> tagAttrs = super.getTagAttrs();
|
||||||
tagAttrs.add(new TagAttr(ATTR_QUERY, true, TagAttrDataType.STRING, "检索词"));
|
tagAttrs.add(new TagAttr(ATTR_QUERY, false, TagAttrDataType.STRING, "检索词"));
|
||||||
tagAttrs.add(new TagAttr(ATTR_CATALOG_ID, false, TagAttrDataType.STRING, "栏目ID"));
|
tagAttrs.add(new TagAttr(ATTR_CATALOG_ID, false, TagAttrDataType.STRING, "栏目ID"));
|
||||||
tagAttrs.add(new TagAttr(ATTR_CONTENT_TYPE, false, TagAttrDataType.STRING, "内容类型"));
|
tagAttrs.add(new TagAttr(ATTR_CONTENT_TYPE, false, TagAttrDataType.STRING, "内容类型"));
|
||||||
tagAttrs.add(new TagAttr(ATTR_MODE, false, TagAttrDataType.STRING, "检索方式",
|
tagAttrs.add(new TagAttr(ATTR_MODE, false, TagAttrDataType.STRING, "检索方式",
|
||||||
@ -77,9 +79,9 @@ public class CmsSearchContentTag extends AbstractListTag {
|
|||||||
long siteId = FreeMarkerUtils.evalLongVariable(env, "Site.siteId");
|
long siteId = FreeMarkerUtils.evalLongVariable(env, "Site.siteId");
|
||||||
String mode = MapUtils.getString(attrs, ATTR_MODE, SearchMode.FullText.name());
|
String mode = MapUtils.getString(attrs, ATTR_MODE, SearchMode.FullText.name());
|
||||||
String query = MapUtils.getString(attrs, ATTR_QUERY);
|
String query = MapUtils.getString(attrs, ATTR_QUERY);
|
||||||
if (StringUtils.isEmpty(query)) {
|
// if (StringUtils.isEmpty(query)) {
|
||||||
throw new TemplateException("Tag attr `query` cannot be empty.", env);
|
// throw new TemplateException("Tag attr `query` cannot be empty.", env);
|
||||||
}
|
// }
|
||||||
String contentType = MapUtils.getString(attrs, ATTR_CONTENT_TYPE);
|
String contentType = MapUtils.getString(attrs, ATTR_CONTENT_TYPE);
|
||||||
Long catalogId = MapUtils.getLong(attrs, ATTR_CATALOG_ID);
|
Long catalogId = MapUtils.getLong(attrs, ATTR_CATALOG_ID);
|
||||||
try {
|
try {
|
||||||
@ -94,25 +96,38 @@ public class CmsSearchContentTag extends AbstractListTag {
|
|||||||
if (IdUtils.validate(catalogId)) {
|
if (IdUtils.validate(catalogId)) {
|
||||||
b.must(must -> must.term(tq -> tq.field("catalogId").value(catalogId)));
|
b.must(must -> must.term(tq -> tq.field("catalogId").value(catalogId)));
|
||||||
}
|
}
|
||||||
if (SearchMode.isFullText(mode)) {
|
if (StringUtils.isNotEmpty(query)) {
|
||||||
b.must(must -> must
|
if (SearchMode.isFullText(mode)) {
|
||||||
.multiMatch(match -> match
|
b.must(must -> must
|
||||||
.analyzer(SearchConsts.IKAnalyzeType_Smart)
|
.multiMatch(match -> match
|
||||||
.fields("title^10", "fullText^1")
|
.analyzer(SearchConsts.IKAnalyzeType_Smart)
|
||||||
.query(query)
|
.fields("title^10", "fullText^1")
|
||||||
)
|
.query(query)
|
||||||
);
|
)
|
||||||
} else {
|
);
|
||||||
b.must(should -> {
|
} else if (SearchMode.isTagAnd(mode)) {
|
||||||
String[] keywords = StringUtils.split(query, ",");
|
String[] keywords = StringUtils.split(query, ",");
|
||||||
for (String keyword : keywords) {
|
for (String keyword : keywords) {
|
||||||
should.constantScore(cs ->
|
if (StringUtils.isNotEmpty(keyword)) {
|
||||||
cs.boost(1F).filter(f ->
|
b.must(must -> must.match(term -> term.field("tags").query(keyword)));
|
||||||
f.match(m ->
|
}
|
||||||
m.field("tags").query(keyword))));
|
|
||||||
}
|
}
|
||||||
return should;
|
} else {
|
||||||
});
|
b.must(must -> {
|
||||||
|
String[] keywords = StringUtils.split(query, ",");
|
||||||
|
for (String keyword : keywords ) {
|
||||||
|
if (StringUtils.isNotEmpty(keyword)) {
|
||||||
|
must.match(m ->
|
||||||
|
m.field("tags").query(keyword));
|
||||||
|
// must.constantScore(cs ->
|
||||||
|
// cs.boost(1F).filter(f ->
|
||||||
|
// f.match(m ->
|
||||||
|
// m.field("tags").query(keyword))));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return must;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return b;
|
return b;
|
||||||
})
|
})
|
||||||
@ -184,7 +199,9 @@ public class CmsSearchContentTag extends AbstractListTag {
|
|||||||
// 所有站点
|
// 所有站点
|
||||||
FullText("全文检索"),
|
FullText("全文检索"),
|
||||||
// 当前站点
|
// 当前站点
|
||||||
Tag("标签检索,多个标签英文逗号隔开");
|
Tag("标签检索,多个标签英文逗号隔开"),
|
||||||
|
// 当前站点
|
||||||
|
TagAnd("标签检索,多个标签英文逗号隔开");
|
||||||
|
|
||||||
private final String desc;
|
private final String desc;
|
||||||
|
|
||||||
@ -200,10 +217,15 @@ public class CmsSearchContentTag extends AbstractListTag {
|
|||||||
return Tag.name().equalsIgnoreCase(mode);
|
return Tag.name().equalsIgnoreCase(mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static boolean isTagAnd(String mode) {
|
||||||
|
return TagAnd.name().equalsIgnoreCase(mode);
|
||||||
|
}
|
||||||
|
|
||||||
static List<TagAttrOption> toTagAttrOptions() {
|
static List<TagAttrOption> toTagAttrOptions() {
|
||||||
return List.of(
|
return List.of(
|
||||||
new TagAttrOption(FullText.name(), FullText.desc),
|
new TagAttrOption(FullText.name(), FullText.desc),
|
||||||
new TagAttrOption(Tag.name(), Tag.desc)
|
new TagAttrOption(Tag.name(), Tag.desc),
|
||||||
|
new TagAttrOption(TagAnd.name(), Tag.desc)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2022-2024 兮玥(190785909@qq.com)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.chestnut.cms.search.template.tag;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.chestnut.cms.search.CmsSearchConstants;
|
||||||
|
import com.chestnut.common.staticize.FreeMarkerUtils;
|
||||||
|
import com.chestnut.common.staticize.tag.AbstractListTag;
|
||||||
|
import com.chestnut.search.domain.SearchWord;
|
||||||
|
import com.chestnut.search.service.ISearchWordService;
|
||||||
|
import freemarker.core.Environment;
|
||||||
|
import freemarker.template.TemplateException;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class CmsSearchWordTag extends AbstractListTag {
|
||||||
|
|
||||||
|
public final static String TAG_NAME = "cms_search_word";
|
||||||
|
|
||||||
|
public final static String NAME = "{FREEMARKER.TAG.NAME." + TAG_NAME + "}";
|
||||||
|
public final static String DESC = "{FREEMARKER.TAG.DESC." + TAG_NAME + "}";
|
||||||
|
|
||||||
|
private final ISearchWordService searchWordService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TagPageData prepareData(Environment env, Map<String, String> attrs, boolean page, int size, int pageIndex) throws TemplateException {
|
||||||
|
long siteId = FreeMarkerUtils.evalLongVariable(env, "Site.siteId");
|
||||||
|
String source = CmsSearchConstants.generateSearchSource(siteId);
|
||||||
|
Page<SearchWord> pageResult = this.searchWordService.lambdaQuery()
|
||||||
|
.eq(SearchWord::getSource, source)
|
||||||
|
.orderByDesc(SearchWord::getTopFlag, SearchWord::getSearchTotal)
|
||||||
|
.page(new Page<>(pageIndex, size, page));
|
||||||
|
return TagPageData.of(pageResult.getRecords(), pageResult.getTotal());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getTagName() {
|
||||||
|
return TAG_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return DESC;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,5 +2,9 @@ FREEMARKER.TAG.NAME.cms_rela_content=相关内容标签
|
|||||||
FREEMARKER.TAG.DESC.cms_rela_content=相关内容标签
|
FREEMARKER.TAG.DESC.cms_rela_content=相关内容标签
|
||||||
FREEMARKER.TAG.NAME.cms_search_content=检索内容标签
|
FREEMARKER.TAG.NAME.cms_search_content=检索内容标签
|
||||||
FREEMARKER.TAG.DESC.cms_search_content=检索内容标签
|
FREEMARKER.TAG.DESC.cms_search_content=检索内容标签
|
||||||
|
FREEMARKER.TAG.NAME.cms_search_word=搜索热词标签
|
||||||
|
FREEMARKER.TAG.DESC.cms_search_word=搜索热词标签
|
||||||
|
|
||||||
CONFIG.CMSSearchAnalyzeType=索引分词方式
|
CONFIG.CMSSearchAnalyzeType=索引分词方式
|
||||||
|
|
||||||
|
DYNAMIC_PAGE_TYPE.NAME.Search=搜索结果页
|
||||||
@ -2,5 +2,9 @@ FREEMARKER.TAG.NAME.cms_rela_content=Rela content tag
|
|||||||
FREEMARKER.TAG.DESC.cms_rela_content=Rela content tag
|
FREEMARKER.TAG.DESC.cms_rela_content=Rela content tag
|
||||||
FREEMARKER.TAG.NAME.cms_search_content=Search content tag
|
FREEMARKER.TAG.NAME.cms_search_content=Search content tag
|
||||||
FREEMARKER.TAG.DESC.cms_search_content=Search content tag
|
FREEMARKER.TAG.DESC.cms_search_content=Search content tag
|
||||||
|
FREEMARKER.TAG.NAME.cms_search_word=Search hot word tag
|
||||||
|
FREEMARKER.TAG.DESC.cms_search_word=Search hot word tag
|
||||||
|
|
||||||
CONFIG.CMSSearchAnalyzeType=ES Index Analyze Type
|
CONFIG.CMSSearchAnalyzeType=ES Index Analyze Type
|
||||||
|
|
||||||
|
DYNAMIC_PAGE_TYPE.NAME.Search=Search result page
|
||||||
@ -2,5 +2,9 @@ FREEMARKER.TAG.NAME.cms_rela_content=相關內容標籤
|
|||||||
FREEMARKER.TAG.DESC.cms_rela_content=相關內容標籤
|
FREEMARKER.TAG.DESC.cms_rela_content=相關內容標籤
|
||||||
FREEMARKER.TAG.NAME.cms_search_content=檢索內容標籤
|
FREEMARKER.TAG.NAME.cms_search_content=檢索內容標籤
|
||||||
FREEMARKER.TAG.DESC.cms_search_content=檢索內容標籤
|
FREEMARKER.TAG.DESC.cms_search_content=檢索內容標籤
|
||||||
|
FREEMARKER.TAG.NAME.cms_search_word=檢索詞熱詞標籤
|
||||||
|
FREEMARKER.TAG.DESC.cms_search_word=檢索詞熱詞標籤
|
||||||
|
|
||||||
CONFIG.CMSSearchAnalyzeType=索引分詞方式
|
CONFIG.CMSSearchAnalyzeType=索引分詞方式
|
||||||
|
|
||||||
|
DYNAMIC_PAGE_TYPE.NAME.Search=搜索結果頁
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.chestnut</groupId>
|
<groupId>com.chestnut</groupId>
|
||||||
<artifactId>chestnut-cms</artifactId>
|
<artifactId>chestnut-cms</artifactId>
|
||||||
<version>1.4.1</version>
|
<version>1.4.2</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>chestnut-cms-seo</artifactId>
|
<artifactId>chestnut-cms-seo</artifactId>
|
||||||
|
|||||||
@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2022-2024 兮玥(190785909@qq.com)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.chestnut.seo.controller;
|
||||||
|
|
||||||
|
import com.chestnut.common.domain.R;
|
||||||
|
import com.chestnut.common.security.anno.Priv;
|
||||||
|
import com.chestnut.common.security.web.BaseRestController;
|
||||||
|
import com.chestnut.common.utils.ServletUtils;
|
||||||
|
import com.chestnut.contentcore.domain.CmsSite;
|
||||||
|
import com.chestnut.contentcore.service.ISiteService;
|
||||||
|
import com.chestnut.seo.service.BaiduPushService;
|
||||||
|
import com.chestnut.system.security.AdminUserType;
|
||||||
|
import jakarta.validation.constraints.NotEmpty;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 百度收录推送前端控制器
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author 兮玥
|
||||||
|
* @email 190785909@qq.com
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/cms/seo")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class SitePushController extends BaseRestController {
|
||||||
|
|
||||||
|
private final ISiteService siteService;
|
||||||
|
|
||||||
|
private final BaiduPushService baiduPushService;
|
||||||
|
|
||||||
|
@Priv(type = AdminUserType.TYPE)
|
||||||
|
@PostMapping("/baidu_push")
|
||||||
|
public R<?> generateSitemap(@RequestBody @NotEmpty List<Long> contentIds) {
|
||||||
|
CmsSite site = siteService.getCurrentSite(ServletUtils.getRequest());
|
||||||
|
|
||||||
|
List<BaiduPushService.BaiduPushResult> results = baiduPushService.pushContents(site, contentIds);
|
||||||
|
|
||||||
|
return R.ok(results);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -44,7 +44,7 @@ public class SitemapPageType extends FixedDictType {
|
|||||||
super(TYPE, "{DICT." + TYPE + "}");
|
super(TYPE, "{DICT." + TYPE + "}");
|
||||||
super.addDictData("{DICT." + TYPE + "." + PC + "}", PC, 1);
|
super.addDictData("{DICT." + TYPE + "." + PC + "}", PC, 1);
|
||||||
super.addDictData("{DICT." + TYPE + "." + Mobile + "}", Mobile, 2);
|
super.addDictData("{DICT." + TYPE + "." + Mobile + "}", Mobile, 2);
|
||||||
super.addDictData("{DICT." + TYPE + ".pc_mobile}", PC_Mobile, 3);
|
super.addDictData("{DICT." + TYPE + "." + PC_Mobile + "}", PC_Mobile, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> void decode(List<T> list, Function<T, String> getter, BiConsumer<T, String> setter) {
|
public static <T> void decode(List<T> list, Function<T, String> getter, BiConsumer<T, String> setter) {
|
||||||
|
|||||||
@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2022-2024 兮玥(190785909@qq.com)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.chestnut.seo.properties;
|
||||||
|
|
||||||
|
import com.chestnut.common.utils.StringUtils;
|
||||||
|
import com.chestnut.contentcore.core.IProperty;
|
||||||
|
import com.chestnut.contentcore.util.ConfigPropertyUtils;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 百度收录API秘钥
|
||||||
|
*
|
||||||
|
* @author 兮玥
|
||||||
|
* @email 190785909@qq.com
|
||||||
|
*/
|
||||||
|
@Component(IProperty.BEAN_NAME_PREFIX + BaiduPushAccessSecretProperty.ID)
|
||||||
|
public class BaiduPushAccessSecretProperty implements IProperty {
|
||||||
|
|
||||||
|
public final static String ID = "BaiduPushAccessSecret";
|
||||||
|
|
||||||
|
private final static String DEFAULT_VALUE = StringUtils.EMPTY;
|
||||||
|
|
||||||
|
static UseType[] UseTypes = new UseType[] { UseType.Site };
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UseType[] getUseTypes() {
|
||||||
|
return UseTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getId() {
|
||||||
|
return ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "百度收录API秘钥";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String defaultValue() {
|
||||||
|
return DEFAULT_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getValue(Map<String, String> configProps) {
|
||||||
|
String value = ConfigPropertyUtils.getStringValue(ID, configProps);
|
||||||
|
if (StringUtils.isEmpty(value)) {
|
||||||
|
value = DEFAULT_VALUE;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2022-2024 兮玥(190785909@qq.com)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.chestnut.seo.service;
|
||||||
|
|
||||||
|
import com.chestnut.common.utils.HttpUtils;
|
||||||
|
import com.chestnut.common.utils.JacksonUtils;
|
||||||
|
import com.chestnut.common.utils.StringUtils;
|
||||||
|
import com.chestnut.contentcore.domain.CmsContent;
|
||||||
|
import com.chestnut.contentcore.domain.CmsPublishPipe;
|
||||||
|
import com.chestnut.contentcore.domain.CmsSite;
|
||||||
|
import com.chestnut.contentcore.service.IContentService;
|
||||||
|
import com.chestnut.contentcore.service.IPublishPipeService;
|
||||||
|
import com.chestnut.seo.properties.BaiduPushAccessSecretProperty;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BaiduUrlPusher
|
||||||
|
*
|
||||||
|
* @author 兮玥
|
||||||
|
* @email 190785909@qq.com
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class BaiduPushService {
|
||||||
|
|
||||||
|
private final IContentService contentService;
|
||||||
|
|
||||||
|
private final IPublishPipeService publishPipeService;
|
||||||
|
|
||||||
|
private static final String API = "http://data.zz.baidu.com/urls?site={0}&token={1}";
|
||||||
|
|
||||||
|
public List<BaiduPushResult> pushContents(CmsSite site, List<Long> contentIds) {
|
||||||
|
String secret = BaiduPushAccessSecretProperty.getValue(site.getConfigProps());
|
||||||
|
if (StringUtils.isEmpty(secret)) {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
List<CmsPublishPipe> publishPipes = publishPipeService.getPublishPipes(site.getSiteId());
|
||||||
|
List<BaiduPushResult> results = new ArrayList<>(publishPipes.size());
|
||||||
|
publishPipes.forEach(pp -> {
|
||||||
|
String domain = site.getUrl(pp.getCode());
|
||||||
|
if (StringUtils.isEmpty(domain)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (domain.contains("://")) {
|
||||||
|
domain = StringUtils.substringAfter(domain, "://");
|
||||||
|
}
|
||||||
|
List<CmsContent> list = contentService.lambdaQuery().in(CmsContent::getContentId, contentIds).list();
|
||||||
|
List<String> urls = list.stream().map(content -> contentService
|
||||||
|
.getContentLink(content, 1, pp.getCode(), false)).toList();
|
||||||
|
|
||||||
|
String apiUrl = StringUtils.messageFormat(API, domain, secret);
|
||||||
|
String body = StringUtils.join(urls, "\n");
|
||||||
|
String response = HttpUtils.post(URI.create(apiUrl), body, Map.of("Content-Type", "text/plain"));
|
||||||
|
BaiduPushResult r = JacksonUtils.from(response, BaiduPushResult.class);
|
||||||
|
r.setPublishPipeCode(pp.getCode());
|
||||||
|
results.add(r);
|
||||||
|
});
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public static class BaiduPushResult {
|
||||||
|
|
||||||
|
private String publishPipeCode;
|
||||||
|
|
||||||
|
private Integer remain;
|
||||||
|
|
||||||
|
private Integer success;
|
||||||
|
|
||||||
|
private List<String> not_same_site;
|
||||||
|
|
||||||
|
private List<String> not_valid;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,4 +5,4 @@ SCHEDULED_TASK.SiteMapJobHandler=站点地图定时更新任务
|
|||||||
DICT.CMSSitemapPageType=发布通道页面类型
|
DICT.CMSSitemapPageType=发布通道页面类型
|
||||||
DICT.CMSSitemapPageType.pc=PC端
|
DICT.CMSSitemapPageType.pc=PC端
|
||||||
DICT.CMSSitemapPageType.mobile=移动端
|
DICT.CMSSitemapPageType.mobile=移动端
|
||||||
DICT.CMSSitemapPageType.pc_mobile=自适应
|
DICT.CMSSitemapPageType.pc,mobile=自适应
|
||||||
@ -5,4 +5,4 @@ SCHEDULED_TASK.SiteMapJobHandler=Sitemap Update Task
|
|||||||
DICT.CMSPublishPipePageType=发布通道页面类型
|
DICT.CMSPublishPipePageType=发布通道页面类型
|
||||||
DICT.CMSPublishPipePageType.pc=PC端
|
DICT.CMSPublishPipePageType.pc=PC端
|
||||||
DICT.CMSPublishPipePageType.mobile=移动端
|
DICT.CMSPublishPipePageType.mobile=移动端
|
||||||
DICT.CMSPublishPipePageType.pc_mobile=自适应
|
DICT.CMSPublishPipePageType.pc,mobile=自适应
|
||||||
@ -5,4 +5,4 @@ SCHEDULED_TASK.SiteMapJobHandler=站點地圖定時更新任務
|
|||||||
DICT.CMSSitemapPageType=發布通道頁面類型
|
DICT.CMSSitemapPageType=發布通道頁面類型
|
||||||
DICT.CMSSitemapPageType.pc=PC端
|
DICT.CMSSitemapPageType.pc=PC端
|
||||||
DICT.CMSSitemapPageType.mobile=移動端
|
DICT.CMSSitemapPageType.mobile=移動端
|
||||||
DICT.CMSSitemapPageType.pc_mobile=自適應
|
DICT.CMSSitemapPageType.pc,mobile=自適應
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.chestnut</groupId>
|
<groupId>com.chestnut</groupId>
|
||||||
<artifactId>chestnut-cms</artifactId>
|
<artifactId>chestnut-cms</artifactId>
|
||||||
<version>1.4.1</version>
|
<version>1.4.2</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>chestnut-cms-stat</artifactId>
|
<artifactId>chestnut-cms-stat</artifactId>
|
||||||
|
|||||||
@ -31,7 +31,7 @@ public class CmsSiteVisitLog implements Serializable {
|
|||||||
|
|
||||||
public final static String TABLE_NAME = "cms_site_visit_log";
|
public final static String TABLE_NAME = "cms_site_visit_log";
|
||||||
|
|
||||||
@TableId(value = "log_id", type = IdType.AUTO)
|
@TableId(value = "log_id", type = IdType.INPUT)
|
||||||
private Long logId;
|
private Long logId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -38,6 +38,8 @@ public class PageViewStatEventHandler implements IStatEventHandler {
|
|||||||
|
|
||||||
public static final String TYPE = "pv";
|
public static final String TYPE = "pv";
|
||||||
|
|
||||||
|
static final String CACHE_PREFIX = "cms:stat:pv:";
|
||||||
|
|
||||||
private final AsyncTaskManager asyncTaskManager;
|
private final AsyncTaskManager asyncTaskManager;
|
||||||
|
|
||||||
private final CmsSiteVisitLogMapper siteVisitLogMapper;
|
private final CmsSiteVisitLogMapper siteVisitLogMapper;
|
||||||
@ -55,7 +57,7 @@ public class PageViewStatEventHandler implements IStatEventHandler {
|
|||||||
public void handle(StatEvent event) {
|
public void handle(StatEvent event) {
|
||||||
CmsSiteVisitLog log = parseSiteVisitLog(event);
|
CmsSiteVisitLog log = parseSiteVisitLog(event);
|
||||||
// 更新Redis数据
|
// 更新Redis数据
|
||||||
this.redisCache.incrCounter("cms:pv:" + log.getUri());
|
this.redisCache.incrLongCounter(CACHE_PREFIX + log.getUri());
|
||||||
// 更新内容浏览量
|
// 更新内容浏览量
|
||||||
if (IdUtils.validate(log.getContentId())) {
|
if (IdUtils.validate(log.getContentId())) {
|
||||||
contentDynamicDataService.increaseViewCount(log.getContentId());
|
contentDynamicDataService.increaseViewCount(log.getContentId());
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.chestnut</groupId>
|
<groupId>com.chestnut</groupId>
|
||||||
<artifactId>chestnut-cms</artifactId>
|
<artifactId>chestnut-cms</artifactId>
|
||||||
<version>1.4.1</version>
|
<version>1.4.2</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>chestnut-cms-vote</artifactId>
|
<artifactId>chestnut-cms-vote</artifactId>
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.chestnut</groupId>
|
<groupId>com.chestnut</groupId>
|
||||||
<artifactId>chestnut-cms</artifactId>
|
<artifactId>chestnut-cms</artifactId>
|
||||||
<version>1.4.1</version>
|
<version>1.4.2</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>chestnut-cms-word</artifactId>
|
<artifactId>chestnut-cms-word</artifactId>
|
||||||
|
|||||||
@ -0,0 +1,129 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2022-2024 兮玥(190785909@qq.com)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.chestnut.cms.word.template.tag;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.chestnut.common.staticize.enums.TagAttrDataType;
|
||||||
|
import com.chestnut.common.staticize.tag.AbstractListTag;
|
||||||
|
import com.chestnut.common.staticize.tag.TagAttr;
|
||||||
|
import com.chestnut.common.staticize.tag.TagAttrOption;
|
||||||
|
import com.chestnut.common.utils.StringUtils;
|
||||||
|
import com.chestnut.word.domain.TagWordGroup;
|
||||||
|
import com.chestnut.word.service.ITagWordGroupService;
|
||||||
|
import freemarker.core.Environment;
|
||||||
|
import freemarker.template.TemplateException;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.apache.commons.collections4.MapUtils;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class CmsTagWordGroupTag extends AbstractListTag {
|
||||||
|
|
||||||
|
public final static String TAG_NAME = "cms_tag_word_group";
|
||||||
|
public final static String NAME = "{FREEMARKER.TAG.NAME." + TAG_NAME + "}";
|
||||||
|
public final static String DESC = "{FREEMARKER.TAG.DESC." + TAG_NAME + "}";
|
||||||
|
|
||||||
|
private static final String TAG_ATTR_CODE = "code";
|
||||||
|
|
||||||
|
private static final String TAG_ATTR_LEVEL = "level";
|
||||||
|
|
||||||
|
private final ITagWordGroupService tagWordGroupService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<TagAttr> getTagAttrs() {
|
||||||
|
List<TagAttr> tagAttrs = super.getTagAttrs();
|
||||||
|
tagAttrs.add(new TagAttr(TAG_ATTR_CODE, true, TagAttrDataType.STRING, "TAG词分组编码") );
|
||||||
|
tagAttrs.add(new TagAttr(TAG_ATTR_LEVEL, false, TagAttrDataType.STRING, "数据获取范围,值为`Root`时忽略属性code",
|
||||||
|
TagWordGroupTagLevel.toTagAttrOptions(), TagWordGroupTagLevel.Current.name()));
|
||||||
|
return tagAttrs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TagPageData prepareData(Environment env, Map<String, String> attrs, boolean page, int size, int pageIndex) throws TemplateException {
|
||||||
|
String group = MapUtils.getString(attrs, TAG_ATTR_CODE);
|
||||||
|
Optional<TagWordGroup> opt = tagWordGroupService.lambdaQuery().eq(TagWordGroup::getCode, group).oneOpt();
|
||||||
|
if (opt.isEmpty()) {
|
||||||
|
throw new TemplateException("Tag word group not found: " + group, env);
|
||||||
|
}
|
||||||
|
String level = MapUtils.getString(attrs, TAG_ATTR_LEVEL);
|
||||||
|
|
||||||
|
TagWordGroup parent = opt.get();
|
||||||
|
LambdaQueryWrapper<TagWordGroup> q = new LambdaQueryWrapper<>();
|
||||||
|
if (TagWordGroupTagLevel.isCurrent(level)) {
|
||||||
|
q.eq(TagWordGroup::getParentId, parent.getParentId());
|
||||||
|
} else if (TagWordGroupTagLevel.isChild(level)) {
|
||||||
|
q.eq(TagWordGroup::getParentId, parent.getGroupId());
|
||||||
|
}
|
||||||
|
|
||||||
|
String condition = MapUtils.getString(attrs, TagAttr.AttrName_Condition);
|
||||||
|
q.apply(StringUtils.isNotEmpty(condition), condition);
|
||||||
|
q.orderByAsc(TagWordGroup::getSortFlag);
|
||||||
|
|
||||||
|
Page<TagWordGroup> pageResult = this.tagWordGroupService.page(new Page<>(pageIndex, size, page), q);
|
||||||
|
return TagPageData.of(pageResult.getRecords(), pageResult.getTotal());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getTagName() {
|
||||||
|
return TAG_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return DESC;
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum TagWordGroupTagLevel {
|
||||||
|
Root("所有分组"), Current("同级分组"), Child("子分组");
|
||||||
|
|
||||||
|
private final String desc;
|
||||||
|
|
||||||
|
TagWordGroupTagLevel(String desc) {
|
||||||
|
this.desc = desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean isRoot(String level) {
|
||||||
|
return Root.name().equalsIgnoreCase(level);
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean isCurrent(String level) {
|
||||||
|
return Current.name().equalsIgnoreCase(level);
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean isChild(String level) {
|
||||||
|
return Child.name().equalsIgnoreCase(level);
|
||||||
|
}
|
||||||
|
|
||||||
|
static List<TagAttrOption> toTagAttrOptions() {
|
||||||
|
return List.of(
|
||||||
|
new TagAttrOption(Root.name(), Root.desc),
|
||||||
|
new TagAttrOption(Current.name(), Current.desc),
|
||||||
|
new TagAttrOption(Child.name(), Child.desc)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -4,4 +4,6 @@ FREEMARKER.FUNC.DESC.replaceSensitiveWord=替换敏感词,例如:${replaceSe
|
|||||||
|
|
||||||
# freemarker模板标签
|
# freemarker模板标签
|
||||||
FREEMARKER.TAG.NAME.cms_tag_word=TAG词列表标签
|
FREEMARKER.TAG.NAME.cms_tag_word=TAG词列表标签
|
||||||
FREEMARKER.TAG.DESC.cms_tag_word=根据TAG词分组编码获取TAG词列表,内嵌<#list DataList as tag>${tag.word}</#list>遍历数据
|
FREEMARKER.TAG.DESC.cms_tag_word=根据TAG词分组编码获取TAG词列表,内嵌<#list DataList as tag>${tag.word}</#list>遍历数据
|
||||||
|
FREEMARKER.TAG.NAME.cms_tag_word_group=TAG词分组列表标签
|
||||||
|
FREEMARKER.TAG.DESC.cms_tag_word_group=根据TAG词分组编码获取TAG词分组列表,内嵌<#list DataList as group>${group.name}</#list>遍历数据
|
||||||
@ -2,5 +2,7 @@
|
|||||||
FREEMARKER.FUNC.DESC.replaceHotWord=Replace hot word in content argument, eg: ${replaceHotWord(content, 'default', '[a href='\{0\}' target='\{2\}']\{1\}[/a]')}
|
FREEMARKER.FUNC.DESC.replaceHotWord=Replace hot word in content argument, eg: ${replaceHotWord(content, 'default', '[a href='\{0\}' target='\{2\}']\{1\}[/a]')}
|
||||||
FREEMARKER.FUNC.DESC.replaceSensitiveWord=Replace sensitive word in content argument, eg: ${replaceSensitiveWord(content, 'xxx')}
|
FREEMARKER.FUNC.DESC.replaceSensitiveWord=Replace sensitive word in content argument, eg: ${replaceSensitiveWord(content, 'xxx')}
|
||||||
|
|
||||||
FREEMARKER.TAG.NAME.cms_link=TAG Word List Tag
|
FREEMARKER.TAG.NAME.cms_tag_word=TAG Word List Tag
|
||||||
FREEMARKER.TAG.DESC.cms_link=Fetch tag-word list, use <#list> in tag like "<#list DataList as tag>${tag.word}</#list>" to walk through the list of tag-words.
|
FREEMARKER.TAG.DESC.cms_tag_word=Fetch tag-word list, use <#list> in tag like "<#list DataList as tag>${tag.word}</#list>" to walk through the list of tag-words.
|
||||||
|
FREEMARKER.TAG.NAME.cms_tag_word_group=TAG Word Group List Tag
|
||||||
|
FREEMARKER.TAG.DESC.cms_tag_word_group=Fetch tag-word-group list, use <#list> in tag like "<#list DataList as group>${group.name}</#list>" to walk through the list of tag-word-groups.
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user